|  |  |  | @@ -19,7 +19,7 @@ x86::Mem get_reg_ptr(jit_holder& jh, unsigned idx) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | x86::Gp get_reg_for(jit_holder& jh, unsigned idx) { | 
		
	
		
			
				|  |  |  |  |     // can check for regs in jh and return them instead of creating new ones | 
		
	
		
			
				|  |  |  |  |     // TODO can check for regs in jh and return them instead of creating new ones | 
		
	
		
			
				|  |  |  |  |     switch(traits::reg_bit_widths[idx]) { | 
		
	
		
			
				|  |  |  |  |     case 8: | 
		
	
		
			
				|  |  |  |  |         return jh.cc.newInt8(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -82,7 +82,9 @@ void gen_instr_prologue(jit_holder& jh, addr_t pc) { | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::PC), jh.next_pc); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//*trap_state=*pending_trap;"); | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), jh.trap_state); | 
		
	
		
			
				|  |  |  |  |     x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  |     cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE)); | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::PENDING_TRAP), current_trap_state); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//increment *next_pc"); | 
		
	
		
			
				|  |  |  |  |     cc.mov(jh.next_pc, pc); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -91,20 +93,20 @@ void gen_instr_epilogue(jit_holder& jh) { | 
		
	
		
			
				|  |  |  |  |     auto& cc = jh.cc; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//if(*trap_state!=0) goto trap_entry;"); | 
		
	
		
			
				|  |  |  |  |     cc.test(jh.trap_state, jh.trap_state); | 
		
	
		
			
				|  |  |  |  |     cc.jnz(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  |     x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  |     cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE)); | 
		
	
		
			
				|  |  |  |  |     cc.cmp(current_trap_state, 0); | 
		
	
		
			
				|  |  |  |  |     cc.jne(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     // Does this need to be done after every single instruction? | 
		
	
		
			
				|  |  |  |  |     // TODO: Does not need to be done for every instruction, only when needed | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//write back regs to mem"); | 
		
	
		
			
				|  |  |  |  |     write_reg_to_mem(jh, jh.pc, traits::PC); | 
		
	
		
			
				|  |  |  |  |     write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC); | 
		
	
		
			
				|  |  |  |  |     write_reg_to_mem(jh, jh.trap_state, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | void gen_block_prologue(jit_holder& jh) override { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     jh.pc = load_reg_from_mem(jh, traits::PC); | 
		
	
		
			
				|  |  |  |  |     jh.next_pc = load_reg_from_mem(jh, traits::NEXT_PC); | 
		
	
		
			
				|  |  |  |  |     jh.trap_state = load_reg_from_mem(jh, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | void gen_block_epilogue(jit_holder& jh) override { | 
		
	
		
			
				|  |  |  |  |     x86::Compiler& cc = jh.cc; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -112,7 +114,12 @@ void gen_block_epilogue(jit_holder& jh) override { | 
		
	
		
			
				|  |  |  |  |     cc.ret(jh.next_pc); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.bind(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//enter_trap(core_ptr, *trap_state, *pc, 0);"); | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//Prepare for enter_trap;"); | 
		
	
		
			
				|  |  |  |  |     // Make sure cached values are written back | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//write back regs to mem"); | 
		
	
		
			
				|  |  |  |  |     write_reg_to_mem(jh, jh.pc, traits::PC); | 
		
	
		
			
				|  |  |  |  |     write_reg_to_mem(jh, jh.next_pc, traits::NEXT_PC); | 
		
	
		
			
				|  |  |  |  |     this->gen_sync(jh, POST_SYNC, -1); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     x86::Gp current_trap_state = get_reg_for(jh, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  |     cc.mov(current_trap_state, get_reg_ptr(jh, traits::TRAP_STATE)); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -121,23 +128,43 @@ void gen_block_epilogue(jit_holder& jh) override { | 
		
	
		
			
				|  |  |  |  |     cc.mov(current_pc, get_reg_ptr(jh, traits::PC)); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     x86::Gp instr = cc.newInt32("instr"); | 
		
	
		
			
				|  |  |  |  |     cc.mov(instr, 0); | 
		
	
		
			
				|  |  |  |  |     cc.mov(instr, 0); // this is not correct | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//enter trap call;"); | 
		
	
		
			
				|  |  |  |  |     InvokeNode* call_enter_trap; | 
		
	
		
			
				|  |  |  |  |     cc.invoke(&call_enter_trap, &enter_trap, FuncSignatureT<uint64_t, void*, uint64_t, uint64_t, uint64_t>()); | 
		
	
		
			
				|  |  |  |  |     call_enter_trap->setArg(0, jh.arch_if_ptr); | 
		
	
		
			
				|  |  |  |  |     call_enter_trap->setArg(1, current_trap_state); | 
		
	
		
			
				|  |  |  |  |     call_enter_trap->setArg(2, current_pc); | 
		
	
		
			
				|  |  |  |  |     call_enter_trap->setArg(3, instr); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     x86::Gp current_next_pc = get_reg_for(jh, traits::NEXT_PC); | 
		
	
		
			
				|  |  |  |  |     cc.mov(current_next_pc, get_reg_ptr(jh, traits::NEXT_PC)); | 
		
	
		
			
				|  |  |  |  |     cc.mov(jh.next_pc, current_next_pc); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//*last_branch = std::numeric_limits<uint32_t>::max();"); | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::LAST_BRANCH), std::numeric_limits<uint32_t>::max()); | 
		
	
		
			
				|  |  |  |  |     cc.comment("\n//return *next_pc;"); | 
		
	
		
			
				|  |  |  |  |     cc.ret(jh.next_pc); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | // TODO implement | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) { jh.cc.comment("//gen_raise"); } | 
		
	
		
			
				|  |  |  |  | void gen_wait(jit_holder& jh, unsigned type) { jh.cc.comment("//gen_wait"); } | 
		
	
		
			
				|  |  |  |  | void gen_leave(jit_holder& jh, unsigned lvl) { jh.cc.comment("//gen_leave"); } | 
		
	
		
			
				|  |  |  |  | /* | 
		
	
		
			
				|  |  |  |  |     inline void raise(uint16_t trap_id, uint16_t cause){ | 
		
	
		
			
				|  |  |  |  |         auto trap_val =  0x80ULL << 24 | (cause << 16) | trap_id; | 
		
	
		
			
				|  |  |  |  |         this->core.reg.trap_state = trap_val; | 
		
	
		
			
				|  |  |  |  |         this->template get_reg<uint32_t>(traits::NEXT_PC) = std::numeric_limits<uint32_t>::max(); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | */ | 
		
	
		
			
				|  |  |  |  | inline void gen_raise(jit_holder& jh, uint16_t trap_id, uint16_t cause) { | 
		
	
		
			
				|  |  |  |  |     auto& cc = jh.cc; | 
		
	
		
			
				|  |  |  |  |     cc.comment("//gen_raise"); | 
		
	
		
			
				|  |  |  |  |     auto tmp1 = get_reg_for(jh, traits::TRAP_STATE); | 
		
	
		
			
				|  |  |  |  |     cc.mov(tmp1, 0x80ULL << 24 | (cause << 16) | trap_id); | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::TRAP_STATE), tmp1); | 
		
	
		
			
				|  |  |  |  |     auto tmp2 = get_reg_for(jh, traits::NEXT_PC); | 
		
	
		
			
				|  |  |  |  |     cc.mov(tmp2, std::numeric_limits<uint32_t>::max()); | 
		
	
		
			
				|  |  |  |  |     cc.mov(get_reg_ptr(jh, traits::NEXT_PC), tmp2); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline void gen_wait(jit_holder& jh, unsigned type) { jh.cc.comment("//gen_wait"); } | 
		
	
		
			
				|  |  |  |  | inline void gen_leave(jit_holder& jh, unsigned lvl) { jh.cc.comment("//gen_leave"); } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | enum operation { add, sub, band, bor, bxor, shl, sar, shr }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -342,24 +369,12 @@ x86::Gp gen_operation(jit_holder& jh, binary_operation op, x86::Gp a) { | 
		
	
		
			
				|  |  |  |  |     return a; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* template <typename T> | 
		
	
		
			
				|  |  |  |  | inline typename std::enable_if_t<std::is_unsigned<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool | 
		
	
		
			
				|  |  |  |  | is_signed) const { auto val_reg = get_reg_for(jh, sizeof(val)*8); auto tmp = get_reg_for(jh, size); jh.cc.mov(val_reg, | 
		
	
		
			
				|  |  |  |  | val); if(is_signed) jh.cc.movsx(tmp, val_reg); else jh.cc.movzx(tmp,val_reg); return tmp; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | template <typename T> | 
		
	
		
			
				|  |  |  |  | inline typename std::enable_if_t<std::is_signed<T>::value, x86::Gp> gen_ext(jit_holder& jh, T val, unsigned size, bool | 
		
	
		
			
				|  |  |  |  | is_signed) const { auto val_reg = get_reg_for(jh, sizeof(val)*8); auto tmp = get_reg_for(jh, size); jh.cc.mov(val_reg, | 
		
	
		
			
				|  |  |  |  | val); if(is_signed) jh.cc.movsx(tmp, val_reg); else jh.cc.movzx(tmp,val_reg); return tmp; | 
		
	
		
			
				|  |  |  |  | } */ | 
		
	
		
			
				|  |  |  |  | template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_ext(jit_holder& jh, T val, unsigned size, bool is_signed) { | 
		
	
		
			
				|  |  |  |  |     auto val_reg = get_reg_for(jh, sizeof(val) * 8); | 
		
	
		
			
				|  |  |  |  |     auto val_reg = get_reg_for(jh, sizeof(val) * 8, is_signed); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(val_reg, val); | 
		
	
		
			
				|  |  |  |  |     return gen_ext(jh, val_reg, size, is_signed); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | // explicit Gp size cast | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signed) { | 
		
	
		
			
				|  |  |  |  |     auto& cc = jh.cc; | 
		
	
		
			
				|  |  |  |  |     if(is_signed) { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -398,7 +413,6 @@ inline x86::Gp gen_ext(jit_holder& jh, x86::Gp val, unsigned size, bool is_signe | 
		
	
		
			
				|  |  |  |  |         throw std::runtime_error("Invalid size in gen_ext"); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     x86::Compiler& cc = jh.cc; | 
		
	
		
			
				|  |  |  |  |     auto ret_reg = cc.newInt32(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -447,31 +461,18 @@ inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, uint3 | 
		
	
		
			
				|  |  |  |  |     invokeNode->setArg(2, mem_type_reg); | 
		
	
		
			
				|  |  |  |  |     invokeNode->setArg(3, addr); | 
		
	
		
			
				|  |  |  |  |     invokeNode->setArg(4, val_ptr); | 
		
	
		
			
				|  |  |  |  |     cc.cmp(ret_reg, 0); | 
		
	
		
			
				|  |  |  |  |     cc.jne(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     cc.mov(val_reg, x86::ptr_64(val_ptr)); | 
		
	
		
			
				|  |  |  |  |     cc.and_(val_reg, mask); | 
		
	
		
			
				|  |  |  |  |     cc.cmp(ret_reg, 0); | 
		
	
		
			
				|  |  |  |  |     cc.jne(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  |     return val_reg; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp length) { | 
		
	
		
			
				|  |  |  |  |     uint32_t length_val = 0; | 
		
	
		
			
				|  |  |  |  |     auto length_ptr = jh.cc.newIntPtr(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(length_ptr, &length_val); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(x86::ptr_32(length_ptr), length); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     return gen_read_mem(jh, type, addr, length); | 
		
	
		
			
				|  |  |  |  |     throw std::runtime_error("Invalid gen_read_mem"); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp length) { | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newInt64(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(addr_reg, addr); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     uint32_t length_val = 0; | 
		
	
		
			
				|  |  |  |  |     auto length_ptr = jh.cc.newIntPtr(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(length_ptr, &length_val); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(x86::ptr_32(length_ptr), length); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     return gen_read_mem(jh, type, addr_reg, length_val); | 
		
	
		
			
				|  |  |  |  |     throw std::runtime_error("Invalid gen_read_mem"); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newInt64(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -479,32 +480,38 @@ inline x86::Gp gen_read_mem(jit_holder& jh, mem_type_e type, uint64_t addr, uint | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     return gen_read_mem(jh, type, addr_reg, length); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val) { | 
		
	
		
			
				|  |  |  |  |     auto val_reg = jh.cc.newInt64(); | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, int64_t val, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     auto val_reg = get_reg_for(jh, length * 8, true); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(val_reg, val); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr, val_reg); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr, val_reg, length); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val) { | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp val, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     x86::Compiler& cc = jh.cc; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     assert(val.size() == length); | 
		
	
		
			
				|  |  |  |  |     auto mem_type_reg = cc.newInt32(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(mem_type_reg, type); | 
		
	
		
			
				|  |  |  |  |     auto space_reg = cc.newInt32(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(space_reg, static_cast<uint16_t>(iss::address_type::VIRTUAL)); | 
		
	
		
			
				|  |  |  |  |     auto ret_reg = cc.newInt32(); | 
		
	
		
			
				|  |  |  |  |     InvokeNode* invokeNode; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     if(val.isGpb()) { | 
		
	
		
			
				|  |  |  |  |     switch(length) { | 
		
	
		
			
				|  |  |  |  |     case 1: | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem1, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint8_t>()); | 
		
	
		
			
				|  |  |  |  |     } else if(val.isGpw()) { | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>()); | 
		
	
		
			
				|  |  |  |  |     } else if(val.isGpd()) { | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>()); | 
		
	
		
			
				|  |  |  |  |     } else if(val.isGpq()) { | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>()); | 
		
	
		
			
				|  |  |  |  |     } else | 
		
	
		
			
				|  |  |  |  |         throw std::runtime_error("Invalid register size in gen_write_mem"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 2: | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem2, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint16_t>()); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 4: | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem4, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint32_t>()); | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     case 8: | 
		
	
		
			
				|  |  |  |  |         cc.invoke(&invokeNode, &write_mem8, FuncSignatureT<uint32_t, uint64_t, uint32_t, uint32_t, uint64_t, uint64_t>()); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         break; | 
		
	
		
			
				|  |  |  |  |     default: | 
		
	
		
			
				|  |  |  |  |         throw std::runtime_error("Invalid register size in gen_ext"); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     invokeNode->setRet(0, ret_reg); | 
		
	
		
			
				|  |  |  |  |     invokeNode->setArg(0, jh.arch_if_ptr); | 
		
	
		
			
				|  |  |  |  |     invokeNode->setArg(1, space_reg); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -515,16 +522,16 @@ inline void gen_write_mem(jit_holder& jh, mem_type_e type, x86::Gp addr, x86::Gp | 
		
	
		
			
				|  |  |  |  |     cc.cmp(ret_reg, 0); | 
		
	
		
			
				|  |  |  |  |     cc.jne(jh.trap_entry); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val) { | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newInt64(); | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, x86::Gp val, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newUInt64(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(addr_reg, addr); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr_reg, val); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr_reg, val, length); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val) { | 
		
	
		
			
				|  |  |  |  |     auto val_reg = jh.cc.newInt64(); | 
		
	
		
			
				|  |  |  |  | inline void gen_write_mem(jit_holder& jh, mem_type_e type, uint64_t addr, int64_t val, uint32_t length) { | 
		
	
		
			
				|  |  |  |  |     auto val_reg = get_reg_for(jh, length * 8, true); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(val_reg, val); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newInt64(); | 
		
	
		
			
				|  |  |  |  |     auto addr_reg = jh.cc.newUInt64(); | 
		
	
		
			
				|  |  |  |  |     jh.cc.mov(addr_reg, addr); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr_reg, val_reg); | 
		
	
		
			
				|  |  |  |  |     gen_write_mem(jh, type, addr_reg, val_reg, length); | 
		
	
		
			
				|  |  |  |  | } |