1# 2# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3# 4# SPDX-License-Identifier: BSD-2-Clause 5# 6 7import re 8import parser 9import subprocess 10from addr_utils import phyAddrP 11verbose = False 12from elf_file import elfFile, rawVals 13 14class ChronosEmitter: 15 def __init__(self, dir_name, function_name, imm_fun, emit_as_dummy=None): 16 self.function_name = function_name 17 self.imm_fun = imm_fun 18 self.imm_file_name = '%s/%s.imm' % (dir_name, function_name) 19 self.imm_f = open(self.imm_file_name, 'w') 20 self.debug_f = open('%s/d_%s.imm' % (dir_name, function_name),'w') 21 self.emitted_loop_counts_file = open('%s/%s_emittedLoopCounts' % (dir_name, function_name),'w') 22 self.emit_as_dummy = emit_as_dummy 23 self.elf_fun_to_skip = elfFile().funcs['clean_D_PoU'] 24 self.skip_fun = False 25 26 def emitTopLevelFunction(self): 27 imm_fun = self.imm_fun 28 imm_f = self.imm_f 29 debug_f = self.debug_f 30 31 self.emitEntry() 32 self.emitSyms() 33 self.emitFunction() 34 self.emitLiterals() 35 36 self.imm_f.close() 37 self.debug_f.close() 38 self.emitted_loop_counts_file.close() 39 40 def emitSyms (self): 41 ef = elfFile() 42 for name in sorted(ef.syms.keys(),key=lambda x: ef.syms[x].addr): 43 flag_str = '' 44 sym = ef.syms[name] 45 #objects(O) in objdump is data 46 if 'O' in sym.flags: 47 flag_str += 'd' 48 #functions are text 49 if 'F' in sym.flags: 50 flag_str += 't' 51 self.imm_f.write('s %s 0x%s %s %s\n' % (name, sym.addr, sym.ali_size, flag_str)) 52 53 def emitEntry(self): 54 entry_addr = self.imm_fun.addr 55 s = 'e %#08x\n' % entry_addr 56 self.emitString(s) 57 58 def emitFunction(self): 59 #def emitFunction(imm_fun,imm_f,debug_f=None): 60 imm_fun = self.imm_fun 61 imm_f = self.imm_f 62 debug_f = self.debug_f 63 64 emitted_loop_counts = {} 65 66 i_nodes = imm_fun.imm_nodes 67 imm_loopheads = imm_fun.imm_loopheads 68 #locate the first and last addresses 69 first_addr,last_addr = self.firstAndLastAddr() 70 print 'first - last addrs : %x-%x' % (first_addr,last_addr) 71 size = 4 72 to_emit = {} 73 74 #dict of complex loop "head"s to ( addrs in the loop, its bound) 75 complex_loops = {} 76 #we need to emit instructions in the order of addresses 77 #firstly, put all the lines in a dict 78 for bb_start_addr in imm_fun.bbs: 79 if self.skip_fun and bb_start_addr in self.elf_fun_to_skip.lines: 80 continue 81 for addr in imm_fun.bbs[bb_start_addr]: 82 if addr in imm_loopheads: 83 p_head, f = imm_loopheads[addr] 84 bin_head = phyAddrP(p_head,imm_fun.f_problems[f]) 85 import graph_refine.loop_bounds 86 if imm_fun.loaded_loop_counts and bin_head in imm_fun.bin_loops_by_fs[f]: 87 #The user specified a manual loop-count override 88 loop_count,desc,_ = imm_fun.bin_loops_by_fs[f][bin_head] 89 else: 90 91 print "imm_fun.loaded_loop_counts: %s, bin_loops_by_fs[f].keys: %s, function: %s" % (imm_fun.loaded_loop_counts, str(imm_fun.loops_by_fs[f]), f ) 92 assert False 93 loop_count,desc = graph_refine.loop_bounds.get_bound_super_ctxt(bin_head, []) 94 if graph_refine.loop_bounds.is_complex_loop(addr): 95 body_addrs = graph_refine.loop_bounds.get_loop_addrs(addr) 96 complex_loops[addr] = (body_addrs, loop_count) 97 emitted_loop_counts[bin_head] = (loop_count, desc) 98 print '%x: bound %d/0x%x, %s' % (addr, loop_count, loop_count,desc) 99 else: 100 loop_count = None 101 to_emit[addr] = (addr,addr == bb_start_addr,loop_count) 102 103 for loop_addr in complex_loops.keys(): 104 print "complex loop at 0x%x" % (addr) 105 print "body: %s" % str(map(hex, body_addrs)) 106 #apply the loopcounts to all the instructions in this complex loop 107 body_addrs, loop_bound = complex_loops[loop_addr] 108 for addr in body_addrs: 109 if addr not in to_emit: 110 #dodge the halt case 111 continue 112 addr, is_start_bb, _ = to_emit[addr] 113 to_emit[addr] = (addr,is_start_bb, loop_bound) 114 emitted_loop_counts[addr] = (loop_bound, "complex_body") 115 116 117 #then emit them in order 118 for addr in xrange (first_addr, last_addr + size, size): 119 if addr in to_emit: 120 addr,is_start_bb, loop_count = to_emit[addr] 121 self.emitImm(addr,i_nodes,is_start_bb,loop_count) 122 else: 123 #pad with nop 124 self.emitNop(addr, size) 125 126 for bin_head in emitted_loop_counts: 127 count, desc = emitted_loop_counts[bin_head] 128 self.emitted_loop_counts_file.write("0x%x : count %d, desc: %s\n" % ( bin_head, count, desc)) 129 130 def firstAndLastAddr(self): 131 i_addrs = [] 132 bbs = self.imm_fun.bbs 133 for bb_n in bbs: 134 i_addrs += bbs[bb_n] 135 #print 'chronos_emit i_addrs %s' % i_addrs 136 return min(i_addrs,key=int), max(i_addrs,key = int) 137 138 def emitLiterals (self): 139 ef = elfFile() 140 for addr in sorted(ef.literals,key=int): 141 (size,value) = ef.literals[addr] 142 self.imm_f.write('v %s %s %d\n'% (hex(addr),value,size)) 143 144 def emitLoopcount (self,addr,loop_count): 145 self.imm_f.write('l 0x%x %s\n'% (addr,loop_count)) 146 print 'l 0x%x %s\n'% (addr,loop_count) 147 if self.debug_f: 148 self.debug_f.write('l 0x%x %s\n'% (addr,loop_count)) 149 150 def emitString(self, s): 151 self.imm_f.write(s) 152 if self.debug_f: 153 self.debug_f.write(s) 154 155 def emitNop(self, addr, size): 156 s = 'i %s %d startbb edges end nop _ _' % (hex(addr), size) 157 if rawVals(addr): 158 _, value = rawVals(addr) 159 s += ' %s' % hexSansX(value) 160 s += '\n' 161 self.emitString(s) 162 163 def emitImm(self,addr,nodes,is_startbb,loop_count): 164 ''' 165 Emit a single line of imm instruction 166 ''' 167 168 s = '' 169 node = nodes[addr] 170 #if this is a loop head, emit its loop count 171 if loop_count != None: 172 self.emitLoopcount (addr,loop_count) 173 if verbose: 174 print 'emitting %s: %s' % (addr,node.text) 175 176 #is this the start of a basic block ? 177 if is_startbb: 178 bb = 'startbb' 179 else: 180 bb = 'contbb' 181 182 #all insts are of size 4 183 s += ('i %s 4 %s' % (hex(addr),bb)) 184 185 #output edges 186 s += ' edges' 187 #types of edges : next, call, callret,tailcall,return 188 #call: function call, callret : where to go when call returns ? 189 #return: this edge returns 190 #tailcall: namesake 191 192 193 for e in sorted(node.edges, key = lambda x: x.targ): 194 if type(e.targ) != int: 195 print 'e.targ %s' % e.targ 196 if e.emit: 197 s += ' next '+ hex(e.targ) 198 dummy_call = False 199 if node.call_edge: 200 assert node.call_ret_edge != None 201 if self.skip_fun and node.call_edge.targ in self.elf_fun_to_skip.lines: 202 assert not node.is_tail_call 203 # skip the function call and go directly to the return site 204 s += ' next ' + hex(node.call_ret_edge.targ) 205 dummy_call = True 206 elif node.is_tail_call: 207 s += ' tailcall ' + hex(node.call_edge.targ) 208 else: 209 s += ' call ' + hex(node.call_edge.targ) 210 #print 'call_ret_edge %s ' % node.call_ret_edge.targ 211 s += ' callret ' + hex(node.call_ret_edge.targ) 212 if node.ret_edge: 213 s += ' return' 214 assert not node.call_edge 215 assert not node.call_ret_edge 216 if verbose and node.edges != []: 217 print ' node.edges : ' 218 for x in node.edges: 219 print ' %s ' % x.targ 220 221 s += (' end') 222 txt = node.text 223 #mnenomic condition setcc, input output etc 224 #print '%s: %s' % (addr,txt) 225 value = node.raw_inst 226 if dummy_call: 227 s += ' nop _ _ %s\n' % hexSansX(value) 228 self.emitString(s) 229 return 230 i = parser.decode_instruction(addr, value, txt) 231 s += ' ' + i.mnemonic + ' ' 232 233 if i.condition: 234 s += i.condition + ' ' 235 else: 236 s += '_ ' 237 238 if i.setcc: 239 s += 's ' 240 else: 241 s += '_ ' 242 243 for reg in i.input_registers: 244 s += 'input ' + reg + ' ' 245 for reg in i.output_registers: 246 s += 'output ' + reg + ' ' 247 if hasattr(i, 'shift_val'): 248 s += 'shift #' + i.shift_val + ' ' + i.shift_mode + ' ' 249 if hasattr(i,'shift_reg'): 250 s += 'shift ' + i.shift_reg + ' ' + i.shift_mode + ' ' 251 #finally the raw inst and the text 252 253 s += '%s ' % hexSansX(value) 254 s += '"%s"' % txt 255 s += '\n' 256 257 self.emitString(s) 258 259 260def hexSansX(n): 261 '''translate the input to a hex without the 0x prefix''' 262 s = hex(n) 263 return s[2:] 264 265 266