北大编译实践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 回复

    快写后面的啊

发表评论

衫小寨 出品