北大编译实践2022 lab Lv2
当偷懒用了cout输出IR之后,马上就开始填坑了,不过贴心的助教xgg为我们提供了能够处理 Koopa IR 的库,我们直接利用代码调库即可。
参考提供的代码,大致了解对应生成的结构构造,然后我们利用助教提供的对应数个Visit函数,进行实现,具体结构和变量就参考提供的koopa.h文件即可。
// 函数声明
// 访问 raw slice
void Visit(const koopa_raw_slice_t &slice);
// 访问函数
void Visit(const koopa_raw_function_t &func);
// 访问基本块
void Visit(const koopa_raw_basic_block_t &bb);
// 访问指令
void Visit(const koopa_raw_value_t &value);
// ...
//return
void Visit(const koopa_raw_return_t &ret) {
printf(" li a0, ");
Visit(ret.value);printf("\n");
printf(" ret\n");
}
//integer
void Visit(const koopa_raw_integer_t &ret) {
std::cout << ret.value;
}
// 访问 raw program
void Visit(const koopa_raw_program_t &program) {
printf(" .text\n");
// 执行一些其他的必要操作
// ...
// 访问所有全局变量
Visit(program.values);
// 访问所有函数
Visit(program.funcs);
}
// 访问 raw slice
void Visit(const koopa_raw_slice_t &slice) {
for (size_t i = 0; i < slice.len; ++i) {
auto ptr = slice.buffer[i];
// 根据 slice 的 kind 决定将 ptr 视作何种元素
switch (slice.kind) {
case KOOPA_RSIK_FUNCTION:
// 访问函数
Visit(reinterpret_cast<koopa_raw_function_t>(ptr));
break;
case KOOPA_RSIK_BASIC_BLOCK:
// 访问基本块
Visit(reinterpret_cast<koopa_raw_basic_block_t>(ptr));
break;
case KOOPA_RSIK_VALUE:
// 访问指令
Visit(reinterpret_cast<koopa_raw_value_t>(ptr));
break;
default:
// 我们暂时不会遇到其他内容, 于是不对其做任何处理
assert(false);
}
}
}
// 访问函数
void Visit(const koopa_raw_function_t &func) {
// 执行一些其他的必要操作
printf(" .globl %s\n",func->name+1);
printf("%s:\n",func->name+1);
// 访问所有基本块
Visit(func->bbs);
}
// 访问基本块
void Visit(const koopa_raw_basic_block_t &bb) {
// 执行一些其他的必要操作
// 访问所有指令
Visit(bb->insts);
}
// 访问指令
void Visit(const koopa_raw_value_t &value) {
// 根据指令类型判断后续需要如何访问
const auto &kind = value->kind;
switch (kind.tag) {
case KOOPA_RVT_RETURN:
// 访问 return 指令
Visit(kind.data.ret);
break;
case KOOPA_RVT_INTEGER:
// 访问 integer 指令
Visit(kind.data.integer);
break;
default:
// 其他类型暂时遇不到
assert(false);
}
}
void generation(const char* str){
koopa_program_t program;
koopa_error_code_t ret = koopa_parse_from_string(str, &program);
assert(ret == KOOPA_EC_SUCCESS); // 确保解析时没有出错
// 创建一个 raw program builder, 用来构建 raw program
koopa_raw_program_builder_t builder = koopa_new_raw_program_builder();
// 将 Koopa IR 程序转换为 raw program
koopa_raw_program_t raw = koopa_build_raw_program(builder, program);
// 释放 Koopa IR 程序占用的内存
koopa_delete_program(program);
// 处理 raw program
Visit(raw);
// 处理完成, 释放 raw program builder 占用的内存
// 注意, raw program 中所有的指针指向的内存均为 raw program builder 的内存
// 所以不要在 raw program 处理完毕之前释放 builder
koopa_delete_raw_program_builder(builder);
}
然后我们稍微修改一下数据输入输出,我们将中间结果保存一下再读取(偷懒的补锅方式x)
if(strcmp(mode,"-koopa")==0){
freopen(output,"w",stdout);
ast->Dump();
fclose(stdout);
}else if(strcmp(mode,"-riscv")==0){
freopen("qaz.tmp","w",stdout);
ast->Dump();
fclose(stdout);
FILE *fp=fopen("qaz.tmp","r");
char *buf=(char *)malloc(100000);
fread(buf, 1, 100000, fp);
freopen(output,"w",stdout);
generation(buf);
fclose(stdout);
}
这时我们发现好像测试报错,稍微读了下大概说@main定义错误,我们看一下生成文件,原来那个处理库将函数名前面的@字符保留了,我们输出名字时将其删去即可
komqaq
快写后面的啊
lqspfM
黒と白のポルノ .JqjNAfLxurb