| 1167 | } |
| 1168 | |
| 1169 | void N64Recomp::LiveGenerator::process_store_op(const StoreOp& op, const InstructionContext& ctx) const { |
| 1170 | sljit_sw src; |
| 1171 | sljit_sw srcw; |
| 1172 | sljit_sw imm = (sljit_sw)(int16_t)ctx.imm16; |
| 1173 | |
| 1174 | get_operand_values(op.value_input, ctx, src, srcw, compiler, Registers::arithmetic_temp2); |
| 1175 | |
| 1176 | // Only LO16 relocs are valid on stores. |
| 1177 | if (ctx.reloc_type != RelocType::R_MIPS_NONE && ctx.reloc_type != RelocType::R_MIPS_LO16) { |
| 1178 | assert(false); |
| 1179 | errored = true; |
| 1180 | return; |
| 1181 | } |
| 1182 | |
| 1183 | if (ctx.reloc_type == RelocType::R_MIPS_LO16) { |
| 1184 | // Load the relocated address into temp1. |
| 1185 | load_relocated_address(ctx, Registers::arithmetic_temp1); |
| 1186 | // Extract the LO16 value from the full address (sign extended lower 16 bits). |
| 1187 | sljit_emit_op1(compiler, SLJIT_MOV_S16, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0); |
| 1188 | // Add the base register (rs) to the LO16 immediate. |
| 1189 | sljit_emit_op2(compiler, SLJIT_ADD, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0, SLJIT_MEM1(Registers::ctx), get_gpr_context_offset(ctx.rs)); |
| 1190 | } |
| 1191 | else { |
| 1192 | // TODO 0 immediate optimization. |
| 1193 | |
| 1194 | // Add the base register (rs) and the immediate to get the address and store it in the arithemtic temp. |
| 1195 | sljit_emit_op2(compiler, SLJIT_ADD, Registers::arithmetic_temp1, 0, SLJIT_MEM1(Registers::ctx), get_gpr_context_offset(ctx.rs), SLJIT_IMM, imm); |
| 1196 | } |
| 1197 | |
| 1198 | auto do_unaligned_store_op = [src, srcw, this](bool left, bool doubleword) { |
| 1199 | // Determine the shift direction to use for calculating the mask and shifting the loaded value. |
| 1200 | sljit_sw shift_op = left ? SLJIT_LSHR : SLJIT_SHL; |
| 1201 | // Determine the operation's word size. |
| 1202 | sljit_sw word_size = doubleword ? 8 : 4; |
| 1203 | |
| 1204 | // Mask the address with the alignment mask to get the misalignment and put it in temp2. |
| 1205 | // misalignment = addr & (word_size - 1); |
| 1206 | sljit_emit_op2(compiler, SLJIT_AND, Registers::arithmetic_temp2, 0, Registers::arithmetic_temp1, 0, SLJIT_IMM, word_size - 1); |
| 1207 | |
| 1208 | // Mask the address with ~alignment_mask to get the aligned address and put it in temp1. |
| 1209 | // addr = addr & ~(word_size - 1); |
| 1210 | sljit_emit_op2(compiler, SLJIT_AND, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp1, 0, SLJIT_IMM, ~(word_size - 1)); |
| 1211 | |
| 1212 | // Load the word at rdram + aligned address into the temp1 with sign-extension. |
| 1213 | // loaded_value = *addr |
| 1214 | if (doubleword) { |
| 1215 | // Rotate the loaded doubleword by 32 bits to swap the two words into the right order. |
| 1216 | sljit_emit_op2(compiler, SLJIT_ROTL, Registers::arithmetic_temp3, 0, SLJIT_MEM2(Registers::rdram, Registers::arithmetic_temp1), 0, SLJIT_IMM, 32); |
| 1217 | } |
| 1218 | else { |
| 1219 | // Use MOV_S32 to sign-extend the loaded word. |
| 1220 | sljit_emit_op1(compiler, SLJIT_MOV_S32, Registers::arithmetic_temp3, 0, SLJIT_MEM2(Registers::rdram, Registers::arithmetic_temp1), 0); |
| 1221 | } |
| 1222 | |
| 1223 | // Inverse the misalignment if this is a right load. |
| 1224 | if (!left) { |
| 1225 | // misalignment = (word_size - 1 - misalignment) * 8 |
| 1226 | sljit_emit_op2(compiler, SLJIT_SUB, Registers::arithmetic_temp2, 0, SLJIT_IMM, word_size - 1, Registers::arithmetic_temp2, 0); |
nothing calls this directly
no test coverage detected