You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							380 lines
						
					
					
						
							13 KiB
						
					
					
				
			
		
		
	
	
							380 lines
						
					
					
						
							13 KiB
						
					
					
				| #include "regalloc.h"
 | |
| #include "instruction.h"
 | |
| #include "riscv.h"
 | |
| 
 | |
| int IntRegID = 32, FloatRegID = 32; // 测试阶段使用
 | |
| 
 | |
| Register *NamefindReg(std::string reg) {
 | |
|   if (reg.size() > 4)
 | |
|     return nullptr;
 | |
| 
 | |
|   Register *reg_to_ret = new Register(Register::Int, 0);
 | |
| 
 | |
|   // Check if int registers
 | |
|   for (int i = 0; i < 32; i++) {
 | |
|     reg_to_ret->rid_ = i;
 | |
|     if (reg_to_ret->print() == reg)
 | |
|       return reg_to_ret;
 | |
|   }
 | |
| 
 | |
|   // Else then float registers
 | |
|   reg_to_ret->regtype_ = reg_to_ret->Float;
 | |
|   for (int i = 0; i < 32; i++) {
 | |
|     reg_to_ret->rid_ = i;
 | |
|     if (reg_to_ret->print() == reg)
 | |
|       return reg_to_ret;
 | |
|   }
 | |
| 
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| RiscvOperand *getRegOperand(std::string reg) {
 | |
|   for (auto regope : regPool) {
 | |
|     if (regope->print() == reg)
 | |
|       return regope;
 | |
|   }
 | |
|   assert(false);
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| RiscvOperand *getRegOperand(Register::RegType op_ty_, int id) {
 | |
|   Register *reg = new Register(op_ty_, id);
 | |
|   for (auto regope : regPool) {
 | |
|     if (regope->print() == reg->print()) {
 | |
|       delete reg;
 | |
|       return regope;
 | |
|     }
 | |
|   }
 | |
|   assert(false);
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| Type *getStoreTypeFromRegType(RiscvOperand *riscvReg) {
 | |
|   return riscvReg->getType() == RiscvOperand::OpTy::FloatReg
 | |
|              ? new Type(Type::TypeID::FloatTyID)
 | |
|              : new Type(Type::TypeID::IntegerTyID);
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findReg(Value *val, RiscvBasicBlock *bb,
 | |
|                                  RiscvInstr *instr, int inReg, int load,
 | |
|                                  RiscvOperand *specified, bool direct) {
 | |
|   safeFindTimeStamp++;
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   bool isGVar = dynamic_cast<GlobalVariable *>(val) != nullptr;
 | |
|   bool isAlloca = dynamic_cast<AllocaInst *>(val) != nullptr;
 | |
|   bool isPointer = val->type_->tid_ == val->type_->PointerTyID;
 | |
| 
 | |
|   // If there is no register allocated for value then get a new one
 | |
|   if (specified != nullptr)
 | |
|     setPositionReg(val, specified, bb, instr);
 | |
|   else if (curReg.find(val) == curReg.end() || isAlloca ||
 | |
|            val->is_constant()) { // Alloca and constant value is always unsafe.
 | |
|     bool found = false;
 | |
|     RiscvOperand *cur = nullptr;
 | |
|     IntRegID = 32;
 | |
|     FloatRegID = 32;
 | |
|     while (!found) {
 | |
|       if (val->type_->tid_ != Type::FloatTyID) {
 | |
|         ++IntRegID;
 | |
|         if (IntRegID > 27)
 | |
|           IntRegID = 18;
 | |
| 
 | |
|         cur = getRegOperand(Register::Int, IntRegID);
 | |
|       } else {
 | |
|         ++FloatRegID;
 | |
|         if (FloatRegID > 27)
 | |
|           FloatRegID = 18;
 | |
|         cur = getRegOperand(Register::Float, FloatRegID);
 | |
|       }
 | |
|       if (regFindTimeStamp.find(cur) == regFindTimeStamp.end() ||
 | |
|           safeFindTimeStamp - regFindTimeStamp[cur] > SAFE_FIND_LIMIT) {
 | |
|         setPositionReg(val, cur, bb, instr);
 | |
|         found = true;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     regFindTimeStamp[curReg[val]] = safeFindTimeStamp;
 | |
|     return curReg[val];
 | |
|   }
 | |
| 
 | |
|   // ! Though all registers are considered unsafe, there is no way
 | |
|   // ! to writeback registers properly in findReg() for now.
 | |
|   // ! Therefore unsafe part below is not being executed for now.
 | |
|   // ! Maybe should consider using writeback() instead.
 | |
|   // For now, all registers are considered unsafe thus registers should always
 | |
|   // load from memory before using and save to memory after using.
 | |
|   auto mem_addr = findMem(val, bb, instr, 1); // Value's direct memory address
 | |
|   auto current_reg = curReg[val];             // Value's current register
 | |
|   auto load_type = val->type_;
 | |
| 
 | |
|   regFindTimeStamp[current_reg] = safeFindTimeStamp; // Update time stamp
 | |
|   if (load) {
 | |
|     // Load before usage.
 | |
|     if (mem_addr != nullptr) {
 | |
|       bb->addInstrBefore(
 | |
|           new LoadRiscvInst(load_type, current_reg, mem_addr, bb), instr);
 | |
|     } else if (val->is_constant()) {
 | |
|       // If value is a int constant, create a LI instruction.
 | |
|       auto cval = dynamic_cast<ConstantInt *>(val);
 | |
|       if (cval != nullptr)
 | |
|         bb->addInstrBefore(new MoveRiscvInst(current_reg, cval->value_, bb),
 | |
|                            instr);
 | |
|       else if (dynamic_cast<ConstantFloat *>(val) != nullptr)
 | |
|         bb->addInstrBefore(
 | |
|             new MoveRiscvInst(current_reg, this->findMem(val), bb), instr);
 | |
|       else {
 | |
|         std::cerr << "[Warning] Trying to find a register for unknown type of "
 | |
|                      "constant value which is not implemented for now."
 | |
|                   << std::endl;
 | |
|       }
 | |
|     } else if (isAlloca) {
 | |
|       bb->addInstrBefore(
 | |
|           new BinaryRiscvInst(
 | |
|               BinaryRiscvInst::ADDI, getRegOperand("fp"),
 | |
|               new RiscvConst(static_cast<RiscvIntPhiReg *>(pos[val])->shift_),
 | |
|               current_reg, bb),
 | |
|           instr);
 | |
|       // std::cerr << "[Debug] Get a alloca position <" << val->print() << ", "
 | |
|       //           << static_cast<RiscvIntPhiReg *>(pos[val])->print()
 | |
|       //           << "> into the register <" << current_reg->print() << ">"
 | |
|       //           << std::endl;
 | |
|     } else {
 | |
|       std::cerr << "[Error] Unknown error in findReg()." << std::endl;
 | |
|       std::terminate();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return current_reg;
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findMem(Value *val, RiscvBasicBlock *bb,
 | |
|                                  RiscvInstr *instr, bool direct) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   if (pos.count(val) == 0 && !val->is_constant()) {
 | |
|     std::cerr << "[Warning] Value " << std::hex << val << " (" << val->name_
 | |
|               << ")'s memory map not found." << std::endl;
 | |
|   }
 | |
|   bool isGVar = dynamic_cast<GlobalVariable *>(val) != nullptr;
 | |
|   bool isPointer = val->type_->tid_ == val->type_->PointerTyID;
 | |
|   bool isAlloca = dynamic_cast<AllocaInst *>(val) != nullptr;
 | |
|   // All float constant considered as global variables for now.
 | |
|   isGVar = isGVar || dynamic_cast<ConstantFloat *>(val) != nullptr;
 | |
|   // Always loading global variable's address into t5 when execute findMem().
 | |
|   if (isGVar) {
 | |
|     if (bb == nullptr) {
 | |
|       std::cerr << "[Warning] Trying to add global var addressing "
 | |
|                    "instruction, but basic block pointer is null."
 | |
|                 << std::endl;
 | |
|       return nullptr;
 | |
|     }
 | |
|     bb->addInstrBefore(
 | |
|         new LoadAddressRiscvInstr(getRegOperand("t5"), pos[val]->print(), bb),
 | |
|         instr);
 | |
|     return new RiscvIntPhiReg("t5");
 | |
|   }
 | |
|   // If not loading pointer's address directly, then use indirect addressing.
 | |
|   // Ignore alloca due to the instruction only being dealt by findReg()
 | |
|   if (isPointer && !isAlloca && !direct) {
 | |
|     if (bb == nullptr) {
 | |
|       std::cerr << "[Warning] Trying to add indirect pointer addressing "
 | |
|                    "instruction, but basic block pointer is null."
 | |
|                 << std::endl;
 | |
|       return nullptr;
 | |
|     }
 | |
| 
 | |
|     bb->addInstrBefore(new LoadRiscvInst(new Type(Type::PointerTyID),
 | |
|                                          getRegOperand("t4"), pos[val], bb),
 | |
|                        instr);
 | |
|     return new RiscvIntPhiReg("t4");
 | |
|   }
 | |
|   // Cannot access to alloca's memory directly.
 | |
|   else if (direct && isAlloca)
 | |
|     return nullptr;
 | |
| 
 | |
|   if (pos.find(val) == pos.end())
 | |
|     return nullptr;
 | |
| 
 | |
|   return pos[val];
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findMem(Value *val) {
 | |
|   return findMem(val, nullptr, nullptr, true);
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findNonuse(Type *ty, RiscvBasicBlock *bb,
 | |
|                                     RiscvInstr *instr) {
 | |
|   if (ty->tid_ == Type::IntegerTyID || ty->tid_ == Type::PointerTyID) {
 | |
|     ++IntRegID;
 | |
|     if (IntRegID > 27)
 | |
|       IntRegID = 18;
 | |
|     return getRegOperand(Register::Int, IntRegID);
 | |
|   } else {
 | |
|     ++FloatRegID;
 | |
|     if (FloatRegID > 27)
 | |
|       FloatRegID = 18;
 | |
|     return getRegOperand(Register::Float, FloatRegID);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void RegAlloca::setPosition(Value *val, RiscvOperand *riscvVal) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   if (pos.find(val) != pos.end()) {
 | |
|     // std::cerr << "[Warning] Trying overwriting memory address map of value "
 | |
|     //           << std::hex << val << " (" << val->name_ << ") ["
 | |
|     //           << riscvVal->print() << " -> " << pos[val]->print() << "]"
 | |
|     //           << std::endl;
 | |
|     // std::terminate();
 | |
|   }
 | |
| 
 | |
|   // std::cerr << "[Debug] [RegAlloca] Map value <" << val->print()
 | |
|   //           << "> to operand <" << riscvVal->print() << ">" << std::endl;
 | |
| 
 | |
|   pos[val] = riscvVal;
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findSpecificReg(Value *val, std::string RegName,
 | |
|                                          RiscvBasicBlock *bb, RiscvInstr *instr,
 | |
|                                          bool direct) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   RiscvOperand *retOperand = getRegOperand(RegName);
 | |
| 
 | |
|   return findReg(val, bb, instr, 0, 1, retOperand, direct);
 | |
| }
 | |
| 
 | |
| void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg,
 | |
|                                RiscvBasicBlock *bb, RiscvInstr *instr) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   Value *old_val = getRegPosition(riscvReg);
 | |
|   RiscvOperand *old_reg = getPositionReg(val);
 | |
|   if (old_val != nullptr && old_val != val)
 | |
|     writeback(riscvReg, bb, instr);
 | |
|   if (old_reg != nullptr && old_reg != riscvReg)
 | |
|     writeback(old_reg, bb, instr);
 | |
|   setPositionReg(val, riscvReg);
 | |
| }
 | |
| 
 | |
| void RegAlloca::setPositionReg(Value *val, RiscvOperand *riscvReg) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   if (riscvReg->isRegister() == false) {
 | |
|     std::cerr << "[Fatal error] Trying to map value " << std::hex << val
 | |
|               << " to not a register operand." << std::endl;
 | |
|     std::terminate();
 | |
|   }
 | |
| 
 | |
|   // std::cerr << "[Debug] Map register <" << riscvReg->print() << "> to value <"
 | |
|   //           << val->print() << ">\n";
 | |
| 
 | |
|   curReg[val] = riscvReg;
 | |
|   regPos[riscvReg] = val;
 | |
|   regUsed.insert(riscvReg);
 | |
| }
 | |
| 
 | |
| RiscvInstr *RegAlloca::writeback(RiscvOperand *riscvReg, RiscvBasicBlock *bb,
 | |
|                                  RiscvInstr *instr) {
 | |
|   Value *value = getRegPosition(riscvReg);
 | |
|   if (value == nullptr)
 | |
|     return nullptr; // Value not found in map
 | |
| 
 | |
|   value = this->DSU_for_Variable.query(value);
 | |
| 
 | |
|   // std::cerr << "[Debug] [RegAlloca] Writeback register <" << riscvReg->print()
 | |
|   //           << "> to value <" << value->print() << ">.\n";
 | |
| 
 | |
|   // Erase map info
 | |
|   regPos.erase(riscvReg);
 | |
|   regFindTimeStamp.erase(riscvReg);
 | |
|   curReg.erase(value);
 | |
| 
 | |
|   RiscvOperand *mem_addr = findMem(value);
 | |
| 
 | |
|   if (mem_addr == nullptr) {
 | |
|     // std::cerr << "[Debug] [RegAlloca] Writeback ignore alloca pointer direct "
 | |
|     //              "access and immvalue.\n";
 | |
|     return nullptr; // Maybe an immediate value or dicrect accessing alloca
 | |
|   }
 | |
| 
 | |
|   auto store_type = value->type_;
 | |
|   auto store_instr = new StoreRiscvInst(value->type_, riscvReg, mem_addr, bb);
 | |
| 
 | |
|   // Write store instruction
 | |
|   if (instr != nullptr)
 | |
|     bb->addInstrBefore(store_instr, instr);
 | |
|   else
 | |
|     bb->addInstrBack(store_instr);
 | |
| 
 | |
|   return store_instr;
 | |
| }
 | |
| 
 | |
| RegAlloca::RegAlloca() {
 | |
|   // 初始化寄存器对象池。
 | |
|   if (regPool.size() == 0) {
 | |
|     for (int i = 0; i < 32; i++)
 | |
|       regPool.push_back(new RiscvIntReg(new Register(Register::Int, i)));
 | |
|     for (int i = 0; i < 32; i++)
 | |
|       regPool.push_back(new RiscvFloatReg(new Register(Register::Float, i)));
 | |
|   }
 | |
| 
 | |
|   // fp 的保护单独进行处理
 | |
|   regUsed.insert(getRegOperand("ra"));
 | |
|   savedRegister.push_back(getRegOperand("ra")); // 保护 ra
 | |
|   // 保护 s1-s11
 | |
|   for (int i = 1; i <= 11; i++)
 | |
|     savedRegister.push_back(getRegOperand("s" + std::to_string(i)));
 | |
|   // 保护 fs0-fs11
 | |
|   for (int i = 0; i <= 11; i++)
 | |
|     savedRegister.push_back(getRegOperand("fs" + std::to_string(i)));
 | |
| }
 | |
| 
 | |
| RiscvInstr *RegAlloca::writeback(Value *val, RiscvBasicBlock *bb,
 | |
|                                  RiscvInstr *instr) {
 | |
|   auto reg = getPositionReg(val);
 | |
|   return writeback(reg, bb, instr);
 | |
| }
 | |
| 
 | |
| Value *RegAlloca::getRegPosition(RiscvOperand *reg) {
 | |
|   if (regPos.find(reg) == regPos.end())
 | |
|     return nullptr;
 | |
|   return this->DSU_for_Variable.query(regPos[reg]);
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::getPositionReg(Value *val) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   if (curReg.find(val) == curReg.end())
 | |
|     return nullptr;
 | |
|   return curReg[val];
 | |
| }
 | |
| 
 | |
| RiscvOperand *RegAlloca::findPtr(Value *val, RiscvBasicBlock *bb,
 | |
|                                  RiscvInstr *instr) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   if (ptrPos.find(val) == ptrPos.end()) {
 | |
|     std::cerr << "[Fatal Error] Value's pointer position not found."
 | |
|               << std::endl;
 | |
|     std::terminate();
 | |
|   }
 | |
|   return ptrPos[val];
 | |
| }
 | |
| 
 | |
| void RegAlloca::writeback_all(RiscvBasicBlock *bb, RiscvInstr *instr) {
 | |
|   std::vector<RiscvOperand *> regs_to_writeback;
 | |
|   for (auto p : regPos)
 | |
|     regs_to_writeback.push_back(p.first);
 | |
|   for (auto r : regs_to_writeback)
 | |
|     writeback(r, bb, instr);
 | |
| }
 | |
| 
 | |
| void RegAlloca::setPointerPos(Value *val, RiscvOperand *PointerMem) {
 | |
|   val = this->DSU_for_Variable.query(val);
 | |
|   assert(val->type_->tid_ == Type::TypeID::PointerTyID ||
 | |
|          val->type_->tid_ == Type::TypeID::ArrayTyID);
 | |
|   // std::cerr << "SET POINTER: " << val->name_ << "!" << PointerMem->print()
 | |
|   //           << "\n";
 | |
|   this->ptrPos[val] = PointerMem;
 | |
| }
 | |
| 
 | |
| void RegAlloca::clear() {
 | |
|   curReg.clear();
 | |
|   regPos.clear();
 | |
|   safeFindTimeStamp = 0;
 | |
|   regFindTimeStamp.clear();
 | |
| } |