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.

222 lines
7.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

from hw4.ir.ir import *
VREG_NUM = 500
REG_NUM = 32
reg_status = {i: None for i in range(REG_NUM)} # 寄存器状态图键为编号值为使用该寄存器的指令None表示空闲
vreg_status = {'v%d' % i: None for i in range(VREG_NUM)} # 虚拟寄存器状态图
class AllocateException(BaseException):
def __init__(self, info):
self.info = info
def __str__(self):
return self.info
# 随机分配空闲虚拟寄存器
def allocate_vreg(ir):
for vreg in vreg_status.keys():
if vreg_status[vreg] is None:
vreg_status[vreg] = ir
return vreg
raise AllocateException('虚拟寄存器已满!')
# 释放某一虚拟寄存器
def free_vreg(i):
vreg_status[i] = None
def free_reg(i):
reg_status[i] = None
def allocate_reg(ir):
for reg in reg_status.keys():
if reg_status[reg] is None:
reg_status[reg] = ir
return reg
# 若寄存器已满,分配虚拟寄存器
allocate_vreg(ir)
# 数据相关性分析
def analyze_hazard(cycle):
hazard = {'RAW': [],
'WAR': [],
'WAW': []}
write = [] # 记录所有写操作
read = [] # 记录所有读操作
# 分析数据相关性
for instr in cycle.instrList: # 标记所有读取和写入的寄存器
if instr.rt is not None:
write.append(instr.rt)
if instr.rs is not None:
read.append(instr.rs)
# 检测写后读(RAW)
for i in range(len(write)):
for j in range(i + 1, len(read)):
if write[i] in read[j]:
hazard['RAW'].append((cycle.instrList[i], cycle.instrList[j]))
# 检测读后写(WAR)
for i in range(len(read)):
for j in range(i + 1, len(write)):
if write[j] in read[i]:
hazard['WAR'].append((cycle.instrList[i], cycle.instrList[j]))
# 检测读后读(WAW)
for i in range(len(write)):
for j in range(i + 1, len(write)):
if write[i] == write[j]:
hazard['WAW'].append((cycle.instrList[i], cycle.instrList[j]))
return hazard
# 判断两条指令是否相关
def judge_hazard(instr1, instr2, hazard):
if (instr1, instr2) in hazard['RAW'] or (instr1, instr2) in hazard['WAR'] or (instr1, instr2) in hazard['WAW']:
return True
elif (instr2, instr1) in hazard['RAW'] or (instr2, instr1) in hazard['WAR'] or (instr2, instr1) in hazard['WAW']:
return True
return False
# 延迟分析
def get_stall(op_this, op_next):
if isinstance(op_this, AluInstr):
if isinstance(op_next, AluInstr):
return 3
elif isinstance(op_next, Store):
return 2
elif isinstance(op_next, Condition):
return 1
else:
return 0
elif isinstance(op_this, Load):
if isinstance(op_next, AluInstr):
return 1
elif isinstance(op_next, Store):
return 0
elif isinstance(op_next, Condition):
return 1
else:
raise ValueError('Error Instruction!')
elif isinstance(op_this, Condition):
return 1
else:
return 0
# 在指令1和指令2之间插入一条不相关的指令
def insert_instr(cycle, hazard, instr1, instr2, isAllocated):
for item in cycle.instrList:
if not judge_hazard(instr1, instr2, hazard):
if isAllocated[item] == 0:
isAllocated[item] = 1
return item
return None
# 循环展开
# 输入:
# ir为源代码的中间表示
# times为展开的次数 不少于2
# 输出:
# ir中循环展开times次的中间表示
def unroll(ir, times):
global ld_rt, ld_rs, ld_offset, st_rt, st_rs, add_rt, add_rs, addi_rt, addi_rs, addi_imm, cycle
rlt = {'before': [],
'last': []}
isAllocated = {}
# 找到循环部分
for item in ir:
if isinstance(item, Loop):
cycle = item
if cycle is None:
raise ValueError('没有循环部分!')
# 分析原始指令的操作数
for item in cycle.instrList:
if isinstance(item, Load):
ld_rt = item.rt
ld_rs = item.rs
ld_offset = item.offset
elif isinstance(item, Store):
st_rt = item.rt
st_rs = item.rs
elif isinstance(item, Add):
add_rt = item.rt
add_rs = item.rs
elif isinstance(item, Addi):
addi_rt = item.rt
addi_rs = item.rs
addi_imm = item.imm
# 前若干次
rlt['before'].append(cycle.instrList[0]) # beq语句
for time in range(cycle.times):
for item in cycle.instrList:
flag_add = 0
flag_load = 0
add_rt_new = None
load_rt_new = None
if isinstance(item, Load):
flag_add = 1
offset = addi_imm * (time + 1) # 每次offset增加一轮
try:
load_rt_new = allocate_reg(item) # 分配虚拟寄存器
new_load = Load(reg1=load_rt_new, offset=offset, reg2=ld_rs)
rlt['before'].append(new_load)
except AllocateException as e:
print(e)
elif isinstance(item, Add):
flag_load = 1
try:
add_rt_new = allocate_reg(item)
new_add = Add(reg1=add_rt_new, reg2=add_rs[0], reg3=add_rs[1])
rlt['before'].append(new_add)
except AllocateException as e:
print(e)
elif isinstance(item, Store):
if flag_add == 1 and flag_load == 1: # 找到与该stroe配套的load和add
flag_add = 0
flag_load = 0
offset = addi_imm * (time + 1)
try:
new_store = Store(reg1=item.rt, offset=offset, reg2=st_rs)
rlt['before'].append(new_store)
# store结束后即可释放之前的寄存器
free_reg(add_rt_new)
free_reg(load_rt_new)
except AllocateException as e:
print(e)
cycle_iter_new = None
for item in cycle.instrList:
if isinstance(item, Addi): # 循环变量自增语句
cycle_iter_new = allocate_reg(item)
new_addi = Addi(reg1=cycle_iter_new, reg2=cycle.iter, imm=cycle.times * addi_imm)
rlt['before'].append(new_addi)
break
# 计算新的终止条件
new_reg_for_stop = allocate_reg(Addi(None, None, None))
new_addi_for_stop = Addi(reg1=new_reg_for_stop, reg2=cycle.times, imm=1 - times)
rlt['before'].append(new_addi_for_stop)
for item in cycle.instrList:
if isinstance(item, Bne): # Bne 循环终止条件为cycle.iter = cycle.times-times+1
new_bne = Bne(reg1=cycle_iter_new, reg2=new_reg_for_stop)
rlt['before'].append(new_bne)
break
# 最后一次
rlt['last'] = cycle
return rlt