Implement workaround for R5900's trunc.w.s issue

This commit is contained in:
angie 2023-04-16 10:05:01 -04:00
parent f6c72f0d29
commit 8a805123d4
12 changed files with 60 additions and 19 deletions

View File

@ -537,7 +537,6 @@ r5900_madda_s,
r5900_msuba_s,
r5900_max_s,
r5900_min_s,
r5900_trunc_w_s,
r5900_c_lt_s,
r5900_c_le_s,
r5900_qmfc2,

View File

@ -48,7 +48,14 @@ typedef struct RabbitizerConfig_ToolchainTweaks {
* However, the break it generates is different than the one it generates with `break N`
* So we replace break instrutions for SN64 with the exact word that the assembler generates when expanding div
*/
bool sn64DivFix;
bool sn64DivFix; //! @deprecated
/**
* Enables various tweaks to allow building matching with GNU as which
* break original compiler behavior and what's specified in the manuals.
*
* Turning this option off implies turning sn64DivFix on.
*/
bool gnuMode;
} RabbitizerConfig_ToolchainTweaks;
typedef struct RabbitizerConfig_Misc {

View File

@ -537,7 +537,6 @@ RABBITIZER_INSTR_ID_r5900_madda_s,
RABBITIZER_INSTR_ID_r5900_msuba_s,
RABBITIZER_INSTR_ID_r5900_max_s,
RABBITIZER_INSTR_ID_r5900_min_s,
RABBITIZER_INSTR_ID_r5900_trunc_w_s,
RABBITIZER_INSTR_ID_r5900_c_lt_s,
RABBITIZER_INSTR_ID_r5900_c_le_s,
RABBITIZER_INSTR_ID_r5900_qmfc2,

View File

@ -103,19 +103,6 @@ RABBITIZER_DEF_INSTR_ID_ALTNAME(
.readsFt=true
) // floating point MINimum
// Due to the R5900's FPU being non properly complaint the instruction cvt.w.s always behaves as trunc.w.s because is because EE can only do round-to-zero.
// Assemblers like GAS workaround this issue by decoding cvt.w.s as trunc.w.s, so we mimic that behaviour to allow assembling with GAS.
// Here's some reading about the binutils rationale:
// https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html
// https://sourceware.org/pipermail/binutils/2013-January/079863.html
RABBITIZER_DEF_INSTR_ID_ALTNAME(
r5900, 0x24, trunc_w_s, trunc.w.s,
.operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs},
.isFloat=true,
.modifiesFd=true,
.readsFs=true
) // Floating-Point Truncate to Word Fixed-Point
RABBITIZER_DEF_INSTR_ID_ALTNAME(
r5900, 0x34, c_lt_s, c.lt.s,
.operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft},

View File

@ -35,8 +35,9 @@ class _RabbitizerConfig:
pseudos_pseudoNegu: bool = True
pseudos_pseudoBal: bool = True
toolchainTweaks_sn64DivFix: bool = False
toolchainTweaks_treatJAsUnconditionalBranch: bool = False
toolchainTweaks_sn64DivFix: bool = False
toolchainTweaks_gnuMode: bool = True
misc_opcodeLJust: int = 11
misc_unknownInstrComment: bool = True

View File

@ -118,6 +118,7 @@ DEF_MEMBER_GET_SET_BOOL(pseudos, pseudoBal)
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, treatJAsUnconditionalBranch)
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, sn64DivFix)
DEF_MEMBER_GET_SET_BOOL(toolchainTweaks, gnuMode)
DEF_MEMBER_GET_SET_INT(misc, opcodeLJust, false, 0, 0)
DEF_MEMBER_GET_SET_BOOL(misc, unknownInstrComment)
@ -144,6 +145,7 @@ static PyGetSetDef rabbitizer_global_config_GetSets[] = {
MEMBER_GET_SET(toolchainTweaks, treatJAsUnconditionalBranch, "", NULL),
MEMBER_GET_SET(toolchainTweaks, sn64DivFix, "", NULL),
MEMBER_GET_SET(toolchainTweaks, gnuMode, "", NULL),
MEMBER_GET_SET(misc, opcodeLJust, "", NULL),
MEMBER_GET_SET(misc, unknownInstrComment, "", NULL),

View File

@ -35,6 +35,7 @@ pub struct PseudoInstr {
pub struct ToolchainTweaks {
pub treat_j_as_unconditional_branch: bool,
pub sn64_div_fix: bool,
pub gnu_mode: bool,
}
#[repr(C)]

View File

@ -40,6 +40,7 @@ RabbitizerConfig RabbitizerConfig_Cfg = {
.toolchainTweaks = {
.treatJAsUnconditionalBranch = true,
.sn64DivFix = false,
.gnuMode = true,
},
.misc = {
.opcodeLJust = 7+4,

View File

@ -537,7 +537,6 @@ const RabbitizerInstrDescriptor RabbitizerInstrDescriptor_Descriptors[] = {
[RABBITIZER_INSTR_ID_r5900_msuba_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
[RABBITIZER_INSTR_ID_r5900_max_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .modifiesFd=true, .readsFs=true, .readsFt=true },
[RABBITIZER_INSTR_ID_r5900_min_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .modifiesFd=true, .readsFs=true, .readsFt=true },
[RABBITIZER_INSTR_ID_r5900_trunc_w_s] = { .operands={RAB_OPERAND_cpu_fd, RAB_OPERAND_cpu_fs}, .isFloat=true, .modifiesFd=true, .readsFs=true },
[RABBITIZER_INSTR_ID_r5900_c_lt_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
[RABBITIZER_INSTR_ID_r5900_c_le_s] = { .operands={RAB_OPERAND_cpu_fs, RAB_OPERAND_cpu_ft}, .isFloat=true, .readsFs=true, .readsFt=true },
[RABBITIZER_INSTR_ID_r5900_qmfc2] = { .operands={RAB_OPERAND_cpu_rt, RAB_OPERAND_r5900_vfs}, .modifiesRt=true },

View File

@ -537,7 +537,6 @@ const char *RabbitizerInstrId_Names[] = {
[RABBITIZER_INSTR_ID_r5900_msuba_s] = "msuba.s",
[RABBITIZER_INSTR_ID_r5900_max_s] = "max.s",
[RABBITIZER_INSTR_ID_r5900_min_s] = "min.s",
[RABBITIZER_INSTR_ID_r5900_trunc_w_s] = "trunc.w.s",
[RABBITIZER_INSTR_ID_r5900_c_lt_s] = "c.lt.s",
[RABBITIZER_INSTR_ID_r5900_c_le_s] = "c.le.s",
[RABBITIZER_INSTR_ID_r5900_qmfc2] = "qmfc2",

View File

@ -2,6 +2,7 @@
/* SPDX-License-Identifier: MIT */
#include "instructions/RabbitizerInstructionR5900.h"
#include "common/RabbitizerConfig.h"
#define RABBITIZER_DEF_INSTR_ID(prefix, caseBits, name, ...) \
case (caseBits): \
@ -132,6 +133,36 @@ void RabbitizerInstructionR5900_processUniqueId_Coprocessor1_FpuS(RabbitizerInst
RabbitizerInstruction_processUniqueId_Coprocessor1_FpuS(self);
break;
}
if (RabbitizerConfig_Cfg.toolchainTweaks.gnuMode) {
switch (self->uniqueId) {
case RABBITIZER_INSTR_ID_cpu_trunc_w_s:
case RABBITIZER_INSTR_ID_cpu_cvt_w_s:
/**
* Due to the R5900's FPU being non properly complaint, the instruction cvt.w.s always behaves as
* trunc.w.s because EE can only do round-to-zero.
*
* Assemblers like GAS workaround this issue by decoding cvt.w.s as trunc.w.s, but other assemblers just
* use trunc.w.s and cvt.w.s as-is.
*
* Here's some reading about the binutils rationale:
* - https://sourceware.org/legacy-ml/binutils/2012-11/msg00360.html
* - https://sourceware.org/pipermail/binutils/2013-January/079863.html
*
* Because of this, building with GAS with the -march=r5900 flag produces:
* - trunc.w.s is built as the cvt.w.s instruction.
* - cvt.w.s errors complaining as not being supported by the processor.
*
* To ensure the produced disassembly will still match when built with GAS, we decode this two
* instructions as .word
*/
self->_mandatorybits = 0x0;
break;
default:
break;
}
}
}
void RabbitizerInstructionR5900_processUniqueId_Coprocessor1(RabbitizerInstruction *self) {

View File

@ -0,0 +1,15 @@
.set noreorder
.section .text
.global test
trunc.w.s $f0, $f12
jr $31
nop
.global test2
cvt.w.s $f0, $f12
jr $31
nop