def _set_bool(self, spotmap, get_reg, asm_code): """Emit code for SET command if arg is boolean type.""" # When any scalar value is converted to _Bool, the result is 0 if the # value compares equal to 0; otherwise, the result is 1 # If arg_asm is a LITERAL or conflicts with output, move to register. if (isinstance(spotmap[self.arg], LiteralSpot) or spotmap[self.arg] == spotmap[self.output]): 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): # noqa D102 arg1_spot = spotmap[self.arg1] arg1_size = self.arg1.ctype.size arg2_spot = spotmap[self.arg2] arg2_size = self.arg2.ctype.size # According Intel® 64 and IA-32 software developer's manual # Vol. 2B 4-582 second (count) operand must be represented as # imm8 or CL register. if not self._is_imm8(arg2_spot) and arg2_spot != spots.RCX: if arg1_spot == spots.RCX: out_spot = spotmap[self.output] temp_spot = get_reg([out_spot, arg1_spot], [arg2_spot, spots.RCX]) asm_code.add(asm_cmds.Mov(temp_spot, arg1_spot, arg1_size)) arg1_spot = temp_spot asm_code.add(asm_cmds.Mov(spots.RCX, arg2_spot, arg2_size)) arg2_spot = spots.RCX 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 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}. The given register is used as an intermediary for transferring values between the target_spot and start_spot. It is *always* safe for `reg` to be one of these two, and in fact it is recommended that if either of target_spot or start_spot is a register then `reg` be equal to that. """ # TODO: consider padding everything to 8 bytes to reduce the # 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): # noqa D102 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_either_literal64( arg1_spot, arg2_spot, 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): # noqa D102 if spotmap[self.arg] != spots.RAX: size = self.arg.ctype.size asm_code.add(asm_cmds.Mov(spots.RAX, spotmap[self.arg], size)) asm_code.add(asm_cmds.Mov(spots.RSP, spots.RBP, 8)) asm_code.add(asm_cmds.Pop(spots.RBP, None, 8)) asm_code.add(asm_cmds.Ret())
def _shared_asm(self, Inst, comm, out, arg1, arg2, spotmap, get_reg, asm_code): """Make the shared ASM for ADD, MULT, and SUB. Inst - the instruction for this comm (Bool) - whether the instruction is commutative. if not, a "neg" instruction is inserted when the order is flipped. """ ctype = arg1.ctype size = ctype.size arg1_spot = spotmap[arg1] arg2_spot = spotmap[arg2] # Get temp register for computation. temp = get_reg([spotmap[out], arg1_spot, arg2_spot]) if temp == arg1_spot: if not self._is_imm64(arg2_spot): asm_code.add(Inst(temp, arg2_spot, size)) else: temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size)) asm_code.add(Inst(temp, temp2, size)) elif temp == arg2_spot: if not self._is_imm64(arg1_spot): asm_code.add(Inst(temp, arg1_spot, size)) else: temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp2, arg1_spot, size)) asm_code.add(Inst(temp, temp2, size)) if not comm: asm_code.add(asm_cmds.Neg(temp, None, size)) else: if (not self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(Inst(temp, arg2_spot, size)) elif (self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(Inst(temp, arg2_spot, size)) elif (not self._is_imm64(arg1_spot) and self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg2_spot, size)) asm_code.add(Inst(temp, arg1_spot, size)) if not comm: asm_code.add(asm_cmds.Neg(temp, None, size)) else: # both are imm64 temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size)) asm_code.add(Inst(temp, temp2, size)) if temp != spotmap[out]: asm_code.add(asm_cmds.Mov(spotmap[out], temp, size))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 """Make the ASM for the operation""" size = None arg1_spot = spotmap[self.arg1] arg2_spot = spotmap[self.arg2] output_spot = spotmap[self.output] r12_spot = spots.RegSpot("r12") r13_spot = spots.RegSpot("r13") """ Both arguments are moved to r12 and r13, to make sure they become regspots Operation will be done on these two regs, with the result always in r12 Then, depending on output_spot being a reg or mem (lit should not be possible), a move or write will be added """ self.move(arg1_spot, r12_spot, asm_code) self.move(arg2_spot, r13_spot, asm_code) asm_code.add(self.Inst(r12_spot, r13_spot, size)) # output if isinstance(output_spot, spots.RegSpot): asm_code.add(asm_cmds.Mov(output_spot, r12_spot, size)) elif isinstance(output_spot, spots.MemSpot): asm_code.add(asm_cmds.Write(output_spot, r12_spot, size))
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))
def make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 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): # noqa D102 if self.output.ctype.weak_compat(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): # noqa D102 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 _fix_either_literal64(self, arg1_spot, arg2_spot, regs, get_reg, asm_code): """Move any 64-bit immediate operands to register.""" if self._is_imm64(arg1_spot): size = self.arg1.ctype.size new_arg1_spot = get_reg([], regs + [arg2_spot]) asm_code.add(asm_cmds.Mov(new_arg1_spot, arg1_spot, size)) return new_arg1_spot, arg2_spot # We cannot have both cases because _fix_both_literal is called # before this. elif self._is_imm64(arg2_spot): size = self.arg2.ctype.size new_arg2_spot = get_reg([], regs + [arg1_spot]) asm_code.add(asm_cmds.Mov(new_arg2_spot, arg2_spot, size)) return arg1_spot, new_arg2_spot else: return arg1_spot, arg2_spot
def make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 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 make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 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.RAX and spotmap[self.arg2] != spots.RAX: moved_to_rax = True asm_code.add(asm_cmds.Mov(spots.RAX, arg1_spot, size)) # If the divisor is a literal or in a bad register, we must move it # to a register. if (self._is_imm(spotmap[self.arg2]) or spotmap[self.arg2] in [spots.RAX, spots.RDX]): r = get_reg([], [spots.RAX, spots.RDX]) 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.RAX, 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.RDX, spots.RDX, 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): # noqa D102 """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: if not self._is_imm64(arg2_spot): asm_code.add(self.Inst(temp, arg2_spot, size)) else: temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size)) asm_code.add(self.Inst(temp, temp2, size)) elif temp == arg2_spot: if not self._is_imm64(arg1_spot): asm_code.add(self.Inst(temp, arg1_spot, size)) else: temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp2, arg1_spot, size)) asm_code.add(self.Inst(temp, temp2, size)) if not self.comm: asm_code.add(asm_cmds.Neg(temp, None, size)) else: if (not self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(self.Inst(temp, arg2_spot, size)) elif (self._is_imm64(arg1_spot) and not self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(self.Inst(temp, arg2_spot, size)) elif (not self._is_imm64(arg1_spot) and self._is_imm64(arg2_spot)): asm_code.add(asm_cmds.Mov(temp, arg2_spot, size)) asm_code.add(self.Inst(temp, arg1_spot, size)) if not self.comm: asm_code.add(asm_cmds.Neg(temp, None, size)) else: # both are imm64 temp2 = get_reg([], [temp]) asm_code.add(asm_cmds.Mov(temp, arg1_spot, size)) asm_code.add(asm_cmds.Mov(temp2, arg2_spot, size)) asm_code.add(self.Inst(temp, temp2, 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): # noqa D102 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 make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 ctype = self.arg1.ctype # Unsigned multiplication if not ctype.signed: arg1_spot = spotmap[self.arg1] arg2_spot = spotmap[self.arg2] size = ctype.size if arg1_spot == spots.RAX: mul_spot = arg2_spot elif arg2_spot == spots.RAX: mul_spot = arg1_spot else: # If either is literal, move that one to RAX if self._is_imm(arg2_spot): asm_code.add(asm_cmds.Mov(spots.RAX, arg2_spot, size)) mul_spot = arg1_spot else: asm_code.add(asm_cmds.Mov(spots.RAX, arg1_spot, size)) mul_spot = arg2_spot # Operand is an immediate, move it to a register if self._is_imm(mul_spot): r = get_reg([], [spots.RAX]) asm_code.add(asm_cmds.Mov(r, mul_spot, ctype.size)) mul_spot = r asm_code.add(asm_cmds.Mul(mul_spot, None, ctype.size)) if spotmap[self.output] != spots.RAX: asm_code.add( asm_cmds.Mov(spotmap[self.output], spots.RAX, ctype.size)) # Signed multiplication else: self._shared_asm(asm_cmds.Imul, True, self.output, self.arg1, self.arg2, spotmap, get_reg, asm_code)
def make_asm(self, spotmap, home_spots, get_reg, asm_code): # noqa D102 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)) asm_code.add(asm_cmds.Call(func_spot, None, self.func.ctype.size)) if not self.void_return and spotmap[self.ret] != spots.RAX: asm_code.add(asm_cmds.Mov(self.ret, spots.RAX, ret_size))
def _generate_asm(self, commands, live_vars, spotmap): """Generate assembly code.""" # This is kinda hacky... max_offset = max(spot.rbp_offset() for spot in spotmap.values()) #if max_offset % 16 != 0: # max_offset += 16 - max_offset % 16 # Back up rbp and move rsp #self.asm_code.add(asm_cmds.Push(spots.RBP, None, 8)) self.asm_code.add(asm_cmds.Sub(spots.RSP, spots.LiteralSpot(1))) self.asm_code.add(asm_cmds.Write(spots.RSP, spots.RBP)) self.asm_code.add(asm_cmds.Mov(spots.RBP, spots.RSP)) offset_spot = LiteralSpot(str(max_offset)) self.asm_code.add(asm_cmds.Sub(spots.RSP, offset_spot)) # 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): # noqa D102 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)) indir_spot = MemSpot(addr_r) if isinstance(value_spot, RegSpot): temp_reg = value_spot else: temp_reg = get_reg([], [addr_r]) self.move_data(indir_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))): # No need to worry about r overlapping with arg1 or arg2 because # in this case both are literal/memory. 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.chunk) # If there is a count in a literal spot, we're good to go. Also, # if count is already in a register, we're good to go by just using # that register for the count. (Because we require the count be 32- # or 64-bit, we know the full register stores exactly the value of # count). if (isinstance(spotmap[self.count], LiteralSpot) or isinstance(spotmap[self.count], RegSpot)): return spotmap[self.base].shift(self.chunk, 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.chunk, r)
def move(self, src_spot, dst_spot, asm_code): # Move data from src_spot to dst_spot """ The following spot type combinations are possible: src dst ----------- lit reg lit mem reg reg reg mem mem reg mem mem Note: moving towards a literal spot makes no sense """ # this stays here until I removed size from all functions size = None # temporary register spot r12_spot = spots.RegSpot("r12") r13_spot = spots.RegSpot("r13") r7_spot = spots.RegSpot("r7") # Warning! also used by read/write cmds # handle memspots with counts that are registers # reminder: base + offset + (chunk * count) if isinstance(src_spot, spots.MemSpot): if isinstance(src_spot.count, spots.RegSpot): asm_code.add( asm_cmds.Load(spots.LiteralSpot(src_spot.chunk), r7_spot, size)) asm_code.add(asm_cmds.Mult(r7_spot, src_spot.count, size)) if src_spot.offset < 0: asm_code.add( asm_cmds.Sub(r7_spot, spots.LiteralSpot(abs(src_spot.offset)), size)) else: asm_code.add( asm_cmds.Add(r7_spot, spots.LiteralSpot(abs(src_spot.offset)), size)) asm_code.add( asm_cmds.Add(r7_spot, spots.LiteralSpot(src_spot.base), size)) asm_code.add(asm_cmds.Read(r7_spot, r12_spot, size)) src_spot = r12_spot orig_dst_spot = dst_spot changed_dst_spot = False # we write to the correct dst_spot later on if isinstance(dst_spot, spots.MemSpot): if isinstance(dst_spot.count, spots.RegSpot): dst_spot = r13_spot changed_dst_spot = True # lit, reg if isinstance(src_spot, spots.LiteralSpot) and isinstance( dst_spot, spots.RegSpot): # load the literal to the destination reg asm_code.add(asm_cmds.Load(src_spot, dst_spot, size)) # lit, mem elif isinstance(src_spot, spots.LiteralSpot) and isinstance( dst_spot, spots.MemSpot): # load the literal to r12, then write r12 to dst # change r12 to r13 if r12 is the destination address tmp_spot = r12_spot if dst_spot == r12_spot: tmp_spot = r13_spot asm_code.add(asm_cmds.Load(src_spot, r12_spot, size)) asm_code.add(asm_cmds.Write(dst_spot, r12_spot, size)) # reg, reg elif isinstance(src_spot, spots.RegSpot) and isinstance( dst_spot, spots.RegSpot): # move the register content using OR r0 asm_code.add(asm_cmds.Mov(dst_spot, src_spot, size)) # reg, mem elif isinstance(src_spot, spots.RegSpot) and isinstance( dst_spot, spots.MemSpot): # write the src reg to dst asm_code.add(asm_cmds.Write(dst_spot, src_spot, size)) # mem, reg elif isinstance(src_spot, spots.MemSpot) and isinstance( dst_spot, spots.RegSpot): # read the src to dst reg asm_code.add(asm_cmds.Read(src_spot, dst_spot, size)) # mem, mem elif isinstance(src_spot, spots.MemSpot) and isinstance( dst_spot, spots.MemSpot): # TODO: add COPY to the assembly list, and use that instead # for now, read src to r12, and write r12 to dst if dst_spot == r12_spot: print( "ERROR: destination is R12. To fix implement copy instruction" ) asm_code.add(asm_cmds.Read(src_spot, r12_spot, size)) asm_code.add(asm_cmds.Write(dst_spot, r12_spot, size)) # if we changed the dst_spot, write it to the original dst_spot if changed_dst_spot: asm_code.add( asm_cmds.Load(spots.LiteralSpot(orig_dst_spot.chunk), r7_spot, size)) asm_code.add(asm_cmds.Mult(r7_spot, orig_dst_spot.count, size)) if orig_dst_spot.offset < 0: asm_code.add( asm_cmds.Sub(r7_spot, spots.LiteralSpot(abs(orig_dst_spot.offset)), size)) else: asm_code.add( asm_cmds.Add(r7_spot, spots.LiteralSpot(orig_dst_spot.offset), size)) asm_code.add( asm_cmds.Add(r7_spot, spots.LiteralSpot(orig_dst_spot.base), size)) asm_code.add(asm_cmds.Write(r7_spot, dst_spot, size))