llvm ir to low-level ir
This commit is contained in:
parent
3191c3ad10
commit
32bb8f38a7
BIN
docs/ARMv7-cheat-sheet.pdf
Normal file
BIN
docs/ARMv7-cheat-sheet.pdf
Normal file
Binary file not shown.
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "3rdparty/easylogging++.h"
|
||||
#include <any>
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
@ -20,6 +21,13 @@ inline sptr(DST) shared_cast(SRC src) {
|
||||
return std::dynamic_pointer_cast<DST>(src);
|
||||
}
|
||||
|
||||
template <typename DST, typename SRC>
|
||||
inline sptr(DST) strict_shared_cast(SRC src) {
|
||||
sptr(DST) dst = std::dynamic_pointer_cast<DST>(src);
|
||||
assert(dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
#define FIND(container, val) std::find(container.begin(), container.end(), val)
|
||||
|
||||
#define panic(message) \
|
||||
|
||||
@ -2,4 +2,11 @@
|
||||
#include "llir_instruction.h"
|
||||
#include "llir_module.h"
|
||||
#include "llir_type.h"
|
||||
#include "llir_value.h"
|
||||
#include "llir_value.h"
|
||||
|
||||
namespace CompSysY {
|
||||
// Utilities
|
||||
TypePtr_t get_pointed_type(TypePtr_t ptr);
|
||||
unsigned get_type_size(TypePtr_t ir_type);
|
||||
unsigned get_pointed_type_size(TypePtr_t ir_type);
|
||||
} // namespace CompSysY
|
||||
@ -31,8 +31,7 @@ enum class InstTag {
|
||||
Gt,
|
||||
Eq,
|
||||
Ne,
|
||||
And,
|
||||
Or,
|
||||
// And, Or,
|
||||
Br,
|
||||
Call,
|
||||
Ret,
|
||||
@ -53,7 +52,7 @@ public:
|
||||
int ir_seqno = -1;
|
||||
InstTag tag;
|
||||
BasicBlockPtr_t parent_bb;
|
||||
// decltype(parent_bb->inst_list.begin()) inst_itr_in_parent;
|
||||
decltype(BasicBlock::inst_list.begin()) inst_itr;
|
||||
Instruction(InstTag inst_tag, TypePtr_t type, BasicBlockPtr_t parent_bb)
|
||||
: User("", type), tag(inst_tag), parent_bb(parent_bb) {}
|
||||
std::string tag_string() {
|
||||
@ -69,8 +68,8 @@ public:
|
||||
case InstTag::Gt: return "icmp sgt";
|
||||
case InstTag::Eq: return "icmp eq";
|
||||
case InstTag::Ne: return "icmp ne";
|
||||
case InstTag::And: return "and";
|
||||
case InstTag::Or: return "or";
|
||||
// case InstTag::And: return "and";
|
||||
// case InstTag::Or: return "or";
|
||||
case InstTag::Br: return "br";
|
||||
case InstTag::Call: return "call";
|
||||
case InstTag::Ret: return "ret";
|
||||
@ -244,7 +243,7 @@ public:
|
||||
}
|
||||
else if (Type::isType<ArrayType>(pointed_type)) {
|
||||
for (int i = 1; i < indices.size(); ++i) {
|
||||
pointed_type = shared_cast<ArrayType>(pointed_type)->element_type;
|
||||
pointed_type = shared_cast<ArrayType>(pointed_type)->elem_type;
|
||||
}
|
||||
return pointed_type;
|
||||
}
|
||||
|
||||
@ -111,11 +111,12 @@ public:
|
||||
|
||||
class ArrayType : public Type {
|
||||
public:
|
||||
TypePtr_t element_type = TypeHelper::TYPE_I32;
|
||||
int element_count = 0;
|
||||
TypePtr_t elem_type = TypeHelper::TYPE_I32;
|
||||
int elem_count = 0; // current dim size
|
||||
int type_size = 0; // = dim_size * size(elem_type)
|
||||
ArrayType() : Type(TypeTag::ArrayType) {}
|
||||
ArrayType(TypePtr_t element_type, int element_count)
|
||||
: Type(TypeTag::ArrayType), element_count(element_count), element_type(element_type) {}
|
||||
: Type(TypeTag::ArrayType), elem_count(element_count), elem_type(element_type) {}
|
||||
static std::shared_ptr<ArrayType> build_from_list(const std::vector<int> &dim_list) {
|
||||
TypePtr_t array_type = TypeHelper::TYPE_I32;
|
||||
sysy_assert(dim_list.size() != 0);
|
||||
@ -125,17 +126,16 @@ public:
|
||||
return std::dynamic_pointer_cast<ArrayType>(array_type);
|
||||
}
|
||||
virtual std::string to_string() override {
|
||||
return "Array[" + std::to_string(element_count) + " x " + element_type->to_string() + "]";
|
||||
return "Array[" + std::to_string(elem_count) + " x " + elem_type->to_string() + "]";
|
||||
}
|
||||
virtual std::string to_IR_string() override {
|
||||
return "[" + std::to_string(element_count) + " x " + element_type->to_IR_string() + "]";
|
||||
return "[" + std::to_string(elem_count) + " x " + elem_type->to_IR_string() + "]";
|
||||
}
|
||||
};
|
||||
|
||||
class PointerType : public Type {
|
||||
public:
|
||||
TypePtr_t pointed_type = TypeHelper::TYPE_I32;
|
||||
PointerType() : Type(TypeTag::PointerType) {}
|
||||
PointerType(TypePtr_t pointed_type) : Type(TypeTag::PointerType), pointed_type(pointed_type) {}
|
||||
static auto make_shared(TypePtr_t pointed_type) {
|
||||
return std::make_shared<PointerType>(pointed_type);
|
||||
@ -146,12 +146,6 @@ public:
|
||||
virtual std::string to_IR_string() override {
|
||||
return pointed_type->to_IR_string() + "*";
|
||||
}
|
||||
|
||||
static TypePtr_t pointedType(TypePtr_t ptr) {
|
||||
assert(Type::isType<PointerType>(ptr));
|
||||
auto pointer_type = Type::asType<PointerType>(ptr);
|
||||
return pointer_type->pointed_type;
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionType : public Type {
|
||||
@ -166,6 +160,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
TypePtr_t pointed_type(TypePtr_t ptr);
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -204,7 +204,7 @@ public:
|
||||
: Constant(name, type), value_list(value_list) {}
|
||||
|
||||
int real_size() const {
|
||||
return std::dynamic_pointer_cast<ArrayType>(type)->element_count;
|
||||
return std::dynamic_pointer_cast<ArrayType>(type)->elem_count;
|
||||
}
|
||||
static std::shared_ptr<ConstantArr> make_shared(
|
||||
const std::string &name,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
using std::make_shared;
|
||||
|
||||
namespace codegen {
|
||||
namespace CompSysY {
|
||||
|
||||
// a?, t?, ra are caller-saved
|
||||
// s? are callee-saved
|
||||
@ -46,7 +46,11 @@ enum class RV64Reg {
|
||||
|
||||
// riscv calling convention see: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc
|
||||
|
||||
const int XLEN = 8;
|
||||
const unsigned XLEN = 8;
|
||||
const unsigned XLEN_MASK = XLEN - 1;
|
||||
inline unsigned xlen_rnd_up(unsigned src) {
|
||||
return (src & XLEN_MASK) ? (src & (~XLEN_MASK)) + XLEN : src;
|
||||
}
|
||||
|
||||
inline std::string RV64_RegName(RV64Reg reg) {
|
||||
std::string regname = "x" + std::to_string((int)reg);
|
||||
@ -68,14 +72,11 @@ public:
|
||||
enum class OpTag {
|
||||
Virt,
|
||||
Imm,
|
||||
Reg,
|
||||
PreColor,
|
||||
} op_type = OpTag::Virt;
|
||||
int value = ~0;
|
||||
|
||||
private:
|
||||
MOperand(OpTag tag, int val) : op_type(tag), value(val) {}
|
||||
|
||||
public:
|
||||
static sptr(MOperand) NewVirtReg(int reg_no) {
|
||||
auto mop = std::make_shared<MOperand>(OpTag::Virt, reg_no);
|
||||
return mop;
|
||||
@ -87,46 +88,62 @@ public:
|
||||
}
|
||||
|
||||
static sptr(MOperand) NewReg(RV64Reg phy_reg) {
|
||||
auto mop = std::make_shared<MOperand>(OpTag::Reg, (int)phy_reg);
|
||||
auto mop = std::make_shared<MOperand>(OpTag::PreColor, (int)phy_reg);
|
||||
return mop;
|
||||
}
|
||||
};
|
||||
|
||||
enum class MInstTag {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Lt,
|
||||
Le,
|
||||
Ge,
|
||||
Gt,
|
||||
Eq,
|
||||
Ne,
|
||||
And,
|
||||
Or,
|
||||
Lsh, // sll
|
||||
Rsh, // srl,sra
|
||||
Move, // actually a pseudo, mv = addi rt, rs, 0
|
||||
Branch,
|
||||
Jmp,
|
||||
Ret,
|
||||
Load,
|
||||
Store,
|
||||
Compare,
|
||||
Call,
|
||||
Globsym,
|
||||
Comment,
|
||||
};
|
||||
|
||||
inline MInstTag inverse_cond(MInstTag src_tag) {
|
||||
switch (src_tag) {
|
||||
case MInstTag::Lt: return MInstTag::Ge;
|
||||
case MInstTag::Le: return MInstTag::Gt;
|
||||
case MInstTag::Ge: return MInstTag::Lt;
|
||||
case MInstTag::Gt: return MInstTag::Le;
|
||||
case MInstTag::Eq: return MInstTag::Ne;
|
||||
case MInstTag::Ne: return MInstTag::Eq;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
class MInst {
|
||||
public:
|
||||
enum class MInstTag {
|
||||
Add,
|
||||
Sub,
|
||||
Rsb,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
Lt,
|
||||
Le,
|
||||
Ge,
|
||||
Gt,
|
||||
Eq,
|
||||
Ne,
|
||||
And,
|
||||
Or,
|
||||
Move, // actually a pseudo, mv = addi rt, rs, 0
|
||||
Branch,
|
||||
Jump,
|
||||
Return,
|
||||
Load,
|
||||
Store,
|
||||
Compare,
|
||||
Call,
|
||||
Global,
|
||||
} tag;
|
||||
MInstTag inst_tag;
|
||||
|
||||
sptr(MBasicBlock) parent_bb;
|
||||
MInst(MInstTag tag, sptr(MBasicBlock) parent_bb) : tag(tag), parent_bb(parent_bb) {}
|
||||
MInst(MInstTag tag, sptr(MBasicBlock) parent_bb) : inst_tag(tag), parent_bb(parent_bb) {}
|
||||
};
|
||||
|
||||
class MBasicBlock {
|
||||
public:
|
||||
sptr(antlrSysY::BasicBlock) ir_bb;
|
||||
sptr(BasicBlock) ir_bb;
|
||||
sptr(MFunction) parent_func;
|
||||
std::list<sptr(MInst)> inst_list;
|
||||
std::list<sptr(MBasicBlock)> pred_list;
|
||||
@ -139,32 +156,39 @@ public:
|
||||
class MFunction {
|
||||
public:
|
||||
std::list<sptr(MBasicBlock)> bb_list;
|
||||
sptr(antlrSysY::Function) ir_func;
|
||||
sptr(Function) ir_func;
|
||||
|
||||
std::list<sptr(MInst)> stack_arg_reloc;
|
||||
unsigned stack_size;
|
||||
|
||||
unsigned virt_reg_cnt = 0;
|
||||
};
|
||||
|
||||
class MGlobalVar {
|
||||
public:
|
||||
};
|
||||
|
||||
class MCModule {
|
||||
public:
|
||||
std::list<sptr(MFunction)> function_list;
|
||||
std::list<sptr(MGlobalVar)> global_list;
|
||||
void IR2MC(const antlrSysY::Module &ir_module);
|
||||
std::list<sptr(GlobalVar)> global_list;
|
||||
void IR2MC(const Module &ir_module);
|
||||
};
|
||||
|
||||
class MInstBinary : public MInst {
|
||||
public:
|
||||
sptr(MOperand) dst;
|
||||
sptr(MOperand) op1;
|
||||
sptr(MOperand) op2;
|
||||
MInstBinary(MInstTag type, sptr(MBasicBlock) parent_bb) : MInst(type, parent_bb) {}
|
||||
|
||||
static sptr(MInstBinary) New(MInstTag type, sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstBinary>(type, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstJump : public MInst {
|
||||
public:
|
||||
sptr(MBasicBlock) target;
|
||||
MInstJump(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Jump, parent_bb) {}
|
||||
MInstJump(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Jmp, parent_bb) {}
|
||||
|
||||
static sptr(MInstJump) New(sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstJump>(parent_bb);
|
||||
@ -173,6 +197,20 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MInstBranch : public MInst {
|
||||
public:
|
||||
sptr(MBasicBlock) target;
|
||||
sptr(MOperand) op1;
|
||||
sptr(MOperand) op2;
|
||||
MInstTag branch_tag;
|
||||
MInstBranch(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Branch, parent_bb) {}
|
||||
static sptr(MInstBranch) New(sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstBranch>(parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstLoad : public MInst {
|
||||
public:
|
||||
sptr(MOperand) dst;
|
||||
@ -187,6 +225,20 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MInstStore : public MInst {
|
||||
public:
|
||||
sptr(MOperand) data;
|
||||
sptr(MOperand) addr;
|
||||
sptr(MOperand) offset;
|
||||
MInstStore(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Load, parent_bb) {}
|
||||
|
||||
static sptr(MInstStore) New(sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstStore>(parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstMove : public MInst {
|
||||
public:
|
||||
sptr(MOperand) dst;
|
||||
@ -201,15 +253,64 @@ public:
|
||||
return inst;
|
||||
}
|
||||
static sptr(MInstMove) New(sptr(MInst) rel_inst, bool insert_after = false) {
|
||||
auto parent_bb = rel_inst->parent_bb;
|
||||
auto inst = make_shared<MInstMove>(parent_bb);
|
||||
auto parent_bb = rel_inst->parent_bb;
|
||||
auto inst = make_shared<MInstMove>(parent_bb);
|
||||
auto rel_inst_itr = FIND(parent_bb->inst_list, rel_inst);
|
||||
assert(rel_inst_itr != parent_bb->inst_list.end());
|
||||
if (insert_after)
|
||||
std::advance(rel_inst_itr, 1);
|
||||
if (insert_after) std::advance(rel_inst_itr, 1);
|
||||
parent_bb->inst_list.insert(rel_inst_itr, inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace codegen
|
||||
class MInstSymbol : public MInst {
|
||||
public:
|
||||
sptr(MOperand) dst;
|
||||
sptr(GlobalVar) symbol;
|
||||
MInstSymbol(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Globsym, parent_bb) {}
|
||||
static sptr(MInstSymbol) New(sptr(MBasicBlock) parent_bb, bool insert_begin = false) {
|
||||
auto inst = make_shared<MInstSymbol>(parent_bb);
|
||||
if (insert_begin)
|
||||
parent_bb->inst_list.push_front(inst);
|
||||
else
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstReturn : public MInst {
|
||||
public:
|
||||
MInstReturn(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Ret, parent_bb) {}
|
||||
static sptr(MInstReturn) New(sptr(MBasicBlock) parent_bb, bool insert_begin = false) {
|
||||
auto inst = make_shared<MInstReturn>(parent_bb);
|
||||
if (insert_begin)
|
||||
parent_bb->inst_list.push_front(inst);
|
||||
else
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstComment : public MInst {
|
||||
public:
|
||||
std::string comment;
|
||||
MInstComment(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Comment, parent_bb) {}
|
||||
static sptr(MInstComment) New(sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstComment>(parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
class MInstCall : public MInst {
|
||||
public:
|
||||
sptr(Function) ir_func;
|
||||
MInstCall(sptr(MBasicBlock) parent_bb) : MInst(MInstTag::Call, parent_bb) {}
|
||||
static sptr(MInstCall) New(sptr(MBasicBlock) parent_bb) {
|
||||
auto inst = make_shared<MInstCall>(parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
return inst;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace CompSysY
|
||||
37
src/llir.cpp
Normal file
37
src/llir.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "llir.h"
|
||||
|
||||
/*
|
||||
Utilities for LLIR
|
||||
*/
|
||||
|
||||
namespace CompSysY {
|
||||
|
||||
TypePtr_t get_pointed_type(TypePtr_t ptr) {
|
||||
assert(Type::isType<PointerType>(ptr));
|
||||
auto pointer_type = Type::asType<PointerType>(ptr);
|
||||
return pointer_type->pointed_type;
|
||||
}
|
||||
|
||||
unsigned get_type_size(TypePtr_t ir_type) {
|
||||
if (auto arr_ty = shared_cast<ArrayType>(ir_type)) {
|
||||
if (!arr_ty->type_size) arr_ty->type_size = arr_ty->elem_count * get_type_size(arr_ty->elem_type);
|
||||
return arr_ty->type_size;
|
||||
}
|
||||
else if (auto int_ty = shared_cast<IntegerType>(ir_type)) {
|
||||
assert(int_ty->isI32());
|
||||
return 4;
|
||||
}
|
||||
assert(0 && "Only IntegerType|ArrayType have size");
|
||||
}
|
||||
|
||||
unsigned get_pointed_type_size(TypePtr_t ir_type) {
|
||||
if (auto arr_ty = shared_cast<ArrayType>(ir_type)) {
|
||||
return get_type_size(arr_ty->elem_type);
|
||||
}
|
||||
else if (auto ptr_ty = shared_cast<PointerType>(ir_type)) {
|
||||
return get_type_size(ptr_ty->pointed_type);
|
||||
}
|
||||
assert(0 && "Only PointerType|ArrayType has pointed type");
|
||||
}
|
||||
|
||||
} // namespace CompSysY
|
||||
@ -127,7 +127,7 @@ int main(int argc, const char **argv) {
|
||||
// std::cout << tree->toStringTree(&parser) << std::endl << std::endl;
|
||||
|
||||
MCModule mc_module;
|
||||
// mc_module.IR2MC(visitor.module);
|
||||
mc_module.IR2MC(visitor.module);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -5,47 +5,77 @@
|
||||
|
||||
using std::make_shared;
|
||||
|
||||
namespace codegen {
|
||||
namespace CompSysY {
|
||||
|
||||
static auto gen_imm(int imm, sptr(MBasicBlock) mc_bb) {
|
||||
auto operand = MOperand::NewImm(imm);
|
||||
// 12 bit signed imm for I/S-type
|
||||
if (-2048 <= imm && imm <= 2047) {
|
||||
return operand;
|
||||
}
|
||||
// load to register, should use pseudo `mv`
|
||||
// TODO TrivialCompiler added a opt trick here, insert before a control tansfer?
|
||||
auto vr = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
auto inst_move = MInstMove::New(mc_bb);
|
||||
inst_move->src = operand;
|
||||
inst_move->dst = vr;
|
||||
return vr;
|
||||
}
|
||||
|
||||
static sptr(MOperand) value2moperand(
|
||||
sptr(antlrSysY::Value) ir_value,
|
||||
sptr(Value) ir_value,
|
||||
sptr(MBasicBlock) mc_bb,
|
||||
std::unordered_map<sptr(antlrSysY::Value), sptr(MOperand)> &val2mop
|
||||
std::unordered_map<sptr(Value), sptr(MOperand)> &val2mop
|
||||
) {
|
||||
if (auto fparam = shared_cast<antlrSysY::FParam>(ir_value)) {
|
||||
if (auto fparam = shared_cast<FParam>(ir_value)) {
|
||||
auto itr = val2mop.find(ir_value);
|
||||
if (itr != val2mop.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
else {
|
||||
auto vr = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
val2mop.insert({ir_value, vr});
|
||||
auto ir_func = mc_bb->parent_func->ir_func;
|
||||
auto fparam_itr = FIND(ir_func->fparam_list, fparam);
|
||||
assert(fparam_itr != ir_func->fparam_list.end());
|
||||
auto fparam_ndx = std::distance(ir_func->fparam_list.begin(), fparam_itr);
|
||||
// according to RV call conv, we can have a0-a7 for params
|
||||
if (fparam_ndx < 8) {
|
||||
// copy param as an vr in func entry
|
||||
auto inst_move = MInstMove::New(mc_bb->parent_func->bb_list.front(), true);
|
||||
inst_move->src = MOperand::NewReg(RV64_RegOffset(RV64Reg::a0, fparam_ndx));
|
||||
inst_move->dst = vr;
|
||||
}
|
||||
else {
|
||||
// read from stack, sp + (i - 8) * 8, since ABI requires the stack to be aligned by XLEN=64
|
||||
// this need to be further re-located since sp may have changed
|
||||
// FramePtr won't get used here, for perf reason. Ref:
|
||||
// https://stackoverflow.com/questions/13006371/does-omitting-the-frame-pointers-really-have-a-positive-effect-on-performance-an
|
||||
// auto vr_tmp = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
auto inst_load = MInstLoad::New(mc_bb); // ld vr, (i-8)*8(sp)
|
||||
// auto inst_move = MInstMove::New(inst_load); // lui vr_t,
|
||||
inst_load->addr = MOperand::NewReg(RV64Reg::sp);
|
||||
inst_load->offset = MOperand::NewImm((fparam_ndx - 8) * XLEN);
|
||||
inst_load->dst = vr;
|
||||
mc_bb->parent_func->stack_arg_reloc.push_back(inst_load);
|
||||
}
|
||||
return vr;
|
||||
auto vr = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
val2mop.insert({ir_value, vr});
|
||||
auto ir_func = mc_bb->parent_func->ir_func;
|
||||
auto fparam_itr = FIND(ir_func->fparam_list, fparam);
|
||||
assert(fparam_itr != ir_func->fparam_list.end());
|
||||
auto fparam_ndx = std::distance(ir_func->fparam_list.begin(), fparam_itr);
|
||||
// according to RV call conv, we can have a0-a7 for params
|
||||
if (fparam_ndx < 8) {
|
||||
// copy param as an vr in func entry
|
||||
auto inst_move = MInstMove::New(mc_bb->parent_func->bb_list.front(), true);
|
||||
inst_move->src = MOperand::NewReg(RV64_RegOffset(RV64Reg::a0, fparam_ndx));
|
||||
inst_move->dst = vr;
|
||||
}
|
||||
else {
|
||||
// read from stack, sp + (i - 8) * 8, since ABI requires the stack to be aligned by XLEN=64
|
||||
// this need to be further re-located since sp may have changed
|
||||
// FramePtr won't get used here, for perf reason. Ref:
|
||||
// https://stackoverflow.com/questions/13006371/does-omitting-the-frame-pointers-really-have-a-positive-effect-on-performance-an
|
||||
// TODO Trivial Compiler(THU2020) use an addition move, but I am not sure why, deleted temporally
|
||||
// auto vr_tmp = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
auto inst_load = MInstLoad::New(mc_bb); // ld vr, (i-8)*8(sp)
|
||||
// auto inst_move = MInstMove::New(inst_load); // lui vr_t,
|
||||
inst_load->addr = MOperand::NewReg(RV64Reg::sp);
|
||||
inst_load->offset = MOperand::NewImm((fparam_ndx - 8) * XLEN);
|
||||
inst_load->dst = vr;
|
||||
mc_bb->parent_func->stack_arg_reloc.push_back(inst_load);
|
||||
}
|
||||
return vr;
|
||||
}
|
||||
else if (auto glob = shared_cast<GlobalVar>(ir_value)) {
|
||||
auto itr = val2mop.find(ir_value);
|
||||
if (itr != val2mop.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
auto inst_symld = MInstSymbol::New(mc_bb->parent_func->bb_list.front(), true);
|
||||
auto vr = MOperand::NewVirtReg(mc_bb->parent_func->virt_reg_cnt++);
|
||||
val2mop.insert({ir_value, vr});
|
||||
inst_symld->symbol = glob;
|
||||
inst_symld->dst = vr;
|
||||
return vr;
|
||||
}
|
||||
else if (auto constant = shared_cast<ConstantInt>(ir_value)) {
|
||||
auto imm = constant->value;
|
||||
return gen_imm(imm, mc_bb);
|
||||
}
|
||||
else {
|
||||
// plain situation
|
||||
@ -61,9 +91,10 @@ static sptr(MOperand) value2moperand(
|
||||
}
|
||||
}
|
||||
|
||||
void MCModule::IR2MC(const antlrSysY::Module &ir_module) {
|
||||
void MCModule::IR2MC(const Module &ir_module) {
|
||||
// Simply copy globals, since they don't need any translation
|
||||
for (auto glob : ir_module.global_var_list) {
|
||||
// TODO copy globals from ir
|
||||
this->global_list.push_back(glob);
|
||||
}
|
||||
|
||||
for (auto func : ir_module.function_list) {
|
||||
@ -73,11 +104,12 @@ void MCModule::IR2MC(const antlrSysY::Module &ir_module) {
|
||||
mc_func->ir_func = func;
|
||||
|
||||
// copy pred/succ info
|
||||
std::unordered_map<sptr(antlrSysY::BasicBlock), sptr(MBasicBlock)> bb_ir2mc;
|
||||
std::unordered_map<sptr(BasicBlock), sptr(MBasicBlock)> bb_ir2mc;
|
||||
for (auto bb : func->bb_list) {
|
||||
auto mc_bb = make_shared<MBasicBlock>();
|
||||
mc_func->bb_list.push_back(mc_bb);
|
||||
mc_bb->ir_bb = bb;
|
||||
mc_bb->parent_func = mc_func;
|
||||
bb_ir2mc.insert({bb, mc_bb});
|
||||
}
|
||||
for (auto bb : func->bb_list) {
|
||||
@ -92,17 +124,378 @@ void MCModule::IR2MC(const antlrSysY::Module &ir_module) {
|
||||
mc_bb->pred_list.push_back(mc_pred);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<sptr(Value), sptr(MOperand)> mp_val2op;
|
||||
std::unordered_map<User *, sptr(Instruction)> mp_br2icmp;
|
||||
// instruction translate
|
||||
for (auto bb : func->bb_list) {
|
||||
auto mc_bb = bb_ir2mc[bb];
|
||||
for (auto inst : bb->inst_list) {
|
||||
if (auto li = shared_cast<antlrSysY::InstLoad>(inst)) {
|
||||
auto mc_li = MInstLoad::New(mc_bb);
|
||||
if (auto ld = shared_cast<InstLoad>(inst)) {
|
||||
auto addr = value2moperand(ld->operand_list[0], mc_bb, mp_val2op);
|
||||
auto mc_li = MInstLoad::New(mc_bb);
|
||||
mc_li->addr = addr;
|
||||
mc_li->dst = value2moperand(ld, mc_bb, mp_val2op);
|
||||
mc_li->offset = nullptr;
|
||||
continue;
|
||||
}
|
||||
if (auto st = shared_cast<InstStore>(inst)) {
|
||||
auto data = value2moperand(st->operand_list[0], mc_bb, mp_val2op);
|
||||
auto addr = value2moperand(st->operand_list[1], mc_bb, mp_val2op);
|
||||
auto mc_li = MInstStore::New(mc_bb);
|
||||
mc_li->addr = addr;
|
||||
mc_li->data = data;
|
||||
mc_li->offset = nullptr;
|
||||
continue;
|
||||
}
|
||||
if (auto gep = shared_cast<InstGEP>(inst)) {
|
||||
// gep <elem_ty> <elem_ty*> ptr, index0, index1
|
||||
// tgt_addr = ptr + index0 * sizeof(elem_ty) + index1 * sizeof(elem_ty->elem_ty)
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto ptr = value2moperand(inst->operand_list[0], mc_bb, mp_val2op);
|
||||
auto index0 = value2moperand(inst->operand_list[1], mc_bb, mp_val2op);
|
||||
decltype(index0) index1 = nullptr;
|
||||
assert(inst->operand_list.size() <= 3);
|
||||
if (inst->operand_list.size() == 3) {
|
||||
assert(index0->op_type == MOperand::OpTag::Imm && index0->value == 0);
|
||||
index1 = value2moperand(inst->operand_list[2], mc_bb, mp_val2op);
|
||||
}
|
||||
// %dst = getelementptr [2x[3xi32]] [2x[3xi32]]* %ptr, i32 0, i32 1
|
||||
auto ptr_type = gep->operand_list[0]->type;
|
||||
auto elem_type = shared_cast<PointerType>(ptr_type)->pointed_type;
|
||||
|
||||
if (!index0->value || !index1 || !index1->value) {
|
||||
// a shortcut for zero gep
|
||||
auto inst_mv = MInstMove::New(mc_bb);
|
||||
inst_mv->dst = dst;
|
||||
inst_mv->src = ptr;
|
||||
VLOG(6) << "trivial gep";
|
||||
}
|
||||
else if (!index1) {
|
||||
// index on same dim: addr = ptr + index0 * sizeof(elem_ty)
|
||||
auto elem_size = get_type_size(elem_type);
|
||||
auto elem_size_imm = gen_imm(elem_size, mc_bb);
|
||||
auto vr = MOperand::NewVirtReg(mc_func->virt_reg_cnt++);
|
||||
auto inst_mul = MInstBinary::New(MInstTag::Mul, mc_bb);
|
||||
inst_mul->dst = vr;
|
||||
inst_mul->op1 = index0;
|
||||
inst_mul->op2 = elem_size_imm;
|
||||
auto inst_add = MInstBinary::New(MInstTag::Add, mc_bb);
|
||||
inst_add->dst = dst;
|
||||
inst_add->op1 = ptr;
|
||||
inst_add->op2 = vr;
|
||||
VLOG(6) << "gep ptr + elem_ty * index";
|
||||
}
|
||||
else {
|
||||
// index on sub dim: addr = ptr + index1 * sizeof(elem_ty.elem_ty)
|
||||
auto elem_elem_size = get_pointed_type_size(elem_type);
|
||||
auto elem_elem_size_imm = gen_imm(elem_elem_size, mc_bb);
|
||||
auto vr = MOperand::NewVirtReg(mc_func->virt_reg_cnt++);
|
||||
auto inst_mul = MInstBinary::New(MInstTag::Mul, mc_bb);
|
||||
inst_mul->dst = vr;
|
||||
inst_mul->op1 = index0;
|
||||
inst_mul->op2 = elem_elem_size_imm;
|
||||
auto inst_add = MInstBinary::New(MInstTag::Add, mc_bb);
|
||||
inst_add->dst = dst;
|
||||
inst_add->op1 = ptr;
|
||||
inst_add->op2 = vr;
|
||||
VLOG(6) << "gep ptr + elem_ty.elem_ty * index";
|
||||
}
|
||||
}
|
||||
else if (auto alc = shared_cast<InstAlloca>(inst)) {
|
||||
unsigned alloca_size = 0;
|
||||
auto allocated_type = get_pointed_type(alc->type);
|
||||
if (shared_cast<IntegerType>(allocated_type) || shared_cast<PointerType>(allocated_type)) {
|
||||
// int on stack has to be aligned
|
||||
// whereas, ptr is possible when a array from fparam: `%arr = alloca [10xi32]*`
|
||||
alloca_size = XLEN;
|
||||
}
|
||||
else {
|
||||
assert(shared_cast<ArrayType>(allocated_type));
|
||||
alloca_size = get_type_size(allocated_type);
|
||||
// align array on stack to XLEN
|
||||
alloca_size = xlen_rnd_up(alloca_size);
|
||||
}
|
||||
assert(alloca_size && !(alloca_size & XLEN_MASK));
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto stk_sz_imm = gen_imm(mc_func->stack_size, mc_bb);
|
||||
auto inst_add = MInstBinary::New(MInstTag::Add, mc_bb);
|
||||
inst_add->dst = dst;
|
||||
inst_add->op1 = MOperand::NewReg(RV64Reg::sp);
|
||||
inst_add->op2 = stk_sz_imm;
|
||||
// dont forget to record stack usage
|
||||
mc_func->stack_size += alloca_size;
|
||||
}
|
||||
else if (auto ret = shared_cast<InstReturn>(inst)) {
|
||||
if (ret->operand_list.size()) {
|
||||
auto retval = value2moperand(ret->operand_list[0], mc_bb, mp_val2op);
|
||||
auto inst_mv = MInstMove::New(mc_bb);
|
||||
inst_mv->src = retval;
|
||||
inst_mv->dst = MOperand::NewReg(RV64Reg::a0);
|
||||
}
|
||||
MInstReturn::New(mc_bb);
|
||||
}
|
||||
else if (auto cal = shared_cast<InstCall>(inst)) {
|
||||
auto target_func = cal->operand_list[0];
|
||||
int nparams = cal->operand_list.size() - 1;
|
||||
for (int i = 1; i < cal->operand_list.size(); ++i) {
|
||||
auto rparam = value2moperand(cal->operand_list[i], mc_bb, mp_val2op);
|
||||
if (i <= 8) {
|
||||
auto inst_move = MInstMove::New(mc_bb);
|
||||
inst_move->src = rparam;
|
||||
inst_move->dst = MOperand::NewReg(RV64_RegOffset(RV64Reg::a0, i - 1));
|
||||
}
|
||||
else {
|
||||
int st_off = -(nparams - (i - 1)) * XLEN;
|
||||
auto st_off_imm = gen_imm(st_off, mc_bb);
|
||||
auto inst_store = MInstStore::New(mc_bb);
|
||||
inst_store->addr = MOperand::NewReg(RV64Reg::sp);
|
||||
inst_store->offset = st_off_imm;
|
||||
inst_store->data = rparam;
|
||||
}
|
||||
}
|
||||
if (nparams > 8) {
|
||||
// sp -= (n-8)*8
|
||||
auto add_inst = new MInstBinary(MInstTag::Sub, mc_bb);
|
||||
add_inst->dst = MOperand::NewReg(RV64Reg::sp);
|
||||
add_inst->op1 = MOperand::NewReg(RV64Reg::sp);
|
||||
add_inst->op2 = gen_imm(XLEN * (nparams - 8), mc_bb);
|
||||
}
|
||||
|
||||
auto inst_call = MInstCall::New(mc_bb);
|
||||
inst_call->ir_func = strict_shared_cast<Function>(cal->operand_list[0]);
|
||||
|
||||
if (nparams > 8) {
|
||||
// sp += (n-8)*8
|
||||
auto add_inst = new MInstBinary(MInstTag::Add, mc_bb);
|
||||
add_inst->dst = MOperand::NewReg(RV64Reg::sp);
|
||||
add_inst->op1 = MOperand::NewReg(RV64Reg::sp);
|
||||
add_inst->op2 = gen_imm(XLEN * (nparams - 8), mc_bb);
|
||||
}
|
||||
// handle return value, if exist
|
||||
if (shared_cast<IntegerType>(cal->type)) {
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto inst_mv = MInstMove::New(mc_bb);
|
||||
inst_mv->src = MOperand::NewReg(RV64Reg::a0);
|
||||
inst_mv->dst = dst;
|
||||
}
|
||||
}
|
||||
else if (auto br = shared_cast<InstBranch>(inst)) {
|
||||
if (br->operand_list.size() == 1) {
|
||||
auto inst_jump = MInstJump::New(mc_bb);
|
||||
auto target = br->operand_list.front();
|
||||
inst_jump->target = bb_ir2mc.at(strict_shared_cast<BasicBlock>(target));
|
||||
}
|
||||
else {
|
||||
if (mp_br2icmp.find(dynamic_cast<User *>(br.get())) != mp_br2icmp.end()) {
|
||||
auto cond = mp_br2icmp.at(dynamic_cast<User *>(br.get()));
|
||||
auto op1 = value2moperand(cond->operand_list[0], mc_bb, mp_val2op);
|
||||
auto op2 = value2moperand(cond->operand_list[1], mc_bb, mp_val2op);
|
||||
auto inst_br = MInstBranch::New(mc_bb);
|
||||
inst_br->op1 = op1;
|
||||
inst_br->op2 = op2;
|
||||
switch (cond->tag) {
|
||||
case InstTag::Lt: inst_br->branch_tag = MInstTag::Lt; break;
|
||||
case InstTag::Le: inst_br->branch_tag = MInstTag::Le; break;
|
||||
case InstTag::Ge: inst_br->branch_tag = MInstTag::Ge; break;
|
||||
case InstTag::Gt: inst_br->branch_tag = MInstTag::Gt; break;
|
||||
case InstTag::Eq: inst_br->branch_tag = MInstTag::Eq; break;
|
||||
case InstTag::Ne: inst_br->branch_tag = MInstTag::Ne; break;
|
||||
default: assert(0);
|
||||
}
|
||||
if (*std::next(mc_bb->ir_bb->itr) == br->operand_list[1]) {
|
||||
// true branch is the next block, while false branch is faraway
|
||||
// branch to false branch and inverse the condition
|
||||
inst_br->branch_tag = inverse_cond(inst_br->branch_tag);
|
||||
inst_br->target = bb_ir2mc.at(strict_shared_cast<BasicBlock>(br->operand_list[1]));
|
||||
}
|
||||
else if (*std::next(mc_bb->ir_bb->itr) == br->operand_list[2]) {
|
||||
inst_br->target = bb_ir2mc.at(strict_shared_cast<BasicBlock>(br->operand_list[2]));
|
||||
}
|
||||
else {
|
||||
panic("Unexpected branch pattern");
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto cond = value2moperand(br->operand_list[0], mc_bb, mp_val2op);
|
||||
auto inst_br = MInstBranch::New(mc_bb);
|
||||
inst_br->op1 = cond;
|
||||
inst_br->op2 = MOperand::NewReg(RV64Reg::x0);
|
||||
inst_br->branch_tag = MInstTag::Ne;
|
||||
if (*std::next(mc_bb->ir_bb->itr) == br->operand_list[1]) {
|
||||
inst_br->branch_tag = inverse_cond(inst_br->branch_tag);
|
||||
inst_br->target = bb_ir2mc.at(strict_shared_cast<BasicBlock>(br->operand_list[1]));
|
||||
}
|
||||
else if (*std::next(mc_bb->ir_bb->itr) == br->operand_list[2]) {
|
||||
inst_br->target = bb_ir2mc.at(strict_shared_cast<BasicBlock>(br->operand_list[2]));
|
||||
}
|
||||
else {
|
||||
panic("Unexpected branch pattern");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto bin = shared_cast<InstBinary>(inst)) {
|
||||
auto op1 = inst->operand_list[0];
|
||||
auto op2 = inst->operand_list[1];
|
||||
// Frontend should promise constant expr to be eliminated
|
||||
// assert(!(shared_cast<ConstantInt>(op1) && shared_cast<ConstantInt>(op2)));
|
||||
if (shared_cast<ConstantInt>(op1) && shared_cast<ConstantInt>(op2)) {
|
||||
LOG(WARNING) << "Constant expr not eliminated: " << bin->to_string();
|
||||
auto res = shared_cast<ConstantInt>(op1)->value + shared_cast<ConstantInt>(op2)->value;
|
||||
auto src_imm = gen_imm(res, mc_bb);
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto inst_mv = MInstMove::New(mc_bb);
|
||||
inst_mv->dst = dst;
|
||||
inst_mv->src = src_imm;
|
||||
continue;
|
||||
}
|
||||
// 2^n replacement
|
||||
auto _is_const_mul_power2 = [&]() -> sptr(ConstantInt) {
|
||||
if (!(bin->tag == InstTag::Mul)) return nullptr;
|
||||
if (auto const_op = shared_cast<ConstantInt>(op1)) {
|
||||
unsigned exp = __builtin_ctz(const_op->value);
|
||||
if (const_op->value == (1U << exp)) {
|
||||
return const_op;
|
||||
}
|
||||
}
|
||||
else if (auto const_op = shared_cast<ConstantInt>(op2)) {
|
||||
unsigned exp = __builtin_ctz(const_op->value);
|
||||
if (const_op->value == (1U << exp)) {
|
||||
return const_op;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
auto _is_const_div_power2 = [&]() -> sptr(ConstantInt) {
|
||||
if (bin->tag != InstTag::Div) return nullptr;
|
||||
if (auto const_op = shared_cast<ConstantInt>(op2)) {
|
||||
if (const_op->value == (1U << __builtin_ctz(const_op->value))) return const_op;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
if (auto const_op = _is_const_mul_power2()) {
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto mc_op = value2moperand(const_op == op1 ? op2 : op1, mc_bb, mp_val2op);
|
||||
unsigned exp = __builtin_ctz(const_op->value);
|
||||
auto inst_rsh = MInstBinary::New(MInstTag::Lsh, mc_bb);
|
||||
inst_rsh->dst = dst;
|
||||
inst_rsh->op1 = mc_op;
|
||||
inst_rsh->op2 = MOperand::NewImm(exp);
|
||||
continue;
|
||||
}
|
||||
if (auto const_op = _is_const_div_power2()) {
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto mc_op1 = value2moperand(op1, mc_bb, mp_val2op);
|
||||
unsigned exp = __builtin_ctz(const_op->value);
|
||||
auto inst_rsh = MInstBinary::New(MInstTag::Rsh, mc_bb);
|
||||
inst_rsh->dst = dst;
|
||||
inst_rsh->op1 = mc_op1;
|
||||
inst_rsh->op2 = MOperand::NewImm(exp);
|
||||
continue;
|
||||
}
|
||||
// no opt for modulo, since they are all signed int, it's wrong
|
||||
// TODO try to use negative imm to reduce instructions
|
||||
if (InstTag::Lt <= bin->tag && bin->tag <= InstTag::Ne) {
|
||||
if (bin->use_list.size() == 1
|
||||
&& dynamic_cast<InstBranch*>(bin->use_list.front().user)
|
||||
&& bin->use_list.front().user == (*std::next(bin->inst_itr)).get()) {
|
||||
// icmp + br, and the result of icmp is only used by that br, merge into single bxx instruction
|
||||
mp_br2icmp.insert({bin->use_list.front().user, bin});
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
LOG(WARNING) << "Condition without branch";
|
||||
/* Notes about compare&set:
|
||||
icmp_slt(r1 < r2) = slt r3, r1, r2
|
||||
icmp_sgt(r1 > r2) = slt r3, r2, r1
|
||||
icmp_sle(r1 <= r2) = slt r3, r2, r1; xori r3, r3, 1
|
||||
icmp_sge(r1 >= r2) = slt r3, r1, r2; xori r3, r3, 1
|
||||
icmp_eq(r1 == r2) = xor r3, r1, r2; seqz r3, r3
|
||||
icmp_ne(r1 != r2) = xor r3, r1, r2; snez r3, r3
|
||||
We can see clearly, though icmp_sge use 1 more inst than icmp_slt,
|
||||
they involve the same set of registers, so it is okay to defer this to the output stage
|
||||
*/
|
||||
}
|
||||
}
|
||||
// else if (InstTag::And <= bin->tag && bin->tag <= InstTag::Or)
|
||||
else {
|
||||
MInstTag minst_tag;
|
||||
switch (bin->tag) {
|
||||
case InstTag::Add: minst_tag = MInstTag::Add; break;
|
||||
case InstTag::Sub: minst_tag = MInstTag::Sub; break;
|
||||
case InstTag::Mul: minst_tag = MInstTag::Mul; break;
|
||||
case InstTag::Div: minst_tag = MInstTag::Div; break;
|
||||
case InstTag::Mod: minst_tag = MInstTag::Mod; break;
|
||||
case InstTag::Lt: minst_tag = MInstTag::Lt; break;
|
||||
case InstTag::Le: minst_tag = MInstTag::Le; break;
|
||||
case InstTag::Ge: minst_tag = MInstTag::Ge; break;
|
||||
case InstTag::Gt: minst_tag = MInstTag::Gt; break;
|
||||
case InstTag::Eq: minst_tag = MInstTag::Eq; break;
|
||||
case InstTag::Ne: minst_tag = MInstTag::Ne; break;
|
||||
default: assert(0);
|
||||
}
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto mc_op1 = value2moperand(op1, mc_bb, mp_val2op);
|
||||
auto mc_op2 = value2moperand(op2, mc_bb, mp_val2op);
|
||||
auto inst_bin = MInstBinary::New(minst_tag, mc_bb);
|
||||
inst_bin->dst = dst;
|
||||
inst_bin->op1 = mc_op1;
|
||||
inst_bin->op2 = mc_op2;
|
||||
}
|
||||
}
|
||||
else if (auto zxt = shared_cast<InstZext>(inst)) {
|
||||
// trivial move
|
||||
auto src = value2moperand(zxt->operand_list[0], mc_bb, mp_val2op);
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
auto inst_mv = MInstMove::New(mc_bb);
|
||||
inst_mv->src = src;
|
||||
inst_mv->dst = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
struct pmv {
|
||||
sptr(MOperand) dst;
|
||||
sptr(MOperand) src;
|
||||
};
|
||||
// phi elimination: SSA Book Algo 3.6
|
||||
// Use some more redundency to save the complicated critical edge split
|
||||
for (auto ir_bb : func->bb_list) {
|
||||
auto mc_bb = bb_ir2mc.at(ir_bb);
|
||||
std::list<pmv> par_mv_cur; // parallel move in current bb
|
||||
std::unordered_map<sptr(MBasicBlock), pmv> par_mv_pred; // parallel move in each pred bb
|
||||
/* 某个bb的开头有一个phi指令
|
||||
%phi_dst = phi [val1 bb1] [val2 bb2] [val3 bb3] ...
|
||||
为这东西新建一个虚拟寄存器vr1
|
||||
在当前的bb开头插入 `mv %phi_dst <- %vr1`
|
||||
然后在前驱%bb_i的末尾插入 `mv %vr1 <- %val_i`
|
||||
*/
|
||||
for (auto inst : ir_bb->inst_list) {
|
||||
if (!shared_cast<InstPhi>(inst)) break;
|
||||
auto phi = shared_cast<InstPhi>(inst);
|
||||
auto vr = MOperand::NewVirtReg(mc_func->virt_reg_cnt++);
|
||||
auto dst = value2moperand(inst, mc_bb, mp_val2op);
|
||||
par_mv_cur.push_back({dst, vr});
|
||||
auto pred_itr = phi->parent_bb->pred_list.begin();
|
||||
auto val_itr = phi->operand_list.begin();
|
||||
// due to sloppy design, pred_bb corresponds in order as incoming val in oplist
|
||||
for (; val_itr != phi->operand_list.end(); ++pred_itr, ++val_itr) {
|
||||
auto pred_mc_bb = bb_ir2mc.at(*pred_itr);
|
||||
auto phi_src_op = value2moperand(*val_itr, pred_mc_bb, mp_val2op);
|
||||
par_mv_pred.insert({pred_mc_bb, {vr, phi_src_op}});
|
||||
}
|
||||
}
|
||||
for (auto &pmv : par_mv_cur) {
|
||||
auto inst_mv = MInstMove::New(mc_bb, true);
|
||||
inst_mv->src = pmv.src;
|
||||
inst_mv->dst = pmv.dst;
|
||||
}
|
||||
for (auto &pmv_pair : par_mv_pred) {
|
||||
auto inst_mv = MInstMove::New(pmv_pair.first, true);
|
||||
inst_mv->src = pmv_pair.second.src;
|
||||
inst_mv->dst = pmv_pair.second.dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace codegen
|
||||
} // namespace CompSysY
|
||||
@ -176,7 +176,7 @@ static void _mem_2_reg(FunctionPtr_t func) {
|
||||
assert(bb == func->bb_list.front() && "Alloca should be at front of a func");
|
||||
auto ai = Value::as<InstAlloca>(inst);
|
||||
// assert(is_alloca_promotable(ai) && "Invalid alloca");
|
||||
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type))) continue;
|
||||
if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) continue;
|
||||
alloca_list.push_back(ai);
|
||||
}
|
||||
}
|
||||
@ -285,7 +285,7 @@ static void _mem_2_reg(FunctionPtr_t func) {
|
||||
continue;
|
||||
}
|
||||
auto ai = Value::as<InstAlloca>(li->operand_list[0]);
|
||||
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type))) {
|
||||
if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) {
|
||||
continue;
|
||||
}
|
||||
int alloca_index = alloca_to_id.at(ai);
|
||||
@ -299,7 +299,7 @@ static void _mem_2_reg(FunctionPtr_t func) {
|
||||
continue;
|
||||
}
|
||||
auto ai = Value::as<InstAlloca>(si->operand_list[1]);
|
||||
if (!Type::isType<IntegerType>(PointerType::pointedType(ai->type))) {
|
||||
if (!Type::isType<IntegerType>(get_pointed_type(ai->type))) {
|
||||
continue;
|
||||
}
|
||||
int alloca_index = alloca_to_id.at(ai);
|
||||
|
||||
@ -819,7 +819,7 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
ptr = build_InstGEP(ptr, {CONST0, exp_val}, _state.current_bb);
|
||||
}
|
||||
if (Type::isType<ArrayType>(PointerType::pointedType(ptr->type))) {
|
||||
if (Type::isType<ArrayType>(get_pointed_type(ptr->type))) {
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
}
|
||||
return ptr;
|
||||
@ -869,7 +869,7 @@ std::any Visitor::visitLVal(SysyParser::LValContext *ctx) {
|
||||
auto exp_val = any_to_Value(visitExp(exp_list[i]));
|
||||
ptr = build_InstGEP(ptr, {CONST0, exp_val}, _state.current_bb);
|
||||
}
|
||||
if (Type::isType<ArrayType>(PointerType::pointedType(ptr->type))) {
|
||||
if (Type::isType<ArrayType>(get_pointed_type(ptr->type))) {
|
||||
ptr = build_InstGEP(ptr, {CONST0, CONST0}, _state.current_bb);
|
||||
}
|
||||
return ptr;
|
||||
|
||||
@ -27,9 +27,9 @@ std::shared_ptr<InstLoad> build_InstLoad(
|
||||
TypePtr_t type,
|
||||
std::shared_ptr<BasicBlock> parent_bb
|
||||
) {
|
||||
auto inst_load = std::make_shared<InstLoad>(value, type, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst_load);
|
||||
return inst_load;
|
||||
auto inst = std::make_shared<InstLoad>(value, type, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstStore> build_InstStore(
|
||||
@ -37,9 +37,9 @@ std::shared_ptr<InstStore> build_InstStore(
|
||||
std::shared_ptr<Value> pointer,
|
||||
std::shared_ptr<BasicBlock> parent_bb
|
||||
) {
|
||||
auto inst_store = std::make_shared<InstStore>(value, pointer, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst_store);
|
||||
return inst_store;
|
||||
auto inst = std::make_shared<InstStore>(value, pointer, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
// a little bit different, we put all alloca in the head of each basic block
|
||||
@ -48,12 +48,12 @@ std::shared_ptr<InstAlloca> build_InstAlloca(
|
||||
TypePtr_t type,
|
||||
std::shared_ptr<BasicBlock> parent_bb
|
||||
) {
|
||||
auto inst_alloca = std::make_shared<InstAlloca>(type, parent_bb);
|
||||
inst_alloca->name = name;
|
||||
auto inst = std::make_shared<InstAlloca>(type, parent_bb);
|
||||
inst->name = name;
|
||||
auto func_head_bb = parent_bb->parent->bb_list.front();
|
||||
func_head_bb->inst_list.insert(func_head_bb->inst_list.begin(), inst_alloca);
|
||||
inst->inst_itr = func_head_bb->inst_list.insert(func_head_bb->inst_list.begin(), inst);
|
||||
// parent_bb->inst_list.push_back(inst_alloca);
|
||||
return inst_alloca;
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstBinary> build_InstBinary(
|
||||
@ -62,12 +62,12 @@ std::shared_ptr<InstBinary> build_InstBinary(
|
||||
std::shared_ptr<Value> op2,
|
||||
std::shared_ptr<BasicBlock> parent_bb
|
||||
) {
|
||||
std::shared_ptr<InstBinary> inst_binary;
|
||||
if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Or) {
|
||||
inst_binary = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I1, op1, op2, parent_bb);
|
||||
std::shared_ptr<InstBinary> inst;
|
||||
if (InstTag::Lt <= inst_tag && inst_tag <= InstTag::Ne) {
|
||||
inst = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I1, op1, op2, parent_bb);
|
||||
}
|
||||
else if (InstTag::Add <= inst_tag && inst_tag <= InstTag::Div) {
|
||||
inst_binary = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I32, op1, op2, parent_bb);
|
||||
inst = std::make_shared<InstBinary>(inst_tag, TypeHelper::TYPE_I32, op1, op2, parent_bb);
|
||||
}
|
||||
else {
|
||||
panic("Invalid Binary Operation");
|
||||
@ -81,14 +81,14 @@ std::shared_ptr<InstBinary> build_InstBinary(
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
parent_bb->inst_list.push_back(inst_binary);
|
||||
return inst_binary;
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstZext> build_InstZext(std::shared_ptr<Value> op, std::shared_ptr<BasicBlock> parent_bb) {
|
||||
auto inst_zext = std::make_shared<InstZext>(op, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst_zext);
|
||||
return inst_zext;
|
||||
auto inst = std::make_shared<InstZext>(op, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstBranch> build_InstBranch(
|
||||
@ -97,26 +97,26 @@ std::shared_ptr<InstBranch> build_InstBranch(
|
||||
BasicBlockPtr_t false_block,
|
||||
BasicBlockPtr_t parent_bb
|
||||
) {
|
||||
auto inst = std::make_shared<InstBranch>(cond, true_block, false_block, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstBranch>(cond, true_block, false_block, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstBranch> build_InstBranch(BasicBlockPtr_t target_block, BasicBlockPtr_t parent_bb) {
|
||||
auto inst = std::make_shared<InstBranch>(target_block, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstBranch>(target_block, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstReturn> build_InstReturn(ValuePtr_t ret_val, BasicBlockPtr_t parent_bb) {
|
||||
auto inst = std::make_shared<InstReturn>(ret_val, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstReturn>(ret_val, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
std::shared_ptr<InstReturn> build_InstReturn(BasicBlockPtr_t parent_bb) {
|
||||
auto inst = std::make_shared<InstReturn>(parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstReturn>(parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
@ -125,8 +125,8 @@ std::shared_ptr<InstCall> build_InstCall(
|
||||
const std::vector<ValuePtr_t> &args,
|
||||
BasicBlockPtr_t parent_bb
|
||||
) {
|
||||
auto inst = std::make_shared<InstCall>(func, args, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstCall>(func, args, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
@ -135,8 +135,8 @@ std::shared_ptr<InstGEP> build_InstGEP(
|
||||
const std::vector<ValuePtr_t> &indices,
|
||||
BasicBlockPtr_t parent_bb
|
||||
) {
|
||||
auto inst = std::make_shared<InstGEP>(pointer, indices, parent_bb);
|
||||
parent_bb->inst_list.push_back(inst);
|
||||
auto inst = std::make_shared<InstGEP>(pointer, indices, parent_bb);
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.end(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
@ -146,9 +146,9 @@ InstPhiPtr_t build_InstPhi(
|
||||
BasicBlockPtr_t parent_bb,
|
||||
const std::string &name
|
||||
) {
|
||||
auto inst = std::make_shared<InstPhi>(type, incoming_vals, parent_bb);
|
||||
inst->name = name;
|
||||
parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst);
|
||||
auto inst = std::make_shared<InstPhi>(type, incoming_vals, parent_bb);
|
||||
inst->name = name;
|
||||
inst->inst_itr = parent_bb->inst_list.insert(parent_bb->inst_list.begin(), inst);
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
@ -21,10 +21,10 @@ std::shared_ptr<ConstantArr> gen_arr_hierarchy(
|
||||
int base,
|
||||
int length
|
||||
) {
|
||||
int dim_n = array_type->element_count;
|
||||
int dim_n = array_type->elem_count;
|
||||
int dim_size = length / dim_n;
|
||||
std::vector<ValuePtr_t> value_list;
|
||||
if (array_type->element_type->type_tag == Type::TypeTag::IntegerType) {
|
||||
if (array_type->elem_type->type_tag == Type::TypeTag::IntegerType) {
|
||||
sysy_assert(dim_size == 1);
|
||||
for (int i = 0; i < dim_n; ++i) {
|
||||
if (const_array[base + i]) {
|
||||
@ -43,7 +43,7 @@ std::shared_ptr<ConstantArr> gen_arr_hierarchy(
|
||||
int last_non_null = -1;
|
||||
for (int i = 0; i < dim_n; ++i) {
|
||||
auto sub_arr = gen_arr_hierarchy(
|
||||
std::dynamic_pointer_cast<ArrayType>(array_type->element_type), const_array, dim_size * i, dim_size
|
||||
std::dynamic_pointer_cast<ArrayType>(array_type->elem_type), const_array, dim_size * i, dim_size
|
||||
);
|
||||
value_list.push_back(sub_arr);
|
||||
if (sub_arr) last_non_null = i;
|
||||
@ -64,7 +64,7 @@ static void _build_arr_init_list(
|
||||
std::shared_ptr<ConstantArr> arr,
|
||||
std::shared_ptr<ArrayType> arr_type
|
||||
) {
|
||||
if (arr_type->element_type->type_tag == Type::TypeTag::IntegerType) {
|
||||
if (arr_type->elem_type->type_tag == Type::TypeTag::IntegerType) {
|
||||
ostr << arr_type->to_IR_string();
|
||||
ostr << " [";
|
||||
for (int i = 0; i < arr->value_list.size(); ++i) {
|
||||
@ -73,7 +73,7 @@ static void _build_arr_init_list(
|
||||
ostr << ", ";
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) {
|
||||
for (int i = 0; i < arr_type->elem_count - arr->value_list.size(); ++i) {
|
||||
ostr << ", i32 0";
|
||||
}
|
||||
ostr << "]";
|
||||
@ -86,16 +86,16 @@ static void _build_arr_init_list(
|
||||
_build_arr_init_list(
|
||||
ostr,
|
||||
std::dynamic_pointer_cast<ConstantArr>(arr->value_list[i]),
|
||||
std::dynamic_pointer_cast<ArrayType>(arr_type->element_type)
|
||||
std::dynamic_pointer_cast<ArrayType>(arr_type->elem_type)
|
||||
);
|
||||
else
|
||||
ostr << arr_type->element_type->to_IR_string() << " zeroinitializer";
|
||||
ostr << arr_type->elem_type->to_IR_string() << " zeroinitializer";
|
||||
if (i < arr->value_list.size() - 1) {
|
||||
ostr << ", ";
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < arr_type->element_count - arr->value_list.size(); ++i) {
|
||||
ostr << ", " << arr_type->element_type->to_IR_string() << " zeroinitializer";
|
||||
for (int i = 0; i < arr_type->elem_count - arr->value_list.size(); ++i) {
|
||||
ostr << ", " << arr_type->elem_type->to_IR_string() << " zeroinitializer";
|
||||
}
|
||||
ostr << "]";
|
||||
}
|
||||
@ -132,8 +132,8 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
|
||||
case InstTag::Gt:
|
||||
case InstTag::Eq:
|
||||
case InstTag::Ne:
|
||||
case InstTag::And:
|
||||
case InstTag::Or:
|
||||
// case InstTag::And:
|
||||
// case InstTag::Or:
|
||||
case InstTag::Load:
|
||||
case InstTag::GEP:
|
||||
case InstTag::Alloca:
|
||||
@ -310,8 +310,8 @@ static void _gen_blocks(std::ostream &ostr, const std::list<BasicBlockPtr_t> &bl
|
||||
case InstTag::Gt:
|
||||
case InstTag::Eq:
|
||||
case InstTag::Ne:
|
||||
case InstTag::And:
|
||||
case InstTag::Or: {
|
||||
|
||||
{
|
||||
auto inst = Value::as<InstBinary>(_inst);
|
||||
ostr << "%" << inst->ir_seqno << " = " << inst->tag_string() << " ";
|
||||
if (Value::is<Instruction>(inst->operand_list[0])) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user