Commit b90933be authored by lxq's avatar lxq

live variable analysis with copy-stmt

parent 4a232c57
......@@ -13,11 +13,16 @@
#include "Instruction.h"
#include "Type.h"
#include "Value.h"
#include "ast.hpp"
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <utility>
#include <vector>
// $r0 $zero constant 0
// $r1 $ra return address
......@@ -95,6 +100,7 @@ CodeGen::run() {
// funtions
for (auto &func : m->get_functions()) {
if (not func.is_declaration()) {
LRA.run(&func);
cur_func = &func;
output.push_back("");
output.push_back(".globl " + func.get_name());
......@@ -113,6 +119,24 @@ CodeGen::run() {
stackMemDealloc();
}
}
// read only data
output.push_back(".section .rodata");
for (auto [constant, name] : ROdata) {
auto int_ = dynamic_cast<ConstantInt *>(constant);
auto float_ = dynamic_cast<ConstantFP *>(constant);
string value;
assert((int_ || float_) && "wrong type");
if (int_) {
value = to_string(int_->get_value());
} else {
std::stringstream ss;
float v = (float_->get_value());
ss << std::hex << *(uint32_t *)&v;
value = "0x" + ss.str();
}
output.push_back(name + ": ");
output.push_back(".word " + value);
}
}
void
......@@ -145,8 +169,23 @@ void
CodeGen::value2reg(Value *v, int id) {
bool is_float = v->get_type()->is_float_type();
auto reg_name = (is_float ? "$fa" : "$a") + to_string(id);
string tmp_ireg = "$t0";
if (dynamic_cast<Constant *>(v)) {
auto constant = static_cast<Constant *>(v);
#ifdef __RO_PART__
if (ROdata.find(constant) == ROdata.end())
ROdata[constant] = ".LC" + to_string(ROdata.size());
string instr_ir, addr = ROdata[constant];
if (dynamic_cast<ConstantInt *>(constant))
instr_ir = "ld.w";
else if (dynamic_cast<ConstantFP *>(constant))
instr_ir = "fld.s";
else
assert(false && "wait for completion");
output.push_back("la.local " + tmp_ireg + ", " + addr);
output.push_back(instr_ir + " " + reg_name + ", " + tmp_ireg + ", 0");
#else
if (dynamic_cast<ConstantInt *>(constant)) {
int k = static_cast<ConstantInt *>(constant)->get_value();
if ((k & 0xfff) != k) {
......@@ -159,7 +198,6 @@ CodeGen::value2reg(Value *v, int id) {
} else if (dynamic_cast<ConstantFP *>(constant)) {
// move the binary code to int-reg, then use movgr2fr to move the
// value to float-reg
string tmp_ireg = "$t0";
float k = static_cast<ConstantFP *>(constant)->get_value();
int hex_int = *(uint32_t *)&k;
if ((hex_int & 0xfff) != hex_int)
......@@ -173,6 +211,7 @@ CodeGen::value2reg(Value *v, int id) {
} else
assert(false && "wait for completion");
#endif
} else if (dynamic_cast<GlobalVariable *>(v)) {
output.push_back("la.local " + reg_name + ", " + v->get_name());
} else if (dynamic_cast<AllocaInst *>(v)) {
......@@ -218,7 +257,6 @@ void
CodeGen::stackMemDealloc() {
output.push_back("# epilog");
// 7: return value should be determined already!
// output.push_back("addi.w $a0, $zero, 0");
output.push_back(cur_func->get_name() + "_end:");
output.push_back("ld.d $ra, $fp, -8");
output.push_back("addi.d $sp, $sp, " + to_string(stackN));
......@@ -391,6 +429,8 @@ CodeGen::IR2assem(BinaryInst *instr) {
value2reg(instr->get_operand(1), 1);
string instr_ir = instr->get_instr_op_name();
if (instr_ir == "sdiv")
instr_ir = "div";
string suff = suffix(instr->get_type());
output.push_back(instr_ir + suff +
(is_float ? " $fa0, $fa0, $fa1" : " $a0, $a0, $a1"));
......
#include "liverange.hpp"
#include "Function.h"
#include "Instruction.h"
#include <algorithm>
#include <iterator>
void
LiveRangeAnalyzer::clear() {
IN.clear();
OUT.clear();
liverange.clear();
instr_id.clear();
}
LiveRangeAnalyzer::LiveSet
LiveRangeAnalyzer::joinFor(BasicBlock *bb) {
LiveSet out;
for (auto succ : bb->get_succ_basic_blocks()) {
auto &irs = succ->get_instructions();
auto it = irs.begin();
while (it != irs.end() and it->is_phi())
++it;
assert(it != irs.end() && "need to find first_ir from copy-stmt");
union_ip(out, IN[instr_id.at(&(*it))]);
// std::cout << "# " + it->print() << std::endl;
}
// std::cout << "\tget out: " << print_liveSet(out) << std::endl;
return out;
}
void
LiveRangeAnalyzer::make_id(Function *func) {
// instruction numbering
// this is also the structure of the IR logically:
// ignore phi, add copy-statement
int ir_cnt = 0;
for (auto &bb : func->get_basic_blocks()) {
for (auto &instr : bb.get_instructions()) {
if (instr.is_phi())
continue;
if (instr.is_br() or instr.is_ret()) {
// insert copy-stmt in front of the jump ir
auto it = phi_map.find(&bb);
if (it != phi_map.end()) {
for (auto pr : it->second) {
cpstmt_id[pr] = ++ir_cnt;
}
}
}
instr_id[&instr] = ++ir_cnt;
}
}
}
void
LiveRangeAnalyzer::run(Function *func) {
clear();
make_id(func);
#ifdef __LRA_PRINT__
print(func, false);
#endif
bool cont = true;
while (cont) {
cont = false;
// reverse traverse BasicBlocks
for (auto rit_bb = func->get_basic_blocks().rbegin();
rit_bb != func->get_basic_blocks().rend();
++rit_bb) {
auto bb = &(*rit_bb);
LiveSet bef_in, out;
bool last_ir = true;
// reverse traverse instructions
for (auto rit_ir = rit_bb->get_instructions().rbegin();
rit_ir != rit_bb->get_instructions().rend();
++rit_ir) {
auto instr = &(*rit_ir);
if (instr->is_phi()) {
assert(not last_ir && "If phi is the last ir, then data "
"flow fails due to ignorance of phi");
continue;
}
//
// get out-set for this instruction
if (last_ir) {
last_ir = false;
out = joinFor(bb);
} else {
out = bef_in;
}
OUT[instr_id.at(instr)] = out;
//
// get in-set
bef_in = transferFunction(instr);
cont |= bef_in != IN[instr_id.at(instr)];
IN[instr_id.at(instr)] = bef_in;
if (instr->is_ret() or instr->is_br()) {
// deal with copy-stmt
auto it = phi_map.find(bb);
if (it != phi_map.end()) {
for (auto rit = it->second.rbegin();
rit != it->second.rend();
++rit) {
auto [lv, rv] = *rit;
if (last_ir) {
last_ir = false;
out = joinFor(bb);
} else
out = bef_in;
OUT[cpstmt_id.at(*rit)] = out;
// transfer manually
out.erase(lv);
if (dynamic_cast<Instruction *>(rv))
out.insert(rv);
cont |= out != IN[cpstmt_id.at(*rit)];
bef_in = IN[cpstmt_id.at(*rit)] = out;
}
}
}
}
}
}
#ifdef __LRA_PRINT__
print(func);
#endif
}
LiveRangeAnalyzer::LiveSet
LiveRangeAnalyzer::transferFunction(Instruction *instr) {
LiveSet in, out = OUT[instr_id.at(instr)];
LiveSet use;
// calculate use for this instruction
for (auto op : instr->get_operands()) {
// op type:
// - global
// - function
// - Constant
// - instruction
// - argument
// - BasicBlock
auto ins = dynamic_cast<Instruction *>(op);
if (ins) {
assert(not ins->is_void() && "instr as op should not be void");
use.insert(op);
}
}
// in = use + (out - def)
auto iter = out.find(instr);
if (iter != out.end())
out.erase(iter);
std::set_union(out.begin(),
out.end(),
use.begin(),
use.end(),
std::inserter(in, in.begin()));
return in;
}
void
LiveRangeAnalyzer::print(Function *func, bool printSet) { // for debug
for (auto &bb : func->get_basic_blocks()) {
for (auto &instr : bb.get_instructions()) {
if (instr.is_phi()) // ignore phi
continue;
// insert copy-stmt
if ((instr.is_br() or instr.is_ret()) and
phi_map.find(&bb) != phi_map.end()) {
for (auto pr : phi_map.find(&bb)->second) {
auto [lv, rv] = pr;
auto idx = cpstmt_id.at(pr);
std::cout
<< cpstmt_id[pr] << ". " << lv->get_name() << " = "
<< (rv->get_name() == "" ? rv->print() : rv->get_name())
<< std::endl;
if (not printSet)
continue;
auto &in = IN.at(idx);
auto &out = OUT.at(idx);
std::cout << "\tin-set: " + print_liveSet(in) << "\n";
std::cout << "\tout-set: " + print_liveSet(out) << "\n";
}
}
// normal ir
std::cout << instr_id[&instr] << ". " << instr.print() << " # "
<< &instr << std::endl;
if (not printSet)
continue;
auto idx = instr_id.at(&instr);
auto &in = IN.at(idx);
auto &out = OUT.at(idx);
std::cout << "\tin-set: " + print_liveSet(in) << "\n";
std::cout << "\tout-set: " + print_liveSet(out) << "\n";
}
/* if (phi_map.find(&bb) != phi_map.end()) {
* for (auto pr : phi_map.find(&bb)->second) {
* auto [lv, rv] = pr;
* auto idx = cpstmt_id.at(pr);
* std::cout << cpstmt_id[pr] << ". " << lv->get_name() << " = "
* << (rv->get_name() == "" ? rv->print()
* : rv->get_name())
* << std::endl;
* if (not printSet)
* continue;
* auto &in = IN.at(idx);
* auto &out = OUT.at(idx);
* std::cout << "\tin-set: " + print_liveSet(in) << "\n";
* std::cout << "\tout-set: " + print_liveSet(out) << "\n";
* }
* } */
}
}
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