def optimize(self, instructions): for i, inst in enumerate(instructions): if inst.name in ("getlocal", "setlocal") and 0 <= inst.argument < 4: new_instruction = "%s%s" % (inst.name, inst.argument) instructions[i] = get_instruction(new_instruction)() return instructions
def optimize(self, instructions): new_instructions = [] for inst1, inst2 in group(instructions): if inst1 is None or inst2 is None: continue key = inst1.name, inst2.name if key in self.branches: combined = get_instruction(self.branches[key]) new_instructions.append(combined(inst2.labelname)) else: new_instructions.append(inst1) return new_instructions
def optimize(self): """ Do some not so simple optimizations. """ for _ in xrange(2): jumps = {} # instructions to remove remv_inst = set() # register -> set([prev, curr]) remv_regs = {} institer = iter(self.instructions) instructions = [institer.next()] # First pass - mark anything needed for the second pass. for newinst in institer: instructions.append(newinst) prev, curr = instructions[-2:] # Gather all jumps by their respective labels. if curr.jumplike: jumps.setdefault(curr.labelname, []).append(curr) S = set((prev, curr)) # Detect if there are any references to this register other than # the setlocal/getlocal sequence here. if prev.name in SET_LOCALS and \ curr.name in GET_LOCALS and \ prev.argument == curr.argument: remv_inst.update(S) remv_regs[curr.argument] = S # PyPy-specific optimization: some opcodes have an unnecessary # StoreResult at the end, so callpropvoid and some setproperty's # have a pushnull and an unused register afterwards. Stop that. elif prev.name in ("pushnull", "pushundefined") and \ curr.name in SET_LOCALS: remv_inst.update(S) remv_regs[curr.argument] = S elif curr.name in GET_LOCALS: if curr.argument in remv_regs: remv_inst -= remv_regs[curr.argument] elif curr.name in SET_LOCALS: # If we have any remv_regs.pop(curr.argument, None) elif curr.name == "kill": # If we're going to remove this register, mark the kill for deletion too. if curr.argument in remv_regs: remv_inst.add(curr) prev = curr institer = iter(self.instructions) instructions = [institer.next()] # Second pass for newinst in institer: instructions.append(newinst) keep_going = True while keep_going: prev, curr = instructions[-2:] test = prev.name, curr.name # Prevent errors with jumps and lone labels. if curr.name == "label" and curr.labelname not in jumps: instructions = instructions[:-1] # Branch optimizations geared for PyPy. elif test in BRANCH_OPTIMIZE: instructions = instructions[:-2] new = get_instruction(BRANCH_OPTIMIZE[test])( curr.labelname) jumps[curr.labelname].remove(curr) jumps[curr.labelname].append(new) instructions.append(new) # Two opcodes in a row that do nothing should be removed. elif prev.name in GET_LOCALS and curr.name in SET_LOCALS \ and prev.argument == curr.argument: instructions = instructions[:-2] # jump then label -> remove the jump. elif test == ("jump", "label" ) and prev.labelname == curr.labelname: # Don't remove the label, we may need it for a backref later on. instructions.pop(-2) jumps[prev.labelname].remove(prev) # return after return -> remove the second return. elif prev.name in ("returnvalue", "returnvoid") and \ curr.name in ("returnvalue", "returnvoid"): instructions.pop() # label then jump -> remove both and rename. elif test == ("label", "jump"): for jump in jumps[prev.labelname]: jump.labelname = curr.labelname jumps[curr.labelname].remove(curr) jumps[curr.labelname].extend(jumps[prev.labelname]) del jumps[prev.labelname] instructions = instructions[:-2] elif curr in remv_inst: instructions.pop() else: keep_going = False self.instructions = instructions # Third pass - pack in those registers. institer = iter(self.instructions) inst = [institer.next()] # local_names is the arguments to the method used_registers = dict((i, i) for i in xrange(len(self.local_names))) for newinst in institer: curr = inst[-1] if curr.name in SET_LOCALS: index = used_registers.setdefault(curr.argument, len(used_registers)) instructions[-1] = get_instruction('setlocal')(index) elif curr.name in GET_LOCALS: inst[-1] = get_instruction('getlocal')(used_registers.get( curr.argument, curr.argument)) elif curr.name == "kill": inst[-1] = get_instruction('kill')(used_registers.get( curr.argument, curr.argument)) self.numlocals = len(used_registers) self.instructions = instructions
def emit(self, name, *a, **kw): """ Emit an instruction, with given arguments. """ return self.add_instruction(get_instruction(name)(*a, **kw))
def optimize(self): """ Do some not so simple optimizations. """ for _ in xrange(2): jumps = {} # instructions to remove remv_inst = set() # register -> set([prev, curr]) remv_regs = {} institer = iter(self.instructions) instructions = [institer.next()] # First pass - mark anything needed for the second pass. for newinst in institer: instructions.append(newinst) prev, curr = instructions[-2:] # Gather all jumps by their respective labels. if curr.jumplike: jumps.setdefault(curr.labelname, []).append(curr) S = set((prev, curr)) # Detect if there are any references to this register other than # the setlocal/getlocal sequence here. if prev.name in SET_LOCALS and curr.name in GET_LOCALS and prev.argument == curr.argument: remv_inst.update(S) remv_regs[curr.argument] = S # PyPy-specific optimization: some opcodes have an unnecessary # StoreResult at the end, so callpropvoid and some setproperty's # have a pushnull and an unused register afterwards. Stop that. elif prev.name in ("pushnull", "pushundefined") and curr.name in SET_LOCALS: remv_inst.update(S) remv_regs[curr.argument] = S elif curr.name in GET_LOCALS: if curr.argument in remv_regs: remv_inst -= remv_regs[curr.argument] elif curr.name in SET_LOCALS: # If we have any remv_regs.pop(curr.argument, None) elif curr.name == "kill": # If we're going to remove this register, mark the kill for deletion too. if curr.argument in remv_regs: remv_inst.add(curr) prev = curr institer = iter(self.instructions) instructions = [institer.next()] # Second pass for newinst in institer: instructions.append(newinst) keep_going = True while keep_going: prev, curr = instructions[-2:] test = prev.name, curr.name # Prevent errors with jumps and lone labels. if curr.name == "label" and curr.labelname not in jumps: instructions = instructions[:-1] # Branch optimizations geared for PyPy. elif test in BRANCH_OPTIMIZE: instructions = instructions[:-2] new = get_instruction(BRANCH_OPTIMIZE[test])(curr.labelname) jumps[curr.labelname].remove(curr) jumps[curr.labelname].append(new) instructions.append(new) # Two opcodes in a row that do nothing should be removed. elif prev.name in GET_LOCALS and curr.name in SET_LOCALS and prev.argument == curr.argument: instructions = instructions[:-2] # jump then label -> remove the jump. elif test == ("jump", "label") and prev.labelname == curr.labelname: # Don't remove the label, we may need it for a backref later on. instructions.pop(-2) jumps[prev.labelname].remove(prev) # return after return -> remove the second return. elif prev.name in ("returnvalue", "returnvoid") and curr.name in ("returnvalue", "returnvoid"): instructions.pop() # label then jump -> remove both and rename. elif test == ("label", "jump"): for jump in jumps[prev.labelname]: jump.labelname = curr.labelname jumps[curr.labelname].remove(curr) jumps[curr.labelname].extend(jumps[prev.labelname]) del jumps[prev.labelname] instructions = instructions[:-2] elif curr in remv_inst: instructions.pop() else: keep_going = False self.instructions = instructions # Third pass - pack in those registers. institer = iter(self.instructions) inst = [institer.next()] # local_names is the arguments to the method used_registers = dict((i, i) for i in xrange(len(self.local_names))) for newinst in institer: curr = inst[-1] if curr.name in SET_LOCALS: index = used_registers.setdefault(curr.argument, len(used_registers)) instructions[-1] = get_instruction("setlocal")(index) elif curr.name in GET_LOCALS: inst[-1] = get_instruction("getlocal")(used_registers.get(curr.argument, curr.argument)) elif curr.name == "kill": inst[-1] = get_instruction("kill")(used_registers.get(curr.argument, curr.argument)) self.numlocals = len(used_registers) self.instructions = instructions
def emit(self, name, *a, **kw): """ Emit an instruction, with given arguments. """ print " ", name, a return self.add_instruction(get_instruction(name)(*a, **kw))