def _gen_code_boolop(self, **kwargs): self.label_true = kwargs.get('on_true', CC.new_label()) self.label_false = kwargs.get('on_false', CC.new_label()) self.label_right = CC.new_label( ) # additional label to jump to the right operand for case in switch(self.type.type): if case(LP.AND): self.add_child_by_idx(0, on_true=self.label_right, on_false=self.label_false) self.add_instr(CC.LABEL, label=self.label_right) self.add_child_by_idx(1, on_true=self.label_true, on_false=self.label_false) break if case(LP.OR): self.add_child_by_idx(0, on_true=self.label_true, on_false=self.label_right) self.add_instr(CC.LABEL, label=self.label_right) self.add_child_by_idx(1, on_true=self.label_true, on_false=self.label_false) break if case(): raise InternalError('wrong bool op type %s' % str(self.type)) # if no jump keywords were given, the result will be used as a value -- push it if not self.has_jump_codes(kwargs): self.label_after = CC.new_label() self.add_instr(CC.LABEL, label=self.label_true) self.add_instr(CC.PUSH, src=Loc.const(1)) self.add_instr(CC.JUMP, label=self.label_after) self.add_instr(CC.LABEL, label=self.label_false) self.add_instr(CC.PUSH, src=Loc.const(0)) self.add_instr(CC.LABEL, label=self.label_after)
def print_codes(self): """ Debug: print the current codes list. """ for i in xrange(len(self.codes)): code = self.codes[i] if (code['type'] == CC.EMPTY): debug('\n', no_hdr=True) continue d = code.copy() del d['type'] debug('[%d]' % i, CC._code_name(code['type']) + '\t' + CC._str_code(d), no_hdr=True)
def codes(self): """ A generator that yields the intermediate codes. """ for instr in self.instr: if CC.is_child(instr): for child_instr in instr['child'].codes(): yield child_instr else: yield instr
def mark_deleted(self, pos_or_iter, **kwargs): """ Mark code for deletion, at a single index or whole iterable. """ if isinstance(pos_or_iter, int): self.codes[pos_or_iter]['_type'] = CC._code_name(self.codes[pos_or_iter]['type']) self.codes[pos_or_iter].update(kwargs) # just for debugging, to put more indicators self.codes[pos_or_iter]['type'] = CC.DELETED else: for pos in pos_or_iter: self.mark_deleted(pos)
def output_assembly(cls): """ Output the assembly code. """ debug('-------------- ASM OUTPUT ---------------------') try: asm_file = sys.stdout if Flags.output_to_stdout() else open( Flags.asm_file, 'w') for instr in Codes.gen_asm(cls.optimizer.codes): print(str(instr), file=asm_file) if not Flags.output_to_stdout(): asm_file.close() except IOError as err: Status.add_error(err, fatal=True)
def __init__(self, tree, **kwargs): super(FunCode, self).__init__(tree, **kwargs) self.ret_type = tree.ret_type self.name = tree.name self.args = tree.args self.add_child(BlockCode(tree.children[0])) self.ret_label = CC.new_label() for i in xrange(len(self.args)): arg = self.args[i] self.tree.add_symbol(Symbol(arg.name, arg.type, Loc.arg_addr(i))) self.var_count = self.children[0].count_local_vars() debug('fun ', self.name, 'VAR COUNT: ', self.var_count) self.used_vars = 0 # how many local variables are currently allocated
def _insert_apply_pockets(self): """ Child function of propagate_constants, used to insert assignments before pocket indicators, because they can't be inserted before when iterating through the list. """ start_pos = 0 debug('APPLY POCKETS') for pos in self.matcher.gen_next(start_pos, attrlist=['apply_pocket']): # Generate the move instructions and insert them inside codes list. moves = map(lambda (reg, val): CC.mkcode(CC.MOV, src=val, dest=reg, comment=CC.S_PROPAGATED), self.codes[pos]['apply_pocket'].iteritems()) debug('apply pocket: insert %d moves at %d' % (len(moves), pos)) del self.codes[pos]['apply_pocket'] self.codes[pos:pos] = moves start_pos = pos + len(moves) - 1 # rebuild the jump maps self.scan_labels()
def _do_push_pop_reduction(self, indexes): """ Child function of reduce_push_pop, that does the actual reduction. Separate function just for code reuse. `indexes` should be a two-element position list.""" p_push, p_pop = indexes src, dest = self.codes[p_push]['src'], self.codes[p_pop]['dest'] if src == dest: debug(' deleting push-pop with same attrs at', str(indexes)) self.mark_deleted(indexes) return 1 else: debug(' combining [push, pop] to mov at', str(indexes)) self.mark_deleted(p_push, _type='[push,pop]', dest=dest) self.codes[p_pop] = CC.mkcode(CC.MOV, src=src, dest=dest, comment='combined from [push,pop]') return 1 return 0
def _cp_empty_pocket_if_needed(self, pos, code): """ Constant propagation: empty the pocket in case of calls or jumps. """ # [1] On function call, empty the pocket. if len(self.pocket) and code['type'] == CC.CALL: debug('function call at %d, emptying pocket' % pos) self.pocket = {} # [2] On function exit, drop %eax and empty pocket. if len(self.pocket) and code['type'] == CC.ENDFUNC: if Loc.reg('a') in self.pocket.keys(): self._add_to_apply_pocket(pos, {Loc.reg('a'): self.pocket[Loc.reg('a')]}) debug('ENDFUNC at %d, dropping reg a' % pos) self.pocket = {} # [3] On jump instructions (both in-/out-bound) assign the pocket values anyway. if len(self.pocket) and code['type'] in [CC.JUMP, CC.IF_JUMP, CC.LABEL]: debug('%s at %d, reassigning pocket values' % (CC._code_name(code['type']), pos)) # We can't insert into a list while iterating, so save the pocket for now # TODO we could later skip at least some of pocket's values, if we check that # a value is the same at label and all jumps to it, or the register is not live. self._add_to_apply_pocket(pos, self.pocket.copy()) self.pocket = {}
def _cp_two_const_operator(self, pos, code): """ Constant propagation for operators: if both operands are consts, calculate the result and propagate it instead.""" # 'lhs' and 'rhs' are both registers with values stored in pocket, or only 'rhs' is and # 'lhs' is an actual constant (e.g. propagated there in previous loop iteration, when 'rhs' # was not yet propagated). if (self.matcher.match( code, type=self.BIN_OPS, lhs=self.CONST_OR_REG, rhs=Loc.reg(Loc.ANY)) and (code['lhs'].is_constant() or code['lhs'] in self.pocket) and code['rhs'] in self.pocket): debug('two-const operator %s at %d' % (CC._code_name(code['type']), pos)) if code['type'] == CC.BOOL_OP: cmp_fun = { 'sete': operator.eq, 'setne': operator.ne, 'setg': operator.gt, 'setge': operator.ge, 'setl': operator.lt, 'setle': operator.le, }[code['op']] # The operator.* bool functions return bool, we want an int to push. op_fun = lambda x, y: int(cmp_fun(x, y)) else: op_fun = { CC.ADD: operator.add, CC.SUB: operator.sub, CC.MUL: operator.mul, CC.DIV: operator.floordiv, CC.MOD: c_modulo }[code['type']] arg1 = int(self.pocket[code['rhs']].value) if code['lhs'].is_constant(): arg2 = int(code['lhs'].value) else: arg2 = int(self.pocket[code['lhs']].value) res_val = op_fun(arg1, arg2) debug(' -> args %d, %d res %d' % (arg1, arg2, res_val)) res_reg = code['dest'] if code['type'] in [CC.DIV, CC.MOD] else code['rhs'] # Delete and re-insert value, to maintain hash properties. if res_reg in self.pocket: del self.pocket[res_reg] self.pocket[res_reg] = Loc.const(res_val) self.mark_deleted(pos, comment=CC.S_PROPAGATED, value=res_val) self.prop_consts += 1 return True
def __init__(self, tree, **kwargs): super(StmtCode, self).__init__(tree, **kwargs) self.type = tree.type if 'no_children' not in kwargs: for child in tree.children: self.add_child(StmtFactory(child)) for case in switch(self.type.type): if case(LP.IF): self.label_after = CC.new_label() # if there are less blocks, just evaluate condition and jump to label_after self.label_then = CC.new_label() if len( self.children) > 1 else self.label_after self.label_else = CC.new_label() if len( self.children) > 2 else self.label_after break if case(LP.WHILE): self.label_after = CC.new_label() self.label_cond = CC.new_label() self.label_block = CC.new_label() if len( self.children) > 1 else self.label_cond break
def add_instr(self, type, **kwargs): """ Appends a code. """ self.instr.append(CC.mkcode(type, **kwargs))