diff --git a/src/coreclr/tools/r2rdump/CoreDisTools.cs b/src/coreclr/tools/r2rdump/CoreDisTools.cs
index f2ab02b1bd34c..2eefbdaa4ecd1 100644
--- a/src/coreclr/tools/r2rdump/CoreDisTools.cs
+++ b/src/coreclr/tools/r2rdump/CoreDisTools.cs
@@ -353,7 +353,7 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
break;
case Machine.LoongArch64:
- //TODO-LoongArch64: maybe should add ProbeLoongArch64Quirks. At least it's unused now.
+ ProbeLoongArch64Quirks(rtf, imageOffset, rtfOffset, ref fixedTranslatedLine);
break;
case Machine.ArmThumb2:
@@ -1392,6 +1392,212 @@ private void AnalyzeRiscV64Itype(uint instruction, out uint rd, out uint rs1, ou
imm = unchecked((int)instruction) >> 20;
}
+ ///
+ /// Improves disassembler output for LoongArch64.
+ ///
+ /// Runtime function
+ /// Offset within the image byte array
+ /// Offset within the runtime function
+ /// Textual representation of the instruction
+ private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, ref string instruction)
+ {
+ const int InstructionSize = 4;
+ uint instr = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
+
+ // The list of PC-relative instructions: BCond(BEQ, BNE, BLT[U], BGE[U]), BEQZ, BNEZ, BCEQZ, BCNEZ, B, BL, JIRL.
+
+ // Handle a B, BL, BCond(BEQ, BNE, BLT[U], BGE[U]), BZ(BEQZ, BNEZ, BCEQZ, BCNEZ) instruction
+ if (IsLoongArch64BCondInstruction(instr, out int offs) ||
+ IsLoongArch64BOrBlInstruction(instr, out offs) ||
+ IsLoongArch64BZInstruction(instr, out offs))
+ {
+ ReplaceRelativeOffset(ref instruction, rtf.StartAddress + rtfOffset + offs, rtf);
+ }
+ else if (IsLoongArch64JirlRAInstruction(instr, out uint rj, out int imm))
+ {
+ // Common Pattern:
+ // pcaddu12i
+ // ld.d
+ // jirl ra, rj, 0
+ //
+ // pcaddu12i
+ // addi.d
+ // ld.d
+ // jirl ra, rj, 0
+ // There may exist some irrelevant instructions between pcaddu12i and jirl.
+ // We need to find relevant instructions based on rj to calculate the jump address.
+ uint register = rj;
+ int immediate = imm;
+ bool isFound = false;
+ int currentInsOffs = rtfOffset - InstructionSize;
+ int currentPC = rtf.StartAddress + currentInsOffs;
+
+ do
+ {
+ instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInsOffs);
+
+ if (IsLoongArch64Ld_dOrAddi_dInstruction(instr, out uint rd, out rj, out imm))
+ {
+ if (rd == register)
+ {
+ register = rj;
+ immediate += imm;
+ }
+ }
+ else if (IsLoongArch64Pcaddu12iInstruction(instr, out rd, out imm))
+ {
+ if (rd == register)
+ {
+ immediate += currentPC + imm;
+ isFound = true;
+ break;
+ }
+ }
+ else
+ {
+ // check if target register is using by an unexpected instruction.
+ rd = (instr & 0x1f);
+ if ((rd == register) && !IsLoongArch64Fld_dInstruction(instr))
+ {
+ break;
+ }
+ }
+
+ currentInsOffs -= InstructionSize;
+ currentPC -= InstructionSize;
+ } while (currentInsOffs > 0);
+
+ if (isFound)
+ {
+ if (!TryGetImportCellName(immediate, out string targetName) || string.IsNullOrWhiteSpace(targetName))
+ {
+ return;
+ }
+
+ instruction = $"{instruction} // {targetName}";
+ }
+ }
+ }
+
+ ///
+ /// Determine whether a given instruction is a BCond(BEQ, BNE, BLT[U], BGE[U]).
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64BCondInstruction(uint ins, out int offs)
+ {
+ uint Opcode = (ins >> 26) & 0x3f;
+ offs = 0;
+ if ((Opcode == 0x16) || (Opcode == 0x17) || (Opcode == 0x18) || (Opcode == 0x19) || (Opcode == 0x1a) || (Opcode == 0x1b))
+ {
+ offs = (short)((ins >> 10) & 0xffff);
+ offs <<= 2;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a B or a BL.
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64BOrBlInstruction(uint ins, out int offs)
+ {
+ uint Opcode = (ins >> 26) & 0x3f;
+ offs = 0;
+ if ((Opcode == 0x14) || (Opcode == 0x15))
+ {
+ offs = (int)(((ins >> 10) & 0xffff) | ((ins & 0x3ff) << 16)) << 6;
+ offs >>= 4;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a BZ(BEQZ, BNEZ, BCEQZ, BCNEZ).
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64BZInstruction(uint ins, out int offs)
+ {
+ uint Opcode = (ins >> 26) & 0x3f;
+ offs = 0;
+ if ((Opcode == 0x10) || (Opcode == 0x11) || (Opcode == 0x12))
+ {
+ offs = (int)((((ins >> 10) & 0xffff) | ((ins & 0x1f) << 16)) << 11);
+ offs >>= 9;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a JIRL RA.
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64JirlRAInstruction(uint ins, out uint rj, out int offs)
+ {
+ rj = 0;
+ offs = 0;
+ if ((((ins >> 26) & 0x3f) == 0x13) && ((ins & 0x1f) == 1))
+ {
+ rj = (ins >> 5) & 0x1f;
+ offs = (short)((ins >> 10) & 0xffff);
+ offs <<= 2;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a PCADDU12I.
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64Pcaddu12iInstruction(uint ins, out uint rd, out int imm)
+ {
+ rd = 0;
+ imm = 0;
+ if (((ins >> 25) & 0x3f) == 0xe)
+ {
+ rd = ins & 0x1f;
+ imm = (int)((ins >> 5) & 0xfffff) << 12;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a LD.D or ADDI.D.
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64Ld_dOrAddi_dInstruction(uint ins, out uint rd, out uint rj, out int imm)
+ {
+ imm = 0;
+ rd = rj = 0;
+
+ if ((((ins >> 22) & 0x3ff) == 0xa3) || (((ins >> 22) & 0x3ff) == 0xb))
+ {
+ rd = ins & 0x1f;
+ rj = (ins >> 5) & 0x1f;
+ imm = (int)((ins >> 10) & 0xfff) << 20;
+ imm >>= 20;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Determine whether a given instruction is a FLD.D.
+ ///
+ /// Assembly code of instruction
+ private bool IsLoongArch64Fld_dInstruction(uint ins)
+ {
+ if (((ins >> 22) & 0x3ff) == 0xae)
+ {
+ return true;
+ }
+ return false;
+ }
+
///
/// Determine whether a given character is an ASCII digit.
///