[midend-GSR]将魔数求解移动到utils的静态方法中。
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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 优化候选项
|
||||
|
||||
@@ -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
|
||||
@@ -123,25 +123,24 @@ bool GlobalStrengthReductionContext::processBasicBlock(BasicBlock *bb) {
|
||||
}
|
||||
|
||||
bool GlobalStrengthReductionContext::processInstruction(Instruction *inst) {
|
||||
bool changed = false;
|
||||
|
||||
if (DEBUG >= 2) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Processing instruction: " << inst->getName() << std::endl;
|
||||
}
|
||||
|
||||
// 先尝试代数优化
|
||||
if (tryAlgebraicOptimization(inst)) {
|
||||
changed = true;
|
||||
algebraicOptCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 再尝试强度削弱
|
||||
if (tryStrengthReduction(inst)) {
|
||||
changed = true;
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -638,7 +637,9 @@ bool GlobalStrengthReductionContext::reduceDivision(BinaryInst *inst) {
|
||||
}
|
||||
|
||||
builder->setPosition(inst->getParent(), inst->getParent()->findInstIterator(inst));
|
||||
auto shiftInst = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), lhs, getConstantInt(shiftAmount));
|
||||
Value* divisor_minus_1 = ConstantInteger::get(constVal - 1);
|
||||
Value* adjusted = builder->createAddInst(lhs, divisor_minus_1);
|
||||
Value* shiftInst = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), adjusted, getConstantInt(shiftAmount));
|
||||
replaceWithOptimized(inst, shiftInst);
|
||||
strengthReductionCount++;
|
||||
return true;
|
||||
@@ -646,18 +647,11 @@ bool GlobalStrengthReductionContext::reduceDivision(BinaryInst *inst) {
|
||||
|
||||
// x / c = x * magic_number (魔数乘法优化 - 使用libdivide算法)
|
||||
if (isConstantInt(rhs, constVal) && constVal > 1 && constVal != (uint32_t)(-1)) {
|
||||
auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
|
||||
if (magicPair.first != -1) { // 有效的魔数
|
||||
if (DEBUG) {
|
||||
std::cout << " StrengthReduction: " << inst->getName()
|
||||
<< " = x / " << constVal << " -> libdivide magic multiplication" << std::endl;
|
||||
}
|
||||
|
||||
Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal), magicPair);
|
||||
replaceWithOptimized(inst, magicResult);
|
||||
divisionOptCount++;
|
||||
return true;
|
||||
}
|
||||
// auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
|
||||
Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal));
|
||||
replaceWithOptimized(inst, magicResult);
|
||||
divisionOptCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -709,251 +703,98 @@ bool GlobalStrengthReductionContext::reducePower(CallInst *inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
// 魔数乘法相关方法
|
||||
// ======================================================================
|
||||
|
||||
// 该实现参考了libdivide的算法
|
||||
std::pair<int, int> GlobalStrengthReductionContext::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;
|
||||
// 返回魔数、移位量,并在移位中编码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};
|
||||
}
|
||||
|
||||
Value* GlobalStrengthReductionContext::createMagicDivision(BinaryInst* divInst, uint32_t divisor, const MagicNumber& magic) {
|
||||
Value* GlobalStrengthReductionContext::createMagicDivisionLibdivide(BinaryInst* divInst, int divisor) {
|
||||
builder->setPosition(divInst->getParent(), divInst->getParent()->findInstIterator(divInst));
|
||||
// 使用mulh指令优化任意常数除法
|
||||
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(divisor);
|
||||
|
||||
Value* dividend = divInst->getLhs();
|
||||
|
||||
// 创建魔数常量
|
||||
Value* magicConst = getConstantInt(static_cast<int>(magic.multiplier));
|
||||
|
||||
// 执行乘法: tmp = dividend * magic
|
||||
Value* tmp = builder->createMulInst(dividend, magicConst);
|
||||
|
||||
if (magic.needAdd) {
|
||||
// 需要额外加法的情况
|
||||
Value* sum = builder->createAddInst(tmp, dividend);
|
||||
if (magic.shift > 0) {
|
||||
Value* shiftConst = getConstantInt(magic.shift);
|
||||
tmp = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), sum, shiftConst);
|
||||
} else {
|
||||
tmp = sum;
|
||||
}
|
||||
} else {
|
||||
// 直接右移
|
||||
if (magic.shift > 0) {
|
||||
Value* shiftConst = getConstantInt(magic.shift);
|
||||
tmp = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), tmp, shiftConst);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理符号:如果被除数为负,结果需要调整
|
||||
// 这里简化处理,假设都是正数除法
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Value* GlobalStrengthReductionContext::createMagicDivisionLibdivide(BinaryInst* divInst, int divisor, const std::pair<int, int>& magicPair) {
|
||||
builder->setPosition(divInst->getParent(), divInst->getParent()->findInstIterator(divInst));
|
||||
|
||||
Value* dividend = divInst->getLhs();
|
||||
int magic = magicPair.first;
|
||||
int encoded_shift = magicPair.second;
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Creating libdivide magic division: magic=" << magic
|
||||
<< ", encoded_shift=" << encoded_shift << std::endl;
|
||||
}
|
||||
|
||||
// 检查是否为2的幂(magic=0表示是2的幂)
|
||||
if (magic == 0) {
|
||||
// 2的幂除法,直接使用算术右移
|
||||
int shift = encoded_shift & 0x3F; // 获取实际移位量
|
||||
bool is_negative = (encoded_shift & 0x80) != 0;
|
||||
|
||||
// 检查是否无法优化(magic == -1, shift == -1 表示失败)
|
||||
if (magic == -1 && shift == -1) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Power of 2 division: shift=" << shift
|
||||
<< ", negative=" << is_negative << std::endl;
|
||||
std::cout << "[SR] Cannot optimize division by " << divisor
|
||||
<< ", keeping original division" << std::endl;
|
||||
}
|
||||
|
||||
Value* result = dividend;
|
||||
if (shift > 0) {
|
||||
Value* shiftConst = getConstantInt(shift);
|
||||
result = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), dividend, shiftConst);
|
||||
}
|
||||
|
||||
// 如果原除数为负,需要取反结果
|
||||
if (is_negative) {
|
||||
result = builder->createNegInst(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
// 返回 nullptr 表示无法优化,调用方应该保持原始除法
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 非2的幂除法,使用魔数乘法
|
||||
int shift = encoded_shift & 0x3F; // 获取移位量(位0-5)
|
||||
bool need_add = (encoded_shift & 0x40) != 0; // 检查ADD_MARKER标志(位6)
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Magic multiplication: shift=" << shift
|
||||
<< ", need_add=" << need_add << std::endl;
|
||||
// 2的幂次方除法可以用移位优化(但这不是魔数法的情况)这种情况应该不会被分类到这里但是还是做一个保护措施
|
||||
if ((divisor & (divisor - 1)) == 0 && divisor > 0) {
|
||||
// 是2的幂次方,可以用移位
|
||||
int shift_amount = 0;
|
||||
int temp = divisor;
|
||||
while (temp > 1) {
|
||||
temp >>= 1;
|
||||
shift_amount++;
|
||||
}
|
||||
|
||||
Value* shiftConstant = ConstantInteger::get(shift_amount);
|
||||
// 对于有符号除法,需要先加上除数-1然后再移位(为了正确处理负数舍入)
|
||||
Value* divisor_minus_1 = ConstantInteger::get(divisor - 1);
|
||||
Value* adjusted = builder->createAddInst(divInst->getOperand(0), divisor_minus_1);
|
||||
return builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
divInst->getOperand(0)->getType(),
|
||||
adjusted,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
// 创建魔数常量
|
||||
Value* magicConst = getConstantInt(magic);
|
||||
|
||||
// 执行高位乘法:mulh(dividend, magic)
|
||||
// 由于我们的IR可能没有直接的mulh指令,我们使用64位乘法然后取高32位
|
||||
// 这里需要根据实际的IR指令集进行调整
|
||||
Value* tmp = builder->createMulInst(dividend, magicConst);
|
||||
|
||||
if (need_add) {
|
||||
// ADD算法:(mulh(dividend, magic) + dividend) >> shift
|
||||
tmp = builder->createAddInst(tmp, dividend);
|
||||
// 检查魔数是否能放入32位,如果不能,则不进行优化
|
||||
if (magic > INT32_MAX || magic < INT32_MIN) {
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Magic number " << magic << " exceeds 32-bit range, skipping optimization" << std::endl;
|
||||
}
|
||||
return nullptr; // 无法优化,保持原始除法
|
||||
}
|
||||
|
||||
if (shift > 0) {
|
||||
Value* shiftConst = getConstantInt(shift);
|
||||
tmp = builder->createBinaryInst(Instruction::kSra, Type::getIntType(), tmp, shiftConst);
|
||||
Value* magicConstant = ConstantInteger::get((int32_t)magic);
|
||||
|
||||
// 检查是否需要ADD_MARKER处理(加法调整)
|
||||
bool needAdd = (shift & 0x40) != 0;
|
||||
int actualShift = shift & 0x3F; // 提取真实的移位量
|
||||
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] IR Generation: magic=" << magic << ", needAdd=" << needAdd
|
||||
<< ", actualShift=" << actualShift << std::endl;
|
||||
}
|
||||
|
||||
// 处理符号位调整
|
||||
// 如果被除数为负数,可能需要额外的符号处理
|
||||
// 这里简化处理,实际实现可能需要更复杂的符号位处理
|
||||
// 执行高位乘法:mulh(x, magic)
|
||||
Value* mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kMulh, // 高位乘法
|
||||
divInst->getOperand(0)->getType(),
|
||||
divInst->getOperand(0),
|
||||
magicConstant
|
||||
);
|
||||
|
||||
return tmp;
|
||||
if (needAdd) {
|
||||
// ADD_MARKER 情况:需要在移位前加上被除数
|
||||
// 这对应于 libdivide 的加法调整算法
|
||||
if (DEBUG) {
|
||||
std::cout << "[SR] Applying ADD_MARKER: adding dividend before shift" << std::endl;
|
||||
}
|
||||
mulhResult = builder->createAddInst(mulhResult, divInst->getOperand(0));
|
||||
}
|
||||
|
||||
if (actualShift > 0) {
|
||||
// 如果需要额外移位
|
||||
Value* shiftConstant = ConstantInteger::get(actualShift);
|
||||
mulhResult = builder->createBinaryInst(
|
||||
Instruction::Kind::kSra, // 算术右移
|
||||
divInst->getOperand(0)->getType(),
|
||||
mulhResult,
|
||||
shiftConstant
|
||||
);
|
||||
}
|
||||
|
||||
// 标准的有符号除法符号修正:如果被除数为负,商需要加1
|
||||
// 这对所有有符号除法都需要,不管是否可能有负数
|
||||
Value* isNegative = builder->createICmpLTInst(divInst->getOperand(0), ConstantInteger::get(0));
|
||||
// 将i1转换为i32:负数时为1,非负数时为0 ICmpLTInst的结果会默认转化为32位
|
||||
mulhResult = builder->createAddInst(mulhResult, isNegative);
|
||||
|
||||
return mulhResult;
|
||||
}
|
||||
|
||||
// ======================================================================
|
||||
@@ -1010,7 +851,7 @@ bool GlobalStrengthReductionContext::hasOnlyLocalUses(Instruction* inst) {
|
||||
}
|
||||
|
||||
void GlobalStrengthReductionContext::replaceWithOptimized(Instruction* original, Value* replacement) {
|
||||
if (DEBUG >= 2) {
|
||||
if (DEBUG) {
|
||||
std::cout << " Replacing " << original->getName()
|
||||
<< " with " << replacement->getName() << std::endl;
|
||||
}
|
||||
|
||||
@@ -106,187 +106,6 @@ bool StrengthReductionContext::analyzeInductionVariableRange(
|
||||
return hasNegativePotential;
|
||||
}
|
||||
|
||||
//该实现参考了libdivide的算法
|
||||
std::pair<int, int> StrengthReductionContext::computeMulhMagicNumbers(int divisor) const {
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
bool LoopStrengthReduction::runOnFunction(Function* F, AnalysisManager& AM) {
|
||||
if (F->getBasicBlocks().empty()) {
|
||||
@@ -1018,7 +837,7 @@ Value* StrengthReductionContext::generateConstantDivisionReplacement(
|
||||
IRBuilder* builder
|
||||
) const {
|
||||
// 使用mulh指令优化任意常数除法
|
||||
auto [magic, shift] = computeMulhMagicNumbers(candidate->multiplier);
|
||||
auto [magic, shift] = SysYIROptUtils::computeMulhMagicNumbers(candidate->multiplier);
|
||||
|
||||
// 检查是否无法优化(magic == -1, shift == -1 表示失败)
|
||||
if (magic == -1 && shift == -1) {
|
||||
|
||||
@@ -78,6 +78,8 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
||||
registerOptimizationPass<LICM>(builderIR);
|
||||
registerOptimizationPass<LoopStrengthReduction>(builderIR);
|
||||
registerOptimizationPass<InductionVariableElimination>();
|
||||
|
||||
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
|
||||
registerOptimizationPass<Reg2Mem>(builderIR);
|
||||
|
||||
registerOptimizationPass<SCCP>(builderIR);
|
||||
|
||||
Reference in New Issue
Block a user