def make_asm(self, spotmap, home_spots, get_reg, asm_code): regs = [] result = get_reg([spotmap[self.output]], [spotmap[self.arg1], spotmap[self.arg2]]) regs.append(result) out_size = self.output.ctype.size eq_val_spot = LiteralSpot(1) asm_code.add(asm_cmds.Mov(result, eq_val_spot, out_size)) arg1_spot, arg2_spot = self.fix_both_literal_or_mem( spotmap[self.arg1], spotmap[self.arg2], regs, get_reg, asm_code) arg1_spot, arg2_spot = self.fix_literal_wrong_order( arg1_spot, arg2_spot) arg_size = self.arg1.ctype.size neq_val_spot = LiteralSpot(0) label = asm_code.get_label() asm_code.add(asm_cmds.Cmp(arg1_spot, arg2_spot, arg_size)) asm_code.add(self.cmp_command()(label)) asm_code.add(asm_cmds.Mov(result, neq_val_spot, out_size)) asm_code.add(asm_cmds.Label(label)) if result != spotmap[self.output]: asm_code.add(asm_cmds.Mov(spotmap[self.output], result, out_size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): if self.output.ctype == ctypes.bool_t: return self.set_bool(spotmap, get_reg, asm_code) elif isinstance(spotmap[self.arg], LiteralSpot): out_spot = spotmap[self.output] arg_spot = spotmap[self.arg] size = self.output.ctype.size asm_code.add(asm_cmds.Mov(out_spot, arg_spot, size)) elif self.output.ctype.size <= self.arg.ctype.size: if spotmap[self.output] == spotmap[self.arg]: return if isinstance(spotmap[self.output], RegSpot): r = spotmap[self.output] elif isinstance(spotmap[self.arg], RegSpot): r = spotmap[self.arg] else: r = get_reg() self.move_data(spotmap[self.output], spotmap[self.arg], self.output.ctype.size, r, asm_code) else: r = get_reg([spotmap[self.output], spotmap[self.arg]]) # Move from arg_asm -> r_asm if self.arg.ctype.signed: asm_code.add(asm_cmds.Movsx(r, spotmap[self.arg], self.output.ctype.size, self.arg.ctype.size)) elif self.arg.ctype.size == 4: asm_code.add(asm_cmds.Mov(r, spotmap[self.arg], 4)) else: asm_code.add(asm_cmds.Movzx(r, spotmap[self.arg], self.output.ctype.size, self.arg.ctype.size)) # If necessary, move from r_asm -> output_asm if r != spotmap[self.output]: asm_code.add(asm_cmds.Mov(spotmap[self.output], r, self.output.ctype.size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): global DIRECT_VAL func_spot = spotmap[self.func] func_size = self.func.ctype.size ret_size = self.func.ctype.arg.ret.size # Check if function pointer spot will be clobbered by moving the arguments into the correct registers. if spotmap[self.func] in self.arg_regs[0:len(self.args)]: # Get a register which isn't one of the unallowed registers. r = get_reg([], self.arg_regs[0:len(self.args)]) asm_code.add(asm_cmds.Mov(r, spotmap[self.func], func_size)) func_spot = r for arg, reg in zip(self.args, self.arg_regs): if spotmap[arg] == reg: continue asm_code.add(asm_cmds.Mov(reg, spotmap[arg], arg.ctype.size)) if len(STR_EX) > 1: DIRECT_VAL.append(spots.LiteralSpot('_ret' + str(Call.counter - 1))) asm_code.add(asm_cmds.Call(func_spot, None, self.func.ctype.size)) if len(STR_EX) > 1: asm_code.add( asm_cmds.Mov(DIRECT_VAL[Call.counter], func_spot, self.func.ctype.size)) Call.counter += 1 if not self.void_return and spotmap[self.ret] != spots.EAX: asm_code.add(asm_cmds.Mov(spotmap[self.ret], spots.EAX, ret_size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): arg1_spot = spotmap[self.arg1] arg1_size = self.arg1.ctype.size arg2_spot = spotmap[self.arg2] arg2_size = self.arg2.ctype.size if not self.is_immediate8(arg2_spot) and arg2_spot != spots.ECX: if arg1_spot == spots.ECX: out_spot = spotmap[self.output] temp_spot = get_reg([out_spot, arg1_spot], [arg2_spot, spots.ECX]) asm_code.add(asm_cmds.Mov(temp_spot, arg1_spot, arg1_size)) arg1_spot = temp_spot asm_code.add(asm_cmds.Mov(spots.ECX, arg2_spot, arg2_size)) arg2_spot = spots.ECX if spotmap[self.output] == arg1_spot: asm_code.add(self.Inst(arg1_spot, arg2_spot, arg1_size, 1)) else: out_spot = spotmap[self.output] temp_spot = get_reg([out_spot, arg1_spot], [arg2_spot]) if arg1_spot != temp_spot: asm_code.add(asm_cmds.Mov(temp_spot, arg1_spot, arg1_size)) asm_code.add(self.Inst(temp_spot, arg2_spot, arg1_size, 1)) if temp_spot != out_spot: asm_code.add(asm_cmds.Mov(out_spot, temp_spot, arg1_size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): if self.arg and spotmap[self.arg] != spots.EAX: size = self.arg.ctype.size asm_code.add(asm_cmds.Mov(spots.EAX, spotmap[self.arg], size)) asm_code.add(asm_cmds.Mov(spots.ESP, spots.EBP, 8)) asm_code.add(asm_cmds.Pop(spots.EBP, None, 8)) asm_code.add(asm_cmds.Ret())
def make_asm(self, spotmap, home_spots, get_reg, asm_code): r = get_reg([spotmap[self.output]]) asm_code.add(asm_cmds.Lea(r, home_spots[self.var])) if r != spotmap[self.output]: size = self.output.ctype.size asm_code.add(asm_cmds.Mov(spotmap[self.output], r, size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): size = self.arg.ctype.size output_spot = spotmap[self.output] arg_spot = spotmap[self.arg] if output_spot != arg_spot: asm_code.add(asm_cmds.Mov(output_spot, arg_spot, size)) asm_code.add(self.Inst(output_spot, None, size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): if not isinstance(spotmap[self.base], MemSpot): raise NotImplementedError("expected base in memory spot") rel_spot = self.get_rel_spot(spotmap, get_reg, asm_code) out_spot = self.get_reg_spot(self.output, spotmap, get_reg) asm_code.add(asm_cmds.Lea(out_spot, rel_spot)) if out_spot != spotmap[self.output]: asm_code.add(asm_cmds.Mov(spotmap[self.output], out_spot, 8))
def move_data(self, target_spot, start_spot, size, reg, asm_code): """Emits code to move data from start to target. Given a target spot, start spot, size of data to move, and a register that can be clobbered in the move, this function emits code to move all the data. It is efficient whether the input spots are registers or memory, and in particular this function works even if the input size is not in {1, 2, 4, 8}. """ # number of mov operations emitted for struct copying. shift = 0 while shift < size: reg_size = self.reg_size(size - shift) start_spot = start_spot.shift(shift) target_spot = target_spot.shift(shift) if isinstance(start_spot, LiteralSpot): reg = start_spot elif reg != start_spot: asm_code.add(asm_cmds.Mov(reg, start_spot, reg_size)) if reg != target_spot: asm_code.add(asm_cmds.Mov(target_spot, reg, reg_size)) shift += reg_size
def make_asm(self, spotmap, home_spots, get_reg, asm_code): ctype = self.arg1.ctype size = ctype.size output_spot = spotmap[self.output] arg1_spot = spotmap[self.arg1] arg2_spot = spotmap[self.arg2] # Move first operand into RAX if we can do so without clobbering other argument moved_to_rax = False if spotmap[self.arg1] != spots.EAX and spotmap[self.arg2] != spots.EAX: moved_to_rax = True asm_code.add(asm_cmds.Mov(spots.EAX, arg1_spot, size)) # If the divisor is a literal or in a bad register, we must move it to a register. if self.is_immediate(spotmap[self.arg2]) or spotmap[self.arg2] in [ spots.EAX, spots.EDX ]: r = get_reg([], [spots.EAX, spots.EDX]) asm_code.add(asm_cmds.Mov(r, arg2_spot, size)) arg2_final_spot = r else: arg2_final_spot = arg2_spot # If we did not move to RAX above, do so here. if not moved_to_rax and arg1_spot != self.return_reg: asm_code.add(asm_cmds.Mov(spots.EAX, arg1_spot, size)) if ctype.signed: if ctype.size == 4: asm_code.add(asm_cmds.Cdq()) elif ctype.size == 8: asm_code.add(asm_cmds.Cqo()) asm_code.add(asm_cmds.Idiv(arg2_final_spot, None, size)) else: # zero out RDX register asm_code.add(asm_cmds.Xor(spots.EDX, spots.EDX, size)) asm_code.add(asm_cmds.Div(arg2_final_spot, None, size)) if spotmap[self.output] != self.return_reg: asm_code.add(asm_cmds.Mov(output_spot, self.return_reg, size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): size = self.cond.ctype.size if isinstance(spotmap[self.cond], LiteralSpot): r = get_reg() asm_code.add(asm_cmds.Mov(r, spotmap[self.cond], size)) cond_spot = r else: cond_spot = spotmap[self.cond] zero_spot = LiteralSpot("0") asm_code.add(asm_cmds.Cmp(cond_spot, zero_spot, size)) asm_code.add(self.command(self.label))
def set_bool(self, spotmap, get_reg, asm_code): """Emit code for SET command if arg is boolean type.""" # If arg_asm is a LITERAL, move to register. if isinstance(spotmap[self.arg], LiteralSpot): r = get_reg([], [spotmap[self.output]]) asm_code.add(asm_cmds.Mov(r, spotmap[self.arg], self.arg.ctype.size)) arg_spot = r else: arg_spot = spotmap[self.arg] label = asm_code.get_label() output_spot = spotmap[self.output] zero = LiteralSpot("0") one = LiteralSpot("1") asm_code.add(asm_cmds.Mov(output_spot, zero, self.output.ctype.size)) asm_code.add(asm_cmds.Cmp(arg_spot, zero, self.arg.ctype.size)) asm_code.add(asm_cmds.Je(label)) asm_code.add(asm_cmds.Mov(output_spot, one, self.output.ctype.size)) asm_code.add(asm_cmds.Label(label))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): """ Make the ASM for ADD, MULT, and SUB """ ctype = self.arg1.ctype size = ctype.size arg1_spot = spotmap[self.arg1] arg2_spot = spotmap[self.arg2] # Get temp register for computation. temp = get_reg([spotmap[self.output], arg1_spot, arg2_spot]) if temp == arg1_spot: asm_code.add(self.Inst(temp, arg2_spot, size)) elif temp == arg2_spot: asm_code.add(self.Inst(temp, arg1_spot, size)) if not self.comm: asm_code.add(asm_cmds.Neg(temp, None, size)) else: asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(self.Inst(temp, arg2_spot, size)) if temp != spotmap[self.output]: asm_code.add(asm_cmds.Mov(spotmap[self.output], temp, size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): addr_spot = spotmap[self.addr] output_spot = spotmap[self.output] if isinstance(addr_spot, RegSpot): addr_r = addr_spot else: addr_r = get_reg([], [output_spot]) asm_code.add(asm_cmds.Mov(addr_r, addr_spot, 8)) indir_spot = MemSpot(addr_r) if isinstance(output_spot, RegSpot): temp_reg = output_spot else: temp_reg = get_reg([], [addr_r]) self.move_data(output_spot, indir_spot, self.output.ctype.size, temp_reg, asm_code)
def make_asm(self, spotmap, home_spots, get_reg, asm_code): addr_spot = spotmap[self.addr] value_spot = spotmap[self.val] if isinstance(addr_spot, RegSpot): addr_r = addr_spot else: addr_r = get_reg([], [value_spot]) asm_code.add(asm_cmds.Mov(addr_r, addr_spot, 8)) indirect_spot = MemSpot(addr_r) if isinstance(value_spot, RegSpot): temp_reg = value_spot else: temp_reg = get_reg([], [addr_r]) self.move_data(indirect_spot, value_spot, self.val.ctype.size, temp_reg, asm_code)
def fix_both_literal_or_mem(self, arg1_spot, arg2_spot, regs, get_reg, asm_code): """ Fix arguments if both are literal or memory. Adds any called registers to given regs list. Returns tuple where first element is new spot of arg1 and second element is new spot of arg2. """ if ((isinstance(arg1_spot, LiteralSpot) and isinstance(arg2_spot, LiteralSpot)) or (isinstance(arg1_spot, MemSpot) and isinstance(arg2_spot, MemSpot))): r = get_reg([], regs) regs.append(r) asm_code.add(asm_cmds.Mov(r, arg1_spot, self.arg1.ctype.size)) return r, arg2_spot else: return arg1_spot, arg2_spot
def get_rel_spot(self, spotmap, get_reg, asm_code): """Get a relative spot for the relative value.""" # If there's no count, we only need to shift by the chunk if not self.count: return spotmap[self.base].shift(self.block) if isinstance(spotmap[self.count], LiteralSpot) or isinstance(spotmap[self.count], RegSpot): return spotmap[self.base].shift(self.block, spotmap[self.count]) # Otherwise, move count to a register. r = get_reg([], [spotmap[self.val]] + self.used_regs) self.used_regs.append(r) count_size = self.count.ctype.size asm_code.add(asm_cmds.Mov(r, spotmap[self.count], count_size)) return spotmap[self.base].shift(self.block, r)
def generate_asm(self, commands, live_vars, spotmap): """ Generate assembly code """ max_offset = max(spot.rbp_offset() for spot in spotmap.values()) if max_offset % 16 != 0: max_offset += 16 - max_offset % 16 # Back up ebp and move esp self.asm_code.add(asm_cmds.Push(spots.EBP, None, 8)) self.asm_code.add(asm_cmds.Mov(spots.EBP, spots.ESP, 8)) offset_spot = LiteralSpot(str(max_offset)) self.asm_code.add(asm_cmds.Sub(spots.ESP, offset_spot, 8)) # Generate code for each command for i, command in enumerate(commands): self.asm_code.add(asm_cmds.Comment(type(command).__name__.upper())) def get_reg(pref=None, conf=None): if not pref: pref = [] if not conf: conf = [] # Spot is bad if it is containing a variable that is live both entering and exiting this command. bad_vars = set(live_vars[i][0]) & set(live_vars[i][1]) bad_spots = set(spotmap[var] for var in bad_vars) # Spot is free if it is where an output is stored. for v in command.outputs(): bad_spots.discard(spotmap[v]) # Spot is bad if it is listed as a conflicting spot. bad_spots |= set(conf) for s in (pref + self.all_registers): if isinstance(s, RegSpot) and s not in bad_spots: return s raise NotImplementedError("spill required for get_reg") command.make_asm(spotmap, spotmap, get_reg, self.asm_code)
def make_asm(self, spotmap, home_spots, get_reg, asm_code): if spotmap[self.output] == self.arg_reg: return else: asm_code.add(asm_cmds.Mov(spotmap[self.output], self.arg_reg, self.output.ctype.size))