[midend-llvmirprint]实现了大部分函数的print方法,TODO:需要完善func和module的print方法以及重命名的逻辑
This commit is contained in:
@@ -5,9 +5,11 @@
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include "IRBuilder.h"
|
||||
|
||||
using namespace std;
|
||||
/**
|
||||
* @file IR.cpp
|
||||
*
|
||||
@@ -15,6 +17,64 @@
|
||||
*/
|
||||
namespace sysy {
|
||||
|
||||
/*相关打印函数*/
|
||||
|
||||
template <typename T>
|
||||
ostream &interleave(std::ostream &os, const T &container, const std::string sep = ", ") {
|
||||
auto b = container.begin(), e = container.end();
|
||||
if (b == e)
|
||||
return os;
|
||||
os << *b;
|
||||
for (b = std::next(b); b != e; b = std::next(b))
|
||||
os << sep << *b;
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ostream &interleave_call(std::ostream &os, const T &container, const std::string sep = ", ") {
|
||||
auto b = container.begin(), e = container.end();
|
||||
b = std::next(b); // Skip the first element
|
||||
if (b == e)
|
||||
return os;
|
||||
os << *b;
|
||||
for (b = std::next(b); b != e; b = std::next(b))
|
||||
os << sep << *b;
|
||||
return os;
|
||||
}
|
||||
|
||||
static inline ostream &printVarName(ostream &os, const Value *var)
|
||||
{
|
||||
if (dynamic_cast<const GlobalValue*>(var) != nullptr) {
|
||||
auto globalVal = dynamic_cast<const GlobalValue*>(var);
|
||||
return os << "@" << globalVal->getName();
|
||||
} else {
|
||||
return os << "%" << var->getName();
|
||||
}
|
||||
}
|
||||
static inline ostream &printBlockName(ostream &os, const BasicBlock *block) {
|
||||
return os << block->getName();
|
||||
}
|
||||
static inline ostream &printFunctionName(ostream &os, const Function *fn) {
|
||||
return os << '@' << fn->getName();
|
||||
}
|
||||
static inline ostream &printOperand(ostream &os, const Value *value) {
|
||||
auto constValue = dynamic_cast<const ConstantValue*>(value);
|
||||
if (constValue != nullptr) {
|
||||
constValue->print(os);
|
||||
return os;
|
||||
}
|
||||
return printVarName(os, value);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Type& type) {
|
||||
type.print(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Value& value) {
|
||||
value.print(os);
|
||||
return os;
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Types
|
||||
//===----------------------------------------------------------------------===//
|
||||
@@ -73,6 +133,37 @@ auto Type::getSize() const -> unsigned {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Type::print(ostream &os) const {
|
||||
auto kind = getKind();
|
||||
switch (kind){
|
||||
case kInt: os << "i32"; break;
|
||||
case kFloat: os << "float"; break;
|
||||
case kVoid: os << "void"; break;
|
||||
case kPointer:
|
||||
static_cast<const PointerType *>(this)->getBaseType()->print(os);
|
||||
os << "*";
|
||||
break;
|
||||
case kFunction:
|
||||
static_cast<const FunctionType *>(this)->getReturnType()->print(os);
|
||||
os << "(";
|
||||
interleave(os, static_cast<const FunctionType *>(this)->getParamTypes());
|
||||
os << ")";
|
||||
break;
|
||||
case kArray:
|
||||
os << "[";
|
||||
os << static_cast<const ArrayType *>(this)->getNumElements();
|
||||
os << " x ";
|
||||
static_cast<const ArrayType *>(this)->getElementType()->print(os);
|
||||
os << "]";
|
||||
break;
|
||||
case kLabel:
|
||||
default:
|
||||
cerr << "error type\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PointerType* PointerType::get(Type *baseType) {
|
||||
static std::map<Type *, std::unique_ptr<PointerType>> pointerTypes;
|
||||
auto iter = pointerTypes.find(baseType);
|
||||
@@ -204,6 +295,214 @@ UndefinedValue* UndefinedValue::get(Type* type) {
|
||||
return newUndef;
|
||||
}
|
||||
|
||||
inline std::string getMachineCode(float fval) {
|
||||
uint32_t mrf = *reinterpret_cast<uint32_t*>(&fval);
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << mrf;
|
||||
return "0x" + ss.str();
|
||||
}
|
||||
|
||||
void ConstantValue::print(std::ostream &os) const {
|
||||
if(dynamic_cast<const ConstantInteger*>(this)) {
|
||||
dynamic_cast<const ConstantInteger*>(this)->print(os);
|
||||
} else if(dynamic_cast<const ConstantFloating*>(this)) {
|
||||
dynamic_cast<const ConstantFloating*>(this)->print(os);
|
||||
} else if(dynamic_cast<const UndefinedValue*>(this)) {
|
||||
dynamic_cast<const UndefinedValue*>(this)->print(os);
|
||||
} else {
|
||||
os << "unknown constant type";
|
||||
}
|
||||
}
|
||||
|
||||
void ConstantInteger::print(std::ostream &os) const {
|
||||
os << "i32 " << this->getInt();
|
||||
}
|
||||
void ConstantFloating::print(std::ostream &os) const {
|
||||
os << "float " << getMachineCode(this->getFloat());
|
||||
}
|
||||
void UndefinedValue::print(std::ostream &os) const {
|
||||
os << this->getType() << " undef";
|
||||
}
|
||||
|
||||
void BasicBlock::print(std::ostream &os) const {
|
||||
assert(this->getName() != "" && "BasicBlock name cannot be empty");
|
||||
os << " ";
|
||||
printBlockName(os, this);
|
||||
os << ":\n";
|
||||
for (auto &inst : instructions) {
|
||||
os << " " << *inst << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void PhiInst::print(std::ostream &os) const {
|
||||
printVarName(os, this);
|
||||
os << " = " << getKindString() << " " << *getType() << " ";
|
||||
for (unsigned i = 0; i < vsize; ++i) {
|
||||
if (i > 0) {
|
||||
os << ", ";
|
||||
}
|
||||
os << " [";
|
||||
printOperand(os, getIncomingValue(i));
|
||||
os << ", ";
|
||||
printBlockName(os, getIncomingBlock(i));
|
||||
os << "]";
|
||||
}
|
||||
}
|
||||
|
||||
void CallInst::print(std::ostream &os) const {
|
||||
if(!getType()->isVoid()) {
|
||||
printVarName(os, this) << " = ";
|
||||
}
|
||||
os << getKindString() << *getType() << " " ;
|
||||
printFunctionName(os, getCallee());
|
||||
os << "(";
|
||||
interleave_call(os, getOperands());
|
||||
os << ")";
|
||||
}
|
||||
|
||||
// 情况比较复杂就不用getkindstring了
|
||||
void UnaryInst::print(std::ostream &os) const {
|
||||
printVarName(os, this) << " = ";
|
||||
switch (getKind()) {
|
||||
case kNeg:
|
||||
os << "sub i32 0, ";
|
||||
printOperand(os, getOperand());
|
||||
break;
|
||||
case kFNeg:
|
||||
os << "fsub float 0.0, ";
|
||||
printOperand(os, getOperand());
|
||||
break;
|
||||
case kNot:
|
||||
os << "xor " << *getOperand()->getType() << " ";
|
||||
printOperand(os, getOperand());
|
||||
os << ", -1";
|
||||
return;
|
||||
case kFNot:
|
||||
os << "fcmp une " << *getOperand()->getType() << " ";
|
||||
printOperand(os, getOperand());
|
||||
os << ", 0.0";
|
||||
return;
|
||||
case kFtoI:
|
||||
os << "fptosi " << *getOperand()->getType() << " ";
|
||||
printOperand(os, getOperand());
|
||||
os << " to " << *getType();
|
||||
return;
|
||||
case kItoF:
|
||||
os << "sitofp " << *getOperand()->getType() << " ";
|
||||
printOperand(os, getOperand());
|
||||
os << " to " << *getType();
|
||||
return;
|
||||
default:
|
||||
os << "error unary inst";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AllocaInst::print(std::ostream &os) const {
|
||||
PointerType *ptrType = dynamic_cast<PointerType *>(getType());
|
||||
Type *baseType = ptrType->getBaseType();
|
||||
printVarName(os, this);
|
||||
os << " = " << getKindString() << " " << *baseType;
|
||||
}
|
||||
|
||||
void BinaryInst::print(std::ostream &os) const {
|
||||
printVarName(os, this) << " = ";
|
||||
|
||||
auto kind = getKind();
|
||||
|
||||
// 检查是否为比较指令
|
||||
if (kind == kICmpEQ || kind == kICmpNE || kind == kICmpLT ||
|
||||
kind == kICmpGT || kind == kICmpLE || kind == kICmpGE) {
|
||||
// 整数比较指令
|
||||
os << getKindString() << " " << *getLhs()->getType() << " ";
|
||||
printOperand(os, getLhs());
|
||||
os << ", ";
|
||||
printOperand(os, getRhs());
|
||||
} else if (kind == kFCmpEQ || kind == kFCmpNE || kind == kFCmpLT ||
|
||||
kind == kFCmpGT || kind == kFCmpLE || kind == kFCmpGE) {
|
||||
// 浮点比较指令
|
||||
os << getKindString() << " " << *getLhs()->getType() << " ";
|
||||
printOperand(os, getLhs());
|
||||
os << ", ";
|
||||
printOperand(os, getRhs());
|
||||
} else {
|
||||
// 算术和逻辑指令
|
||||
os << getKindString() << " " << *getType() << " ";
|
||||
printOperand(os, getLhs());
|
||||
os << ", ";
|
||||
printOperand(os, getRhs());
|
||||
}
|
||||
}
|
||||
|
||||
void ReturnInst::print(std::ostream &os) const {
|
||||
os << "ret ";
|
||||
if (hasReturnValue()) {
|
||||
os << *getReturnValue()->getType() << " ";
|
||||
printOperand(os, getReturnValue());
|
||||
} else {
|
||||
os << "void";
|
||||
}
|
||||
}
|
||||
|
||||
void UncondBrInst::print(std::ostream &os) const {
|
||||
os << "br label %";
|
||||
printBlockName(os, getBlock());
|
||||
}
|
||||
|
||||
void CondBrInst::print(std::ostream &os) const {
|
||||
os << "br " << *getCondition()->getType() << " ";
|
||||
printOperand(os, getCondition());
|
||||
os << ", label %";
|
||||
printBlockName(os, getThenBlock());
|
||||
os << ", label %";
|
||||
printBlockName(os, getElseBlock());
|
||||
}
|
||||
|
||||
void GetElementPtrInst::print(std::ostream &os) const {
|
||||
printVarName(os, this) << " = getelementptr ";
|
||||
|
||||
// 获取基指针的基类型
|
||||
auto basePtr = getBasePointer();
|
||||
auto basePtrType = basePtr->getType()->as<PointerType>();
|
||||
auto baseType = basePtrType->getBaseType();
|
||||
|
||||
os << *baseType << ", " << *basePtr->getType() << " ";
|
||||
printOperand(os, basePtr);
|
||||
|
||||
// 打印索引 - 使用getIndex方法而不是getIndices
|
||||
for (unsigned i = 0; i < getNumIndices(); ++i) {
|
||||
auto index = getIndex(i);
|
||||
os << ", " << *index->getType() << " ";
|
||||
printOperand(os, index);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadInst::print(std::ostream &os) const {
|
||||
printVarName(os, this) << " = load " << *getType() << ", " << *getPointer()->getType() << " ";
|
||||
printOperand(os, getPointer());
|
||||
}
|
||||
|
||||
void MemsetInst::print(std::ostream &os) const {
|
||||
os << "call void @llvm.memset.p0i8.i32(i8* ";
|
||||
printOperand(os, getPointer());
|
||||
os << ", i8 ";
|
||||
printOperand(os, getOperand(3)); // value
|
||||
os << ", i32 ";
|
||||
printOperand(os, getOperand(2)); // size
|
||||
os << ", i1 false)";
|
||||
}
|
||||
|
||||
void StoreInst::print(std::ostream &os) const {
|
||||
os << "store " << *getValue()->getType() << " ";
|
||||
printOperand(os, getValue());
|
||||
os << ", " << *getPointer()->getType() << " ";
|
||||
printOperand(os, getPointer());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
auto Function::getCalleesWithNoExternalAndSelf() -> std::set<Function *> {
|
||||
std::set<Function *> result;
|
||||
@@ -389,17 +688,6 @@ void PhiInst::replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, V
|
||||
addIncoming(newValue, newBlock);
|
||||
}
|
||||
|
||||
CallInst::CallInst(Function *callee, const std::vector<Value *> &args, BasicBlock *parent, const std::string &name)
|
||||
: Instruction(kCall, callee->getReturnType(), parent, name) {
|
||||
addOperand(callee);
|
||||
for (auto arg : args) {
|
||||
addOperand(arg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取被调用函数的指针
|
||||
*/
|
||||
Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOperand(0)); }
|
||||
|
||||
/**
|
||||
* 获取变量指针
|
||||
|
||||
Reference in New Issue
Block a user