| 891 | } |
| 892 | |
| 893 | void N64Recomp::LiveGenerator::process_unary_op(const UnaryOp& op, const InstructionContext& ctx) const { |
| 894 | // Skip instructions that output to $zero |
| 895 | if (outputs_to_zero(op.output, ctx)) { |
| 896 | return; |
| 897 | } |
| 898 | |
| 899 | // A unary op may have a float u32l as the source or destination, but not both. |
| 900 | if (is_fpr_u32l(op.input) && is_fpr_u32l(op.output)) { |
| 901 | assert(false); |
| 902 | errored = true; |
| 903 | return; |
| 904 | } |
| 905 | |
| 906 | sljit_sw dst; |
| 907 | sljit_sw dstw; |
| 908 | sljit_sw src; |
| 909 | sljit_sw srcw; |
| 910 | bool output_good = get_operand_values(op.output, ctx, dst, dstw, compiler, Registers::arithmetic_temp3); |
| 911 | bool input_good = get_operand_values(op.input, ctx, src, srcw, compiler, Registers::arithmetic_temp3); |
| 912 | |
| 913 | if (!output_good || !input_good) { |
| 914 | assert(false); |
| 915 | errored = true; |
| 916 | return; |
| 917 | } |
| 918 | |
| 919 | // If a relocation is needed for the input operand, perform the relocation and store the result directly. |
| 920 | if (ctx.reloc_type != RelocType::R_MIPS_NONE) { |
| 921 | // Only allow relocation of lui with an immediate. |
| 922 | if (op.operation != UnaryOpType::Lui || op.input != Operand::ImmU16) { |
| 923 | assert(false); |
| 924 | errored = true; |
| 925 | return; |
| 926 | } |
| 927 | // Only allow HI16 relocs. |
| 928 | if (ctx.reloc_type != RelocType::R_MIPS_HI16) { |
| 929 | assert(false); |
| 930 | errored = true; |
| 931 | return; |
| 932 | } |
| 933 | // Load the relocated address into temp1. |
| 934 | load_relocated_address(ctx, Registers::arithmetic_temp1); |
| 935 | |
| 936 | // HI16 reloc on a lui |
| 937 | // The 32-bit address (a) is equal to section address + section offset |
| 938 | // The 16-bit immediate is equal to (a - (int16_t)a) >> 16 |
| 939 | // Therefore, the register should be set to (int32_t)(a - (int16_t)a) as the shifts cancel out and the lower 16 bits are zero. |
| 940 | |
| 941 | // Extract a sign extended 16-bit value from the lower half of the relocated address and put it in temp2. |
| 942 | sljit_emit_op1(compiler, SLJIT_MOV_S16, Registers::arithmetic_temp2, 0, Registers::arithmetic_temp1, 0); |
| 943 | |
| 944 | // Subtract the sign extended 16-bit value from the full address to get the HI16 value and place it in the destination. |
| 945 | sljit_emit_op2(compiler, SLJIT_SUB, dst, dstw, Registers::arithmetic_temp1, 0, Registers::arithmetic_temp2, 0); |
| 946 | return; |
| 947 | } |
| 948 | |
| 949 | sljit_s32 jit_op = SLJIT_BREAKPOINT; |
| 950 |
nothing calls this directly
no test coverage detected