diff --git a/src/include/midend/IR.h b/src/include/midend/IR.h index ff30db7..241f28f 100644 --- a/src/include/midend/IR.h +++ b/src/include/midend/IR.h @@ -83,6 +83,7 @@ class Type { auto as() const -> std::enable_if_t, T *> { return dynamic_cast(const_cast(this)); } + virtual void print(std::ostream& os) const; }; class PointerType : public Type { @@ -97,6 +98,7 @@ class PointerType : public Type { public: Type* getBaseType() const { return baseType; } ///< 获取指向的类型 + void print(std::ostream& os) const override; }; class FunctionType : public Type { @@ -116,6 +118,7 @@ class FunctionType : public Type { Type* getReturnType() const { return returnType; } ///< 获取返回值类信息 auto getParamTypes() const { return make_range(paramTypes); } ///< 获取形参类型列表 unsigned getNumParams() const { return paramTypes.size(); } ///< 获取形参数量 + void print(std::ostream& os) const override; }; class ArrayType : public Type { @@ -132,6 +135,7 @@ class ArrayType : public Type { : Type(Kind::kArray), elementType(elementType), numElements(numElements) {} Type *elementType; unsigned numElements; // 当前维度的大小 + void print(std::ostream& os) const override; }; /*! @@ -206,6 +210,7 @@ class Use { User* getUser() const { return user; } ///< 返回使用者 Value* getValue() const { return value; } ///< 返回被使用的值 void setValue(Value *newValue) { value = newValue; } ///< 将被使用的值设置为newValue + void print(std::ostream& os) const; }; //! The base class of all value types @@ -238,6 +243,7 @@ class Value { uses.remove(use); } ///< 删除使用关系use void removeAllUses(); + virtual void print(std::ostream& os) const = 0; ///< 输出值信息到输出流 }; /** @@ -402,6 +408,7 @@ public: virtual bool isZero() const = 0; virtual bool isOne() const = 0; + void print(std::ostream& os) const = 0; }; class ConstantInteger : public ConstantValue { @@ -428,6 +435,7 @@ public: bool isZero() const override { return constVal == 0; } bool isOne() const override { return constVal == 1; } + void print(std::ostream& os) const; }; class ConstantFloating : public ConstantValue { @@ -454,6 +462,7 @@ public: bool isZero() const override { return constFVal == 0.0f; } bool isOne() const override { return constFVal == 1.0f; } + void print(std::ostream& os) const; }; class UndefinedValue : public ConstantValue { @@ -485,6 +494,7 @@ public: bool isZero() const override { return false; } bool isOne() const override { return false; } + void print(std::ostream& os) const; }; // --- End of refactored ConstantValue and related classes --- @@ -625,6 +635,7 @@ public: } } ///< 移除指定位置的指令 iterator moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block); + void print(std::ostream& os) const; }; //! User is the abstract base type of `Value` types which use other `Value` as @@ -736,57 +747,57 @@ public: std::string getKindString() const{ switch (kind) { case kInvalid: - return "Invalid"; + return "invalid"; case kAdd: - return "Add"; + return "add"; case kSub: - return "Sub"; + return "sub"; case kMul: - return "Mul"; + return "mul"; case kDiv: - return "Div"; + return "sdiv"; case kRem: - return "Rem"; + return "srem"; case kICmpEQ: - return "ICmpEQ"; + return "icmp eq"; case kICmpNE: - return "ICmpNE"; + return "icmp ne"; case kICmpLT: - return "ICmpLT"; + return "icmp slt"; case kICmpGT: - return "ICmpGT"; + return "icmp sgt"; case kICmpLE: - return "ICmpLE"; + return "icmp sle"; case kICmpGE: - return "ICmpGE"; + return "icmp sge"; case kFAdd: - return "FAdd"; + return "fadd"; case kFSub: - return "FSub"; + return "fsub"; case kFMul: - return "FMul"; + return "fmul"; case kFDiv: - return "FDiv"; + return "fdiv"; case kFCmpEQ: - return "FCmpEQ"; + return "fcmp oeq"; case kFCmpNE: - return "FCmpNE"; + return "fcmp one"; case kFCmpLT: - return "FCmpLT"; + return "fcmp olt"; case kFCmpGT: - return "FCmpGT"; + return "fcmp ogt"; case kFCmpLE: - return "FCmpLE"; + return "fcmp ole"; case kFCmpGE: - return "FCmpGE"; + return "fcmp oge"; case kAnd: - return "And"; + return "and"; case kOr: - return "Or"; + return "or"; case kNeg: - return "Neg"; + return "neg"; case kNot: - return "Not"; + return "not"; case kFNeg: return "FNeg"; case kFNot: @@ -794,27 +805,29 @@ public: case kFtoI: return "FtoI"; case kItoF: - return "IToF"; + return "iToF"; case kCall: - return "Call"; + return "call"; case kCondBr: - return "CondBr"; + return "condBr"; case kBr: - return "Br"; + return "br"; case kReturn: - return "Return"; + return "return"; + case kUnreachable: + return "unreachable"; case kAlloca: - return "Alloca"; + return "alloca"; case kLoad: - return "Load"; + return "load"; case kStore: - return "Store"; + return "store"; case kGetElementPtr: - return "GetElementPtr"; + return "getElementPtr"; case kMemset: - return "Memset"; + return "memset"; case kPhi: - return "Phi"; + return "phi"; case kBitItoF: return "BitItoF"; case kBitFtoI: @@ -887,6 +900,7 @@ public: static constexpr uint64_t DefineOpMask = kAlloca | kStore | kPhi; return (kind & DefineOpMask) != 0U; } + virtual void print(std::ostream& os) const = 0; }; // class Instruction class Function; @@ -957,6 +971,7 @@ class PhiInst : public Instruction { } } ///< 刷新块到值的映射关系 auto getValues() { return make_range(std::next(operand_begin()), operand_end()); } + void print(std::ostream& os) const override; }; @@ -965,16 +980,20 @@ class CallInst : public Instruction { friend class IRBuilder; protected: - CallInst(Function *callee, const std::vector &args = {}, - BasicBlock *parent = nullptr, const std::string &name = ""); - + CallInst(Function *callee, const std::vector &args, BasicBlock *parent = nullptr, const std::string &name = "") + : Instruction(kCall, callee->getReturnType(), parent, name) { + addOperand(callee); + for (auto arg : args) { + addOperand(arg); + } + } public: - Function* getCallee() const; + Function *getCallee() const { return dynamic_cast(getOperand(0)); } auto getArguments() const { return make_range(std::next(operand_begin()), operand_end()); } - + void print(std::ostream& os) const override; }; // class CallInst //! Unary instruction, includes '!', '-' and type conversion. @@ -992,7 +1011,7 @@ protected: public: Value* getOperand() const { return User::getOperand(0); } - + void print(std::ostream& os) const override; }; // class UnaryInst //! Binary instruction, e.g., arithmatic, relation, logic, etc. @@ -1071,6 +1090,7 @@ public: // 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象 return new BinaryInst(kind, type, lhs, rhs, parent, name); } + void print(std::ostream& os) const override; }; // class BinaryInst //! The return statement @@ -1091,6 +1111,7 @@ class ReturnInst : public Instruction { Value* getReturnValue() const { return hasReturnValue() ? getOperand(0) : nullptr; } + void print(std::ostream& os) const override; }; //! Unconditional branch @@ -1120,7 +1141,7 @@ public: } return succs; } - + void print(std::ostream& os) const override; }; // class UncondBrInst //! Conditional branch @@ -1160,7 +1181,7 @@ public: } return succs; } - + void print(std::ostream& os) const override; }; // class CondBrInst class UnreachableInst : public Instruction { @@ -1168,7 +1189,7 @@ public: // 构造函数:设置指令类型为 kUnreachable explicit UnreachableInst(const std::string& name, BasicBlock *parent = nullptr) : Instruction(kUnreachable, Type::getVoidType(), parent, "") {} - + void print(std::ostream& os) const { os << "unreachable"; } }; //! Allocate memory for stack variables, used for non-global variable declartion @@ -1186,7 +1207,7 @@ public: Type* getAllocatedType() const { return getType()->as()->getBaseType(); } ///< 获取分配的类型 - + void print(std::ostream& os) const override; }; // class AllocaInst @@ -1224,6 +1245,7 @@ public: BasicBlock *parent = nullptr, const std::string &name = "") { return new GetElementPtrInst(resultType, basePointer, indices, parent, name); } + void print(std::ostream& os) const override; }; //! Load a value from memory address specified by a pointer value @@ -1241,7 +1263,7 @@ protected: public: Value* getPointer() const { return getOperand(0); } - + void print(std::ostream& os) const override; }; // class LoadInst //! Store a value to memory address specified by a pointer value @@ -1260,7 +1282,7 @@ protected: public: Value* getValue() const { return getOperand(0); } Value* getPointer() const { return getOperand(1); } - + void print(std::ostream& os) const override; }; // class StoreInst //! Memset instruction @@ -1290,7 +1312,7 @@ public: Value* getBegin() const { return getOperand(1); } Value* getSize() const { return getOperand(2); } Value* getValue() const { return getOperand(3); } - + void print(std::ostream& os) const override; }; class GlobalValue; @@ -1308,6 +1330,7 @@ public: public: Function* getParent() const { return func; } int getIndex() const { return index; } + void print(std::ostream& os) const; }; @@ -1385,6 +1408,7 @@ protected: blocks.emplace_front(block); return block; } + void print(std::ostream& os) const; }; //! Global value declared at file scope @@ -1450,6 +1474,7 @@ public: return getByIndex(index); } ///< 通过多维索引indices获取初始值 const ValueCounter& getInitValues() const { return initValues; } + void print(std::ostream& os) const; }; // class GlobalValue @@ -1507,6 +1532,8 @@ class ConstantVariable : public Value { return getByIndex(index); } ///< 通过多维索引indices获取初始值 const ValueCounter& getInitValues() const { return initValues; } ///< 获取初始值 + void print(std::ostream& os) const; + void print_init(std::ostream& os) const; }; using SymbolTableNode = struct SymbolTableNode { @@ -1620,6 +1647,8 @@ class Module { void leaveScope() { variableTable.leaveScope(); } ///< 离开作用域 bool isInGlobalArea() const { return variableTable.isInGlobalScope(); } ///< 是否位于全局作用域 + + void print(std::ostream& os) const; }; /*! diff --git a/src/midend/IR.cpp b/src/midend/IR.cpp index ae676f0..37e1a9a 100644 --- a/src/midend/IR.cpp +++ b/src/midend/IR.cpp @@ -5,9 +5,11 @@ #include #include #include +#include #include #include "IRBuilder.h" +using namespace std; /** * @file IR.cpp * @@ -15,6 +17,64 @@ */ namespace sysy { +/*相关打印函数*/ + +template +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 +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(var) != nullptr) { + auto globalVal = dynamic_cast(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(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(this)->getBaseType()->print(os); + os << "*"; + break; + case kFunction: + static_cast(this)->getReturnType()->print(os); + os << "("; + interleave(os, static_cast(this)->getParamTypes()); + os << ")"; + break; + case kArray: + os << "["; + os << static_cast(this)->getNumElements(); + os << " x "; + static_cast(this)->getElementType()->print(os); + os << "]"; + break; + case kLabel: + default: + cerr << "error type\n"; + break; + } +} + PointerType* PointerType::get(Type *baseType) { static std::map> 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(&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(this)) { + dynamic_cast(this)->print(os); + } else if(dynamic_cast(this)) { + dynamic_cast(this)->print(os); + } else if(dynamic_cast(this)) { + dynamic_cast(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(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(); + 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 { std::set result; @@ -389,17 +688,6 @@ void PhiInst::replaceIncomingBlock(BasicBlock *oldBlock, BasicBlock *newBlock, V addIncoming(newValue, newBlock); } -CallInst::CallInst(Function *callee, const std::vector &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(getOperand(0)); } /** * 获取变量指针