Compare commits
10 Commits
midend-Fun
...
midend
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d72601d9db | ||
|
|
8094fd5705 | ||
|
|
ad5f35c1a0 | ||
|
|
839791e862 | ||
|
|
751d3df2ac | ||
|
|
1d59e9e256 | ||
|
|
db122cabbd | ||
|
|
ce4d4b5f5b | ||
| 042b1a5d99 | |||
| 937833117e |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -36,7 +36,7 @@ doxygen
|
|||||||
|
|
||||||
!/testdata/functional/*.out
|
!/testdata/functional/*.out
|
||||||
!/testdata/h_functional/*.out
|
!/testdata/h_functional/*.out
|
||||||
!/testdata/performance/*.out
|
testdata/performance/
|
||||||
build/
|
build/
|
||||||
.antlr
|
.antlr
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|||||||
@@ -20,18 +20,19 @@ QEMU_RISCV64="qemu-riscv64"
|
|||||||
|
|
||||||
# --- 初始化变量 ---
|
# --- 初始化变量 ---
|
||||||
EXECUTE_MODE=false
|
EXECUTE_MODE=false
|
||||||
IR_EXECUTE_MODE=false # 新增
|
IR_EXECUTE_MODE=false
|
||||||
CLEAN_MODE=false
|
CLEAN_MODE=false
|
||||||
OPTIMIZE_FLAG=""
|
OPTIMIZE_FLAG=""
|
||||||
SYSYC_TIMEOUT=30
|
SYSYC_TIMEOUT=30
|
||||||
LLC_TIMEOUT=10 # 新增
|
LLC_TIMEOUT=10
|
||||||
GCC_TIMEOUT=10
|
GCC_TIMEOUT=10
|
||||||
EXEC_TIMEOUT=30
|
EXEC_TIMEOUT=30
|
||||||
MAX_OUTPUT_LINES=20
|
MAX_OUTPUT_LINES=20
|
||||||
|
MAX_OUTPUT_CHARS=1000
|
||||||
SY_FILES=()
|
SY_FILES=()
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
FAILED_CASES_LIST=""
|
FAILED_CASES_LIST=""
|
||||||
INTERRUPTED=false # 新增
|
INTERRUPTED=false
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# --- 函数定义 ---
|
# --- 函数定义 ---
|
||||||
@@ -50,22 +51,31 @@ show_help() {
|
|||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
|
echo " -et N 设置 qemu 自动化执行超时为 N 秒 (默认: 30)。"
|
||||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||||
|
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
echo ""
|
echo ""
|
||||||
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
echo "可在任何时候按 Ctrl+C 来中断测试并显示当前已完成的测例总结。"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 显示文件内容并根据行数和字符数截断的函数
|
||||||
display_file_content() {
|
display_file_content() {
|
||||||
local file_path="$1"
|
local file_path="$1"
|
||||||
local title="$2"
|
local title="$2"
|
||||||
local max_lines="$3"
|
local max_lines="$3"
|
||||||
|
local max_chars="$4" # 新增参数
|
||||||
if [ ! -f "$file_path" ]; then return; fi
|
if [ ! -f "$file_path" ]; then return; fi
|
||||||
echo -e "$title"
|
echo -e "$title"
|
||||||
local line_count
|
local line_count
|
||||||
|
local char_count
|
||||||
line_count=$(wc -l < "$file_path")
|
line_count=$(wc -l < "$file_path")
|
||||||
|
char_count=$(wc -c < "$file_path")
|
||||||
|
|
||||||
if [ "$line_count" -gt "$max_lines" ]; then
|
if [ "$line_count" -gt "$max_lines" ]; then
|
||||||
head -n "$max_lines" "$file_path"
|
head -n "$max_lines" "$file_path"
|
||||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||||
|
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||||
|
head -c "$max_chars" "$file_path"
|
||||||
|
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||||
else
|
else
|
||||||
cat "$file_path"
|
cat "$file_path"
|
||||||
fi
|
fi
|
||||||
@@ -131,6 +141,7 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-h|--help) show_help; exit 0 ;;
|
-h|--help) show_help; exit 0 ;;
|
||||||
-*) echo "未知选项: $1"; show_help; exit 1 ;;
|
-*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||||
*)
|
*)
|
||||||
@@ -180,6 +191,8 @@ TOTAL_CASES=${#SY_FILES[@]}
|
|||||||
echo "SysY 单例测试运行器启动..."
|
echo "SysY 单例测试运行器启动..."
|
||||||
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
if [ -n "$OPTIMIZE_FLAG" ]; then echo "优化等级: ${OPTIMIZE_FLAG}"; fi
|
||||||
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
echo "超时设置: sysyc=${SYSYC_TIMEOUT}s, llc=${LLC_TIMEOUT}s, gcc=${GCC_TIMEOUT}s, qemu=${EXEC_TIMEOUT}s"
|
||||||
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
|
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
for sy_file in "${SY_FILES[@]}"; do
|
for sy_file in "${SY_FILES[@]}"; do
|
||||||
@@ -260,8 +273,8 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
out_ok=1
|
out_ok=1
|
||||||
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
if ! diff -q <(tr -d '[:space:]' < "${output_actual_file}") <(tr -d '[:space:]' < "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
|
||||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; out_ok=0
|
||||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
|
if [ "$ret_ok" -eq 1 ] && [ "$out_ok" -eq 1 ]; then echo -e "\e[32m 返回码与标准输出测试成功。\e[0m"; else is_passed=0; fi
|
||||||
@@ -271,8 +284,8 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
echo -e "\e[32m 标准输出测试成功。\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
echo -e "\e[31m 标准输出测试失败。\e[0m"; is_passed=0
|
||||||
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_reference_file}" " \e[36m--- 期望输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file}" " \e[36m--- 实际输出 ---\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -301,4 +314,4 @@ for sy_file in "${SY_FILES[@]}"; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# --- 打印最终总结 ---
|
# --- 打印最终总结 ---
|
||||||
print_summary
|
print_summary
|
||||||
|
|||||||
@@ -27,11 +27,12 @@ LLC_TIMEOUT=10
|
|||||||
GCC_TIMEOUT=10
|
GCC_TIMEOUT=10
|
||||||
EXEC_TIMEOUT=30
|
EXEC_TIMEOUT=30
|
||||||
MAX_OUTPUT_LINES=20
|
MAX_OUTPUT_LINES=20
|
||||||
|
MAX_OUTPUT_CHARS=1000
|
||||||
TEST_SETS=()
|
TEST_SETS=()
|
||||||
TOTAL_CASES=0
|
TOTAL_CASES=0
|
||||||
PASSED_CASES=0
|
PASSED_CASES=0
|
||||||
FAILED_CASES_LIST=""
|
FAILED_CASES_LIST=""
|
||||||
INTERRUPTED=false # 新增:用于标记是否被中断
|
INTERRUPTED=false
|
||||||
|
|
||||||
# =================================================================
|
# =================================================================
|
||||||
# --- 函数定义 ---
|
# --- 函数定义 ---
|
||||||
@@ -53,6 +54,7 @@ show_help() {
|
|||||||
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
echo " -gct N 设置 gcc 交叉编译超时为 N 秒 (默认: 10)。"
|
||||||
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
|
echo " -et N 设置 qemu 执行超时为 N 秒 (默认: 30)。"
|
||||||
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
echo " -ml N, --max-lines N 当输出对比失败时,最多显示 N 行内容 (默认: 20)。"
|
||||||
|
echo " -mc N, --max-chars N 当输出对比失败时,最多显示 N 个字符 (默认: 1000)。"
|
||||||
echo " -h, --help 显示此帮助信息并退出。"
|
echo " -h, --help 显示此帮助信息并退出。"
|
||||||
echo ""
|
echo ""
|
||||||
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
echo "注意: 默认行为 (无 -e 或 -eir) 是将 .sy 文件同时编译为 .s (汇编) 和 .ll (IR),不执行。"
|
||||||
@@ -60,18 +62,25 @@ show_help() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# 显示文件内容并根据行数截断的函数
|
# 显示文件内容并根据行数和字符数截断的函数
|
||||||
display_file_content() {
|
display_file_content() {
|
||||||
local file_path="$1"
|
local file_path="$1"
|
||||||
local title="$2"
|
local title="$2"
|
||||||
local max_lines="$3"
|
local max_lines="$3"
|
||||||
|
local max_chars="$4" # 新增参数
|
||||||
if [ ! -f "$file_path" ]; then return; fi
|
if [ ! -f "$file_path" ]; then return; fi
|
||||||
echo -e "$title"
|
echo -e "$title"
|
||||||
local line_count
|
local line_count
|
||||||
|
local char_count
|
||||||
line_count=$(wc -l < "$file_path")
|
line_count=$(wc -l < "$file_path")
|
||||||
|
char_count=$(wc -c < "$file_path")
|
||||||
|
|
||||||
if [ "$line_count" -gt "$max_lines" ]; then
|
if [ "$line_count" -gt "$max_lines" ]; then
|
||||||
head -n "$max_lines" "$file_path"
|
head -n "$max_lines" "$file_path"
|
||||||
echo -e "\e[33m[... 输出已截断,共 ${line_count} 行 ...]\e[0m"
|
echo -e "\e[33m[... 输出因行数过多 (共 ${line_count} 行) 而截断 ...]\e[0m"
|
||||||
|
elif [ "$char_count" -gt "$max_chars" ]; then
|
||||||
|
head -c "$max_chars" "$file_path"
|
||||||
|
echo -e "\n\e[33m[... 输出因字符数过多 (共 ${char_count} 字符) 而截断 ...]\e[0m"
|
||||||
else
|
else
|
||||||
cat "$file_path"
|
cat "$file_path"
|
||||||
fi
|
fi
|
||||||
@@ -151,6 +160,7 @@ while [[ "$#" -gt 0 ]]; do
|
|||||||
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-gct) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then GCC_TIMEOUT="$2"; shift 2; else echo "错误: -gct 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-et) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then EXEC_TIMEOUT="$2"; shift 2; else echo "错误: -et 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
-ml|--max-lines) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_LINES="$2"; shift 2; else echo "错误: --max-lines 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
|
-mc|--max-chars) if [[ -n "$2" && "$2" =~ ^[0-9]+$ ]]; then MAX_OUTPUT_CHARS="$2"; shift 2; else echo "错误: --max-chars 需要一个正整数参数。" >&2; exit 1; fi ;;
|
||||||
-h|--help) show_help; exit 0 ;;
|
-h|--help) show_help; exit 0 ;;
|
||||||
*) echo "未知选项: $1"; show_help; exit 1 ;;
|
*) echo "未知选项: $1"; show_help; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
@@ -204,6 +214,7 @@ echo "运行模式: ${RUN_MODE_INFO}"
|
|||||||
echo "${TIMEOUT_INFO}"
|
echo "${TIMEOUT_INFO}"
|
||||||
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
|
if ${EXECUTE_MODE} || ${IR_EXECUTE_MODE}; then
|
||||||
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
echo "失败输出最大行数: ${MAX_OUTPUT_LINES}"
|
||||||
|
echo "失败输出最大字符数: ${MAX_OUTPUT_CHARS}"
|
||||||
fi
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
@@ -298,8 +309,8 @@ while IFS= read -r sy_file; do
|
|||||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
test_logic_passed=0
|
test_logic_passed=0
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -308,8 +319,8 @@ while IFS= read -r sy_file; do
|
|||||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file_from_ir}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
test_logic_passed=0
|
test_logic_passed=0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -375,8 +386,8 @@ while IFS= read -r sy_file; do
|
|||||||
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
[ "$test_logic_passed" -eq 1 ] && echo -e "\e[32m 标准输出测试成功\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 标准输出测试失败\e[0m"
|
echo -e "\e[31m 标准输出测试失败\e[0m"
|
||||||
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${EXPECTED_STDOUT_FILE}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
test_logic_passed=0
|
test_logic_passed=0
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -385,8 +396,8 @@ while IFS= read -r sy_file; do
|
|||||||
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
echo -e "\e[32m 成功: 输出与参考输出匹配\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
echo -e "\e[31m 失败: 输出不匹配\e[0m"
|
||||||
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_reference_file}" " \e[36m---------- 期望输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}"
|
display_file_content "${output_actual_file_S}" " \e[36m---------- 实际输出 ----------\e[0m" "${MAX_OUTPUT_LINES}" "${MAX_OUTPUT_CHARS}"
|
||||||
test_logic_passed=0
|
test_logic_passed=0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -634,6 +634,22 @@ void PeepholeOptimizer::runOnMachineFunction(MachineFunction *mfunc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 8. 消除无用移动指令: mv a, a -> (删除)
|
||||||
|
else if (mi1->getOpcode() == RVOpcodes::MV &&
|
||||||
|
mi1->getOperands().size() == 2) {
|
||||||
|
if (mi1->getOperands()[0]->getKind() == MachineOperand::KIND_REG &&
|
||||||
|
mi1->getOperands()[1]->getKind() == MachineOperand::KIND_REG) {
|
||||||
|
auto *dst = static_cast<RegOperand *>(mi1->getOperands()[0].get());
|
||||||
|
auto *src = static_cast<RegOperand *>(mi1->getOperands()[1].get());
|
||||||
|
|
||||||
|
// 检查源和目标寄存器是否相同
|
||||||
|
if (areRegsEqual(dst, src)) {
|
||||||
|
// 删除这条无用指令
|
||||||
|
instrs.erase(instrs.begin() + i);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 根据是否发生变化调整遍历索引
|
// 根据是否发生变化调整遍历索引
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
|
|||||||
@@ -1007,6 +1007,7 @@ class PhiInst : public Instruction {
|
|||||||
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue);
|
void replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, Value *newValue);
|
||||||
void refreshMap() {
|
void refreshMap() {
|
||||||
blk2val.clear();
|
blk2val.clear();
|
||||||
|
vsize = getNumOperands() / 2;
|
||||||
for (unsigned i = 0; i < vsize; ++i) {
|
for (unsigned i = 0; i < vsize; ++i) {
|
||||||
blk2val[getIncomingBlock(i)] = getIncomingValue(i);
|
blk2val[getIncomingBlock(i)] = getIncomingValue(i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,34 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// PHI指令消除相关方法
|
||||||
|
static bool eliminateRedundantPhisInFunction(Function* func){
|
||||||
|
bool changed = false;
|
||||||
|
std::vector<Instruction *> toDelete;
|
||||||
|
for (auto &bb : func->getBasicBlocks()) {
|
||||||
|
for (auto &inst : bb->getInstructions()) {
|
||||||
|
if (auto phi = dynamic_cast<PhiInst *>(inst.get())) {
|
||||||
|
auto incoming = phi->getIncomingValues();
|
||||||
|
if(DEBUG){
|
||||||
|
std::cout << "Checking Phi: " << phi->getName() << " with " << incoming.size() << " incoming values." << std::endl;
|
||||||
|
}
|
||||||
|
if (incoming.size() == 1) {
|
||||||
|
Value *singleVal = incoming[0].second;
|
||||||
|
inst->replaceAllUsesWith(singleVal);
|
||||||
|
toDelete.push_back(inst.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break; // 只处理Phi指令
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto *phi : toDelete) {
|
||||||
|
usedelete(phi);
|
||||||
|
changed = true; // 标记为已更改
|
||||||
|
}
|
||||||
|
return changed; // 返回是否有删除发生
|
||||||
|
}
|
||||||
|
|
||||||
//该实现参考了libdivide的算法
|
//该实现参考了libdivide的算法
|
||||||
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
|
static std::pair<int, int> computeMulhMagicNumbers(int divisor) {
|
||||||
|
|
||||||
|
|||||||
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
39
src/include/midend/Pass/Optimize/TailCallOpt.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Pass.h"
|
||||||
|
#include "Dom.h"
|
||||||
|
#include "Loop.h"
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TailCallOpt
|
||||||
|
* @brief 优化尾调用的中端优化通道。
|
||||||
|
*
|
||||||
|
* 该类实现了一个针对函数级别的尾调用优化的优化通道(OptimizationPass)。
|
||||||
|
* 通过分析和转换 IR(中间表示),将可优化的尾调用转换为更高效的形式,
|
||||||
|
* 以减少函数调用的开销,提升程序性能。
|
||||||
|
*
|
||||||
|
* @note 需要传入 IRBuilder 指针用于 IR 构建和修改。
|
||||||
|
*
|
||||||
|
* @method runOnFunction
|
||||||
|
* 对指定函数进行尾调用优化。
|
||||||
|
*
|
||||||
|
* @method getPassID
|
||||||
|
* 获取当前优化通道的唯一标识符。
|
||||||
|
*
|
||||||
|
* @method getAnalysisUsage
|
||||||
|
* 指定该优化通道所依赖和失效的分析集合。
|
||||||
|
*/
|
||||||
|
class TailCallOpt : public OptimizationPass {
|
||||||
|
private:
|
||||||
|
IRBuilder* builder;
|
||||||
|
public:
|
||||||
|
TailCallOpt(IRBuilder* builder) : OptimizationPass("TailCallOpt", Granularity::Function), builder(builder) {}
|
||||||
|
static void *ID;
|
||||||
|
bool runOnFunction(Function *F, AnalysisManager &AM) override;
|
||||||
|
void *getPassID() const override { return &ID; }
|
||||||
|
void getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@@ -25,6 +25,7 @@ add_library(midend_lib STATIC
|
|||||||
Pass/Optimize/GlobalStrengthReduction.cpp
|
Pass/Optimize/GlobalStrengthReduction.cpp
|
||||||
Pass/Optimize/BuildCFG.cpp
|
Pass/Optimize/BuildCFG.cpp
|
||||||
Pass/Optimize/LargeArrayToGlobal.cpp
|
Pass/Optimize/LargeArrayToGlobal.cpp
|
||||||
|
Pass/Optimize/TailCallOpt.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# 包含中端模块所需的头文件路径
|
# 包含中端模块所需的头文件路径
|
||||||
|
|||||||
@@ -757,7 +757,7 @@ void BinaryInst::print(std::ostream &os) const {
|
|||||||
auto lhs_hash = std::hash<const void*>{}(static_cast<const void*>(getLhs()));
|
auto lhs_hash = std::hash<const void*>{}(static_cast<const void*>(getLhs()));
|
||||||
auto rhs_hash = std::hash<const void*>{}(static_cast<const void*>(getRhs()));
|
auto rhs_hash = std::hash<const void*>{}(static_cast<const void*>(getRhs()));
|
||||||
size_t combined_hash = inst_hash ^ (lhs_hash << 1) ^ (rhs_hash << 2);
|
size_t combined_hash = inst_hash ^ (lhs_hash << 1) ^ (rhs_hash << 2);
|
||||||
std::string tmpName = "tmp_icmp_" + std::to_string(combined_hash % 1000000);
|
std::string tmpName = "tmp_icmp_" + std::to_string(combined_hash % 1000000007);
|
||||||
os << "%" << tmpName << " = " << getKindString() << " " << *getLhs()->getType() << " ";
|
os << "%" << tmpName << " = " << getKindString() << " " << *getLhs()->getType() << " ";
|
||||||
printOperand(os, getLhs());
|
printOperand(os, getLhs());
|
||||||
os << ", ";
|
os << ", ";
|
||||||
@@ -772,7 +772,7 @@ void BinaryInst::print(std::ostream &os) const {
|
|||||||
auto lhs_hash = std::hash<const void*>{}(static_cast<const void*>(getLhs()));
|
auto lhs_hash = std::hash<const void*>{}(static_cast<const void*>(getLhs()));
|
||||||
auto rhs_hash = std::hash<const void*>{}(static_cast<const void*>(getRhs()));
|
auto rhs_hash = std::hash<const void*>{}(static_cast<const void*>(getRhs()));
|
||||||
size_t combined_hash = inst_hash ^ (lhs_hash << 1) ^ (rhs_hash << 2);
|
size_t combined_hash = inst_hash ^ (lhs_hash << 1) ^ (rhs_hash << 2);
|
||||||
std::string tmpName = "tmp_fcmp_" + std::to_string(combined_hash % 1000000);
|
std::string tmpName = "tmp_fcmp_" + std::to_string(combined_hash % 1000000007);
|
||||||
os << "%" << tmpName << " = " << getKindString() << " " << *getLhs()->getType() << " ";
|
os << "%" << tmpName << " = " << getKindString() << " " << *getLhs()->getType() << " ";
|
||||||
printOperand(os, getLhs());
|
printOperand(os, getLhs());
|
||||||
os << ", ";
|
os << ", ";
|
||||||
@@ -834,7 +834,7 @@ void CondBrInst::print(std::ostream &os) const {
|
|||||||
if (condName.empty()) {
|
if (condName.empty()) {
|
||||||
// 使用条件值地址的哈希值作为唯一标识
|
// 使用条件值地址的哈希值作为唯一标识
|
||||||
auto ptr_hash = std::hash<const void*>{}(static_cast<const void*>(condition));
|
auto ptr_hash = std::hash<const void*>{}(static_cast<const void*>(condition));
|
||||||
condName = "const_" + std::to_string(ptr_hash % 100000);
|
condName = "const_" + std::to_string(ptr_hash % 1000000007);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组合指令地址、条件地址和目标块地址的哈希来确保唯一性
|
// 组合指令地址、条件地址和目标块地址的哈希来确保唯一性
|
||||||
@@ -843,7 +843,7 @@ void CondBrInst::print(std::ostream &os) const {
|
|||||||
auto then_hash = std::hash<const void*>{}(static_cast<const void*>(getThenBlock()));
|
auto then_hash = std::hash<const void*>{}(static_cast<const void*>(getThenBlock()));
|
||||||
auto else_hash = std::hash<const void*>{}(static_cast<const void*>(getElseBlock()));
|
auto else_hash = std::hash<const void*>{}(static_cast<const void*>(getElseBlock()));
|
||||||
size_t combined_hash = inst_hash ^ (cond_hash << 1) ^ (then_hash << 2) ^ (else_hash << 3);
|
size_t combined_hash = inst_hash ^ (cond_hash << 1) ^ (then_hash << 2) ^ (else_hash << 3);
|
||||||
std::string uniqueSuffix = std::to_string(combined_hash % 1000000);
|
std::string uniqueSuffix = std::to_string(combined_hash % 1000000007);
|
||||||
|
|
||||||
os << "%tmp_cond_" << condName << "_" << uniqueSuffix << " = icmp ne i32 ";
|
os << "%tmp_cond_" << condName << "_" << uniqueSuffix << " = icmp ne i32 ";
|
||||||
printOperand(os, condition);
|
printOperand(os, condition);
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ void DCEContext::run(Function *func, AnalysisManager *AM, bool &changed) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
changed |= SysYIROptUtils::eliminateRedundantPhisInFunction(func); // 如果有活跃指令,则标记为已更改
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断指令是否是"天然活跃"的实现
|
// 判断指令是否是"天然活跃"的实现
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ bool GVN::runOnFunction(Function *func, AnalysisManager &AM) {
|
|||||||
}
|
}
|
||||||
std::cout << "=== GVN completed for function: " << func->getName() << " ===" << std::endl;
|
std::cout << "=== GVN completed for function: " << func->getName() << " ===" << std::endl;
|
||||||
}
|
}
|
||||||
|
changed |= SysYIROptUtils::eliminateRedundantPhisInFunction(func);
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -671,13 +671,13 @@ bool GlobalStrengthReductionContext::reduceDivision(BinaryInst *inst) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// x / c = x * magic_number (魔数乘法优化 - 使用libdivide算法)
|
// x / c = x * magic_number (魔数乘法优化 - 使用libdivide算法)
|
||||||
if (isConstantInt(rhs, constVal) && constVal > 1 && constVal != (uint32_t)(-1)) {
|
// if (isConstantInt(rhs, constVal) && constVal > 1 && constVal != (uint32_t)(-1)) {
|
||||||
// auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
|
// // auto magicPair = computeMulhMagicNumbers(static_cast<int>(constVal));
|
||||||
Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal));
|
// Value* magicResult = createMagicDivisionLibdivide(inst, static_cast<int>(constVal));
|
||||||
replaceWithOptimized(inst, magicResult);
|
// replaceWithOptimized(inst, magicResult);
|
||||||
divisionOptCount++;
|
// divisionOptCount++;
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ bool InductionVariableEliminationContext::run(Function* F, AnalysisManager& AM)
|
|||||||
printDebugInfo();
|
printDebugInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modified |= SysYIROptUtils::eliminateRedundantPhisInFunction(F);
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -661,9 +661,9 @@ bool StrengthReductionContext::replaceOriginalInstruction(StrengthReductionCandi
|
|||||||
|
|
||||||
case StrengthReductionCandidate::DIVIDE_CONST: {
|
case StrengthReductionCandidate::DIVIDE_CONST: {
|
||||||
// 任意常数除法
|
// 任意常数除法
|
||||||
builder->setPosition(candidate->containingBlock,
|
// builder->setPosition(candidate->containingBlock,
|
||||||
candidate->containingBlock->findInstIterator(candidate->originalInst));
|
// candidate->containingBlock->findInstIterator(candidate->originalInst));
|
||||||
replacementValue = generateConstantDivisionReplacement(candidate, builder);
|
// replacementValue = generateConstantDivisionReplacement(candidate, builder);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,17 +683,19 @@ bool StrengthReductionContext::replaceOriginalInstruction(StrengthReductionCandi
|
|||||||
);
|
);
|
||||||
|
|
||||||
// 检查原值是否为负数
|
// 检查原值是否为负数
|
||||||
Value* zero = ConstantInteger::get(0);
|
Value* shift31condidata = builder->createBinaryInst(
|
||||||
Value* isNegative = builder->createICmpLTInst(candidate->inductionVar, zero);
|
Instruction::Kind::kSra, candidate->inductionVar->getType(),
|
||||||
|
candidate->inductionVar, ConstantInteger::get(31)
|
||||||
|
);
|
||||||
|
|
||||||
// 如果为负数,需要调整结果
|
// 如果为负数,需要调整结果
|
||||||
Value* adjustment = ConstantInteger::get(candidate->multiplier);
|
Value* adjustment = builder->createAndInst(shift31condidata, maskConstant);
|
||||||
Value* adjustedTemp = builder->createAddInst(temp, adjustment);
|
Value* adjustedTemp = builder->createAddInst(candidate->inductionVar, adjustment);
|
||||||
|
Value* adjustedResult = builder->createBinaryInst(
|
||||||
// 使用条件分支来模拟select操作
|
Instruction::Kind::kAnd, candidate->inductionVar->getType(),
|
||||||
// 为简化起见,这里先用一个更复杂但可工作的方式
|
adjustedTemp, maskConstant
|
||||||
// 实际应该创建条件分支,但这里先简化处理
|
);
|
||||||
replacementValue = temp; // 简化版本,假设大多数情况下不是负数
|
replacementValue = adjustedResult;
|
||||||
} else {
|
} else {
|
||||||
// 非负数的取模,直接使用位与
|
// 非负数的取模,直接使用位与
|
||||||
replacementValue = builder->createBinaryInst(
|
replacementValue = builder->createBinaryInst(
|
||||||
|
|||||||
@@ -1357,9 +1357,8 @@ void SCCPContext::run(Function *func, AnalysisManager &AM) {
|
|||||||
bool changed_control_flow = SimplifyControlFlow(func);
|
bool changed_control_flow = SimplifyControlFlow(func);
|
||||||
|
|
||||||
// 如果任何一个阶段修改了 IR,标记分析结果为失效
|
// 如果任何一个阶段修改了 IR,标记分析结果为失效
|
||||||
if (changed_constant_propagation || changed_control_flow) {
|
bool changed = changed_constant_propagation || changed_control_flow;
|
||||||
// AM.invalidate(); // 假设有这样的方法来使所有分析结果失效
|
changed |= SysYIROptUtils::eliminateRedundantPhisInFunction(func);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCCP Pass methods
|
// SCCP Pass methods
|
||||||
|
|||||||
125
src/midend/Pass/Optimize/TailCallOpt.cpp
Normal file
125
src/midend/Pass/Optimize/TailCallOpt.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include "TailCallOpt.h"
|
||||||
|
#include "IR.h"
|
||||||
|
#include "IRBuilder.h"
|
||||||
|
#include "SysYIROptUtils.h"
|
||||||
|
#include <vector>
|
||||||
|
// #include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace sysy {
|
||||||
|
|
||||||
|
void *TailCallOpt::ID = (void *)&TailCallOpt::ID;
|
||||||
|
|
||||||
|
void TailCallOpt::getAnalysisUsage(std::set<void *> &analysisDependencies, std::set<void *> &analysisInvalidations) const {
|
||||||
|
analysisInvalidations.insert(&DominatorTreeAnalysisPass::ID);
|
||||||
|
analysisInvalidations.insert(&LoopAnalysisPass::ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TailCallOpt::runOnFunction(Function *F, AnalysisManager &AM) {
|
||||||
|
std::vector<CallInst *> tailCallInsts;
|
||||||
|
// 遍历函数的所有基本块
|
||||||
|
for (auto &bb_ptr : F->getBasicBlocks()) {
|
||||||
|
auto BB = bb_ptr.get();
|
||||||
|
if (BB->getInstructions().empty()) continue; // 跳过空基本块
|
||||||
|
|
||||||
|
auto term_iter = BB->terminator();
|
||||||
|
if (term_iter == BB->getInstructions().end()) continue; // 没有终结指令则跳过
|
||||||
|
auto term = (*term_iter).get();
|
||||||
|
|
||||||
|
if (!term || !term->isReturn()) continue; // 不是返回指令则跳过
|
||||||
|
auto retInst = static_cast<ReturnInst *>(term);
|
||||||
|
|
||||||
|
Instruction *prevInst = nullptr;
|
||||||
|
if (BB->getInstructions().size() > 1) {
|
||||||
|
auto it = term_iter;
|
||||||
|
--it; // 获取返回指令前的指令
|
||||||
|
prevInst = (*it).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!prevInst || !prevInst->isCall()) continue; // 前一条不是调用指令则跳过
|
||||||
|
auto callInst = static_cast<CallInst *>(prevInst);
|
||||||
|
|
||||||
|
// 检查是否为尾递归调用:被调用函数与当前函数相同且返回值与调用结果匹配
|
||||||
|
if (callInst->getCallee() == F) {
|
||||||
|
// 对于尾递归,返回值应为调用结果或为 void 类型
|
||||||
|
if (retInst->getReturnValue() == callInst ||
|
||||||
|
(retInst->getReturnValue() == nullptr && callInst->getType()->isVoid())) {
|
||||||
|
tailCallInsts.push_back(callInst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tailCallInsts.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个新的入口基本块,作为循环的前置块
|
||||||
|
auto original_entry = F->getEntryBlock();
|
||||||
|
auto new_entry = F->addBasicBlock("tco.entry." + F->getName());
|
||||||
|
auto loop_header = F->addBasicBlock("tco.loop_header." + F->getName());
|
||||||
|
|
||||||
|
// 将原入口块中的所有指令移动到循环头块
|
||||||
|
loop_header->getInstructions().splice(loop_header->end(), original_entry->getInstructions());
|
||||||
|
original_entry->setName("tco.pre_header");
|
||||||
|
|
||||||
|
// 为函数参数创建 phi 节点
|
||||||
|
builder->setPosition(loop_header, loop_header->begin());
|
||||||
|
std::vector<PhiInst *> phis;
|
||||||
|
auto original_args = F->getArguments();
|
||||||
|
for (auto &arg : original_args) {
|
||||||
|
auto phi = builder->createPhiInst(arg->getType(), {}, {}, "tco.phi."+arg->getName());
|
||||||
|
phis.push_back(phi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用 phi 节点替换所有原始参数的使用
|
||||||
|
for (size_t i = 0; i < original_args.size(); ++i) {
|
||||||
|
original_args[i]->replaceAllUsesWith(phis[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 phi 节点的输入值
|
||||||
|
for (size_t i = 0; i < phis.size(); ++i) {
|
||||||
|
phis[i]->addIncoming(original_args[i], new_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接各个基本块
|
||||||
|
builder->setPosition(original_entry, original_entry->end());
|
||||||
|
builder->createUncondBrInst(new_entry);
|
||||||
|
original_entry->addSuccessor(new_entry);
|
||||||
|
|
||||||
|
builder->setPosition(new_entry, new_entry->end());
|
||||||
|
builder->createUncondBrInst(loop_header);
|
||||||
|
new_entry->addSuccessor(loop_header);
|
||||||
|
loop_header->addPredecessor(new_entry);
|
||||||
|
|
||||||
|
// 处理每一个尾递归调用
|
||||||
|
for (auto callInst : tailCallInsts) {
|
||||||
|
auto tail_call_block = callInst->getParent();
|
||||||
|
|
||||||
|
// 收集尾递归调用的参数
|
||||||
|
auto args_range = callInst->getArguments();
|
||||||
|
std::vector<Value*> args;
|
||||||
|
std::transform(args_range.begin(), args_range.end(), std::back_inserter(args),
|
||||||
|
[](auto& use_ptr){ return use_ptr->getValue(); });
|
||||||
|
|
||||||
|
// 用新的参数值更新 phi 节点
|
||||||
|
for (size_t i = 0; i < phis.size(); ++i) {
|
||||||
|
phis[i]->addIncoming(args[i], tail_call_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除原有的调用和返回指令
|
||||||
|
auto term_iter = tail_call_block->terminator();
|
||||||
|
SysYIROptUtils::usedelete(term_iter);
|
||||||
|
auto call_iter = tail_call_block->findInstIterator(callInst);
|
||||||
|
SysYIROptUtils::usedelete(call_iter);
|
||||||
|
|
||||||
|
// 添加跳转回循环头块的分支指令
|
||||||
|
builder->setPosition(tail_call_block, tail_call_block->end());
|
||||||
|
builder->createUncondBrInst(loop_header);
|
||||||
|
tail_call_block->addSuccessor(loop_header);
|
||||||
|
loop_header->addPredecessor(tail_call_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sysy
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "LoopStrengthReduction.h"
|
#include "LoopStrengthReduction.h"
|
||||||
#include "InductionVariableElimination.h"
|
#include "InductionVariableElimination.h"
|
||||||
#include "GlobalStrengthReduction.h"
|
#include "GlobalStrengthReduction.h"
|
||||||
|
#include "TailCallOpt.h"
|
||||||
#include "Pass.h"
|
#include "Pass.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
@@ -81,6 +82,7 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
|
|
||||||
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
|
registerOptimizationPass<GlobalStrengthReduction>(builderIR);
|
||||||
registerOptimizationPass<Reg2Mem>(builderIR);
|
registerOptimizationPass<Reg2Mem>(builderIR);
|
||||||
|
registerOptimizationPass<TailCallOpt>(builderIR);
|
||||||
|
|
||||||
registerOptimizationPass<SCCP>(builderIR);
|
registerOptimizationPass<SCCP>(builderIR);
|
||||||
|
|
||||||
@@ -139,6 +141,16 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
this->addPass(&GVN::ID);
|
this->addPass(&GVN::ID);
|
||||||
this->run();
|
this->run();
|
||||||
|
|
||||||
|
this->clearPasses();
|
||||||
|
this->addPass(&TailCallOpt::ID);
|
||||||
|
this->run();
|
||||||
|
|
||||||
|
if(DEBUG) {
|
||||||
|
std::cout << "=== IR After TailCallOpt ===\n";
|
||||||
|
SysYPrinter printer(moduleIR);
|
||||||
|
printer.printIR();
|
||||||
|
}
|
||||||
|
|
||||||
if(DEBUG) {
|
if(DEBUG) {
|
||||||
std::cout << "=== IR After GVN Optimizations ===\n";
|
std::cout << "=== IR After GVN Optimizations ===\n";
|
||||||
printPasses();
|
printPasses();
|
||||||
@@ -192,9 +204,9 @@ void PassManager::runOptimizationPipeline(Module* moduleIR, IRBuilder* builderIR
|
|||||||
printPasses();
|
printPasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
// this->clearPasses();
|
this->clearPasses();
|
||||||
// this->addPass(&Reg2Mem::ID);
|
this->addPass(&Reg2Mem::ID);
|
||||||
// this->run();
|
this->run();
|
||||||
|
|
||||||
if(DEBUG) {
|
if(DEBUG) {
|
||||||
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
|
std::cout << "=== IR After Reg2Mem Optimizations ===\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user