Commit e5688ba2 authored by lxq's avatar lxq

Merge branch 'master' of...

Merge branch 'master' of https://cscourse.ustc.edu.cn/vdir/Gitlab/compiler_staff/2022fall-compiler_cminus
parents 066f2d5d 258a7391
......@@ -4,5 +4,12 @@ compile_commands.json
.cache
.vscode
todo.txt
tmp.cminus
/build/
.clangd
compile_commands.json
/.vscode/
/.cache/
test.c
test
*.s
......@@ -281,19 +281,37 @@ valuePhiFunc(ve,P)
GVN 通过数据流分析来检测冗余的变量和计算,通过替换和死代码删除结合,实现优化效果。前述的例子中主要以二元运算语句来解释原理,且助教为大家提供了代码替换和删除的逻辑,除此之外,需要完成的方向有:
1. 对冗余指令的检测与消除包括(二元运算指令,cmp,gep,类型转换指令)
1. 对冗余指令的检测与消除包括
2. 对纯函数的冗余调用消除(助教提供了纯函数分析,见[FuncInfo.h](../../include/optimization/FuncInfo.h)
- 二元运算指令:add, sub, mul, sdiv, fadd, fsub, fmul, fdiv
该 Pass 的接口`is_pure_function`接受一个lightIR Function,判断该函数是否为纯函数;对于纯函数,如果其参数等价,对这个纯函数的不同调用也等价。
- 地址运算指令:getelementptr
3. 常量传播
- 比较指令:cmp, fcmp
在数据流分析的过程中,可以使用常量折叠来实现常量传播,从而将可在编译时计算的结果计算好,减少运行时开销。(助教提供了常量折叠类,在辅助类的介绍中)
- 类型转换指令:zext, fptosi, sitofp
2. 对于 call 指令冗余的检测与消除:
- 对纯函数的冗余调用需要进行检测与消除
- 对于非纯函数(例如 input())的多次调用不得分析成同一个等价类中
**注**:助教提供了纯函数分析,见[FuncInfo.h](../../include/optimization/FuncInfo.h),该 Pass 的接口`is_pure_function`接受一个lightIR Function,判断该函数是否为纯函数;对于纯函数,如果其参数等价,对这个纯函数的不同调用也等价。
3. 常量传播:在数据流分析的过程中,需要使用常量折叠来实现常量传播,从而将可在编译时计算的结果计算好,减少运行时开销。
- 本次实验要求借助 GVN 的数据流分析框架,实现常量传播,在含有常量的等价类中,通过将 leader_ 设置为 Constant* 类型,在常量传播后将指令替换成相应的常数。
**注**:助教提供了常量折叠类,在辅助类的介绍中
4. value phi function 的冗余的检测与消除:
- 通过 value phi function 可以在某个程序点比较两个变量每条路径的等价关系,为了简化这部分逻辑,仅考察 `phi(a+b, c+d)``phi(a,c)+phi(b,d)` 之间的冗余。+ 代表 add, sub, mul, sdiv, fadd, fsub, fmul, fdiv。a,b,c,d 代表不含常数的等价类
我们会在测试样例中对这三点进行考察。
**case 考察范围说明:**在 Lab4-2 的公开 case 与隐藏 case 中,以下情况不会出现:
**case 考察范围说明**在 Lab4-2 的公开 case 与隐藏 case 中,以下情况不会出现:
1. 不会对加法乘法运算的交换律,结合律造成的冗余进行考察。
2. 不会对访存指令之间的等价性进行考察。
......
This diff is collapsed.
# 寄存器分配
寄存器分配算法类型:
1. 线性扫描
1. Poletto
2. lifetime hole
3. linear scan on SSA
2. 图着色
1. Chaitin
2. Graph Coloring on SSA
3. Other techniques
1. Rematerialization
2. pbqp
# Linear Scan
线性扫描由Poletto等人在1999年首次提出。
线性扫描分配寄存器前需要
1. 对基本块进行排序,给出一个线性序(Depth-First order较优)
2. 决定变量的活跃区间(活跃变量分析)
[活跃区间的定义]
变量v的活跃区间为[i,j]表示在任意i'<i或者j'>j的指令,v均不为活跃变量。但在[i,j]内,可能有部分指令处,v也不为活跃变量。
## Poletto
Poletto版本的线性扫描不是在SSA形式上的,需要进行Phi指令消除(同Lab4)
算法介绍如下:
1.前置条件:给定R个可用寄存器和一个活跃区间列表(包含所有变量的活跃区间),该列表以起点(即[i,j]中的i)递增的顺序排列。
2.伪代码:
```C++
//线性扫描算法
LinearScan:
active <- {}
//维护有序列表active,存储当前在寄存器中的变量的活跃区间,按终点([i,j]中的j)递增顺序排列
for each live interval i, in order of increasing start point
//遍历所有变量的活跃区间
ExpireOldIntervals(i)
//移除所有过期的区间
if length(active) = R then //表示此时所有寄存器均不空闲
SpillAtInterval(i)
//溢出一个当前活跃区间
else //存在空闲的寄存器
register[i] <- a register removed from pool of free registers
//为变量i赋予一个空闲的寄存器
add i to active, sorted by incresing end point
//将i的活跃区间加入active,并排序
//移除所有过期的区间:
//过期区间:终点在新区间起点之前的区间
ExpireOldIntervals(i):
for each interval j in active, in order of increasing end point
//遍历列表active
if endpoint[j] ≥ startpoint[i] then
//当找到一个未过期区间后退出循环
return
remove j from active
//在active中移除过期区间
add register[j] to pool of free registers
//释放过期区间对应的寄存器
//溢出一个当前活跃区间:
//决定要溢出哪个区间有多种选择方法,此处我们选择溢出终点最晚的区间(即列表active中最后的区间或者新区间)
SpillAtInterval(i):
spill <- last interval in active
//spill初始化为active中最后的区间
//比较列表active中最后的区间和新区间
if endpoint[spill] > endpoint[i] then //溢出active中最后的区间
register[i] <- register[spill]
//spill的寄存器给新区间所代表的变量
location[spill] <- new stack location
remove spill from active
add i to active, sorted by increasing end point
//spill移出active,i加入active
else //溢出新区间
location[i] <- new stack location
```
3.算法复杂度分析:变量个数为V,寄存器个数为R。当查找列表方式为二分查找时,复杂度为$O(V\log R)$,为线性查找时,复杂度为$O(VR)$。
更多介绍参考如下文章:
[http://web.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf](http://web.cs.ucla.edu/~palsberg/course/cs132/linearscan.pdf)
## Live Ranges with Lifetime Holes
Poletto版本的活跃变量区间是一大块的,它没有考虑到区间的lifetime hole,即 "不需要变量值的区间"。
以下两篇文章在非SSA形式上处理了带有hole的活跃变量区间
[https://dl.acm.org/doi/10.1145/277650.277714](https://dl.acm.org/doi/10.1145/277650.277714)
[https://dl.acm.org/doi/10.1145/1064979.1064998](https://dl.acm.org/doi/10.1145/1064979.1064998)
## Linear Scan on SSA
以上参考文献都在非SSA形式上工作,对于llvm ir,需要将phi指令手动转换成赋值语句,比较麻烦
这篇文章在SSA形式上进行线性扫描
[https://dl.acm.org/doi/10.1145/1772954.1772979](https://dl.acm.org/doi/10.1145/1772954.1772979)
其简要思想即为在代码生成阶段进行phi resolution
### 建议
不进行Phi指令消除,对SSA form的IR进行最简易的线性扫描(Poletto),在emitting machine code时插入move指令
# Graph Coloring
图着色寄存器分配是解决寄存器分配的主要方法,其生成的代码质量较线性扫描更高,但是也更加耗时。
在这种算法中,图的节点代表活跃变量区间,两个节点相连代表存在相互干扰的区间,即至少在一个程序点上同时存在的区间。然后,寄存器分配简化为图的着色问题,其中颜色(寄存器)被分配给节点,使得由边连接的两个节点不会得到相同的颜色。
使用活跃变量分析,可以建立一个interference graph干扰图。干扰图是一个无向图,其中的节点是程序的变量,用来模拟哪些变量不能被分配到同一个寄存器。
## Chaitin
经典算法,伪代码见
[https://dl.acm.org/doi/10.1145/872726.806984](https://dl.acm.org/doi/10.1145/872726.806984)
## Graph Coloring on SSA
SSA带来的特性能够简化图着色,参考
[https://dl.acm.org/doi/10.1007/11688839_20](https://dl.acm.org/doi/10.1007/11688839_20)
# Rematerialization
Chaitin等人讨论了几个提高溢出代码质量的想法。他们指出,某些数值可以在一条指令中**重新计算**,而且所需的操作数总是可以用来计算的
[https://dl.acm.org/doi/10.1145/143103.143143](https://dl.acm.org/doi/10.1145/143103.143143)
## PBPQ
LLVM的其中一个分配器,采用线性规划,参考
[https://dl.acm.org/doi/10.1007/11860990_21](https://dl.acm.org/doi/10.1007/11860990_21)
[https://dl.acm.org/doi/abs/10.1145/513829.513854](https://dl.acm.org/doi/abs/10.1145/513829.513854)
### 评测脚本
性能测试脚本位于tests/5-bonus/test_time.py,在实现自己的汇编代码生成功能前,可以使用脚本的 `--clang`选项,用clang完成编译和汇编。
下面用yourcmminus指代你完成的汇编代码生成项目。
脚本会对yourcminus或clang生成的可执行文件的**输出结果****运行时间**进行测试,性能测试结果会写入同目录下test_result文件,脚本的`--console`选项用来控制是否同时将性能测试结果打印到控制台。
**注**:默认要求yourcminus在生成汇编代码时使用的指令是`cminusfc file.cminus -mem2reg -S a.s`,你也可以根据你自己的实现更改脚本中的标有`###可修改###`的部分。
下面是开启`-console``-clang`时的生成结果示例 :
```bash
$ python3 test_time.py --console --clang
[1/13] 1-return.cminus: pass, costs 0.001559s
[2/13] 10-float.cminus: pass, costs 0.001864s
[3/13] 11-floatcall.cminus: pass, costs 0.001632s
[4/13] 12-global.cminus: pass, costs 0.001614s
[5/13] 13-complex.cminus: pass, costs 0.001423s
[6/13] 2-calculate.cminus: pass, costs 0.001770s
[7/13] 3-output.cminus: pass, costs 0.001356s
[8/13] 4-if.cminus: pass, costs 0.001618s
[9/13] 5-while.cminus: pass, costs 0.001637s
[10/13] 6-array.cminus: pass, costs 0.002292s
[11/13] 7-function.cminus: pass, costs 0.001389s
[12/13] 8-store.cminus: pass, costs 0.001849s
[13/13] 9-fibonacci.cminus: pass, costs 0.002904s
0 tests failed
total time is 0.022907666116952895s
avg time is 0.0017621281628425304s
13 tests finishes in time limit
testcase clang baseline
1-return.cminus 0.001559 0.000883
10-float.cminus 0.001864 0.001716
11-floatcall.cminus 0.001632 0.001657
12-global.cminus 0.001614 0.001491
13-complex.cminus 0.001423 0.001820
2-calculate.cminus 0.001770 0.001738
3-output.cminus 0.001356 0.001946
4-if.cminus 0.001618 0.001651
5-while.cminus 0.001637 0.002021
6-array.cminus 0.002292 0.002570
7-function.cminus 0.001389 0.001677
8-store.cminus 0.001849 0.001600
9-fibonacci.cminus 0.002904 0.004012
===============================================================
```
### 分数计算
+ 功能测试(40%)
从 IR 到龙芯汇编翻译,生成龙芯汇编代码,执行结果与预期结果一致。
得分为 通过测试用例数 / 总测试用例数 * 40
+ 性能测试(40%)
对于每个测试用例,将所有人的运行时间排序,得分为(总人数 - 排名 + 1) / 总人数 * 40,性能测试的分数将取所有测试用例的平均值。
+ 工作总结汇报(20%)
以 ppt 形式汇报,介绍项目的设计思想、学生自由发挥部分等内容。
......@@ -3,6 +3,7 @@
## 目前已布置的实验
* [lab1](./Documentations/1-parser/)
<<<<<<< HEAD
+ DDL:2022-10-03 23:59:59 (UTC+8)
- [report](./Reports/1-parser/)
......@@ -27,12 +28,28 @@
+ DDL: 2022-12-12 23:59:59 (UTC+8)
- [report](./Reports/4.2-gvn/report.md)
=======
+ DDL:2021-10-06(~~10-03~~) 23:59:59 (UTC+8)
* [lab2](./Documentations/2-ir-gen-warmup/)
+ DDL:2021-10-22 23:59:59 (UTC+8)
* [lab3](./Documentations/3-ir-gen/)
+ DDL: 2021-11-21 23:59:59 (UTC+8)
* [lab4](./Documentations/4-ir-opt)
+ DDL:
+ **阶段一**:2021/11/29 23:59:59 (UTC+8)
+ **阶段二**:2022/12/13 23:59:59 (UTC+8)
* [lab5](./Documentations/5-bonus/)
+ DDL:
+ **建议报名期限**:2023/01/29
+ **实验提交**:2023 年 3 月初,具体时间待定
+ **答辩时间**:2023 年 3 月初,具体时间待定
>>>>>>> 258a73911f85493b8766ab5470b0db50e19580e3
## FAQ: How to merge upstream remote branches
In brief, you need another alias for upstream repository (we assume you are now in your local copy of forked repository on Gitlab):
```shell
$ git remote add upstream git@202.38.79.174:compiler_staff/2022fall-compiler_cminus.git
$ git remote add upstream http://211.86.152.198:8080/staff/2021fall-compiler_cminus.git
```
Then try to merge remote commits to your local repository:
......
#ifndef CODEGEN_HPP
#define CODEGEN_HPP
#include "Module.h"
#include "logging.hpp"
using std::string;
using std::vector;
class CodeGen {
public:
CodeGen(Module *module) : m(module) {}
string print() {
string result;
for (auto line : output) {
if (line.find(":") == string::npos and line != "")
result += "\t"; // 添加缩进
result += line + "\n";
}
return result;
}
void run();
private:
Module *m;
vector<string> output;
};
#endif
......@@ -2,5 +2,6 @@ add_subdirectory(parser)
add_subdirectory(common)
add_subdirectory(io)
add_subdirectory(lightir)
add_subdirectory(cminusfc)
add_subdirectory(optimization)
add_subdirectory(cminusfc)
add_subdirectory(codegen)
......@@ -6,15 +6,14 @@ add_executable(
target_link_libraries(
cminusfc
OP_lib
IR_lib
common
syntax
OP_lib
codegen
)
install(
TARGETS cminusfc
RUNTIME DESTINATION bin
)
#include "ActiveVars.hpp"
#include "ConstPropagation.hpp"
#include "DeadCode.h"
#include "Dominators.h"
#include "GVN.h"
#include "LoopInvHoist.hpp"
#include "LoopSearch.hpp"
#include "Mem2Reg.hpp"
#include "PassManager.hpp"
#include "cminusf_builder.hpp"
#include "codegen.hpp"
#include "logging.hpp"
#include <fstream>
......@@ -69,17 +75,12 @@ int main(int argc, char **argv) {
return -1;
} else {
// if (input_path.substr(pos) != ".cminus") {
if (input_path.substr(pos).substr(0, 2) != ".c") {
std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl;
return -1;
}
if (emit) {
target_path = input_path.substr(0, pos);
} else {
// std::cerr << argv[0] << ": input file " << input_path << " has unknown filetype!" << std::endl;
// return -1;
// }
target_path = input_path.substr(0, pos);
}
}
}
auto s = parse(input_path.c_str());
auto a = AST(s);
......@@ -100,13 +101,23 @@ int main(int argc, char **argv) {
if (mem2reg) {
PM.add_pass<Mem2Reg>(emit);
}
if (gvn)
if (gvn) {
PM.add_pass<DeadCode>(false); // remove some undef
PM.add_pass<GVN>(emit, dump_json);
PM.add_pass<DeadCode>(false); // delete unused instructions created by GVN
}
PM.run();
auto IR = m->print();
CodeGen codegen(m.get());
codegen.run();
std::ofstream target_file(target_path + ".s");
target_file << codegen.print();
target_file.close();
std::ofstream output_stream;
auto output_file = target_path + ".ll";
output_stream.open(output_file, std::ios::out);
......@@ -118,7 +129,7 @@ int main(int argc, char **argv) {
std::string lib_path = " -L"s + argv[0];
auto idx = lib_path.rfind('/');
if (idx != std::string::npos)
lib_path.erase(idx);
lib_path.erase(lib_path.rfind('/'));
else
lib_path.clear();
auto cmd_str = "clang -O0 -w -no-pie "s + target_path + ".ll -o " + target_path + lib_path + " -lcminus_io";
......
add_library(codegen STATIC
codegen.cpp
)
target_link_libraries(common)
#include "codegen.hpp"
// $r0 $zero constant 0
// $r1 $ra return address
// $r2 $tp thread pointer
// $r3 $sp stack pointer
// $r4 - $r5 $a0 - $a1 argument, return value
// $r6 - $r11 $a2 - $a7 argument
// $r12 - $r20 $t0 - $t8 temporary
// $r21 saved
// $r22 $fp frame pointer
// $r23 - $r31 $s0 - $s8 static
class Reg {
public:
Reg(int index) : id(index) {}
int id;
string print() {
if (id == 0)
return "$zero";
if (id == 1)
return "$ra";
if (id == 2)
return "$tp";
if (id == 3)
return "$sp";
if (4 <= id and id <= 11)
return "$a" + std::to_string(id - 4);
if (12 <= id and id <= 20)
return "$t" + std::to_string(id - 12);
if (id == 22)
return "$fp";
assert(false);
}
};
void CodeGen::run() {
// TODO: implement
// 以下内容生成 int main() { return 0; } 的汇编代码
output.push_back(".text");
for (auto &func : m->get_functions())
if (not func.is_declaration()) {
output.push_back(".globl " + func.get_name());
output.push_back(".type " + func.get_name() + ", @function");
output.push_back(func.get_name() + ":");
output.push_back("addi.d $sp, $sp, -16");
output.push_back("st.d $ra, $sp, 8");
output.push_back("addi.d $fp, $sp, 16");
output.push_back("addi.w $a0, $zero, 0");
output.push_back("ld.d $ra, $sp, 8");
output.push_back("addi.d $sp, $sp, 16");
output.push_back("jr $ra");
}
}
......@@ -11,6 +11,7 @@ from pathlib import Path
# you can run the script from anywhere!
cminusfc_path = Path(__file__).absolute().parents[2] / "build/cminusfc"
cminusfc = str(cminusfc_path)
cminus_io = str(cminusfc_path.parent)
try:
from tqdm import tqdm
......@@ -50,7 +51,7 @@ def compile_baseline_files(file_lists):
exec_files = list()
for each in file_lists:
exec_file, _ = os.path.splitext(each)
COMMAND = "clang -O0 -w " + each + " -o " + exec_file + " -L. -lcminus_io"
COMMAND = f"clang -O0 -w {each} -o {exec_file} -L{cminus_io} -lcminus_io"
try:
result = subprocess.run(
COMMAND,
......@@ -63,8 +64,7 @@ def compile_baseline_files(file_lists):
exec_files.append(exec_file)
else:
exec_files.append(None)
print(
f"\nCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
print(f"\nCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
except Exception as _:
exec_files.append(None)
print(f"Compile {each.split('/')[-1]} \033[31;1m failed\033[0m")
......@@ -94,8 +94,7 @@ def compile_testcases(file_lists, option):
exec_files.append(exec_file)
else:
exec_files.append(None)
print(
f"\nCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
print(f"\nCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
except Exception as _:
exec_files.append(None)
print(f"Compile {each.split('/')[-1]} \033[31;1m failed\033[0m")
......@@ -157,8 +156,7 @@ def check_if_correct(exec_file, check_mode=True):
return False
except Exception as e:
print(
f"Execute {exec_file.split('/')[-1]} \033[31;1m failed\033[0m")
print(f"Execute {exec_file.split('/')[-1]} \033[31;1m failed\033[0m")
return False
else:
return True
......@@ -194,8 +192,7 @@ def table_print(testcase, before_optimization, after_optimization, baseline):
[len(before_optimization), len(after_optimization), len(baseline)]
)
if len(before_optimization) < max_len:
before_optimization += [None] * \
(max_len - len(before_optimization))
before_optimization += [None] * (max_len - len(before_optimization))
if len(after_optimization) < max_len:
after_optimization += [None] * (max_len - len(after_optimization))
if len(baseline) < max_len:
......@@ -271,18 +268,13 @@ if __name__ == "__main__":
os.path.dirname(script_path), "testcases/GVN/performance"
)
testcases = get_raw_testcases(root_path=root_path)
exec_files1 = compile_testcases(
file_lists=testcases, option="-mem2reg")
results1 = gvn_evaluate(file_lists=exec_files1,
metric_func=get_execute_time)
exec_files2 = compile_testcases(
file_lists=testcases, option="-mem2reg -gvn")
results2 = gvn_evaluate(file_lists=exec_files2,
metric_func=get_execute_time)
baseline_files = get_baseline_files(
os.path.join(root_path, "baseline"))
exec_files1 = compile_testcases(file_lists=testcases, option="-mem2reg")
results1 = gvn_evaluate(file_lists=exec_files1, metric_func=get_execute_time)
exec_files2 = compile_testcases(file_lists=testcases, option="-mem2reg -gvn")
results2 = gvn_evaluate(file_lists=exec_files2, metric_func=get_execute_time)
baseline_files = get_baseline_files(os.path.join(root_path, "baseline"))
exec_files3 = compile_baseline_files(baseline_files)
results3 = gvn_evaluate(
file_lists=exec_files3, metric_func=get_execute_time, check_mode=False
......@@ -335,11 +327,9 @@ if __name__ == "__main__":
score_list.append((each_base, score))
subprocess.call(["rm", "-rf", exec_file + ".ll"])
else:
print(
f"\nnCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
print(f"\nnCompile {each.split('/')[-1]} \033[31;1m failed\033[0m")
except Exception as _:
print(
f"Analyze {each.split('/')[-1]} \033[31;1m failed\033[0m")
print(f"Analyze {each.split('/')[-1]} \033[31;1m failed\033[0m")
progess_bar.update(1)
progess_bar.close()
......
/* c and d are redundant, a and b is not redundant */
int main(void) {
int a;
int b;
int c;
int d;
if (input() > input()) {
a = input();
b = a + a;
c = a + b;
} else {
a = input();
b = a;
c = a + b;
}
output(c);
d = a + b;
output(d);
}
[
{
"function": "main",
"pout": {
"label_entry": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
],
"label5": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op6",
"%op12",
],
[
"%op7",
"%op11",
],
[
"%op8",
"%op10",
],
],
"label9": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op12",
],
[
"%op11",
],
[
"%op13",
"%op10",
],
],
"label14": [
[
"%op0",
],
[
"%op1",
],
[
"%op2",
],
[
"%op3",
],
[
"%op4",
],
[
"%op15",
"%op12",
"%op11",
],
[
"%op16",
"%op10",
],
],
}
},
]
\ No newline at end of file
int state;
int buffer[32768];
int getrandom(void) {
state = state + (state * 8192);
state = state + (state / 131072);
state = state + (state * 32);
return state;
}
int remainder(int x, int y) {
int t;
t = x / y;
return x - y * t;
}
int rotlone(int x) { return x * 2 + remainder(x, 2); }
int rotlfive(int x) { return x * 32 + remainder(x, 32); }
int rotlthirty(int x) { return x * 1073741824 + remainder(x, 1073741824); }
int andc(int a, int b) { return a + b; }
int notc(int x) {
int t;
t = 0 - 1;
return t - x;
}
int xorc(int a, int b) { return a - andc(a, b) + b - andc(a, b); }
int orc(int a, int b) { return xorc(xorc(a, b), andc(a, b)); }
/* we need to change the first argument to `inputarr` to avoid conflict with the function `input` */
void pseudosha(int inputarr[], int inputlen, int outputarray[]) {
int ha;
int hb;
int hc;
int hd;
int he;
int a;
int b;
int c;
int d;
int e;
int f;
int k;
int origlen;
int chunkstart;
int words[80];
int i;
int t;
ha = 1732584193;
hb = 0 - 271733879;
hc = 0 - 1732584194;
hd = 271733878;
he = 0 - 1009589776;
origlen = inputlen;
inputarr[inputlen] = 128;
inputlen = inputlen + 1;
while (remainder(inputlen, 64) != 60) {
inputarr[inputlen] = 0;
inputlen = inputlen + 1;
}
inputarr[inputlen] = remainder(origlen / 16777216, 256);
inputarr[inputlen + 1] = remainder(origlen / 65536, 256);
inputarr[inputlen + 2] = remainder(origlen / 256, 256);
inputarr[inputlen + 3] = remainder(origlen, 256);
inputlen = inputlen + 4;
chunkstart = 0;
while (chunkstart < inputlen) {
a = ha;
b = hb;
c = hc;
d = hd;
e = he;
i = 0;
while (i < 16) {
words[i] = inputarr[chunkstart + i * 4] * 16777216 + inputarr[chunkstart + i * 4 + 1] * 65536 +
inputarr[chunkstart + i * 4 + 2] * 256 + inputarr[chunkstart + i * 4 + 3] * 1;
i = i + 1;
}
while (i < 80) {
words[i] = rotlone(xorc(xorc(xorc(words[i - 3], words[i - 8]), words[i - 14]), words[i - 16]));
i = i + 1;
}
i = 0;
while (i < 80) {
if (i < 20) {
f = orc(andc(b, c), andc(notc(b), d));
k = 1518500249;
} else if (i < 40) {
f = xorc(xorc(b, c), d);
k = 1859775361;
} else if (i < 60) {
f = orc(orc(andc(b, c), andc(b, d)), andc(c, d));
k = 0 - 1894007588;
} else {
f = xorc(xorc(b, c), d);
k = 0 - 899497722;
}
t = rotlfive(a) + f + e + k + words[i];
e = d;
d = c;
c = rotlthirty(b);
b = a;
a = t;
i = i + 1;
}
ha = ha + a;
hb = hb + b;
hc = hc + c;
hd = hd + d;
he = he + e;
chunkstart = chunkstart + 64;
}
/* see the comment below for this strange indexing */
outputarray[input()] = ha;
outputarray[input()] = hb;
outputarray[input()] = hc;
outputarray[input()] = hd;
outputarray[input()] = he;
}
int main(void) {
int rounds;
int i;
int outputarray[5];
int outputbuf[5];
int len;
state = 19260817;
i = 0;
rounds = 12;
state = input();
rounds = input();
/**
* note: this should be outputbuf[0] ... outputbuf[4], but some students think
* icmp slt i32 0, 0
* and
* icmp slt i32 1, 0
* are equivalent, while some not,
* so we use input() to assure all the non-negative checks are distinct
**/
outputbuf[input()] = 0;
outputbuf[input()] = 0;
outputbuf[input()] = 0;
outputbuf[input()] = 0;
outputbuf[input()] = 0;
while (rounds > 0) {
len = 32000;
i = 0;
while (i < len) {
buffer[i] = remainder(getrandom(), 256);
i = i + 1;
}
pseudosha(buffer, len, outputarray);
i = 0;
while (i < 5) {
outputbuf[i] = xorc(outputbuf[i], outputarray[i]);
i = i + 1;
}
rounds = rounds - 1;
}
i = 0;
while (i < 5) {
output(outputbuf[i]);
i = i + 1;
}
return 0;
}
This diff is collapsed.
int main(void) {
int i;
int j;
int sum;
i = 0;
j = 0;
sum = 0;
while (i < 10) {
j = 0;
while (j < 5) {
/* i+1 in this block are redundant */
sum = sum + (i + 1) * (i + 1) * (j + 1) * (j + 1);
j = j + 1;
}
/* but not this one */
i = i + 1;
}
output(sum);
return 0;
}
[
{
"function": "main",
"pout": {
"label_entry": [
[
"%op3",
"%op1",
],
],
"label0": [
[
"%op1",
],
[
"%op3",
],
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
],
"label7": [
[
"%op10",
"%op1",
],
[
"%op3",
],
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
[
"%op11",
],
],
"label8": [
[
"%op1",
],
[
"%op3",
],
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
],
"label9": [
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
[
"%op3",
],
[
"%op1",
],
[
"%op10",
],
[
"%op11",
],
[
"%op12",
],
[
"%op13",
],
[
"%op14",
],
],
"label15": [
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
[
"%op3",
],
[
"%op1",
],
[
"%op12",
],
[
"%op13",
],
[
"%op14",
],
[
"%op16",
"%op17",
],
[
"%op18",
],
[
"%op19",
"%op21",
"%op24",
"%op11",
],
[
"%op20",
],
[
"%op22",
],
[
"%op23",
"%op10",
],
],
"label25": [
[
"%op4",
],
[
"%op5",
],
[
"%op6",
],
[
"%op10",
"%op1",
],
[
"%op11",
],
[
"%op12",
],
[
"%op13",
],
[
"%op14",
],
[
"%op26",
"%op3",
],
],
}
},
]
\ No newline at end of file
int one(void) { return 1; }
int main(void) {
int a;
int b;
int c;
int d;
int e;
int i;
int n;
float f;
a = input();
b = input();
i = n = c = d = e = 0;
f = 0.0;
if (a > b) {
f = input() / 2.0;
c = f + 8;
outputFloat(c * 0.01);
/**
* note: this was supposed to be a constant (eg. d = 23)
* but the documentation over-constrained
* so we have to relax a little bit in this case
**/
d = input();
e = c / d;
} else if (a < b - 10) {
c = d = one();
e = c / d;
} else {
n = input();
i = 0;
c = d = one() + one();
e = c / d;
while (i < n) {
c = d = one() * one();
e = c / d;
output(i);
i = i + 1;
}
}
outputFloat(e);
output(c / d);
return 0;
}
This diff is collapsed.
import os
import sys
import timeit
import shutil
import argparse
import subprocess
test_dir = os.path.dirname(os.path.abspath(__file__)) # 当前文件夹路径 tests/5-bonus
cminus = os.path.join(test_dir, '../../build/cminus') # ===可修改===
testfile_dir = os.path.join(test_dir, './testcases')
output_file_name = os.path.join(test_dir, './test_result')
io = os.path.join(test_dir, '../../src/io/io.c')
total_failed_count = 0
class Outputer:
def __init__(self, console=False, filename="test_result") -> None:
self.console = console
self.fd = open(filename, "a")
def write(self, msg):
if self.console:
print(msg, end="")
sys.stdout.flush()
self.fd.write(msg)
self.fd.flush()
def __del__(self) -> None:
self.fd.close()
def eval(console=False, test_dir=testfile_dir, use_clang=False):
output_file = Outputer(console, output_file_name)
failed_count = 0
succ_count = 0
total_time = 0
single_begin = timeit.default_timer()
testfiles = os.listdir(testfile_dir)
testfiles.sort()
# 过滤出以.cminus结尾的file
testfiles = filter(lambda s: s.endswith('.cminus'), testfiles)
testfiles = list(testfiles)
test_count = len(testfiles)
testtime = []
for count, file_name in enumerate(testfiles):
start_time = timeit.default_timer()
testtime.append(-1)
# 超时,跳过
if start_time - total_start > 30 * 60 or start_time - single_begin > 30 * 60:
output_file.write(f"[{count+1}/{test_count}] " + file_name + ': skipped due to exceeded total time limit\n')
continue
# 未超时
output_file.write(f"[{count+1}/{test_count}] " + file_name + ': ')
filepath = os.path.join(testfile_dir, file_name)
outpath = os.path.join(testfile_dir, file_name[:-7] + '.out')
### 编译 ###
if not use_clang:
try:
# ===可修改===
compile_res = subprocess.run([cminus, filepath, '-mem2reg', '-S', 'a.s'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=300)
except subprocess.TimeoutExpired as _:
output_file.write('compile-1 timeout\n')
failed_count += 1
continue
except Exception:
output_file.write("compile-1 failed with an unexcept error\n")
failed_count += 1
continue
try:
compile_res = subprocess.run(['gcc', 'a.s', io, '-o', 'a.out'],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=300)
except subprocess.TimeoutExpired as _:
output_file.write('compile-2 timeout\n')
failed_count += 1
continue
except Exception:
output_file.write("compile-2 failed with an unexcept error\n")
failed_count += 1
continue
else:
try:
cfilepath = filepath.replace(".cminus", ".c")
shutil.move(filepath, cfilepath)
compile_res = subprocess.run(["clang", cfilepath, io, "-o", "a.out"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=300)
shutil.move(cfilepath, filepath)
except subprocess.TimeoutExpired as _:
output_file.write('compile timeout\n')
failed_count += 1
continue
except Exception:
output_file.write("compile failed with an unexcept error\n")
failed_count += 1
continue
### 运行 ###
try:
input_option = None
inpath = os.path.join(testfile_dir, file_name[:-7] + '.in')
if os.path.exists(inpath): # testfile存在输入文件
with open(inpath, 'rb') as fin:
input_option = fin.read()
# 记录运行时间
start = timeit.default_timer()
for i in range(10):
exe_res = subprocess.run(['./a.out'],
input=input_option,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
timeout=100)
end = timeit.default_timer()
except subprocess.TimeoutExpired:
output_file.write("executable time limit exceeded\n")
failed_count += 1
continue
except Exception as _:
output_file.write('executable runtime error\n')
failed_count += 1
continue
# 输出
with open(outpath, 'r') as fout:
ref = fout.read().replace(' ', '').replace('\n', '')
try:
actual = exe_res.stdout.decode('utf-8').replace(' ', '').replace('\n', '').replace('\r', '') + str(
exe_res.returncode)
except UnicodeDecodeError:
output_file.write('executable output illegal characters\n')
failed_count += 1
continue
if ref == actual or use_clang:
time = (end - start) / 10
total_time += time
output_file.write(f'pass, costs {time:.6f}s\n')
succ_count += 1
testtime[count] = time
else:
output_file.write('output is different from standard answer, this may be caused by wrong return code\n'
) # 因为退出码也会作为输出的一部分,因此输出和答案不同可能是程序崩溃造成的
failed_count += 1
output_file.write(f"{failed_count} tests failed\n")
output_file.write(
f"total time is {total_time}s\navg time is {total_time/succ_count if succ_count>0 else 0}s\n{succ_count} tests finishes in time limit\n"
)
output_file.write('testcase')
output_file.write('\t\t\tyour_cminus')
for count, file_name in enumerate(testfiles):
output_file.write('{:<20}'.format(file_name))
output_file.write('\t\t %.6f' % testtime[count] if testtime[count] != -1 else '\t\t None ')
output_file.write("===================================================================\n")
if __name__ == "__main__":
total_start = timeit.default_timer()
parser = argparse.ArgumentParser(description="functional test")
parser.add_argument("--console", action="store_true", help="specify whether to output the result to console")
parser.add_argument("--clang", action="store_true", help="estimate runtime when compile with clang")
args = parser.parse_args()
eval(args.console, testfile_dir, use_clang=args.clang)
int main(void) { return 111; }
int main(void) {
float a;
float b;
float c;
a = 1.1;
b = 1.5;
c = 1.2;
outputFloat(a * b + c);
return 0;
}
/* float function call */
float mod(float x, float y) {
int div;
div = x / y;
return x - div * y;
}
int main(void) {
float a;
float b;
a = 11.2;
b = 2.2;
outputFloat(mod(a, b));
return 0;
}
int seed;
int randomLCG(void) {
seed = seed * 1103515245 + 12345;
return seed;
}
int randBin(void) {
if (randomLCG() > 0)
return 1;
else
return 0;
}
/* random walk */
int returnToZeroSteps(void) {
int x;
int steps;
x = 0;
steps = 0;
while (steps < 20) {
if (randBin())
x = x + 1;
else
x = x - 1;
steps = steps + 1;
if (x == 0)
return steps;
}
return 20;
}
int main(void) {
int i;
i = 0;
seed = 3407;
while (i < 20) {
output(returnToZeroSteps());
i = i + 1;
}
return 0;
}
4
2
2
4
8
2
2
2
2
2
6
2
10
8
4
2
20
2
2
8
0
/* 01 背包问题 */
int n;
int m;
int w[5];
int v[5];
int dp[66]; /* dp[n * 11 + size] 表示前 n 个物品放入容量为 size 的背包中的最大价值,初始化为 -1 */
int max(int a, int b) {
if (a > b)
return a;
else
return b;
}
/* 状态转移方程:
dp[n][size] = max(dp[n - 1][size], dp[n - 1][size - w[n]] + v[n])
边界条件:
dp[n][size <= 0] = 0
dp[0][size] = 0 */
int knapsack(int n, int size) {
int result;
if (size <= 0)
return 0;
if (n == 0)
return 0;
if (dp[n * 11 + size] >= 0)
return dp[n * 11 + size];
if (size < w[n - 1])
result = knapsack(n - 1, size);
else
result = max(knapsack(n - 1, size), knapsack(n - 1, size - w[n - 1]) + v[n - 1]);
dp[n * 11 + size] = result;
return result;
}
int main(void) {
int i;
i = 0;
n = 5;
m = 10;
w[0] = 2;
w[1] = 2;
w[2] = 6;
w[3] = 5;
w[4] = 4;
v[0] = 6;
v[1] = 3;
v[2] = 5;
v[3] = 4;
v[4] = 6;
while (i < 66) {
dp[i] = 0-1;
i = i + 1;
}
output(knapsack(n, m));
return 0;
}
15
0
\ No newline at end of file
int main(void) {
int a;
int b;
int c;
a = 23;
b = 25;
c = 4;
return a + b * c;
}
int main(void) {
output(11);
output(22222);
return 0;
}
int main(void) {
int a;
int b;
int c;
a = 11;
b = 22;
c = 33;
/* max value */
if (a > b) {
if (a > c)
output(a);
else
output(c);
} else {
if (c < b)
output(b);
else
output(c);
}
return 0;
}
int main(void) {
int n;
int i;
n = 10;
i = 0;
while (i < n) {
output(i);
i = i + 1;
}
return 0;
}
int main(void) {
int a[10];
int i;
i = 0;
a[0] = 11;
a[4] = 22;
a[9] = 33;
output(a[0]);
output(a[4]);
output(a[9]);
return 0;
}
int min(int a, int b) {
if (a <= b)
return a;
else
return b;
}
int main(void) {
int a;
int b;
int c;
a = 11;
b = 22;
c = 33;
output(min(a, b));
output(min(b, c));
output(min(c, a));
return 0;
}
int store(int arr[], int index, int value) {
arr[index] = value;
return value;
}
int main(void) {
int a[10];
int i;
int sum;
i = 0;
while (i < 10) {
store(a, i, i * 2);
i = i + 1;
}
sum = 0;
i = 0;
while (i < 10) {
sum = sum + a[i];
i = i + 1;
}
output(sum);
return 0;
}
int fibonacci(int n) {
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return fibonacci(n - 1) + fibonacci(n - 2);
}
int main(void) {
int n;
int i;
n = 10;
i = 0;
while (i < n) {
output(fibonacci(i));
i = i + 1;
}
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment