Skip to content

Commit af11dbc

Browse files
LuckyXu-HFam11
andauthored
[LoongArch64] Add ProbeLoongArch64Quirks() for R2RDump tool. (#102146)
* [LoongArch64] Add ProbeLoongArch64Quirks() for R2RDump tool. * Update src/coreclr/tools/r2rdump/CoreDisTools.cs Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --------- Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com>
1 parent 6943160 commit af11dbc

File tree

1 file changed

+207
-1
lines changed

1 file changed

+207
-1
lines changed

src/coreclr/tools/r2rdump/CoreDisTools.cs

Lines changed: 207 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
353353
break;
354354

355355
case Machine.LoongArch64:
356-
//TODO-LoongArch64: maybe should add ProbeLoongArch64Quirks. At least it's unused now.
356+
ProbeLoongArch64Quirks(rtf, imageOffset, rtfOffset, ref fixedTranslatedLine);
357357
break;
358358

359359
case Machine.ArmThumb2:
@@ -1392,6 +1392,212 @@ private void AnalyzeRiscV64Itype(uint instruction, out uint rd, out uint rs1, ou
13921392
imm = unchecked((int)instruction) >> 20;
13931393
}
13941394

1395+
/// <summary>
1396+
/// Improves disassembler output for LoongArch64.
1397+
/// </summary>
1398+
/// <param name="rtf">Runtime function</param>
1399+
/// <param name="imageOffset">Offset within the image byte array</param>
1400+
/// <param name="rtfOffset">Offset within the runtime function</param>
1401+
/// <param name="instruction">Textual representation of the instruction</param>
1402+
private void ProbeLoongArch64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, ref string instruction)
1403+
{
1404+
const int InstructionSize = 4;
1405+
uint instr = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
1406+
1407+
// The list of PC-relative instructions: BCond(BEQ, BNE, BLT[U], BGE[U]), BEQZ, BNEZ, BCEQZ, BCNEZ, B, BL, JIRL.
1408+
1409+
// Handle a B, BL, BCond(BEQ, BNE, BLT[U], BGE[U]), BZ(BEQZ, BNEZ, BCEQZ, BCNEZ) instruction
1410+
if (IsLoongArch64BCondInstruction(instr, out int offs) ||
1411+
IsLoongArch64BOrBlInstruction(instr, out offs) ||
1412+
IsLoongArch64BZInstruction(instr, out offs))
1413+
{
1414+
ReplaceRelativeOffset(ref instruction, rtf.StartAddress + rtfOffset + offs, rtf);
1415+
}
1416+
else if (IsLoongArch64JirlRAInstruction(instr, out uint rj, out int imm))
1417+
{
1418+
// Common Pattern:
1419+
// pcaddu12i
1420+
// ld.d
1421+
// jirl ra, rj, 0
1422+
//
1423+
// pcaddu12i
1424+
// addi.d
1425+
// ld.d
1426+
// jirl ra, rj, 0
1427+
// There may exist some irrelevant instructions between pcaddu12i and jirl.
1428+
// We need to find relevant instructions based on rj to calculate the jump address.
1429+
uint register = rj;
1430+
int immediate = imm;
1431+
bool isFound = false;
1432+
int currentInsOffs = rtfOffset - InstructionSize;
1433+
int currentPC = rtf.StartAddress + currentInsOffs;
1434+
1435+
do
1436+
{
1437+
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInsOffs);
1438+
1439+
if (IsLoongArch64Ld_dOrAddi_dInstruction(instr, out uint rd, out rj, out imm))
1440+
{
1441+
if (rd == register)
1442+
{
1443+
register = rj;
1444+
immediate += imm;
1445+
}
1446+
}
1447+
else if (IsLoongArch64Pcaddu12iInstruction(instr, out rd, out imm))
1448+
{
1449+
if (rd == register)
1450+
{
1451+
immediate += currentPC + imm;
1452+
isFound = true;
1453+
break;
1454+
}
1455+
}
1456+
else
1457+
{
1458+
// check if target register is using by an unexpected instruction.
1459+
rd = (instr & 0x1f);
1460+
if ((rd == register) && !IsLoongArch64Fld_dInstruction(instr))
1461+
{
1462+
break;
1463+
}
1464+
}
1465+
1466+
currentInsOffs -= InstructionSize;
1467+
currentPC -= InstructionSize;
1468+
} while (currentInsOffs > 0);
1469+
1470+
if (isFound)
1471+
{
1472+
if (!TryGetImportCellName(immediate, out string targetName) || string.IsNullOrWhiteSpace(targetName))
1473+
{
1474+
return;
1475+
}
1476+
1477+
instruction = $"{instruction} // {targetName}";
1478+
}
1479+
}
1480+
}
1481+
1482+
/// <summary>
1483+
/// Determine whether a given instruction is a BCond(BEQ, BNE, BLT[U], BGE[U]).
1484+
/// </summary>
1485+
/// <param name="ins">Assembly code of instruction</param>
1486+
private bool IsLoongArch64BCondInstruction(uint ins, out int offs)
1487+
{
1488+
uint Opcode = (ins >> 26) & 0x3f;
1489+
offs = 0;
1490+
if ((Opcode == 0x16) || (Opcode == 0x17) || (Opcode == 0x18) || (Opcode == 0x19) || (Opcode == 0x1a) || (Opcode == 0x1b))
1491+
{
1492+
offs = (short)((ins >> 10) & 0xffff);
1493+
offs <<= 2;
1494+
return true;
1495+
}
1496+
return false;
1497+
}
1498+
1499+
/// <summary>
1500+
/// Determine whether a given instruction is a B or a BL.
1501+
/// </summary>
1502+
/// <param name="ins">Assembly code of instruction</param>
1503+
private bool IsLoongArch64BOrBlInstruction(uint ins, out int offs)
1504+
{
1505+
uint Opcode = (ins >> 26) & 0x3f;
1506+
offs = 0;
1507+
if ((Opcode == 0x14) || (Opcode == 0x15))
1508+
{
1509+
offs = (int)(((ins >> 10) & 0xffff) | ((ins & 0x3ff) << 16)) << 6;
1510+
offs >>= 4;
1511+
return true;
1512+
}
1513+
return false;
1514+
}
1515+
1516+
/// <summary>
1517+
/// Determine whether a given instruction is a BZ(BEQZ, BNEZ, BCEQZ, BCNEZ).
1518+
/// </summary>
1519+
/// <param name="ins">Assembly code of instruction</param>
1520+
private bool IsLoongArch64BZInstruction(uint ins, out int offs)
1521+
{
1522+
uint Opcode = (ins >> 26) & 0x3f;
1523+
offs = 0;
1524+
if ((Opcode == 0x10) || (Opcode == 0x11) || (Opcode == 0x12))
1525+
{
1526+
offs = (int)((((ins >> 10) & 0xffff) | ((ins & 0x1f) << 16)) << 11);
1527+
offs >>= 9;
1528+
return true;
1529+
}
1530+
return false;
1531+
}
1532+
1533+
/// <summary>
1534+
/// Determine whether a given instruction is a JIRL RA.
1535+
/// </summary>
1536+
/// <param name="ins">Assembly code of instruction</param>
1537+
private bool IsLoongArch64JirlRAInstruction(uint ins, out uint rj, out int offs)
1538+
{
1539+
rj = 0;
1540+
offs = 0;
1541+
if ((((ins >> 26) & 0x3f) == 0x13) && ((ins & 0x1f) == 1))
1542+
{
1543+
rj = (ins >> 5) & 0x1f;
1544+
offs = (short)((ins >> 10) & 0xffff);
1545+
offs <<= 2;
1546+
return true;
1547+
}
1548+
return false;
1549+
}
1550+
1551+
/// <summary>
1552+
/// Determine whether a given instruction is a PCADDU12I.
1553+
/// </summary>
1554+
/// <param name="ins">Assembly code of instruction</param>
1555+
private bool IsLoongArch64Pcaddu12iInstruction(uint ins, out uint rd, out int imm)
1556+
{
1557+
rd = 0;
1558+
imm = 0;
1559+
if (((ins >> 25) & 0x3f) == 0xe)
1560+
{
1561+
rd = ins & 0x1f;
1562+
imm = (int)((ins >> 5) & 0xfffff) << 12;
1563+
return true;
1564+
}
1565+
return false;
1566+
}
1567+
1568+
/// <summary>
1569+
/// Determine whether a given instruction is a LD.D or ADDI.D.
1570+
/// </summary>
1571+
/// <param name="ins">Assembly code of instruction</param>
1572+
private bool IsLoongArch64Ld_dOrAddi_dInstruction(uint ins, out uint rd, out uint rj, out int imm)
1573+
{
1574+
imm = 0;
1575+
rd = rj = 0;
1576+
1577+
if ((((ins >> 22) & 0x3ff) == 0xa3) || (((ins >> 22) & 0x3ff) == 0xb))
1578+
{
1579+
rd = ins & 0x1f;
1580+
rj = (ins >> 5) & 0x1f;
1581+
imm = (int)((ins >> 10) & 0xfff) << 20;
1582+
imm >>= 20;
1583+
return true;
1584+
}
1585+
return false;
1586+
}
1587+
1588+
/// <summary>
1589+
/// Determine whether a given instruction is a FLD.D.
1590+
/// </summary>
1591+
/// <param name="ins">Assembly code of instruction</param>
1592+
private bool IsLoongArch64Fld_dInstruction(uint ins)
1593+
{
1594+
if (((ins >> 22) & 0x3ff) == 0xae)
1595+
{
1596+
return true;
1597+
}
1598+
return false;
1599+
}
1600+
13951601
/// <summary>
13961602
/// Determine whether a given character is an ASCII digit.
13971603
/// </summary>

0 commit comments

Comments
 (0)