Skip to content

Commit c084ef3

Browse files
authored
[RISC-V] R2RDump: revamp probing quirks (#118980)
Bring back `ProbeRiscV64Quirks` disabled in #117408, see #117408 (comment) for context. I reimplemented it to avoid iterating the instruction stream backwards, which is impossible with compressed instructions without keeping a backlog of seen instruction sizes. The new implementation recognizes only canonical `auipc + jalr/ld/addi` patterns. On one hand it introduces a temporary inconvenience of putting the cell name next to unnecessary `addi` instead of `ld/jalr` for patterns like this: ```asm 18ef20: 17 bf 44 01 auipc t5, 5195 18ef24: 13 0f 8f 45 addi t5, t5, 1112 // void Interop.ThrowExceptionForIoErrno(Interop+ErrorInfo, string, bool) (METHOD_ENTRY_DEF_TOKEN) 18ef28: 83 36 0f 00 ld a3, 0(t5) // <----- addi's immediate should go here instead 18ef2c: e7 80 06 00 jalr a3 ``` On the other hand, it is much simpler (one third of the original code size) and comments on all handles (e.g. strings), the hitherto implementation limited itself to only to calls. Compressed `jalr/ld/addi` are not recognized yet, they will be implemented as we teach JIT to emit these encodings. Part of #84834, cc @dotnet/samsung
1 parent 119baa9 commit c084ef3

File tree

1 file changed

+48
-148
lines changed

1 file changed

+48
-148
lines changed

src/coreclr/tools/r2rdump/CoreDisTools.cs

Lines changed: 48 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ internal sealed class Disassembler : IDisposable
131131
/// </summary>
132132
private int _addInstructionTarget;
133133

134+
/// <summary>
135+
/// RISC-V: temporary address for combos like "auipc temp, hi20; jalr/addi/ld rd, temp, lo12"
136+
/// </summary>
137+
private (uint Register, int Value) _address;
138+
134139
/// <summary>
135140
/// Indentation of instruction mnemonics.
136141
/// </summary>
@@ -358,7 +363,7 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
358363
break;
359364

360365
case Machine.RiscV64:
361-
// TODO-RISCV64-RVC: Add back ProbeRiscV64Quirks here once it's modified to support compressed instructions.
366+
ProbeRiscV64Quirks(rtf, imageOffset, rtfOffset, instrSize, ref fixedTranslatedLine);
362367
break;
363368

364369
default:
@@ -1217,178 +1222,73 @@ private static bool IsAnotherRuntimeFunctionWithinMethod(int rva, RuntimeFunctio
12171222
/// <param name="rtf">Runtime function</param>
12181223
/// <param name="imageOffset">Offset within the image byte array</param>
12191224
/// <param name="rtfOffset">Offset within the runtime function</param>
1225+
/// <param name="instrSize">Instruction size</param>
12201226
/// <param name="instruction">Textual representation of the instruction</param>
1221-
private void ProbeRiscV64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, ref string instruction)
1227+
private void ProbeRiscV64Quirks(RuntimeFunction rtf, int imageOffset, int rtfOffset, int instrSize, ref string instruction)
12221228
{
1223-
// TODO-RISCV64-RVC: Modify this method to detect patterns in forward traversal. See ProbeArm64Quirks implementation.
1224-
const int InstructionSize = 4;
1225-
uint instr = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
1229+
uint instr = (instrSize == 4)
1230+
? BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset)
1231+
: BitConverter.ToUInt16(_reader.Image, imageOffset + rtfOffset);
1232+
Debug.Assert((instrSize == 4) == ((instr & 0b11) == 0b11), "instruction size mismatch");
12261233

1227-
if (IsRiscV64JalrInstruction(instr))
1234+
// Lookup cell name for auipc + jalr/ld/addi
1235+
if (AnalyzeRiscV64Auipc(instr, ref _address.Register, out int imm))
12281236
{
1229-
/*
1230-
Supported patterns:
1231-
auipc
1232-
addi
1233-
ld
1234-
jalr
1235-
1236-
auipc
1237-
ld
1238-
jalr
1239-
1240-
auipc
1241-
addi
1242-
ld
1243-
ld
1244-
jalr
1245-
1246-
Irrelevant instructions for calle address calculations are skiped.
1247-
*/
1248-
1249-
AnalyzeRiscV64Itype(instr, out uint rd, out uint rs1, out int imm);
1250-
uint register = rs1;
1251-
int target = imm;
1252-
1253-
bool isFound = false;
1254-
int currentInstrOffset = rtfOffset - InstructionSize;
1255-
int currentPC = rtf.StartAddress + currentInstrOffset;
1256-
do
1257-
{
1258-
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);
1259-
1260-
if (IsRiscV64LdInstruction(instr))
1261-
{
1262-
AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
1263-
if (rd == register)
1264-
{
1265-
target = imm;
1266-
register = rs1;
1267-
}
1268-
}
1269-
else if (IsRiscV64AddiInstruction(instr))
1270-
{
1271-
AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
1272-
if (rd == register)
1273-
{
1274-
target =+ imm;
1275-
register = rs1;
1276-
}
1277-
}
1278-
else if (IsRiscV64AuipcInstruction(instr))
1279-
{
1280-
AnalyzeRiscV64Utype(instr, out rd, out imm);
1281-
if (rd == register)
1282-
{
1283-
target += currentPC + imm;
1284-
isFound = true;
1285-
break;
1286-
}
1287-
}
1288-
else
1289-
{
1290-
// check if callee address is calculated using an unsupported instruction
1291-
rd = (instr >> 7) & 0b_11111U;
1292-
if (rd == register)
1293-
{
1294-
break;
1295-
}
1296-
}
1297-
1298-
currentInstrOffset -= InstructionSize;
1299-
currentPC -= InstructionSize;
1300-
} while (currentInstrOffset > 0);
1301-
1302-
if (isFound)
1303-
{
1304-
if (!TryGetImportCellName(target, out string targetName) || string.IsNullOrWhiteSpace(targetName))
1305-
{
1306-
return;
1307-
}
1308-
1309-
instruction = $"{instruction} // {targetName}";
1310-
}
1237+
_address.Value = rtf.StartAddress + rtfOffset + imm;
1238+
return;
13111239
}
1240+
else if (_address.Register != 0 && AnalyzeRiscV64Itype(instr, _address.Register, out imm))
1241+
{
1242+
_address.Value += imm;
1243+
if (TryGetImportCellName(_address.Value, out string name) && !string.IsNullOrWhiteSpace(name))
1244+
instruction = $"{instruction} // {name}";
1245+
}
1246+
_address.Register = 0;
13121247
}
13131248

13141249
/// <summary>
1315-
/// Checks if instruction is auipc.
1316-
/// </summary>
1317-
/// <param name="instruction">Assembly code of instruction</param>
1318-
/// <returns>It returns true if instruction is auipc. Otherwise false</returns>
1319-
private bool IsRiscV64AuipcInstruction(uint instruction)
1320-
{
1321-
const uint OpcodeAuipc = 0b_0010111;
1322-
return (instruction & 0x7f) == OpcodeAuipc;
1323-
}
1324-
1325-
/// <summary>
1326-
/// Checks if instruction is jalr.
1327-
/// </summary>
1328-
/// <param name="instruction">Assembly code of instruction</param>
1329-
/// <returns>It returns true if instruction is jalr. Otherwise false</returns>
1330-
private bool IsRiscV64JalrInstruction(uint instruction)
1331-
{
1332-
const uint OpcodeJalr = 0b_1100111;
1333-
const uint Funct3Jalr = 0b_000;
1334-
return (instruction & 0x7f) == OpcodeJalr &&
1335-
((instruction >> 12) & 0b_111) == Funct3Jalr;
1336-
}
1337-
1338-
/// <summary>
1339-
/// Checks if instruction is addi.
1340-
/// </summary>
1341-
/// <param name="instruction">Assembly code of instruction</param>
1342-
/// <returns>It returns true if instruction is addi. Otherwise false</returns>
1343-
private bool IsRiscV64AddiInstruction(uint instruction)
1344-
{
1345-
const uint OpcodeAddi = 0b_0010011;
1346-
const uint Funct3Addi = 0b_000;
1347-
return (instruction & 0x7f) == OpcodeAddi &&
1348-
((instruction >> 12) & 0b_111) == Funct3Addi;
1349-
}
1350-
1351-
/// <summary>
1352-
/// Checks if instruction is ld.
1353-
/// </summary>
1354-
/// <param name="instruction">Assembly code of instruction</param>
1355-
/// <returns>It returns true if instruction is ld. Otherwise false</returns>
1356-
private bool IsRiscV64LdInstruction(uint instruction)
1357-
{
1358-
const uint OpcodeLd = 0b_0000011;
1359-
const uint Funct3Ld = 0b_011;
1360-
return (instruction & 0x7f) == OpcodeLd &&
1361-
((instruction >> 12) & 0b_111) == Funct3Ld;
1362-
}
1363-
1364-
/// <summary>
1365-
/// Retrieves output register and immediate value from U-type instruction.
1250+
/// Retrieves destination register and immediate value from an auipc instruction.
13661251
/// </summary>
13671252
/// <param name="instruction">Assembly code of instruction</param>
1368-
/// <param name="rd">Output register</param>
1253+
/// <param name="rd">Destination register</param>
13691254
/// <param name="imm">Immediate value</param>
1370-
private void AnalyzeRiscV64Utype(uint instruction, out uint rd, out int imm)
1255+
/// <returns>Whether the instruction is an auipc</returns>
1256+
private bool AnalyzeRiscV64Auipc(uint instruction, ref uint rd, out int imm)
13711257
{
13721258
// U-type 31 12 11 7 6 0
13731259
// [ imm ] [ rd ] [ opcode ]
1260+
const uint Auipc = 0b_0010111;
1261+
if ((instruction & 0x7f) != Auipc)
1262+
{
1263+
imm = 0;
1264+
return false;
1265+
}
13741266
rd = (instruction >> 7) & 0b_11111U;
13751267
imm = unchecked((int)(instruction & (0xfffff << 12)));
1268+
return true;
13761269
}
13771270

13781271
/// <summary>
1379-
/// Retrieves output register, resource register and immediate value from U-type instruction.
1272+
/// Retrieves immediate value from an I-type instruction that is interesting,
1273+
/// i.e. jalr, ld, addi with source register matching the address register.
13801274
/// </summary>
13811275
/// <param name="instruction">Assembly code of instruction</param>
1382-
/// <param name="rd">Output register</param>
1383-
/// <param name="rs1">Resource register</param>
1276+
/// <param name="addrReg">address register</param>
13841277
/// <param name="imm">Immediate value</param>
1385-
private void AnalyzeRiscV64Itype(uint instruction, out uint rd, out uint rs1, out int imm)
1278+
/// <returns>Whether the instruction is an interesting I-type</returns>
1279+
private bool AnalyzeRiscV64Itype(uint instruction, uint addrReg, out int imm)
13861280
{
13871281
// I-type 31 20 19 15 14 12 11 7 6 0
13881282
// [ imm ] [ rs1 ] [ funct3 ] [ rd ] [ opcode ]
1389-
rd = (instruction >> 7) & 0b_11111U;
1390-
rs1 = (instruction >> 15) & 0b_11111U;
1391-
imm = unchecked((int)instruction) >> 20;
1283+
const uint Mask = 0b_111_00000_1111111;
1284+
const uint Jalr = 0b_000_00000_1100111;
1285+
const uint Ld = 0b_011_00000_0000011;
1286+
const uint Addi = 0b_000_00000_0010011;
1287+
1288+
uint rs1 = (instruction >> 15) & 0b_11111U;
1289+
bool isInteresting = ((instruction & Mask) is Jalr or Ld or Addi) && (rs1 == addrReg);
1290+
imm = isInteresting ? unchecked((int)instruction) >> 20 : 0;
1291+
return isInteresting;
13921292
}
13931293

13941294
/// <summary>

0 commit comments

Comments
 (0)