Compare commits
26 Commits
midend-mem
...
backend-la
| Author | SHA1 | Date | |
|---|---|---|---|
| 6550c8a25b | |||
| e4ad23a1a5 | |||
| ec91a4e259 | |||
| 92c89f7616 | |||
| 66047dc6a3 | |||
| 22cf18a1d6 | |||
| 19a433c94f | |||
| 45dfbc8d59 | |||
| f8e423f579 | |||
| 5b43f208ac | |||
| 845f969c2e | |||
| 9c5d9ea78c | |||
| 0ce742a86e | |||
| f312792fe9 | |||
| a1cf60c420 | |||
| 004ef82488 | |||
| 8f1d592d4e | |||
| 537533ee43 | |||
| 384f7c548b | |||
| 57fe17dc21 | |||
| 373726b02f | |||
| 8fe9867f33 | |||
| 166d0fc372 | |||
| 873dbf64d0 | |||
| f387aecc03 | |||
| 03e88eee70 |
@ -60,11 +60,7 @@ display_file_content() {
|
|||||||
# 清理临时文件的函数
|
# 清理临时文件的函数
|
||||||
clean_tmp() {
|
clean_tmp() {
|
||||||
echo "正在清理临时目录: ${TMP_DIR}"
|
echo "正在清理临时目录: ${TMP_DIR}"
|
||||||
rm -rf "${TMP_DIR}"/*.s \
|
rm -rf "${TMP_DIR}"/*
|
||||||
"${TMP_DIR}"/*_sysyc_riscv64 \
|
|
||||||
"${TMP_DIR}"/*_sysyc_riscv64.actual_out \
|
|
||||||
"${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \
|
|
||||||
"${TMP_DIR}"/*_sysyc_riscv64.o
|
|
||||||
echo "清理完成。"
|
echo "清理完成。"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,7 @@ QEMU_RISCV64="qemu-riscv64"
|
|||||||
# --- 初始化变量 ---
|
# --- 初始化变量 ---
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
CLEAN_MODE=false
|
CLEAN_MODE=false
|
||||||
|
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||||
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
EXEC_TIMEOUT=5 # qemu 自动化执行超时 (秒)
|
||||||
@ -39,6 +40,7 @@ show_help() {
|
|||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
echo " -e, --executable 编译为可执行文件并运行测试 (必须)。"
|
||||||
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
echo " -c, --clean 清理 tmp 临时目录下的所有文件。"
|
||||||
|
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 5)。"
|
||||||
@ -68,7 +70,7 @@ display_file_content() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- 本次修改点: 整个参数解析逻辑被重写 ---
|
# --- 参数解析 ---
|
||||||
# 使用标准的 while 循环来健壮地处理任意顺序的参数
|
# 使用标准的 while 循环来健壮地处理任意顺序的参数
|
||||||
while [[ "$#" -gt 0 ]]; do
|
while [[ "$#" -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -80,6 +82,10 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
CLEAN_MODE=true
|
CLEAN_MODE=true
|
||||||
shift # 消耗选项
|
shift # 消耗选项
|
||||||
;;
|
;;
|
||||||
|
-O1)
|
||||||
|
OPTIMIZE_FLAG="-O1"
|
||||||
|
shift # 消耗选项
|
||||||
|
;;
|
||||||
-sct)
|
-sct)
|
||||||
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then SYSYC_TIMEOUT="$2"; shift 2; else echo "错误: -sct 需要一个正整数参数。" >&2; exit 1; fi
|
||||||
;;
|
;;
|
||||||
@ -144,6 +150,7 @@ mkdir -p "${TMP_DIR}"
|
|||||||
TOTAL_CASES=${#SY_FILES[@]}
|
TOTAL_CASES=${#SY_FILES[@]}
|
||||||
|
|
||||||
echo "SysY 单例测试运行器启动..."
|
echo "SysY 单例测试运行器启动..."
|
||||||
|
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
echo ""
|
echo ""
|
||||||
@ -164,9 +171,21 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
echo "======================================================================"
|
echo "======================================================================"
|
||||||
echo "正在处理: ${sy_file}"
|
echo "正在处理: ${sy_file}"
|
||||||
|
|
||||||
|
# --- 本次修改点: 拷贝源文件到 tmp 目录 ---
|
||||||
|
echo " 拷贝源文件到 ${TMP_DIR}..."
|
||||||
|
cp "${sy_file}" "${TMP_DIR}/$(basename "${sy_file}")"
|
||||||
|
if [ -f "${input_file}" ]; then
|
||||||
|
cp "${input_file}" "${TMP_DIR}/$(basename "${input_file}")"
|
||||||
|
fi
|
||||||
|
if [ -f "${output_reference_file}" ]; then
|
||||||
|
cp "${output_reference_file}" "${TMP_DIR}/$(basename "${output_reference_file}")"
|
||||||
|
fi
|
||||||
|
|
||||||
# 步骤 1: sysyc 编译
|
# 步骤 1: sysyc 编译
|
||||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" > "${ir_file}"
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" ${OPTIMIZE_FLAG} -o "${assembly_file}"
|
||||||
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s ir "${sy_file}" ${OPTIMIZE_FLAG} > "${ir_file}"
|
||||||
|
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
||||||
SYSYC_STATUS=$?
|
SYSYC_STATUS=$?
|
||||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
|
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR超时\e[0m"
|
||||||
@ -175,12 +194,10 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败,退出码: ${SYSYC_STATUS}\e[0m"
|
echo -e "\e[31m错误: SysY 编译 ${sy_file} IR失败,退出码: ${SYSYC_STATUS}\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
echo -e "\e[31m错误: SysY 编译失败或超时。\e[0m"
|
||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
# timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -s asmd "${sy_file}" > "${assembly_debug_file}" 2>&1
|
|
||||||
|
|
||||||
# 步骤 2: GCC 编译
|
# 步骤 2: GCC 编译
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
|
|||||||
@ -16,8 +16,8 @@ SYSYC="${BUILD_BIN_DIR}/sysyc"
|
|||||||
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
GCC_RISCV64="riscv64-linux-gnu-gcc"
|
||||||
QEMU_RISCV64="qemu-riscv64"
|
QEMU_RISCV64="qemu-riscv64"
|
||||||
|
|
||||||
# --- 新增功能: 初始化变量 ---
|
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
|
OPTIMIZE_FLAG="" # 用于存储 -O1 标志
|
||||||
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
SYSYC_TIMEOUT=10 # sysyc 编译超时 (秒)
|
||||||
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
GCC_TIMEOUT=10 # gcc 编译超时 (秒)
|
||||||
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
EXEC_TIMEOUT=5 # qemu 执行超时 (秒)
|
||||||
@ -35,6 +35,7 @@ show_help() {
|
|||||||
echo "选项:"
|
echo "选项:"
|
||||||
echo " -e, --executable 编译为可执行文件并运行测试。"
|
echo " -e, --executable 编译为可执行文件并运行测试。"
|
||||||
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
|
||||||
|
echo " -O1 启用 sysyc 的 -O1 优化。"
|
||||||
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
echo " -set [f|h|p|all]... 指定要运行的测试集 (functional, h_functional, performance)。可多选,默认为 all。"
|
||||||
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
echo " -sct N 设置 sysyc 编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
@ -85,9 +86,12 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
clean_tmp
|
clean_tmp
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
-O1)
|
||||||
|
OPTIMIZE_FLAG="-O1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
-set)
|
-set)
|
||||||
shift # 移过 '-set'
|
shift # 移过 '-set'
|
||||||
# 消耗所有后续参数直到遇到下一个选项
|
|
||||||
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
|
while [[ "$#" -gt 0 && ! "$1" =~ ^- ]]; do
|
||||||
TEST_SETS+=("$1")
|
TEST_SETS+=("$1")
|
||||||
shift
|
shift
|
||||||
@ -125,7 +129,6 @@ SET_MAP[p]="performance"
|
|||||||
|
|
||||||
SEARCH_PATHS=()
|
SEARCH_PATHS=()
|
||||||
|
|
||||||
# 如果未指定测试集,或指定了 'all',则搜索所有目录
|
|
||||||
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
if [ ${#TEST_SETS[@]} -eq 0 ] || [[ " ${TEST_SETS[@]} " =~ " all " ]]; then
|
||||||
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
SEARCH_PATHS+=("${TESTDATA_DIR}")
|
||||||
else
|
else
|
||||||
@ -138,13 +141,13 @@ else
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 如果没有有效的搜索路径,则退出
|
|
||||||
if [ ${#SEARCH_PATHS[@]} -eq 0 ]; then
|
if [ ${#SEARCH_PATHS[@]} -eq 0 ]; then
|
||||||
echo -e "\e[31m错误: 没有找到有效的测试集目录,测试中止。\e[0m"
|
echo -e "\e[31m错误: 没有找到有效的测试集目录,测试中止。\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "SysY 测试运行器启动..."
|
echo "SysY 测试运行器启动..."
|
||||||
|
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||||
echo "输入目录: ${SEARCH_PATHS[@]}"
|
echo "输入目录: ${SEARCH_PATHS[@]}"
|
||||||
echo "临时目录: ${TMP_DIR}"
|
echo "临时目录: ${TMP_DIR}"
|
||||||
echo "执行模式: ${EXECUTE_MODE}"
|
echo "执行模式: ${EXECUTE_MODE}"
|
||||||
@ -154,7 +157,6 @@ if ${EXECUTE_MODE}; then
|
|||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# 使用构建好的路径查找 .sy 文件并排序
|
|
||||||
sy_files=$(find "${SEARCH_PATHS[@]}" -name "*.sy" | sort -V)
|
sy_files=$(find "${SEARCH_PATHS[@]}" -name "*.sy" | sort -V)
|
||||||
if [ -z "$sy_files" ]; then
|
if [ -z "$sy_files" ]; then
|
||||||
echo "在指定目录中未找到任何 .sy 文件。"
|
echo "在指定目录中未找到任何 .sy 文件。"
|
||||||
@ -162,7 +164,6 @@ if [ -z "$sy_files" ]; then
|
|||||||
fi
|
fi
|
||||||
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
TOTAL_CASES=$(echo "$sy_files" | wc -w)
|
||||||
|
|
||||||
# --- 修复: 使用 here-string (<<<) 代替管道 (|) 来避免子 shell 问题 ---
|
|
||||||
while IFS= read -r sy_file; do
|
while IFS= read -r sy_file; do
|
||||||
is_passed=1 # 1 表示通过, 0 表示失败
|
is_passed=1 # 1 表示通过, 0 表示失败
|
||||||
|
|
||||||
@ -176,10 +177,8 @@ while IFS= read -r sy_file; do
|
|||||||
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
|
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
|
||||||
|
|
||||||
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
echo "正在处理: $(basename "$sy_file") (路径: ${relative_path_no_ext}.sy)"
|
||||||
|
|
||||||
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
|
|
||||||
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
echo " 使用 sysyc 编译 (超时 ${SYSYC_TIMEOUT}s)..."
|
||||||
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}"
|
timeout -s KILL ${SYSYC_TIMEOUT} "${SYSYC}" -S "${sy_file}" -o "${assembly_file}" ${OPTIMIZE_FLAG}
|
||||||
SYSYC_STATUS=$?
|
SYSYC_STATUS=$?
|
||||||
if [ $SYSYC_STATUS -eq 124 ]; then
|
if [ $SYSYC_STATUS -eq 124 ]; then
|
||||||
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
echo -e "\e[31m错误: SysY 编译 ${sy_file} 超时\e[0m"
|
||||||
@ -189,9 +188,7 @@ while IFS= read -r sy_file; do
|
|||||||
is_passed=0
|
is_passed=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 只有当 EXECUTE_MODE 为 true 且上一步成功时才继续
|
|
||||||
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
if ${EXECUTE_MODE} && [ "$is_passed" -eq 1 ]; then
|
||||||
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
|
|
||||||
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
echo " 使用 gcc 编译 (超时 ${GCC_TIMEOUT}s)..."
|
||||||
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
timeout -s KILL ${GCC_TIMEOUT} "${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
|
||||||
GCC_STATUS=$?
|
GCC_STATUS=$?
|
||||||
@ -213,7 +210,6 @@ while IFS= read -r sy_file; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 步骤 3, 4, 5: 只有当编译都成功时才执行
|
|
||||||
if [ "$is_passed" -eq 1 ]; then
|
if [ "$is_passed" -eq 1 ]; then
|
||||||
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
echo " 正在执行 (超时 ${EXEC_TIMEOUT}s)..."
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,11 @@ add_library(riscv64_backend_lib STATIC
|
|||||||
Handler/CalleeSavedHandler.cpp
|
Handler/CalleeSavedHandler.cpp
|
||||||
Handler/LegalizeImmediates.cpp
|
Handler/LegalizeImmediates.cpp
|
||||||
Handler/PrologueEpilogueInsertion.cpp
|
Handler/PrologueEpilogueInsertion.cpp
|
||||||
|
Handler/EliminateFrameIndices.cpp
|
||||||
Optimize/Peephole.cpp
|
Optimize/Peephole.cpp
|
||||||
Optimize/PostRA_Scheduler.cpp
|
Optimize/PostRA_Scheduler.cpp
|
||||||
Optimize/PreRA_Scheduler.cpp
|
Optimize/PreRA_Scheduler.cpp
|
||||||
|
Optimize/DivStrengthReduction.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 包含后端模块所需的头文件路径
|
# 包含后端模块所需的头文件路径
|
||||||
|
|||||||
@ -8,11 +8,6 @@ namespace sysy {
|
|||||||
|
|
||||||
char CalleeSavedHandler::ID = 0;
|
char CalleeSavedHandler::ID = 0;
|
||||||
|
|
||||||
// 辅助函数,用于判断一个物理寄存器是否为浮点寄存器
|
|
||||||
static bool is_fp_reg(PhysicalReg reg) {
|
|
||||||
return reg >= PhysicalReg::F0 && reg <= PhysicalReg::F31;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
// This pass works on MachineFunction level, not IR level
|
// This pass works on MachineFunction level, not IR level
|
||||||
return false;
|
return false;
|
||||||
@ -20,114 +15,37 @@ bool CalleeSavedHandler::runOnFunction(Function *F, AnalysisManager& AM) {
|
|||||||
|
|
||||||
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
void CalleeSavedHandler::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
|
const std::set<PhysicalReg>& used_callee_saved = frame_info.used_callee_saved_regs;
|
||||||
std::set<PhysicalReg> used_callee_saved;
|
|
||||||
|
|
||||||
// 1. 扫描所有指令,找出被使用的callee-saved寄存器
|
|
||||||
// 这个Pass在RegAlloc之后运行,所以可以访问到物理寄存器
|
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
|
||||||
for (auto& instr : mbb->getInstructions()) {
|
|
||||||
for (auto& op : instr->getOperands()) {
|
|
||||||
|
|
||||||
auto check_and_insert_reg = [&](RegOperand* reg_op) {
|
|
||||||
if (reg_op && !reg_op->isVirtual()) {
|
|
||||||
PhysicalReg preg = reg_op->getPReg();
|
|
||||||
|
|
||||||
// 检查整数 s1-s11
|
|
||||||
if (preg >= PhysicalReg::S1 && preg <= PhysicalReg::S11) {
|
|
||||||
used_callee_saved.insert(preg);
|
|
||||||
}
|
|
||||||
// 检查浮点 fs0-fs11 (f8,f9,f18-f27)
|
|
||||||
else if ((preg >= PhysicalReg::F8 && preg <= PhysicalReg::F9) || (preg >= PhysicalReg::F18 && preg <= PhysicalReg::F27)) {
|
|
||||||
used_callee_saved.insert(preg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (op->getKind() == MachineOperand::KIND_REG) {
|
|
||||||
check_and_insert_reg(static_cast<RegOperand*>(op.get()));
|
|
||||||
} else if (op->getKind() == MachineOperand::KIND_MEM) {
|
|
||||||
check_and_insert_reg(static_cast<MemOperand*>(op.get())->getBase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (used_callee_saved.empty()) {
|
if (used_callee_saved.empty()) {
|
||||||
frame_info.callee_saved_size = 0;
|
frame_info.callee_saved_size = 0;
|
||||||
|
frame_info.callee_saved_regs_to_store.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 计算并更新 frame_info
|
// 1. 计算被调用者保存寄存器所需的总空间大小
|
||||||
frame_info.callee_saved_size = used_callee_saved.size() * 8;
|
// s0 总是由 PEI Pass 单独处理,这里不计入大小,但要确保它在列表中
|
||||||
|
int size = 0;
|
||||||
// 为了布局确定性和恢复顺序一致,对寄存器排序
|
std::set<PhysicalReg> regs_to_save = used_callee_saved;
|
||||||
std::vector<PhysicalReg> sorted_regs(used_callee_saved.begin(), used_callee_saved.end());
|
if (regs_to_save.count(PhysicalReg::S0)) {
|
||||||
std::sort(sorted_regs.begin(), sorted_regs.end());
|
regs_to_save.erase(PhysicalReg::S0);
|
||||||
|
|
||||||
// 3. 在函数序言中插入保存指令
|
|
||||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
|
||||||
auto& entry_instrs = entry_block->getInstructions();
|
|
||||||
// 插入点在函数入口标签之后,或者就是最开始
|
|
||||||
auto insert_pos = entry_instrs.begin();
|
|
||||||
if (!entry_instrs.empty() && entry_instrs.front()->getOpcode() == RVOpcodes::LABEL) {
|
|
||||||
insert_pos = std::next(insert_pos);
|
|
||||||
}
|
}
|
||||||
|
size = regs_to_save.size() * 8; // 每个寄存器占8字节 (64-bit)
|
||||||
std::vector<std::unique_ptr<MachineInstr>> save_instrs;
|
frame_info.callee_saved_size = size;
|
||||||
// [关键] 从局部变量区域之后开始分配空间
|
|
||||||
int current_offset = - (16 + frame_info.locals_size);
|
|
||||||
|
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
// 2. 创建一个有序的、需要保存的寄存器列表,以便后续 Pass 确定地生成代码
|
||||||
current_offset -= 8;
|
// s0 不应包含在此列表中,因为它由 PEI Pass 特殊处理
|
||||||
RVOpcodes save_op = is_fp_reg(reg) ? RVOpcodes::FSD : RVOpcodes::SD;
|
std::vector<PhysicalReg> sorted_regs(regs_to_save.begin(), regs_to_save.end());
|
||||||
|
std::sort(sorted_regs.begin(), sorted_regs.end(), [](PhysicalReg a, PhysicalReg b){
|
||||||
|
return static_cast<int>(a) < static_cast<int>(b);
|
||||||
|
});
|
||||||
|
frame_info.callee_saved_regs_to_store = sorted_regs;
|
||||||
|
|
||||||
auto save_instr = std::make_unique<MachineInstr>(save_op);
|
// 3. 更新栈帧总大小。
|
||||||
save_instr->addOperand(std::make_unique<RegOperand>(reg));
|
// 这是初步计算,PEI Pass 会进行最终的对齐。
|
||||||
save_instr->addOperand(std::make_unique<MemOperand>(
|
frame_info.total_size = frame_info.locals_size +
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针 s0
|
frame_info.spill_size +
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
frame_info.callee_saved_size;
|
||||||
));
|
|
||||||
save_instrs.push_back(std::move(save_instr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!save_instrs.empty()) {
|
|
||||||
entry_instrs.insert(insert_pos,
|
|
||||||
std::make_move_iterator(save_instrs.begin()),
|
|
||||||
std::make_move_iterator(save_instrs.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 在函数结尾(ret之前)插入恢复指令
|
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
|
||||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
|
||||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
|
||||||
std::vector<std::unique_ptr<MachineInstr>> restore_instrs;
|
|
||||||
// [关键] 使用与保存时完全相同的逻辑来计算偏移量
|
|
||||||
current_offset = - (16 + frame_info.locals_size);
|
|
||||||
|
|
||||||
for (PhysicalReg reg : sorted_regs) {
|
|
||||||
current_offset -= 8;
|
|
||||||
RVOpcodes restore_op = is_fp_reg(reg) ? RVOpcodes::FLD : RVOpcodes::LD;
|
|
||||||
|
|
||||||
auto restore_instr = std::make_unique<MachineInstr>(restore_op);
|
|
||||||
restore_instr->addOperand(std::make_unique<RegOperand>(reg));
|
|
||||||
restore_instr->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(current_offset)
|
|
||||||
));
|
|
||||||
restore_instrs.push_back(std::move(restore_instr));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!restore_instrs.empty()) {
|
|
||||||
mbb->getInstructions().insert(it,
|
|
||||||
std::make_move_iterator(restore_instrs.begin()),
|
|
||||||
std::make_move_iterator(restore_instrs.end()));
|
|
||||||
}
|
|
||||||
goto next_block_label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next_block_label:;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
235
src/backend/RISCv64/Handler/EliminateFrameIndices.cpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
#include "EliminateFrameIndices.h"
|
||||||
|
#include "RISCv64ISel.h"
|
||||||
|
#include <cassert>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
// getTypeSizeInBytes 是一个通用辅助函数,保持不变
|
||||||
|
unsigned EliminateFrameIndicesPass::getTypeSizeInBytes(Type* type) {
|
||||||
|
if (!type) {
|
||||||
|
assert(false && "Cannot get size of a null type.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type->getKind()) {
|
||||||
|
case Type::kInt:
|
||||||
|
case Type::kFloat:
|
||||||
|
return 4;
|
||||||
|
case Type::kPointer:
|
||||||
|
return 8;
|
||||||
|
case Type::kArray: {
|
||||||
|
auto arrayType = type->as<ArrayType>();
|
||||||
|
return arrayType->getNumElements() * getTypeSizeInBytes(arrayType->getElementType());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(false && "Unsupported type for size calculation.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EliminateFrameIndicesPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
|
Function* F = mfunc->getFunc();
|
||||||
|
RISCv64ISel* isel = mfunc->getISel();
|
||||||
|
|
||||||
|
// 在这里处理栈传递的参数,以便在寄存器分配前就将数据流显式化,修复溢出逻辑的BUG。
|
||||||
|
|
||||||
|
// 2. 只为局部变量(AllocaInst)分配栈空间和计算偏移量
|
||||||
|
// 局部变量从 s0 下方(负偏移量)开始分配,紧接着为 ra 和 s0 预留的16字节之后
|
||||||
|
int local_var_offset = 16;
|
||||||
|
|
||||||
|
if(F) { // 确保函数指针有效
|
||||||
|
for (auto& bb : F->getBasicBlocks()) {
|
||||||
|
for (auto& inst : bb->getInstructions()) {
|
||||||
|
if (auto alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||||
|
Type* allocated_type = alloca->getType()->as<PointerType>()->getBaseType();
|
||||||
|
int size = getTypeSizeInBytes(allocated_type);
|
||||||
|
|
||||||
|
// 优化栈帧大小:对于大数组使用4字节对齐,小对象使用8字节对齐
|
||||||
|
if (size >= 256) { // 大数组优化
|
||||||
|
size = (size + 3) & ~3; // 4字节对齐
|
||||||
|
} else {
|
||||||
|
size = (size + 7) & ~7; // 8字节对齐
|
||||||
|
}
|
||||||
|
if (size == 0) size = 4; // 最小4字节
|
||||||
|
|
||||||
|
local_var_offset += size;
|
||||||
|
unsigned alloca_vreg = isel->getVReg(alloca);
|
||||||
|
// 局部变量使用相对于s0的负向偏移
|
||||||
|
frame_info.alloca_offsets[alloca_vreg] = -local_var_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录仅由AllocaInst分配的局部变量的总大小
|
||||||
|
frame_info.locals_size = local_var_offset - 16;
|
||||||
|
// 记录局部变量区域分配结束的最终偏移量
|
||||||
|
frame_info.locals_end_offset = -local_var_offset;
|
||||||
|
|
||||||
|
// 在函数入口为所有栈传递的参数插入load指令
|
||||||
|
// 这个步骤至关重要:它在寄存器分配之前,为这些参数的vreg创建了明确的“定义(def)”指令。
|
||||||
|
// 这解决了在高寄存器压力下,当这些vreg被溢出时,`rewriteProgram`找不到其定义点而崩溃的问题。
|
||||||
|
if (F && isel && !mfunc->getBlocks().empty()) {
|
||||||
|
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||||
|
std::vector<std::unique_ptr<MachineInstr>> arg_load_instrs;
|
||||||
|
|
||||||
|
// 步骤 3.1: 生成所有加载栈参数的指令,暂存起来
|
||||||
|
int arg_idx = 0;
|
||||||
|
for (Argument* arg : F->getArguments()) {
|
||||||
|
// 根据ABI,前8个整型/指针参数通过寄存器传递,这里只处理超出部分。
|
||||||
|
if (arg_idx >= 8) {
|
||||||
|
// 计算参数在调用者栈帧中的位置,该位置相对于被调用者的帧指针s0是正向偏移。
|
||||||
|
// 第9个参数(arg_idx=8)位于 0(s0),第10个(arg_idx=9)位于 8(s0),以此类推。
|
||||||
|
int offset = (arg_idx - 8) * 8;
|
||||||
|
unsigned arg_vreg = isel->getVReg(arg);
|
||||||
|
Type* arg_type = arg->getType();
|
||||||
|
|
||||||
|
// 根据参数类型选择正确的加载指令
|
||||||
|
RVOpcodes load_op;
|
||||||
|
if (arg_type->isFloat()) {
|
||||||
|
load_op = RVOpcodes::FLW; // 单精度浮点
|
||||||
|
} else if (arg_type->isPointer()) {
|
||||||
|
load_op = RVOpcodes::LD; // 64位指针
|
||||||
|
} else {
|
||||||
|
load_op = RVOpcodes::LW; // 32位整数
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建加载指令: lw/ld/flw vreg, offset(s0)
|
||||||
|
auto load_instr = std::make_unique<MachineInstr>(load_op);
|
||||||
|
load_instr->addOperand(std::make_unique<RegOperand>(arg_vreg));
|
||||||
|
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::S0), // 基址为帧指针
|
||||||
|
std::make_unique<ImmOperand>(offset)
|
||||||
|
));
|
||||||
|
arg_load_instrs.push_back(std::move(load_instr));
|
||||||
|
}
|
||||||
|
arg_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//仅当有需要加载的栈参数时,才执行插入逻辑
|
||||||
|
if (!arg_load_instrs.empty()) {
|
||||||
|
auto& entry_instrs = entry_block->getInstructions();
|
||||||
|
auto insertion_point = entry_instrs.begin(); // 默认插入点为块的开头
|
||||||
|
auto last_arg_save_it = entry_instrs.end();
|
||||||
|
|
||||||
|
// 步骤 3.2: 寻找一个安全的插入点。
|
||||||
|
// 遍历入口块的指令,找到最后一条保存“寄存器传递参数”的伪指令。
|
||||||
|
// 这样可以确保我们在所有 a0-a7 参数被保存之后,才执行可能覆盖它们的加载指令。
|
||||||
|
for (auto it = entry_instrs.begin(); it != entry_instrs.end(); ++it) {
|
||||||
|
MachineInstr* instr = it->get();
|
||||||
|
// 寻找代表保存参数到栈的伪指令
|
||||||
|
if (instr->getOpcode() == RVOpcodes::FRAME_STORE_W ||
|
||||||
|
instr->getOpcode() == RVOpcodes::FRAME_STORE_D ||
|
||||||
|
instr->getOpcode() == RVOpcodes::FRAME_STORE_F) {
|
||||||
|
|
||||||
|
// 检查被保存的值是否是寄存器参数 (arg_no < 8)
|
||||||
|
auto& operands = instr->getOperands();
|
||||||
|
if (operands.empty() || operands[0]->getKind() != MachineOperand::KIND_REG) continue;
|
||||||
|
|
||||||
|
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||||
|
Value* ir_value = isel->getVRegValueMap().count(src_vreg) ? isel->getVRegValueMap().at(src_vreg) : nullptr;
|
||||||
|
|
||||||
|
if (auto ir_arg = dynamic_cast<Argument*>(ir_value)) {
|
||||||
|
if (ir_arg->getIndex() < 8) {
|
||||||
|
last_arg_save_it = it; // 找到了一个保存寄存器参数的指令,更新位置
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果找到了这样的保存指令,我们的插入点就在它之后
|
||||||
|
if (last_arg_save_it != entry_instrs.end()) {
|
||||||
|
insertion_point = std::next(last_arg_save_it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤 3.3: 在计算出的安全位置,一次性插入所有新创建的参数加载指令
|
||||||
|
entry_instrs.insert(insertion_point,
|
||||||
|
std::make_move_iterator(arg_load_instrs.begin()),
|
||||||
|
std::make_move_iterator(arg_load_instrs.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 遍历所有机器指令,将访问局部变量的伪指令展开为真实指令
|
||||||
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
|
std::vector<std::unique_ptr<MachineInstr>> new_instructions;
|
||||||
|
for (auto& instr_ptr : mbb->getInstructions()) {
|
||||||
|
RVOpcodes opcode = instr_ptr->getOpcode();
|
||||||
|
|
||||||
|
if (opcode == RVOpcodes::FRAME_LOAD_W || opcode == RVOpcodes::FRAME_LOAD_D || opcode == RVOpcodes::FRAME_LOAD_F) {
|
||||||
|
RVOpcodes real_load_op;
|
||||||
|
if (opcode == RVOpcodes::FRAME_LOAD_W) real_load_op = RVOpcodes::LW;
|
||||||
|
else if (opcode == RVOpcodes::FRAME_LOAD_D) real_load_op = RVOpcodes::LD;
|
||||||
|
else real_load_op = RVOpcodes::FLW;
|
||||||
|
|
||||||
|
auto& operands = instr_ptr->getOperands();
|
||||||
|
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||||
|
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||||
|
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||||
|
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||||
|
|
||||||
|
// 展开为: addi addr_vreg, s0, offset
|
||||||
|
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||||
|
new_instructions.push_back(std::move(addi));
|
||||||
|
|
||||||
|
// 展开为: lw/ld/flw dest_vreg, 0(addr_vreg)
|
||||||
|
auto load_instr = std::make_unique<MachineInstr>(real_load_op);
|
||||||
|
load_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
load_instr->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(addr_vreg),
|
||||||
|
std::make_unique<ImmOperand>(0)));
|
||||||
|
new_instructions.push_back(std::move(load_instr));
|
||||||
|
|
||||||
|
} else if (opcode == RVOpcodes::FRAME_STORE_W || opcode == RVOpcodes::FRAME_STORE_D || opcode == RVOpcodes::FRAME_STORE_F) {
|
||||||
|
RVOpcodes real_store_op;
|
||||||
|
if (opcode == RVOpcodes::FRAME_STORE_W) real_store_op = RVOpcodes::SW;
|
||||||
|
else if (opcode == RVOpcodes::FRAME_STORE_D) real_store_op = RVOpcodes::SD;
|
||||||
|
else real_store_op = RVOpcodes::FSW;
|
||||||
|
|
||||||
|
auto& operands = instr_ptr->getOperands();
|
||||||
|
unsigned src_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||||
|
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||||
|
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||||
|
auto addr_vreg = isel->getNewVReg(Type::getPointerType(Type::getIntType()));
|
||||||
|
|
||||||
|
// 展开为: addi addr_vreg, s0, offset
|
||||||
|
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(addr_vreg));
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||||
|
new_instructions.push_back(std::move(addi));
|
||||||
|
|
||||||
|
// 展开为: sw/sd/fsw src_vreg, 0(addr_vreg)
|
||||||
|
auto store_instr = std::make_unique<MachineInstr>(real_store_op);
|
||||||
|
store_instr->addOperand(std::make_unique<RegOperand>(src_vreg));
|
||||||
|
store_instr->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(addr_vreg),
|
||||||
|
std::make_unique<ImmOperand>(0)));
|
||||||
|
new_instructions.push_back(std::move(store_instr));
|
||||||
|
|
||||||
|
} else if (instr_ptr->getOpcode() == RVOpcodes::FRAME_ADDR) {
|
||||||
|
auto& operands = instr_ptr->getOperands();
|
||||||
|
unsigned dest_vreg = static_cast<RegOperand*>(operands[0].get())->getVRegNum();
|
||||||
|
unsigned alloca_vreg = static_cast<RegOperand*>(operands[1].get())->getVRegNum();
|
||||||
|
int offset = frame_info.alloca_offsets.at(alloca_vreg);
|
||||||
|
|
||||||
|
// 将 `frame_addr rd, rs` 展开为 `addi rd, s0, offset`
|
||||||
|
auto addi = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
addi->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
|
addi->addOperand(std::make_unique<ImmOperand>(offset));
|
||||||
|
new_instructions.push_back(std::move(addi));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
new_instructions.push_back(std::move(instr_ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mbb->getInstructions() = std::move(new_instructions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -1,17 +1,22 @@
|
|||||||
#include "PrologueEpilogueInsertion.h"
|
#include "PrologueEpilogueInsertion.h"
|
||||||
|
#include "RISCv64LLIR.h" // 假设包含了 PhysicalReg, RVOpcodes 等定义
|
||||||
#include "RISCv64ISel.h"
|
#include "RISCv64ISel.h"
|
||||||
#include "RISCv64RegAlloc.h" // 需要访问RegAlloc的结果
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
char PrologueEpilogueInsertionPass::ID = 0;
|
char PrologueEpilogueInsertionPass::ID = 0;
|
||||||
|
|
||||||
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc) {
|
||||||
|
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
||||||
|
Function* F = mfunc->getFunc();
|
||||||
|
RISCv64ISel* isel = mfunc->getISel();
|
||||||
|
|
||||||
|
// 1. 清理 KEEPALIVE 伪指令
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
auto& instrs = mbb->getInstructions();
|
auto& instrs = mbb->getInstructions();
|
||||||
|
|
||||||
// 使用标准的 Erase-Remove Idiom 来删除满足条件的元素
|
|
||||||
instrs.erase(
|
instrs.erase(
|
||||||
std::remove_if(instrs.begin(), instrs.end(),
|
std::remove_if(instrs.begin(), instrs.end(),
|
||||||
[](const std::unique_ptr<MachineInstr>& instr) {
|
[](const std::unique_ptr<MachineInstr>& instr) {
|
||||||
@ -22,39 +27,59 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackFrameInfo& frame_info = mfunc->getFrameInfo();
|
// 2. 确定需要保存的被调用者保存寄存器 (callee-saved)
|
||||||
Function* F = mfunc->getFunc();
|
|
||||||
RISCv64ISel* isel = mfunc->getISel();
|
|
||||||
|
|
||||||
// [关键] 获取寄存器分配的结果 (vreg -> preg 的映射)
|
|
||||||
// RegAlloc Pass 必须已经运行过
|
|
||||||
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
auto& vreg_to_preg_map = frame_info.vreg_to_preg_map;
|
||||||
|
std::set<PhysicalReg> used_callee_saved_regs_set;
|
||||||
|
const auto& callee_saved_int = getCalleeSavedIntRegs();
|
||||||
|
const auto& callee_saved_fp = getCalleeSavedFpRegs();
|
||||||
|
|
||||||
// 完全遵循 AsmPrinter 中的计算逻辑
|
for (const auto& pair : vreg_to_preg_map) {
|
||||||
|
PhysicalReg preg = pair.second;
|
||||||
|
bool is_int_cs = std::find(callee_saved_int.begin(), callee_saved_int.end(), preg) != callee_saved_int.end();
|
||||||
|
bool is_fp_cs = std::find(callee_saved_fp.begin(), callee_saved_fp.end(), preg) != callee_saved_fp.end();
|
||||||
|
if ((is_int_cs && preg != PhysicalReg::S0) || is_fp_cs) {
|
||||||
|
used_callee_saved_regs_set.insert(preg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame_info.callee_saved_regs_to_store.assign(
|
||||||
|
used_callee_saved_regs_set.begin(), used_callee_saved_regs_set.end()
|
||||||
|
);
|
||||||
|
std::sort(frame_info.callee_saved_regs_to_store.begin(), frame_info.callee_saved_regs_to_store.end());
|
||||||
|
frame_info.callee_saved_size = frame_info.callee_saved_regs_to_store.size() * 8;
|
||||||
|
|
||||||
|
// 3. 计算最终的栈帧总大小,包含栈溢出保护
|
||||||
int total_stack_size = frame_info.locals_size +
|
int total_stack_size = frame_info.locals_size +
|
||||||
frame_info.spill_size +
|
frame_info.spill_size +
|
||||||
frame_info.callee_saved_size +
|
frame_info.callee_saved_size +
|
||||||
16; // 为 ra 和 s0 固定的16字节
|
16;
|
||||||
|
|
||||||
|
// 栈溢出保护:增加最大栈帧大小以容纳大型数组
|
||||||
|
const int MAX_STACK_FRAME_SIZE = 8192; // 8KB to handle large arrays like 256*4*2 = 2048 bytes
|
||||||
|
if (total_stack_size > MAX_STACK_FRAME_SIZE) {
|
||||||
|
// 如果仍然超过限制,尝试优化对齐方式
|
||||||
|
std::cerr << "Warning: Stack frame size " << total_stack_size
|
||||||
|
<< " exceeds recommended limit " << MAX_STACK_FRAME_SIZE << " for function "
|
||||||
|
<< mfunc->getName() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优化:减少对齐开销,使用16字节对齐而非更大的对齐
|
||||||
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
int aligned_stack_size = (total_stack_size + 15) & ~15;
|
||||||
frame_info.total_size = aligned_stack_size;
|
frame_info.total_size = aligned_stack_size;
|
||||||
|
|
||||||
// 只有在需要分配栈空间时才生成指令
|
|
||||||
if (aligned_stack_size > 0) {
|
if (aligned_stack_size > 0) {
|
||||||
// --- 1. 插入序言 ---
|
// --- 4. 插入完整的序言 ---
|
||||||
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
MachineBasicBlock* entry_block = mfunc->getBlocks().front().get();
|
||||||
auto& entry_instrs = entry_block->getInstructions();
|
auto& entry_instrs = entry_block->getInstructions();
|
||||||
|
|
||||||
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
std::vector<std::unique_ptr<MachineInstr>> prologue_instrs;
|
||||||
|
|
||||||
// 1. addi sp, sp, -aligned_stack_size
|
// 4.1. 分配栈帧
|
||||||
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
auto alloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
alloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
alloc_stack->addOperand(std::make_unique<ImmOperand>(-aligned_stack_size));
|
||||||
prologue_instrs.push_back(std::move(alloc_stack));
|
prologue_instrs.push_back(std::move(alloc_stack));
|
||||||
|
|
||||||
// 2. sd ra, (aligned_stack_size - 8)(sp)
|
// 4.2. 保存 ra 和 s0
|
||||||
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
auto save_ra = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||||
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
save_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||||
save_ra->addOperand(std::make_unique<MemOperand>(
|
save_ra->addOperand(std::make_unique<MemOperand>(
|
||||||
@ -62,8 +87,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||||
));
|
));
|
||||||
prologue_instrs.push_back(std::move(save_ra));
|
prologue_instrs.push_back(std::move(save_ra));
|
||||||
|
|
||||||
// 3. sd s0, (aligned_stack_size - 16)(sp)
|
|
||||||
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
auto save_fp = std::make_unique<MachineInstr>(RVOpcodes::SD);
|
||||||
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
save_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
save_fp->addOperand(std::make_unique<MemOperand>(
|
save_fp->addOperand(std::make_unique<MemOperand>(
|
||||||
@ -72,66 +95,54 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
));
|
));
|
||||||
prologue_instrs.push_back(std::move(save_fp));
|
prologue_instrs.push_back(std::move(save_fp));
|
||||||
|
|
||||||
// 4. addi s0, sp, aligned_stack_size
|
// 4.3. 设置新的帧指针 s0
|
||||||
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
auto set_fp = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
set_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
set_fp->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||||
prologue_instrs.push_back(std::move(set_fp));
|
prologue_instrs.push_back(std::move(set_fp));
|
||||||
|
|
||||||
// --- 在s0设置完毕后,使用物理寄存器加载栈参数 ---
|
|
||||||
if (F && isel) {
|
|
||||||
int arg_idx = 0;
|
|
||||||
for (Argument* arg : F->getArguments()) {
|
|
||||||
if (arg_idx >= 8) {
|
|
||||||
unsigned vreg = isel->getVReg(arg);
|
|
||||||
|
|
||||||
if (frame_info.alloca_offsets.count(vreg) && vreg_to_preg_map.count(vreg)) {
|
|
||||||
int offset = frame_info.alloca_offsets.at(vreg);
|
|
||||||
PhysicalReg dest_preg = vreg_to_preg_map.at(vreg);
|
|
||||||
Type* arg_type = arg->getType();
|
|
||||||
|
|
||||||
if (arg_type->isFloat()) {
|
|
||||||
auto load_arg = std::make_unique<MachineInstr>(RVOpcodes::FLW);
|
|
||||||
load_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
|
||||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(offset)
|
|
||||||
));
|
|
||||||
prologue_instrs.push_back(std::move(load_arg));
|
|
||||||
} else {
|
|
||||||
RVOpcodes load_op = arg_type->isPointer() ? RVOpcodes::LD : RVOpcodes::LW;
|
|
||||||
auto load_arg = std::make_unique<MachineInstr>(load_op);
|
|
||||||
load_arg->addOperand(std::make_unique<RegOperand>(dest_preg));
|
|
||||||
load_arg->addOperand(std::make_unique<MemOperand>(
|
|
||||||
std::make_unique<RegOperand>(PhysicalReg::S0),
|
|
||||||
std::make_unique<ImmOperand>(offset)
|
|
||||||
));
|
|
||||||
prologue_instrs.push_back(std::move(load_arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arg_idx++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确定插入点
|
// 4.4. 保存所有使用到的被调用者保存寄存器
|
||||||
auto insert_pos = entry_instrs.begin();
|
int next_available_offset = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||||
|
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||||
// 一次性将所有序言指令插入
|
// 采用“先使用,后更新”逻辑
|
||||||
if (!prologue_instrs.empty()) {
|
RVOpcodes store_op = isFPR(reg) ? RVOpcodes::FSD : RVOpcodes::SD;
|
||||||
entry_instrs.insert(insert_pos,
|
auto save_cs_reg = std::make_unique<MachineInstr>(store_op);
|
||||||
std::make_move_iterator(prologue_instrs.begin()),
|
save_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
std::make_move_iterator(prologue_instrs.end()));
|
save_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||||
|
std::make_unique<ImmOperand>(next_available_offset) // 使用当前偏移
|
||||||
|
));
|
||||||
|
prologue_instrs.push_back(std::move(save_cs_reg));
|
||||||
|
next_available_offset -= 8; // 为下一个寄存器准备偏移
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 2. 插入尾声 (此部分逻辑保持不变) ---
|
// 4.5. 将所有生成的序言指令一次性插入到函数入口
|
||||||
|
entry_instrs.insert(entry_instrs.begin(),
|
||||||
|
std::make_move_iterator(prologue_instrs.begin()),
|
||||||
|
std::make_move_iterator(prologue_instrs.end()));
|
||||||
|
|
||||||
|
// --- 5. 插入完整的尾声 ---
|
||||||
for (auto& mbb : mfunc->getBlocks()) {
|
for (auto& mbb : mfunc->getBlocks()) {
|
||||||
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
for (auto it = mbb->getInstructions().begin(); it != mbb->getInstructions().end(); ++it) {
|
||||||
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
if ((*it)->getOpcode() == RVOpcodes::RET) {
|
||||||
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
std::vector<std::unique_ptr<MachineInstr>> epilogue_instrs;
|
||||||
|
|
||||||
|
// 5.1. 恢复被调用者保存寄存器
|
||||||
|
int next_available_offset_restore = -(16 + frame_info.locals_size + frame_info.spill_size);
|
||||||
|
for (const auto& reg : frame_info.callee_saved_regs_to_store) {
|
||||||
|
RVOpcodes load_op = isFPR(reg) ? RVOpcodes::FLD : RVOpcodes::LD;
|
||||||
|
auto restore_cs_reg = std::make_unique<MachineInstr>(load_op);
|
||||||
|
restore_cs_reg->addOperand(std::make_unique<RegOperand>(reg));
|
||||||
|
restore_cs_reg->addOperand(std::make_unique<MemOperand>(
|
||||||
|
std::make_unique<RegOperand>(PhysicalReg::S0),
|
||||||
|
std::make_unique<ImmOperand>(next_available_offset_restore) // 使用当前偏移
|
||||||
|
));
|
||||||
|
epilogue_instrs.push_back(std::move(restore_cs_reg));
|
||||||
|
next_available_offset_restore -= 8; // 为下一个寄存器准备偏移
|
||||||
|
}
|
||||||
|
|
||||||
// 1. ld ra
|
// 5.2. 恢复 ra 和 s0
|
||||||
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
auto restore_ra = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||||
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
restore_ra->addOperand(std::make_unique<RegOperand>(PhysicalReg::RA));
|
||||||
restore_ra->addOperand(std::make_unique<MemOperand>(
|
restore_ra->addOperand(std::make_unique<MemOperand>(
|
||||||
@ -139,8 +150,6 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
std::make_unique<ImmOperand>(aligned_stack_size - 8)
|
||||||
));
|
));
|
||||||
epilogue_instrs.push_back(std::move(restore_ra));
|
epilogue_instrs.push_back(std::move(restore_ra));
|
||||||
|
|
||||||
// 2. ld s0
|
|
||||||
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
auto restore_fp = std::make_unique<MachineInstr>(RVOpcodes::LD);
|
||||||
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
restore_fp->addOperand(std::make_unique<RegOperand>(PhysicalReg::S0));
|
||||||
restore_fp->addOperand(std::make_unique<MemOperand>(
|
restore_fp->addOperand(std::make_unique<MemOperand>(
|
||||||
@ -149,18 +158,18 @@ void PrologueEpilogueInsertionPass::runOnMachineFunction(MachineFunction* mfunc)
|
|||||||
));
|
));
|
||||||
epilogue_instrs.push_back(std::move(restore_fp));
|
epilogue_instrs.push_back(std::move(restore_fp));
|
||||||
|
|
||||||
// 3. addi sp, sp, aligned_stack_size
|
// 5.3. 释放栈帧
|
||||||
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
auto dealloc_stack = std::make_unique<MachineInstr>(RVOpcodes::ADDI);
|
||||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
dealloc_stack->addOperand(std::make_unique<RegOperand>(PhysicalReg::SP));
|
||||||
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
dealloc_stack->addOperand(std::make_unique<ImmOperand>(aligned_stack_size));
|
||||||
epilogue_instrs.push_back(std::move(dealloc_stack));
|
epilogue_instrs.push_back(std::move(dealloc_stack));
|
||||||
|
|
||||||
if (!epilogue_instrs.empty()) {
|
// 将尾声指令插入到 RET 指令之前
|
||||||
mbb->getInstructions().insert(it,
|
mbb->getInstructions().insert(it,
|
||||||
std::make_move_iterator(epilogue_instrs.begin()),
|
std::make_move_iterator(epilogue_instrs.begin()),
|
||||||
std::make_move_iterator(epilogue_instrs.end()));
|
std::make_move_iterator(epilogue_instrs.end()));
|
||||||
}
|
|
||||||
goto next_block;
|
goto next_block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
282
src/backend/RISCv64/Optimize/DivStrengthReduction.cpp
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
#include "DivStrengthReduction.h"
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
char DivStrengthReduction::ID = 0;
|
||||||
|
|
||||||
|
bool DivStrengthReduction::runOnFunction(Function *F, AnalysisManager& AM) {
|
||||||
|
// This pass works on MachineFunction level, not IR level
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DivStrengthReduction::runOnMachineFunction(MachineFunction *mfunc) {
|
||||||
|
if (!mfunc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool debug = false; // Set to true for debugging
|
||||||
|
if (debug)
|
||||||
|
std::cout << "Running DivStrengthReduction optimization..." << std::endl;
|
||||||
|
|
||||||
|
int next_temp_reg = 1000;
|
||||||
|
auto createTempReg = [&]() -> int {
|
||||||
|
return next_temp_reg++;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MagicInfo {
|
||||||
|
int64_t magic;
|
||||||
|
int shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto computeMagic = [](int64_t d, bool is_32bit) -> MagicInfo {
|
||||||
|
int word_size = is_32bit ? 32 : 64;
|
||||||
|
uint64_t ad = std::abs(d);
|
||||||
|
|
||||||
|
if (ad == 0) return {0, 0};
|
||||||
|
|
||||||
|
int l = std::floor(std::log2(ad));
|
||||||
|
if ((ad & (ad - 1)) == 0) { // power of 2
|
||||||
|
l = 0; // special case for power of 2, shift will be calculated differently
|
||||||
|
}
|
||||||
|
|
||||||
|
__int128_t one = 1;
|
||||||
|
__int128_t num;
|
||||||
|
int total_shift;
|
||||||
|
|
||||||
|
if (is_32bit) {
|
||||||
|
total_shift = 31 + l;
|
||||||
|
num = one << total_shift;
|
||||||
|
} else {
|
||||||
|
total_shift = 63 + l;
|
||||||
|
num = one << total_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
__int128_t den = ad;
|
||||||
|
int64_t magic = (num / den) + 1;
|
||||||
|
|
||||||
|
return {magic, total_shift};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto isPowerOfTwo = [](int64_t n) -> bool {
|
||||||
|
return n > 0 && (n & (n - 1)) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getPowerOfTwoExponent = [](int64_t n) -> int {
|
||||||
|
if (n <= 0 || (n & (n - 1)) != 0) return -1;
|
||||||
|
int shift = 0;
|
||||||
|
while (n > 1) {
|
||||||
|
n >>= 1;
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
return shift;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InstructionReplacement {
|
||||||
|
size_t index;
|
||||||
|
size_t count_to_erase;
|
||||||
|
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto &mbb_uptr : mfunc->getBlocks()) {
|
||||||
|
auto &mbb = *mbb_uptr;
|
||||||
|
auto &instrs = mbb.getInstructions();
|
||||||
|
std::vector<InstructionReplacement> replacements;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < instrs.size(); ++i) {
|
||||||
|
auto *instr = instrs[i].get();
|
||||||
|
|
||||||
|
bool is_32bit = (instr->getOpcode() == RVOpcodes::DIVW);
|
||||||
|
|
||||||
|
if (instr->getOpcode() != RVOpcodes::DIV && !is_32bit) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instr->getOperands().size() != 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *dst_op = instr->getOperands()[0].get();
|
||||||
|
auto *src1_op = instr->getOperands()[1].get();
|
||||||
|
auto *src2_op = instr->getOperands()[2].get();
|
||||||
|
|
||||||
|
int64_t divisor = 0;
|
||||||
|
bool const_divisor_found = false;
|
||||||
|
size_t instructions_to_replace = 1;
|
||||||
|
|
||||||
|
if (src2_op->getKind() == MachineOperand::KIND_IMM) {
|
||||||
|
divisor = static_cast<ImmOperand *>(src2_op)->getValue();
|
||||||
|
const_divisor_found = true;
|
||||||
|
} else if (src2_op->getKind() == MachineOperand::KIND_REG) {
|
||||||
|
if (i > 0) {
|
||||||
|
auto *prev_instr = instrs[i - 1].get();
|
||||||
|
if (prev_instr->getOpcode() == RVOpcodes::LI && prev_instr->getOperands().size() == 2) {
|
||||||
|
auto *li_dst_op = prev_instr->getOperands()[0].get();
|
||||||
|
auto *li_imm_op = prev_instr->getOperands()[1].get();
|
||||||
|
if (li_dst_op->getKind() == MachineOperand::KIND_REG && li_imm_op->getKind() == MachineOperand::KIND_IMM) {
|
||||||
|
auto *div_reg_op = static_cast<RegOperand *>(src2_op);
|
||||||
|
auto *li_dst_reg_op = static_cast<RegOperand *>(li_dst_op);
|
||||||
|
if (div_reg_op->isVirtual() && li_dst_reg_op->isVirtual() &&
|
||||||
|
div_reg_op->getVRegNum() == li_dst_reg_op->getVRegNum()) {
|
||||||
|
divisor = static_cast<ImmOperand *>(li_imm_op)->getValue();
|
||||||
|
const_divisor_found = true;
|
||||||
|
instructions_to_replace = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!const_divisor_found) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *dst_reg = static_cast<RegOperand *>(dst_op);
|
||||||
|
auto *src1_reg = static_cast<RegOperand *>(src1_op);
|
||||||
|
|
||||||
|
if (divisor == 0) continue;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<MachineInstr>> newInstrs;
|
||||||
|
|
||||||
|
if (divisor == 1) {
|
||||||
|
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
newInstrs.push_back(std::move(moveInstr));
|
||||||
|
}
|
||||||
|
else if (divisor == -1) {
|
||||||
|
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
newInstrs.push_back(std::move(negInstr));
|
||||||
|
}
|
||||||
|
else if (isPowerOfTwo(std::abs(divisor))) {
|
||||||
|
int shift = getPowerOfTwoExponent(std::abs(divisor));
|
||||||
|
int temp_reg = createTempReg();
|
||||||
|
|
||||||
|
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||||
|
sraSignInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||||
|
newInstrs.push_back(std::move(sraSignInstr));
|
||||||
|
|
||||||
|
auto srlInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRLIW : RVOpcodes::SRLI);
|
||||||
|
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
srlInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
srlInstr->addOperand(std::make_unique<ImmOperand>((is_32bit ? 32 : 64) - shift));
|
||||||
|
newInstrs.push_back(std::move(srlInstr));
|
||||||
|
|
||||||
|
auto addInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||||
|
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
addInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
addInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
newInstrs.push_back(std::move(addInstr));
|
||||||
|
|
||||||
|
auto sraInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<ImmOperand>(shift));
|
||||||
|
newInstrs.push_back(std::move(sraInstr));
|
||||||
|
|
||||||
|
if (divisor < 0) {
|
||||||
|
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
newInstrs.push_back(std::move(negInstr));
|
||||||
|
} else {
|
||||||
|
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
newInstrs.push_back(std::move(moveInstr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto magic_info = computeMagic(divisor, is_32bit);
|
||||||
|
int magic_reg = createTempReg();
|
||||||
|
int temp_reg = createTempReg();
|
||||||
|
|
||||||
|
auto loadInstr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
|
loadInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||||
|
loadInstr->addOperand(std::make_unique<ImmOperand>(magic_info.magic));
|
||||||
|
newInstrs.push_back(std::move(loadInstr));
|
||||||
|
|
||||||
|
if (is_32bit) {
|
||||||
|
auto mulInstr = std::make_unique<MachineInstr>(RVOpcodes::MUL);
|
||||||
|
mulInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
mulInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
mulInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||||
|
newInstrs.push_back(std::move(mulInstr));
|
||||||
|
|
||||||
|
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<ImmOperand>(magic_info.shift));
|
||||||
|
newInstrs.push_back(std::move(sraInstr));
|
||||||
|
} else {
|
||||||
|
auto mulhInstr = std::make_unique<MachineInstr>(RVOpcodes::MULH);
|
||||||
|
mulhInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
mulhInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
mulhInstr->addOperand(std::make_unique<RegOperand>(magic_reg));
|
||||||
|
newInstrs.push_back(std::move(mulhInstr));
|
||||||
|
|
||||||
|
int post_shift = magic_info.shift - 63;
|
||||||
|
if (post_shift > 0) {
|
||||||
|
auto sraInstr = std::make_unique<MachineInstr>(RVOpcodes::SRAI);
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
sraInstr->addOperand(std::make_unique<ImmOperand>(post_shift));
|
||||||
|
newInstrs.push_back(std::move(sraInstr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sign_reg = createTempReg();
|
||||||
|
auto sraSignInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SRAIW : RVOpcodes::SRAI);
|
||||||
|
sraSignInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||||
|
sraSignInstr->addOperand(std::make_unique<RegOperand>(*src1_reg));
|
||||||
|
sraSignInstr->addOperand(std::make_unique<ImmOperand>(is_32bit ? 31 : 63));
|
||||||
|
newInstrs.push_back(std::move(sraSignInstr));
|
||||||
|
|
||||||
|
auto subInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||||
|
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
subInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
subInstr->addOperand(std::make_unique<RegOperand>(sign_reg));
|
||||||
|
newInstrs.push_back(std::move(subInstr));
|
||||||
|
|
||||||
|
if (divisor < 0) {
|
||||||
|
auto negInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::SUBW : RVOpcodes::SUB);
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
negInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
newInstrs.push_back(std::move(negInstr));
|
||||||
|
} else {
|
||||||
|
auto moveInstr = std::make_unique<MachineInstr>(is_32bit ? RVOpcodes::ADDW : RVOpcodes::ADD);
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(*dst_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(temp_reg));
|
||||||
|
moveInstr->addOperand(std::make_unique<RegOperand>(PhysicalReg::ZERO));
|
||||||
|
newInstrs.push_back(std::move(moveInstr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newInstrs.empty()) {
|
||||||
|
size_t start_index = i;
|
||||||
|
if (instructions_to_replace == 2) {
|
||||||
|
start_index = i - 1;
|
||||||
|
}
|
||||||
|
replacements.push_back({start_index, instructions_to_replace, std::move(newInstrs)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = replacements.rbegin(); it != replacements.rend(); ++it) {
|
||||||
|
instrs.erase(instrs.begin() + it->index, instrs.begin() + it->index + it->count_to_erase);
|
||||||
|
instrs.insert(instrs.begin() + it->index,
|
||||||
|
std::make_move_iterator(it->newInstrs.begin()),
|
||||||
|
std::make_move_iterator(it->newInstrs.end()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -60,7 +60,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
|||||||
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
case RVOpcodes::ADD: *OS << "add "; break; case RVOpcodes::ADDI: *OS << "addi "; break;
|
||||||
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
case RVOpcodes::ADDW: *OS << "addw "; break; case RVOpcodes::ADDIW: *OS << "addiw "; break;
|
||||||
case RVOpcodes::SUB: *OS << "sub "; break; case RVOpcodes::SUBW: *OS << "subw "; break;
|
case RVOpcodes::SUB: *OS << "sub "; break; case RVOpcodes::SUBW: *OS << "subw "; break;
|
||||||
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break;
|
case RVOpcodes::MUL: *OS << "mul "; break; case RVOpcodes::MULW: *OS << "mulw "; break; case RVOpcodes::MULH: *OS << "mulh "; break;
|
||||||
case RVOpcodes::DIV: *OS << "div "; break; case RVOpcodes::DIVW: *OS << "divw "; break;
|
case RVOpcodes::DIV: *OS << "div "; break; case RVOpcodes::DIVW: *OS << "divw "; break;
|
||||||
case RVOpcodes::REM: *OS << "rem "; break; case RVOpcodes::REMW: *OS << "remw "; break;
|
case RVOpcodes::REM: *OS << "rem "; break; case RVOpcodes::REMW: *OS << "remw "; break;
|
||||||
case RVOpcodes::XOR: *OS << "xor "; break; case RVOpcodes::XORI: *OS << "xori "; break;
|
case RVOpcodes::XOR: *OS << "xor "; break; case RVOpcodes::XORI: *OS << "xori "; break;
|
||||||
@ -104,7 +104,7 @@ void RISCv64AsmPrinter::printInstruction(MachineInstr* instr, bool debug) {
|
|||||||
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
case RVOpcodes::FMV_S: *OS << "fmv.s "; break;
|
||||||
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
case RVOpcodes::FMV_W_X: *OS << "fmv.w.x "; break;
|
||||||
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
case RVOpcodes::FMV_X_W: *OS << "fmv.x.w "; break;
|
||||||
case RVOpcodes::CALL: { // [核心修改] 为CALL指令添加特殊处理逻辑
|
case RVOpcodes::CALL: { // 为CALL指令添加特殊处理逻辑
|
||||||
*OS << "call ";
|
*OS << "call ";
|
||||||
// 遍历所有操作数,只寻找并打印函数名标签
|
// 遍历所有操作数,只寻找并打印函数名标签
|
||||||
for (const auto& op : instr->getOperands()) {
|
for (const auto& op : instr->getOperands()) {
|
||||||
|
|||||||
@ -73,7 +73,7 @@ std::string RISCv64CodeGen::module_gen() {
|
|||||||
for (const auto& global_ptr : module->getGlobals()) {
|
for (const auto& global_ptr : module->getGlobals()) {
|
||||||
GlobalValue* global = global_ptr.get();
|
GlobalValue* global = global_ptr.get();
|
||||||
|
|
||||||
// [核心修改] 使用更健壮的逻辑来判断是否为大型零初始化数组
|
// 使用更健壮的逻辑来判断是否为大型零初始化数组
|
||||||
bool is_all_zeros = true;
|
bool is_all_zeros = true;
|
||||||
const auto& init_values = global->getInitValues();
|
const auto& init_values = global->getInitValues();
|
||||||
|
|
||||||
@ -174,15 +174,43 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
// === 完整的后端处理流水线 ===
|
// === 完整的后端处理流水线 ===
|
||||||
|
|
||||||
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
// 阶段 1: 指令选择 (sysy::IR -> LLIR with virtual registers)
|
||||||
|
DEBUG = 0;
|
||||||
|
DEEPDEBUG = 0;
|
||||||
|
|
||||||
RISCv64ISel isel;
|
RISCv64ISel isel;
|
||||||
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
std::unique_ptr<MachineFunction> mfunc = isel.runOnFunction(func);
|
||||||
|
|
||||||
// 第一次调试打印输出
|
// 第一次调试打印输出
|
||||||
std::stringstream ss1;
|
std::stringstream ss_after_isel;
|
||||||
RISCv64AsmPrinter printer1(mfunc.get());
|
RISCv64AsmPrinter printer_isel(mfunc.get());
|
||||||
printer1.run(ss1, true);
|
printer_isel.run(ss_after_isel, true);
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << ss_after_isel.str();
|
||||||
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cerr << "====== Intermediate Representation after Instruction Selection ======\n"
|
||||||
|
<< ss_after_isel.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阶段 2: 消除帧索引 (展开伪指令,计算局部变量偏移)
|
||||||
|
// 这个Pass必须在寄存器分配之前运行
|
||||||
|
EliminateFrameIndicesPass efi_pass;
|
||||||
|
efi_pass.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
// 阶段 2: 指令调度 (Instruction Scheduling)
|
if (DEBUG) {
|
||||||
|
std::cerr << "====== stack info after eliminate frame indices ======\n";
|
||||||
|
mfunc->dumpStackFrameInfo(std::cerr);
|
||||||
|
std::stringstream ss_after_eli;
|
||||||
|
printer_isel.run(ss_after_eli, true);
|
||||||
|
std::cerr << "====== LLIR after eliminate frame indices ======\n"
|
||||||
|
<< ss_after_eli.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阶段 2: 除法强度削弱优化 (Division Strength Reduction)
|
||||||
|
DivStrengthReduction div_strength_reduction;
|
||||||
|
div_strength_reduction.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
|
// 阶段 2.1: 指令调度 (Instruction Scheduling)
|
||||||
PreRA_Scheduler scheduler;
|
PreRA_Scheduler scheduler;
|
||||||
scheduler.runOnMachineFunction(mfunc.get());
|
scheduler.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
@ -190,10 +218,20 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
RISCv64RegAlloc reg_alloc(mfunc.get());
|
RISCv64RegAlloc reg_alloc(mfunc.get());
|
||||||
reg_alloc.run();
|
reg_alloc.run();
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cerr << "====== stack info after reg alloc ======\n";
|
||||||
|
mfunc->dumpStackFrameInfo(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
// 阶段 3.1: 处理被调用者保存寄存器
|
// 阶段 3.1: 处理被调用者保存寄存器
|
||||||
CalleeSavedHandler callee_handler;
|
CalleeSavedHandler callee_handler;
|
||||||
callee_handler.runOnMachineFunction(mfunc.get());
|
callee_handler.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cerr << "====== stack info after callee handler ======\n";
|
||||||
|
mfunc->dumpStackFrameInfo(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
// 阶段 4: 窥孔优化 (Peephole Optimization)
|
||||||
PeepholeOptimizer peephole;
|
PeepholeOptimizer peephole;
|
||||||
peephole.runOnMachineFunction(mfunc.get());
|
peephole.runOnMachineFunction(mfunc.get());
|
||||||
@ -206,7 +244,7 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
PrologueEpilogueInsertionPass pei_pass;
|
PrologueEpilogueInsertionPass pei_pass;
|
||||||
pei_pass.runOnMachineFunction(mfunc.get());
|
pei_pass.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
// 阶段 3.3: 清理产生的大立即数
|
// 阶段 3.3: 大立即数合法化
|
||||||
LegalizeImmediatesPass legalizer;
|
LegalizeImmediatesPass legalizer;
|
||||||
legalizer.runOnMachineFunction(mfunc.get());
|
legalizer.runOnMachineFunction(mfunc.get());
|
||||||
|
|
||||||
@ -214,8 +252,9 @@ std::string RISCv64CodeGen::function_gen(Function* func) {
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
RISCv64AsmPrinter printer(mfunc.get());
|
RISCv64AsmPrinter printer(mfunc.get());
|
||||||
printer.run(ss);
|
printer.run(ss);
|
||||||
if (DEBUG) ss << "\n" << ss1.str(); // 将指令选择阶段的结果也包含在最终输出中
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
@ -2,8 +2,8 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <cmath> // For std::fabs
|
#include <cmath>
|
||||||
#include <limits> // For std::numeric_limits
|
#include <limits>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
@ -402,7 +402,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
Value* base = nullptr;
|
Value* base = nullptr;
|
||||||
Value* offset = nullptr;
|
Value* offset = nullptr;
|
||||||
|
|
||||||
// [修改] 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
// 扩展基地址的判断,使其可以识别 AllocaInst 或 GlobalValue
|
||||||
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
|
if (dynamic_cast<AllocaInst*>(lhs) || dynamic_cast<GlobalValue*>(lhs)) {
|
||||||
base = lhs;
|
base = lhs;
|
||||||
offset = rhs;
|
offset = rhs;
|
||||||
@ -421,7 +421,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(li));
|
CurMBB->addInstruction(std::move(li));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. [修改] 根据基地址的类型,生成不同的指令来获取基地址
|
// 2. 根据基地址的类型,生成不同的指令来获取基地址
|
||||||
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
|
auto base_addr_vreg = getNewVReg(Type::getIntType()); // 创建一个新的临时vreg来存放基地址
|
||||||
|
|
||||||
// 情况一:基地址是局部栈变量
|
// 情况一:基地址是局部栈变量
|
||||||
@ -452,7 +452,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [V2优点] 在BINARY节点内部按需加载常量操作数。
|
// 在BINARY节点内部按需加载常量操作数。
|
||||||
auto load_val_if_const = [&](Value* val) {
|
auto load_val_if_const = [&](Value* val) {
|
||||||
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
if (auto c = dynamic_cast<ConstantValue*>(val)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -483,7 +483,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto dest_vreg = getVReg(bin);
|
auto dest_vreg = getVReg(bin);
|
||||||
auto lhs_vreg = getVReg(lhs);
|
auto lhs_vreg = getVReg(lhs);
|
||||||
|
|
||||||
// [V2优点] 融合 ADDIW 优化。
|
// 融合 ADDIW 优化。
|
||||||
if (rhs_is_imm_opt) {
|
if (rhs_is_imm_opt) {
|
||||||
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
|
auto rhs_const = dynamic_cast<ConstantValue*>(rhs);
|
||||||
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::ADDIW);
|
||||||
@ -539,6 +539,15 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
CurMBB->addInstruction(std::move(instr));
|
CurMBB->addInstruction(std::move(instr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Instruction::kSRA: {
|
||||||
|
auto rhs_const = dynamic_cast<ConstantInteger*>(rhs);
|
||||||
|
auto instr = std::make_unique<MachineInstr>(RVOpcodes::SRAIW);
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
|
instr->addOperand(std::make_unique<RegOperand>(lhs_vreg));
|
||||||
|
instr->addOperand(std::make_unique<ImmOperand>(rhs_const->getInt()));
|
||||||
|
CurMBB->addInstruction(std::move(instr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
|
case BinaryInst::kICmpEQ: { // 等于 (a == b) -> (subw; seqz)
|
||||||
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
auto sub = std::make_unique<MachineInstr>(RVOpcodes::SUBW);
|
||||||
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
sub->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
@ -943,7 +952,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
|
|
||||||
// --- 步骤 3: 生成CALL指令 ---
|
// --- 步骤 3: 生成CALL指令 ---
|
||||||
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
auto call_instr = std::make_unique<MachineInstr>(RVOpcodes::CALL);
|
||||||
// [协议] 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
|
// 如果函数有返回值,将它的目标虚拟寄存器作为第一个操作数
|
||||||
if (!call->getType()->isVoid()) {
|
if (!call->getType()->isVoid()) {
|
||||||
unsigned dest_vreg = getVReg(call);
|
unsigned dest_vreg = getVReg(call);
|
||||||
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
call_instr->addOperand(std::make_unique<RegOperand>(dest_vreg));
|
||||||
@ -1020,7 +1029,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
} else {
|
} else {
|
||||||
// --- 处理整数/指针返回值 ---
|
// --- 处理整数/指针返回值 ---
|
||||||
// 返回值需要被放入 a0
|
// 返回值需要被放入 a0
|
||||||
// [V2优点] 在RETURN节点内加载常量返回值
|
// 在RETURN节点内加载常量返回值
|
||||||
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
if (auto const_val = dynamic_cast<ConstantValue*>(ret_val)) {
|
||||||
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li_instr = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
li_instr->addOperand(std::make_unique<RegOperand>(PhysicalReg::A0));
|
||||||
@ -1034,7 +1043,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// [V1设计保留] 函数尾声(epilogue)不由RETURN节点生成,
|
// 函数尾声(epilogue)不由RETURN节点生成,
|
||||||
// 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。
|
// 而是由后续的AsmPrinter或其它Pass统一处理,这是一种常见且有效的模块化设计。
|
||||||
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
auto ret_mi = std::make_unique<MachineInstr>(RVOpcodes::RET);
|
||||||
CurMBB->addInstruction(std::move(ret_mi));
|
CurMBB->addInstruction(std::move(ret_mi));
|
||||||
@ -1048,7 +1057,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
auto then_bb_name = cond_br->getThenBlock()->getName();
|
auto then_bb_name = cond_br->getThenBlock()->getName();
|
||||||
auto else_bb_name = cond_br->getElseBlock()->getName();
|
auto else_bb_name = cond_br->getElseBlock()->getName();
|
||||||
|
|
||||||
// [优化] 检查分支条件是否为编译期常量
|
// 检查分支条件是否为编译期常量
|
||||||
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
|
if (auto const_cond = dynamic_cast<ConstantValue*>(condition)) {
|
||||||
// 如果条件是常量,直接生成一个无条件跳转J,而不是BNE
|
// 如果条件是常量,直接生成一个无条件跳转J,而不是BNE
|
||||||
if (const_cond->getInt() != 0) { // 条件为 true
|
if (const_cond->getInt() != 0) { // 条件为 true
|
||||||
@ -1063,7 +1072,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
// 如果条件不是常量,则执行标准流程
|
// 如果条件不是常量,则执行标准流程
|
||||||
else {
|
else {
|
||||||
// [修复] 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
// 为条件变量生成加载指令(如果它是常量的话,尽管上面已经处理了)
|
||||||
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
|
// 这一步是为了逻辑完整,以防有其他类型的常量没有被捕获
|
||||||
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
|
if (auto const_val = dynamic_cast<ConstantValue*>(condition)) {
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
@ -1097,7 +1106,7 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case DAGNode::MEMSET: {
|
case DAGNode::MEMSET: {
|
||||||
// [V1设计保留] Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
// Memset的核心展开逻辑在虚拟寄存器层面是正确的,无需修改。
|
||||||
// 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。
|
// 之前的bug是由于其输入(地址、值、大小)的虚拟寄存器未被正确初始化。
|
||||||
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。
|
// 在修复了CONSTANT/ALLOCA_ADDR的加载问题后,此处的逻辑现在可以正常工作。
|
||||||
|
|
||||||
@ -1280,14 +1289,19 @@ void RISCv64ISel::selectNode(DAGNode* node) {
|
|||||||
if (stride != 0) {
|
if (stride != 0) {
|
||||||
// --- 为当前索引和步长生成偏移计算指令 ---
|
// --- 为当前索引和步长生成偏移计算指令 ---
|
||||||
auto offset_vreg = getNewVReg();
|
auto offset_vreg = getNewVReg();
|
||||||
auto index_vreg = getVReg(indexValue);
|
|
||||||
|
// 处理索引 - 区分常量与动态值
|
||||||
// 如果索引是常量,先用 LI 指令加载到虚拟寄存器
|
unsigned index_vreg;
|
||||||
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
if (auto const_index = dynamic_cast<ConstantValue*>(indexValue)) {
|
||||||
|
// 对于常量索引,直接创建新的虚拟寄存器
|
||||||
|
index_vreg = getNewVReg();
|
||||||
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
auto li = std::make_unique<MachineInstr>(RVOpcodes::LI);
|
||||||
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
li->addOperand(std::make_unique<RegOperand>(index_vreg));
|
||||||
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
li->addOperand(std::make_unique<ImmOperand>(const_index->getInt()));
|
||||||
CurMBB->addInstruction(std::move(li));
|
CurMBB->addInstruction(std::move(li));
|
||||||
|
} else {
|
||||||
|
// 对于动态索引,使用已存在的虚拟寄存器
|
||||||
|
index_vreg = getVReg(indexValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法
|
// 优化:如果步长是1,可以直接移动(MV)作为偏移量,无需乘法
|
||||||
@ -1445,7 +1459,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
|||||||
|
|
||||||
// 依次添加所有索引作为后续的操作数
|
// 依次添加所有索引作为后续的操作数
|
||||||
for (auto index : gep->getIndices()) {
|
for (auto index : gep->getIndices()) {
|
||||||
// [修复] 从 Use 对象中获取真正的 Value*
|
// 从 Use 对象中获取真正的 Value*
|
||||||
gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage));
|
gep_node->operands.push_back(get_operand_node(index->getValue(), value_to_node, nodes_storage));
|
||||||
}
|
}
|
||||||
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
} else if (auto load = dynamic_cast<LoadInst*>(inst)) {
|
||||||
@ -1473,7 +1487,7 @@ std::vector<std::unique_ptr<RISCv64ISel::DAGNode>> RISCv64ISel::build_dag(BasicB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bin->getKind() >= Instruction::kFAdd) { // 假设浮点指令枚举值更大
|
if (bin->isFPBinary()) { // 假设浮点指令枚举值更大
|
||||||
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
|
auto fbin_node = create_node(DAGNode::FBINARY, bin, value_to_node, nodes_storage);
|
||||||
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
fbin_node->operands.push_back(get_operand_node(bin->getLhs(), value_to_node, nodes_storage));
|
||||||
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
fbin_node->operands.push_back(get_operand_node(bin->getRhs(), value_to_node, nodes_storage));
|
||||||
@ -1549,7 +1563,7 @@ unsigned RISCv64ISel::getTypeSizeInBytes(Type* type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// [新] 打印DAG图以供调试的辅助函数
|
// 打印DAG图以供调试的辅助函数
|
||||||
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
|
void RISCv64ISel::print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name) {
|
||||||
// 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印
|
// 检查是否有DEBUG宏或者全局变量,避免在非调试模式下打印
|
||||||
// if (!DEBUG) return;
|
// if (!DEBUG) return;
|
||||||
|
|||||||
@ -1,6 +1,122 @@
|
|||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <iostream> // 用于 std::ostream 和 std::cerr
|
||||||
|
#include <string> // 用于 std::string
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
}
|
// 辅助函数:将 PhysicalReg 枚举转换为可读的字符串
|
||||||
|
std::string regToString(PhysicalReg reg) {
|
||||||
|
switch (reg) {
|
||||||
|
case PhysicalReg::ZERO: return "x0"; case PhysicalReg::RA: return "ra";
|
||||||
|
case PhysicalReg::SP: return "sp"; case PhysicalReg::GP: return "gp";
|
||||||
|
case PhysicalReg::TP: return "tp"; case PhysicalReg::T0: return "t0";
|
||||||
|
case PhysicalReg::T1: return "t1"; case PhysicalReg::T2: return "t2";
|
||||||
|
case PhysicalReg::S0: return "s0"; case PhysicalReg::S1: return "s1";
|
||||||
|
case PhysicalReg::A0: return "a0"; case PhysicalReg::A1: return "a1";
|
||||||
|
case PhysicalReg::A2: return "a2"; case PhysicalReg::A3: return "a3";
|
||||||
|
case PhysicalReg::A4: return "a4"; case PhysicalReg::A5: return "a5";
|
||||||
|
case PhysicalReg::A6: return "a6"; case PhysicalReg::A7: return "a7";
|
||||||
|
case PhysicalReg::S2: return "s2"; case PhysicalReg::S3: return "s3";
|
||||||
|
case PhysicalReg::S4: return "s4"; case PhysicalReg::S5: return "s5";
|
||||||
|
case PhysicalReg::S6: return "s6"; case PhysicalReg::S7: return "s7";
|
||||||
|
case PhysicalReg::S8: return "s8"; case PhysicalReg::S9: return "s9";
|
||||||
|
case PhysicalReg::S10: return "s10"; case PhysicalReg::S11: return "s11";
|
||||||
|
case PhysicalReg::T3: return "t3"; case PhysicalReg::T4: return "t4";
|
||||||
|
case PhysicalReg::T5: return "t5"; case PhysicalReg::T6: return "t6";
|
||||||
|
case PhysicalReg::F0: return "f0"; case PhysicalReg::F1: return "f1";
|
||||||
|
case PhysicalReg::F2: return "f2"; case PhysicalReg::F3: return "f3";
|
||||||
|
case PhysicalReg::F4: return "f4"; case PhysicalReg::F5: return "f5";
|
||||||
|
case PhysicalReg::F6: return "f6"; case PhysicalReg::F7: return "f7";
|
||||||
|
case PhysicalReg::F8: return "f8"; case PhysicalReg::F9: return "f9";
|
||||||
|
case PhysicalReg::F10: return "f10"; case PhysicalReg::F11: return "f11";
|
||||||
|
case PhysicalReg::F12: return "f12"; case PhysicalReg::F13: return "f13";
|
||||||
|
case PhysicalReg::F14: return "f14"; case PhysicalReg::F15: return "f15";
|
||||||
|
case PhysicalReg::F16: return "f16"; case PhysicalReg::F17: return "f17";
|
||||||
|
case PhysicalReg::F18: return "f18"; case PhysicalReg::F19: return "f19";
|
||||||
|
case PhysicalReg::F20: return "f20"; case PhysicalReg::F21: return "f21";
|
||||||
|
case PhysicalReg::F22: return "f22"; case PhysicalReg::F23: return "f23";
|
||||||
|
case PhysicalReg::F24: return "f24"; case PhysicalReg::F25: return "f25";
|
||||||
|
case PhysicalReg::F26: return "f26"; case PhysicalReg::F27: return "f27";
|
||||||
|
case PhysicalReg::F28: return "f28"; case PhysicalReg::F29: return "f29";
|
||||||
|
case PhysicalReg::F30: return "f30"; case PhysicalReg::F31: return "f31";
|
||||||
|
default: return "UNKNOWN_REG";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印栈帧信息的完整实现
|
||||||
|
void MachineFunction::dumpStackFrameInfo(std::ostream& os) const {
|
||||||
|
const StackFrameInfo& info = frame_info;
|
||||||
|
|
||||||
|
os << "--- Stack Frame Info for function '" << getName() << "' ---\n";
|
||||||
|
|
||||||
|
// 打印尺寸信息
|
||||||
|
os << " Sizes:\n";
|
||||||
|
os << " Total Size: " << info.total_size << " bytes\n";
|
||||||
|
os << " Locals Size: " << info.locals_size << " bytes\n";
|
||||||
|
os << " Spill Size: " << info.spill_size << " bytes\n";
|
||||||
|
os << " Callee-Saved Size: " << info.callee_saved_size << " bytes\n";
|
||||||
|
os << "\n";
|
||||||
|
|
||||||
|
// 打印 Alloca 变量的偏移量
|
||||||
|
os << " Alloca Offsets (vreg -> offset from FP):\n";
|
||||||
|
if (info.alloca_offsets.empty()) {
|
||||||
|
os << " (None)\n";
|
||||||
|
} else {
|
||||||
|
for (const auto& pair : info.alloca_offsets) {
|
||||||
|
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
|
||||||
|
// 打印溢出变量的偏移量
|
||||||
|
os << " Spill Offsets (vreg -> offset from FP):\n";
|
||||||
|
if (info.spill_offsets.empty()) {
|
||||||
|
os << " (None)\n";
|
||||||
|
} else {
|
||||||
|
for (const auto& pair : info.spill_offsets) {
|
||||||
|
os << " %vreg" << pair.first << " -> " << pair.second << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
|
||||||
|
// 打印使用的被调用者保存寄存器
|
||||||
|
os << " Used Callee-Saved Registers:\n";
|
||||||
|
if (info.used_callee_saved_regs.empty()) {
|
||||||
|
os << " (None)\n";
|
||||||
|
} else {
|
||||||
|
os << " { ";
|
||||||
|
for (const auto& reg : info.used_callee_saved_regs) {
|
||||||
|
os << regToString(reg) << " ";
|
||||||
|
}
|
||||||
|
os << "}\n";
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
|
||||||
|
// 打印需要保存/恢复的被调用者保存寄存器 (有序)
|
||||||
|
os << " Callee-Saved Registers to Store/Restore:\n";
|
||||||
|
if (info.callee_saved_regs_to_store.empty()) {
|
||||||
|
os << " (None)\n";
|
||||||
|
} else {
|
||||||
|
os << " [ ";
|
||||||
|
for (const auto& reg : info.callee_saved_regs_to_store) {
|
||||||
|
os << regToString(reg) << " ";
|
||||||
|
}
|
||||||
|
os << "]\n";
|
||||||
|
}
|
||||||
|
os << "\n";
|
||||||
|
|
||||||
|
// 打印最终的寄存器分配结果
|
||||||
|
os << " Final Register Allocation Map (vreg -> preg):\n";
|
||||||
|
if (info.vreg_to_preg_map.empty()) {
|
||||||
|
os << " (None)\n";
|
||||||
|
} else {
|
||||||
|
for (const auto& pair : info.vreg_to_preg_map) {
|
||||||
|
os << " %vreg" << pair.first << " -> " << regToString(pair.second) << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os << "---------------------------------------------------\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
20
src/include/backend/RISCv64/Handler/EliminateFrameIndices.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef ELIMINATE_FRAME_INDICES_H
|
||||||
|
#define ELIMINATE_FRAME_INDICES_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
class EliminateFrameIndicesPass {
|
||||||
|
public:
|
||||||
|
// Pass 的主入口函数
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 帮助计算类型大小的辅助函数,从原RegAlloc中移出
|
||||||
|
unsigned getTypeSizeInBytes(Type* type);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // ELIMINATE_FRAME_INDICES_H
|
||||||
30
src/include/backend/RISCv64/Optimize/DivStrengthReduction.h
Normal file
30
src/include/backend/RISCv64/Optimize/DivStrengthReduction.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||||
|
#define RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||||
|
|
||||||
|
#include "RISCv64LLIR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class DivStrengthReduction
|
||||||
|
* @brief 除法强度削弱优化器
|
||||||
|
* * 将除法运算转换为乘法运算,使用magic number算法
|
||||||
|
* 适用于除数为常数的情况,可以显著提高性能
|
||||||
|
*/
|
||||||
|
class DivStrengthReduction : public Pass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
|
||||||
|
DivStrengthReduction() : Pass("div-strength-reduction", Granularity::Function, PassKind::Optimization) {}
|
||||||
|
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager& AM) override;
|
||||||
|
|
||||||
|
void runOnMachineFunction(MachineFunction* mfunc);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
|
|
||||||
|
#endif // RISCV64_DIV_STRENGTH_REDUCTION_H
|
||||||
@ -22,7 +22,6 @@ private:
|
|||||||
// 函数级代码生成 (实现新的流水线)
|
// 函数级代码生成 (实现新的流水线)
|
||||||
std::string function_gen(Function* func);
|
std::string function_gen(Function* func);
|
||||||
|
|
||||||
|
|
||||||
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
// 私有辅助函数,用于根据类型计算其占用的字节数。
|
||||||
unsigned getTypeSizeInBytes(Type* type);
|
unsigned getTypeSizeInBytes(Type* type);
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "IR.h" // 确保包含了您自己的IR头文件
|
#include "IR.h" // 确保包含了您自己的IR头文件
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@ -38,14 +39,14 @@ enum class PhysicalReg {
|
|||||||
|
|
||||||
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
// 用于内部表示物理寄存器在干扰图中的节点ID(一个简单的特殊ID,确保不与vreg_counter冲突)
|
||||||
// 假设 vreg_counter 不会达到这么大的值
|
// 假设 vreg_counter 不会达到这么大的值
|
||||||
PHYS_REG_START_ID = 100000,
|
PHYS_REG_START_ID = 1000000,
|
||||||
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
PHYS_REG_END_ID = PHYS_REG_START_ID + 320, // 预留足够的空间
|
||||||
};
|
};
|
||||||
|
|
||||||
// RISC-V 指令操作码枚举
|
// RISC-V 指令操作码枚举
|
||||||
enum class RVOpcodes {
|
enum class RVOpcodes {
|
||||||
// 算术指令
|
// 算术指令
|
||||||
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, DIV, DIVW, REM, REMW,
|
ADD, ADDI, ADDW, ADDIW, SUB, SUBW, MUL, MULW, MULH, DIV, DIVW, REM, REMW,
|
||||||
// 逻辑指令
|
// 逻辑指令
|
||||||
XOR, XORI, OR, ORI, AND, ANDI,
|
XOR, XORI, OR, ORI, AND, ANDI,
|
||||||
// 移位指令
|
// 移位指令
|
||||||
@ -195,6 +196,11 @@ public:
|
|||||||
preg = new_preg;
|
preg = new_preg;
|
||||||
is_virtual = false;
|
is_virtual = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setVRegNum(unsigned new_vreg_num) {
|
||||||
|
vreg_num = new_vreg_num;
|
||||||
|
is_virtual = true; // 确保设置vreg时,操作数状态正确
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
unsigned vreg_num = 0;
|
unsigned vreg_num = 0;
|
||||||
PhysicalReg preg = PhysicalReg::ZERO;
|
PhysicalReg preg = PhysicalReg::ZERO;
|
||||||
@ -274,14 +280,15 @@ private:
|
|||||||
// 栈帧信息
|
// 栈帧信息
|
||||||
struct StackFrameInfo {
|
struct StackFrameInfo {
|
||||||
int locals_size = 0; // 仅为AllocaInst分配的大小
|
int locals_size = 0; // 仅为AllocaInst分配的大小
|
||||||
|
int locals_end_offset = 0; // 记录局部变量分配结束后的偏移量(相对于s0,为负)
|
||||||
int spill_size = 0; // 仅为溢出分配的大小
|
int spill_size = 0; // 仅为溢出分配的大小
|
||||||
int total_size = 0; // 总大小
|
int total_size = 0; // 总大小
|
||||||
int callee_saved_size = 0; // 保存寄存器的大小
|
int callee_saved_size = 0; // 保存寄存器的大小
|
||||||
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
std::map<unsigned, int> alloca_offsets; // <AllocaInst的vreg, 栈偏移>
|
||||||
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
std::map<unsigned, int> spill_offsets; // <溢出vreg, 栈偏移>
|
||||||
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
std::set<PhysicalReg> used_callee_saved_regs; // 使用的保存寄存器
|
||||||
std::map<unsigned, PhysicalReg> vreg_to_preg_map;
|
std::map<unsigned, PhysicalReg> vreg_to_preg_map; // RegAlloc最终的分配结果
|
||||||
std::vector<PhysicalReg> callee_saved_regs; // 用于存储需要保存的被调用者保存寄存器列表
|
std::vector<PhysicalReg> callee_saved_regs_to_store; // 已排序的、需要存取的被调用者保存寄存器
|
||||||
};
|
};
|
||||||
|
|
||||||
// 机器函数
|
// 机器函数
|
||||||
@ -295,7 +302,7 @@ public:
|
|||||||
StackFrameInfo& getFrameInfo() { return frame_info; }
|
StackFrameInfo& getFrameInfo() { return frame_info; }
|
||||||
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
|
const std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() const { return blocks; }
|
||||||
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
|
std::vector<std::unique_ptr<MachineBasicBlock>>& getBlocks() { return blocks; }
|
||||||
|
void dumpStackFrameInfo(std::ostream& os = std::cerr) const;
|
||||||
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
|
void addBlock(std::unique_ptr<MachineBasicBlock> block) {
|
||||||
blocks.push_back(std::move(block));
|
blocks.push_back(std::move(block));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,10 @@
|
|||||||
#include "CalleeSavedHandler.h"
|
#include "CalleeSavedHandler.h"
|
||||||
#include "LegalizeImmediates.h"
|
#include "LegalizeImmediates.h"
|
||||||
#include "PrologueEpilogueInsertion.h"
|
#include "PrologueEpilogueInsertion.h"
|
||||||
|
#include "EliminateFrameIndices.h"
|
||||||
#include "Pass.h"
|
#include "Pass.h"
|
||||||
|
#include "DivStrengthReduction.h"
|
||||||
|
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,15 @@
|
|||||||
|
|
||||||
#include "RISCv64LLIR.h"
|
#include "RISCv64LLIR.h"
|
||||||
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
#include "RISCv64ISel.h" // 包含 RISCv64ISel.h 以访问 ISel 和 Value 类型
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
extern int DEBUG;
|
extern int DEBUG;
|
||||||
extern int DEEPDEBUG;
|
extern int DEEPDEBUG;
|
||||||
|
extern int DEBUGLENGTH; // 用于限制调试输出的长度
|
||||||
|
extern int DEEPERDEBUG; // 用于更深层次的调试输出
|
||||||
|
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
@ -17,58 +23,98 @@ public:
|
|||||||
void run();
|
void run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using LiveSet = std::set<unsigned>; // 活跃虚拟寄存器集合
|
// 类型定义,与Python版本对应
|
||||||
using InterferenceGraph = std::map<unsigned, std::set<unsigned>>;
|
using VRegSet = std::set<unsigned>;
|
||||||
|
using InterferenceGraph = std::map<unsigned, VRegSet>;
|
||||||
|
using VRegStack = std::vector<unsigned>; // 使用vector模拟栈,方便遍历
|
||||||
|
using MoveList = std::map<unsigned, std::set<const MachineInstr*>>;
|
||||||
|
using AliasMap = std::map<unsigned, unsigned>;
|
||||||
|
using ColorMap = std::map<unsigned, PhysicalReg>;
|
||||||
|
using VRegMoveSet = std::set<const MachineInstr*>;
|
||||||
|
|
||||||
// 栈帧管理
|
// --- 核心算法流程 ---
|
||||||
void eliminateFrameIndices();
|
void initialize();
|
||||||
|
void build();
|
||||||
// 活跃性分析
|
void makeWorklist();
|
||||||
|
void simplify();
|
||||||
|
void coalesce();
|
||||||
|
void freeze();
|
||||||
|
void selectSpill();
|
||||||
|
void assignColors();
|
||||||
|
void rewriteProgram();
|
||||||
|
bool doAllocation();
|
||||||
|
void applyColoring();
|
||||||
|
|
||||||
|
void dumpState(const std::string &stage);
|
||||||
|
|
||||||
|
void precolorByCallingConvention();
|
||||||
|
|
||||||
|
// --- 辅助函数 ---
|
||||||
|
void getInstrUseDef(const MachineInstr* instr, VRegSet& use, VRegSet& def);
|
||||||
|
void getInstrUseDef_Liveness(const MachineInstr *instr, VRegSet &use, VRegSet &def);
|
||||||
|
void addEdge(unsigned u, unsigned v);
|
||||||
|
VRegSet adjacent(unsigned n);
|
||||||
|
VRegMoveSet nodeMoves(unsigned n);
|
||||||
|
bool moveRelated(unsigned n);
|
||||||
|
void decrementDegree(unsigned m);
|
||||||
|
void enableMoves(const VRegSet& nodes);
|
||||||
|
unsigned getAlias(unsigned n);
|
||||||
|
void addWorklist(unsigned u);
|
||||||
|
bool briggsHeuristic(unsigned u, unsigned v);
|
||||||
|
bool georgeHeuristic(unsigned u, unsigned v);
|
||||||
|
void combine(unsigned u, unsigned v);
|
||||||
|
void freezeMoves(unsigned u);
|
||||||
|
void collectUsedCalleeSavedRegs();
|
||||||
|
bool isFPVReg(unsigned vreg) const;
|
||||||
|
std::string regToString(PhysicalReg reg);
|
||||||
|
std::string regIdToString(unsigned id);
|
||||||
|
|
||||||
|
// --- 活跃性分析 ---
|
||||||
void analyzeLiveness();
|
void analyzeLiveness();
|
||||||
|
|
||||||
// 构建干扰图
|
|
||||||
void buildInterferenceGraph();
|
|
||||||
|
|
||||||
// 图着色分配寄存器
|
|
||||||
void colorGraph();
|
|
||||||
|
|
||||||
// 重写函数,替换vreg并插入溢出代码
|
|
||||||
void rewriteFunction();
|
|
||||||
|
|
||||||
// 辅助函数,获取指令的Use/Def集合
|
|
||||||
void getInstrUseDef(MachineInstr* instr, LiveSet& use, LiveSet& def);
|
|
||||||
|
|
||||||
// 辅助函数,处理调用约定
|
|
||||||
void handleCallingConvention();
|
|
||||||
|
|
||||||
MachineFunction* MFunc;
|
MachineFunction* MFunc;
|
||||||
|
RISCv64ISel* ISel;
|
||||||
// 活跃性分析结果
|
|
||||||
std::map<const MachineInstr*, LiveSet> live_in_map;
|
|
||||||
std::map<const MachineInstr*, LiveSet> live_out_map;
|
|
||||||
|
|
||||||
// 干扰图
|
// --- 算法数据结构 ---
|
||||||
InterferenceGraph interference_graph;
|
// 寄存器池
|
||||||
|
|
||||||
// 图着色结果
|
|
||||||
std::map<unsigned, PhysicalReg> color_map; // vreg -> preg
|
|
||||||
std::set<unsigned> spilled_vregs; // 被溢出的vreg集合
|
|
||||||
|
|
||||||
// 可用的物理寄存器池
|
|
||||||
std::vector<PhysicalReg> allocable_int_regs;
|
std::vector<PhysicalReg> allocable_int_regs;
|
||||||
std::vector<PhysicalReg> allocable_fp_regs;
|
std::vector<PhysicalReg> allocable_fp_regs;
|
||||||
|
int K_int; // 整数寄存器数量
|
||||||
|
int K_fp; // 浮点寄存器数量
|
||||||
|
|
||||||
// 存储vreg到IR Value*的反向映射
|
// 节点集合
|
||||||
// 这个map将在run()函数开始时被填充,并在rewriteFunction()中使用。
|
VRegSet precolored; // 预着色的节点 (物理寄存器)
|
||||||
std::map<unsigned, Value*> vreg_to_value_map;
|
VRegSet initial; // 初始的、所有待处理的虚拟寄存器节点
|
||||||
std::map<PhysicalReg, unsigned> preg_to_vreg_id_map; // 物理寄存器到特殊vreg ID的映射
|
VRegSet simplifyWorklist;
|
||||||
|
VRegSet freezeWorklist;
|
||||||
// 用于计算类型大小的辅助函数
|
VRegSet spillWorklist;
|
||||||
unsigned getTypeSizeInBytes(Type* type);
|
VRegSet spilledNodes;
|
||||||
|
VRegSet coalescedNodes;
|
||||||
|
VRegSet coloredNodes;
|
||||||
|
VRegStack selectStack;
|
||||||
|
|
||||||
// 辅助函数,用于打印集合
|
// Move指令相关
|
||||||
static void printLiveSet(const LiveSet& s, const std::string& name, std::ostream& os);
|
std::set<const MachineInstr*> coalescedMoves;
|
||||||
|
std::set<const MachineInstr*> constrainedMoves;
|
||||||
|
std::set<const MachineInstr*> frozenMoves;
|
||||||
|
std::set<const MachineInstr*> worklistMoves;
|
||||||
|
std::set<const MachineInstr*> activeMoves;
|
||||||
|
|
||||||
|
// 数据结构
|
||||||
|
InterferenceGraph adjSet;
|
||||||
|
std::map<unsigned, VRegSet> adjList; // 邻接表
|
||||||
|
std::map<unsigned, int> degree;
|
||||||
|
MoveList moveList;
|
||||||
|
AliasMap alias;
|
||||||
|
ColorMap color_map;
|
||||||
|
|
||||||
|
// 活跃性分析结果
|
||||||
|
std::map<const MachineInstr*, VRegSet> live_in_map;
|
||||||
|
std::map<const MachineInstr*, VRegSet> live_out_map;
|
||||||
|
|
||||||
|
// VReg -> Value* 和 VReg -> Type* 的映射
|
||||||
|
const std::map<unsigned, Value*>& vreg_to_value_map;
|
||||||
|
const std::map<unsigned, Type*>& vreg_type_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sysy
|
} // namespace sysy
|
||||||
|
|||||||
@ -728,6 +728,8 @@ class Instruction : public User {
|
|||||||
kPhi = 0x1UL << 39,
|
kPhi = 0x1UL << 39,
|
||||||
kBitItoF = 0x1UL << 40,
|
kBitItoF = 0x1UL << 40,
|
||||||
kBitFtoI = 0x1UL << 41,
|
kBitFtoI = 0x1UL << 41,
|
||||||
|
kSRA = 0x1UL << 42,
|
||||||
|
kMulh = 0x1UL << 43
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -824,6 +826,12 @@ public:
|
|||||||
return "Memset";
|
return "Memset";
|
||||||
case kPhi:
|
case kPhi:
|
||||||
return "Phi";
|
return "Phi";
|
||||||
|
case kBitItoF:
|
||||||
|
return "BitItoF";
|
||||||
|
case kBitFtoI:
|
||||||
|
return "BitFtoI";
|
||||||
|
case kSRA:
|
||||||
|
return "SRA";
|
||||||
default:
|
default:
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
@ -835,11 +843,15 @@ public:
|
|||||||
|
|
||||||
bool isBinary() const {
|
bool isBinary() const {
|
||||||
static constexpr uint64_t BinaryOpMask =
|
static constexpr uint64_t BinaryOpMask =
|
||||||
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr) |
|
(kAdd | kSub | kMul | kDiv | kRem | kAnd | kOr | kSRA | kMulh) |
|
||||||
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE) |
|
(kICmpEQ | kICmpNE | kICmpLT | kICmpGT | kICmpLE | kICmpGE);
|
||||||
|
return kind & BinaryOpMask;
|
||||||
|
}
|
||||||
|
bool isFPBinary() const {
|
||||||
|
static constexpr uint64_t FPBinaryOpMask =
|
||||||
(kFAdd | kFSub | kFMul | kFDiv) |
|
(kFAdd | kFSub | kFMul | kFDiv) |
|
||||||
(kFCmpEQ | kFCmpNE | kFCmpLT | kFCmpGT | kFCmpLE | kFCmpGE);
|
(kFCmpEQ | kFCmpNE | kFCmpLT | kFCmpGT | kFCmpLE | kFCmpGE);
|
||||||
return kind & BinaryOpMask;
|
return kind & FPBinaryOpMask;
|
||||||
}
|
}
|
||||||
bool isUnary() const {
|
bool isUnary() const {
|
||||||
static constexpr uint64_t UnaryOpMask =
|
static constexpr uint64_t UnaryOpMask =
|
||||||
|
|||||||
@ -217,6 +217,12 @@ class IRBuilder {
|
|||||||
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
BinaryInst * createOrInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||||
return createBinaryInst(Instruction::kOr, Type::getIntType(), lhs, rhs, name);
|
return createBinaryInst(Instruction::kOr, Type::getIntType(), lhs, rhs, name);
|
||||||
} ///< 创建按位或指令
|
} ///< 创建按位或指令
|
||||||
|
BinaryInst * createSRAInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||||
|
return createBinaryInst(Instruction::kSRA, Type::getIntType(), lhs, rhs, name);
|
||||||
|
} ///< 创建算术右移指令
|
||||||
|
BinaryInst * createMulhInst(Value *lhs, Value *rhs, const std::string &name = "") {
|
||||||
|
return createBinaryInst(Instruction::kMulh, Type::getIntType(), lhs, rhs, name);
|
||||||
|
} ///< 创建高位乘法指令
|
||||||
CallInst * createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name = "") {
|
CallInst * createCallInst(Function *callee, const std::vector<Value *> &args, const std::string &name = "") {
|
||||||
std::string newName;
|
std::string newName;
|
||||||
if (name.empty() && callee->getReturnType() != Type::getVoidType()) {
|
if (name.empty() && callee->getReturnType() != Type::getVoidType()) {
|
||||||
|
|||||||
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
20
src/include/midend/Pass/Optimize/BuildCFG.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IR.h"
|
||||||
|
#include "Pass.h"
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
class BuildCFG : public OptimizationPass {
|
||||||
|
public:
|
||||||
|
static void *ID;
|
||||||
|
BuildCFG() : OptimizationPass("BuildCFG", Granularity::Function) {}
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||||
|
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
24
src/include/midend/Pass/Optimize/LargeArrayToGlobal.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Pass.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
class LargeArrayToGlobalPass : public OptimizationPass {
|
||||||
|
public:
|
||||||
|
static void *ID;
|
||||||
|
|
||||||
|
LargeArrayToGlobalPass() : OptimizationPass("LargeArrayToGlobal", Granularity::Module) {}
|
||||||
|
|
||||||
|
bool runOnModule(Module *M, AnalysisManager &AM) override;
|
||||||
|
void *getPassID() const override {
|
||||||
|
return &ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned calculateTypeSize(Type *type);
|
||||||
|
void convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M);
|
||||||
|
std::string generateUniqueGlobalName(AllocaInst *alloca, Function *F);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -279,7 +279,7 @@ private:
|
|||||||
IRBuilder *pBuilder;
|
IRBuilder *pBuilder;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PassManager() = default;
|
PassManager() = delete;
|
||||||
~PassManager() = default;
|
~PassManager() = default;
|
||||||
|
|
||||||
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
PassManager(Module *module, IRBuilder *builder) : pmodule(module) ,pBuilder(builder), analysisManager(module) {}
|
||||||
|
|||||||
@ -11,6 +11,8 @@ add_library(midend_lib STATIC
|
|||||||
Pass/Optimize/Reg2Mem.cpp
|
Pass/Optimize/Reg2Mem.cpp
|
||||||
Pass/Optimize/SysYIRCFGOpt.cpp
|
Pass/Optimize/SysYIRCFGOpt.cpp
|
||||||
Pass/Optimize/SCCP.cpp
|
Pass/Optimize/SCCP.cpp
|
||||||
|
Pass/Optimize/BuildCFG.cpp
|
||||||
|
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 包含中端模块所需的头文件路径
|
# 包含中端模块所需的头文件路径
|
||||||
|
|||||||
79
src/midend/Pass/Optimize/BuildCFG.cpp
Normal file
79
src/midend/Pass/Optimize/BuildCFG.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include "BuildCFG.h"
|
||||||
|
#include "Dom.h"
|
||||||
|
#include "Liveness.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <queue>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
void *BuildCFG::ID = (void *)&BuildCFG::ID; // 定义唯一的 Pass ID
|
||||||
|
|
||||||
|
// 声明Pass的分析使用
|
||||||
|
void BuildCFG::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||||
|
// BuildCFG不依赖其他分析
|
||||||
|
// analysisDependencies.insert(&DominatorTreeAnalysisPass::ID); // 错误的例子
|
||||||
|
|
||||||
|
// BuildCFG会使所有依赖于CFG的分析结果失效,所以它必须声明这些失效
|
||||||
|
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||||
|
analysisInvalidations.insert(&LivenessAnalysisPass::ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildCFG::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||||
|
if (DEBUG) {
|
||||||
|
std::cout << "Running BuildCFG pass on function: " << F->getName() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
// 1. 清空所有基本块的前驱和后继列表
|
||||||
|
for (auto &bb : F->getBasicBlocks()) {
|
||||||
|
bb->clearPredecessors();
|
||||||
|
bb->clearSuccessors();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 遍历每个基本块,重建CFG
|
||||||
|
for (auto &bb : F->getBasicBlocks()) {
|
||||||
|
// 获取基本块的最后一条指令
|
||||||
|
auto &inst = *bb->terminator();
|
||||||
|
Instruction *termInst = inst.get();
|
||||||
|
// 确保基本块有终结指令
|
||||||
|
if (!termInst) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据终结指令类型,建立前驱后继关系
|
||||||
|
if (termInst->isBranch()) {
|
||||||
|
// 无条件跳转
|
||||||
|
if (termInst->isUnconditional()) {
|
||||||
|
auto brInst = dynamic_cast<UncondBrInst *>(termInst);
|
||||||
|
BasicBlock *succ = dynamic_cast<BasicBlock *>(brInst->getBlock());
|
||||||
|
assert(succ && "Branch instruction's target must be a BasicBlock");
|
||||||
|
bb->addSuccessor(succ);
|
||||||
|
succ->addPredecessor(bb.get());
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
// 条件跳转
|
||||||
|
} else if (termInst->isConditional()) {
|
||||||
|
auto brInst = dynamic_cast<CondBrInst *>(termInst);
|
||||||
|
BasicBlock *trueSucc = dynamic_cast<BasicBlock *>(brInst->getThenBlock());
|
||||||
|
BasicBlock *falseSucc = dynamic_cast<BasicBlock *>(brInst->getElseBlock());
|
||||||
|
|
||||||
|
assert(trueSucc && falseSucc && "Branch instruction's targets must be BasicBlocks");
|
||||||
|
|
||||||
|
bb->addSuccessor(trueSucc);
|
||||||
|
trueSucc->addPredecessor(bb.get());
|
||||||
|
bb->addSuccessor(falseSucc);
|
||||||
|
falseSucc->addPredecessor(bb.get());
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
} else if (auto retInst = dynamic_cast<ReturnInst *>(termInst)) {
|
||||||
|
// RetInst没有后继,无需处理
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
143
src/midend/Pass/Optimize/LargeArrayToGlobal.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
#include "../../include/midend/Pass/Optimize/LargeArrayToGlobal.h"
|
||||||
|
#include "../../IR.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
// Helper function to convert type to string
|
||||||
|
static std::string typeToString(Type *type) {
|
||||||
|
if (!type) return "null";
|
||||||
|
|
||||||
|
switch (type->getKind()) {
|
||||||
|
case Type::kInt:
|
||||||
|
return "int";
|
||||||
|
case Type::kFloat:
|
||||||
|
return "float";
|
||||||
|
case Type::kPointer:
|
||||||
|
return "ptr";
|
||||||
|
case Type::kArray: {
|
||||||
|
auto *arrayType = type->as<ArrayType>();
|
||||||
|
return "[" + std::to_string(arrayType->getNumElements()) + " x " +
|
||||||
|
typeToString(arrayType->getElementType()) + "]";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *LargeArrayToGlobalPass::ID = &LargeArrayToGlobalPass::ID;
|
||||||
|
|
||||||
|
bool LargeArrayToGlobalPass::runOnModule(Module *M, AnalysisManager &AM) {
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
if (!M) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all alloca instructions from all functions
|
||||||
|
std::vector<std::pair<AllocaInst*, Function*>> allocasToConvert;
|
||||||
|
|
||||||
|
for (auto &funcPair : M->getFunctions()) {
|
||||||
|
Function *F = funcPair.second.get();
|
||||||
|
if (!F || F->getBasicBlocks().begin() == F->getBasicBlocks().end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &BB : F->getBasicBlocks()) {
|
||||||
|
for (auto &inst : BB->getInstructions()) {
|
||||||
|
if (auto *alloca = dynamic_cast<AllocaInst*>(inst.get())) {
|
||||||
|
Type *allocatedType = alloca->getAllocatedType();
|
||||||
|
|
||||||
|
// Calculate the size of the allocated type
|
||||||
|
unsigned size = calculateTypeSize(allocatedType);
|
||||||
|
|
||||||
|
// Debug: print size information
|
||||||
|
std::cout << "LargeArrayToGlobalPass: Found alloca with size " << size
|
||||||
|
<< " for type " << typeToString(allocatedType) << std::endl;
|
||||||
|
|
||||||
|
// Convert arrays of 1KB (1024 bytes) or larger to global variables
|
||||||
|
if (size >= 1024) {
|
||||||
|
std::cout << "LargeArrayToGlobalPass: Converting array of size " << size << " to global" << std::endl;
|
||||||
|
allocasToConvert.emplace_back(alloca, F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the collected alloca instructions to global variables
|
||||||
|
for (auto [alloca, F] : allocasToConvert) {
|
||||||
|
convertAllocaToGlobal(alloca, F, M);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned LargeArrayToGlobalPass::calculateTypeSize(Type *type) {
|
||||||
|
if (!type) return 0;
|
||||||
|
|
||||||
|
switch (type->getKind()) {
|
||||||
|
case Type::kInt:
|
||||||
|
case Type::kFloat:
|
||||||
|
return 4;
|
||||||
|
case Type::kPointer:
|
||||||
|
return 8;
|
||||||
|
case Type::kArray: {
|
||||||
|
auto *arrayType = type->as<ArrayType>();
|
||||||
|
return arrayType->getNumElements() * calculateTypeSize(arrayType->getElementType());
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LargeArrayToGlobalPass::convertAllocaToGlobal(AllocaInst *alloca, Function *F, Module *M) {
|
||||||
|
Type *allocatedType = alloca->getAllocatedType();
|
||||||
|
|
||||||
|
// Create a unique name for the global variable
|
||||||
|
std::string globalName = generateUniqueGlobalName(alloca, F);
|
||||||
|
|
||||||
|
// Create the global variable - GlobalValue expects pointer type
|
||||||
|
Type *pointerType = Type::getPointerType(allocatedType);
|
||||||
|
GlobalValue *globalVar = M->createGlobalValue(globalName, pointerType);
|
||||||
|
|
||||||
|
if (!globalVar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace all uses of the alloca with the global variable
|
||||||
|
alloca->replaceAllUsesWith(globalVar);
|
||||||
|
|
||||||
|
// Remove the alloca instruction from its basic block
|
||||||
|
for (auto &BB : F->getBasicBlocks()) {
|
||||||
|
auto &instructions = BB->getInstructions();
|
||||||
|
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
|
||||||
|
if (it->get() == alloca) {
|
||||||
|
instructions.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string LargeArrayToGlobalPass::generateUniqueGlobalName(AllocaInst *alloca, Function *F) {
|
||||||
|
std::string baseName = alloca->getName();
|
||||||
|
if (baseName.empty()) {
|
||||||
|
baseName = "array";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure uniqueness by appending function name and counter
|
||||||
|
static std::unordered_map<std::string, int> nameCounter;
|
||||||
|
std::string key = F->getName() + "." + baseName;
|
||||||
|
|
||||||
|
int counter = nameCounter[key]++;
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << key << "." << counter;
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@ -6,6 +6,8 @@
|
|||||||
#include "Mem2Reg.h"
|
#include "Mem2Reg.h"
|
||||||
#include "Reg2Mem.h"
|
#include "Reg2Mem.h"
|
||||||
#include "SCCP.h"
|
#include "SCCP.h"
|
||||||
|
#include "BuildCFG.h"
|
||||||
|
#include "LargeArrayToGlobal.h"
|
||||||
#include "Pass.h"
|
#include "Pass.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@ -35,10 +37,13 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
3. 添加优化passid
|
3. 添加优化passid
|
||||||
*/
|
*/
|
||||||
// 注册分析遍
|
// 注册分析遍
|
||||||
registerAnalysisPass<sysy::DominatorTreeAnalysisPass>();
|
registerAnalysisPass<DominatorTreeAnalysisPass>();
|
||||||
registerAnalysisPass<sysy::LivenessAnalysisPass>();
|
registerAnalysisPass<LivenessAnalysisPass>();
|
||||||
|
|
||||||
// 注册优化遍
|
// 注册优化遍
|
||||||
|
registerOptimizationPass<BuildCFG>();
|
||||||
|
registerOptimizationPass<LargeArrayToGlobalPass>();
|
||||||
|
|
||||||
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
registerOptimizationPass<SysYDelInstAfterBrPass>();
|
||||||
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
registerOptimizationPass<SysYDelNoPreBLockPass>();
|
||||||
registerOptimizationPass<SysYBlockMergePass>();
|
registerOptimizationPass<SysYBlockMergePass>();
|
||||||
@ -58,14 +63,24 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
|
if (DEBUG) std::cout << "Applying -O1 optimizations.\n";
|
||||||
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
|
if (DEBUG) std::cout << "--- Running custom optimization sequence ---\n";
|
||||||
|
|
||||||
// this->clearPasses();
|
if(DEBUG) {
|
||||||
// this->addPass(&SysYDelInstAfterBrPass::ID);
|
std::cout << "=== IR Before CFGOpt Optimizations ===\n";
|
||||||
// this->addPass(&SysYDelNoPreBLockPass::ID);
|
printPasses();
|
||||||
// this->addPass(&SysYBlockMergePass::ID);
|
}
|
||||||
// this->addPass(&SysYDelEmptyBlockPass::ID);
|
|
||||||
// this->addPass(&SysYCondBr2BrPass::ID);
|
this->clearPasses();
|
||||||
// this->addPass(&SysYAddReturnPass::ID);
|
this->addPass(&BuildCFG::ID);
|
||||||
// this->run();
|
this->addPass(&LargeArrayToGlobalPass::ID);
|
||||||
|
this->run();
|
||||||
|
|
||||||
|
this->clearPasses();
|
||||||
|
this->addPass(&SysYDelInstAfterBrPass::ID);
|
||||||
|
this->addPass(&SysYDelNoPreBLockPass::ID);
|
||||||
|
this->addPass(&SysYBlockMergePass::ID);
|
||||||
|
this->addPass(&SysYDelEmptyBlockPass::ID);
|
||||||
|
this->addPass(&SysYCondBr2BrPass::ID);
|
||||||
|
this->addPass(&SysYAddReturnPass::ID);
|
||||||
|
this->run();
|
||||||
|
|
||||||
if(DEBUG) {
|
if(DEBUG) {
|
||||||
std::cout << "=== IR After CFGOpt Optimizations ===\n";
|
std::cout << "=== IR After CFGOpt Optimizations ===\n";
|
||||||
|
|||||||
@ -15,6 +15,29 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
namespace sysy {
|
namespace sysy {
|
||||||
|
|
||||||
|
std::pair<long long, int> calculate_signed_magic(int d) {
|
||||||
|
if (d == 0) throw std::runtime_error("Division by zero");
|
||||||
|
if (d == 1 || d == -1) return {0, 0}; // Not used by strength reduction
|
||||||
|
|
||||||
|
int k = 0;
|
||||||
|
unsigned int ad = (d > 0) ? d : -d;
|
||||||
|
unsigned int temp = ad;
|
||||||
|
while (temp > 0) {
|
||||||
|
temp >>= 1;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if ((ad & (ad - 1)) == 0) { // if power of 2
|
||||||
|
k--;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned __int128 m_val = 1;
|
||||||
|
m_val <<= (32 + k - 1);
|
||||||
|
unsigned __int128 m_prime = m_val / ad;
|
||||||
|
long long m = m_prime + 1;
|
||||||
|
|
||||||
|
return {m, k};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// std::vector<Value*> BinaryValueStack; ///< 用于存储value的栈
|
// std::vector<Value*> BinaryValueStack; ///< 用于存储value的栈
|
||||||
// std::vector<int> BinaryOpStack; ///< 用于存储二元表达式的操作符栈
|
// std::vector<int> BinaryOpStack; ///< 用于存储二元表达式的操作符栈
|
||||||
@ -249,7 +272,26 @@ void SysYIRGenerator::compute() {
|
|||||||
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
|
case BinaryOp::ADD: resultValue = builder.createAddInst(lhs, rhs); break;
|
||||||
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
|
case BinaryOp::SUB: resultValue = builder.createSubInst(lhs, rhs); break;
|
||||||
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
|
case BinaryOp::MUL: resultValue = builder.createMulInst(lhs, rhs); break;
|
||||||
case BinaryOp::DIV: resultValue = builder.createDivInst(lhs, rhs); break;
|
case BinaryOp::DIV: {
|
||||||
|
ConstantInteger *rhsConst = dynamic_cast<ConstantInteger *>(rhs);
|
||||||
|
if (rhsConst) {
|
||||||
|
int divisor = rhsConst->getInt();
|
||||||
|
if (divisor > 0 && (divisor & (divisor - 1)) == 0) {
|
||||||
|
int shift = 0;
|
||||||
|
int temp = divisor;
|
||||||
|
while (temp > 1) {
|
||||||
|
temp >>= 1;
|
||||||
|
shift++;
|
||||||
|
}
|
||||||
|
resultValue = builder.createSRAInst(lhs, ConstantInteger::get(shift));
|
||||||
|
} else {
|
||||||
|
resultValue = builder.createDivInst(lhs, rhs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultValue = builder.createDivInst(lhs, rhs);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case BinaryOp::MOD: resultValue = builder.createRemInst(lhs, rhs); break;
|
case BinaryOp::MOD: resultValue = builder.createRemInst(lhs, rhs); break;
|
||||||
}
|
}
|
||||||
} else if (commonType == Type::getFloatType()) {
|
} else if (commonType == Type::getFloatType()) {
|
||||||
|
|||||||
@ -240,6 +240,8 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
case Kind::kMul:
|
case Kind::kMul:
|
||||||
case Kind::kDiv:
|
case Kind::kDiv:
|
||||||
case Kind::kRem:
|
case Kind::kRem:
|
||||||
|
case Kind::kSRA:
|
||||||
|
case Kind::kMulh:
|
||||||
case Kind::kFAdd:
|
case Kind::kFAdd:
|
||||||
case Kind::kFSub:
|
case Kind::kFSub:
|
||||||
case Kind::kFMul:
|
case Kind::kFMul:
|
||||||
@ -272,6 +274,8 @@ void SysYPrinter::printInst(Instruction *pInst) {
|
|||||||
case Kind::kMul: std::cout << "mul"; break;
|
case Kind::kMul: std::cout << "mul"; break;
|
||||||
case Kind::kDiv: std::cout << "sdiv"; break;
|
case Kind::kDiv: std::cout << "sdiv"; break;
|
||||||
case Kind::kRem: std::cout << "srem"; break;
|
case Kind::kRem: std::cout << "srem"; break;
|
||||||
|
case Kind::kSRA: std::cout << "ashr"; break;
|
||||||
|
case Kind::kMulh: std::cout << "mulh"; break;
|
||||||
case Kind::kFAdd: std::cout << "fadd"; break;
|
case Kind::kFAdd: std::cout << "fadd"; break;
|
||||||
case Kind::kFSub: std::cout << "fsub"; break;
|
case Kind::kFSub: std::cout << "fsub"; break;
|
||||||
case Kind::kFMul: std::cout << "fmul"; break;
|
case Kind::kFMul: std::cout << "fmul"; break;
|
||||||
|
|||||||
@ -21,6 +21,8 @@ using namespace sysy;
|
|||||||
|
|
||||||
int DEBUG = 0;
|
int DEBUG = 0;
|
||||||
int DEEPDEBUG = 0;
|
int DEEPDEBUG = 0;
|
||||||
|
int DEEPERDEBUG = 0;
|
||||||
|
int DEBUGLENGTH = 50;
|
||||||
|
|
||||||
static string argStopAfter;
|
static string argStopAfter;
|
||||||
static string argInputFile;
|
static string argInputFile;
|
||||||
|
|||||||
Reference in New Issue
Block a user