[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

[RISC-V] Add quirks for riscv to R2RDump - #101683

Merged
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv
May 16, 2024
Merged

[RISC-V] Add quirks for riscv to R2RDump#101683
jkotas merged 5 commits into
dotnet:mainfrom
SzpejnaDawid:r2rdumpriscv

Conversation

@SzpejnaDawid

Copy link
Copy Markdown
Contributor

This PR adds a functionality ProbeRiscV64Quirks(...) to R2RDump in order to provide target function labels in the form of comments at the end of any jalr instructions. it mimics a similar solution for x64 and arm.

Part of #84834, cc @dotnet/samsung

@ghostghost added the area-R2RDump-coreclr Ready-to-run image dump tool label Apr 29, 2024
@dotnet-policy-servicedotnet-policy-serviceBot added the community-contribution Indicates that the PR has been added by a community member label Apr 29, 2024
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

@dotnet-policy-service agree company="Samsung"

@am11

am11 commented Apr 29, 2024

Copy link
Copy Markdown
Member

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@clamp03clamp03 added the arch-riscv Related to the RISC-V architecture label Apr 30, 2024

@clamp03clamp03 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you test this PR? Thank you.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
@LuckyXu-HF

Copy link
Copy Markdown
Contributor

cc @LuckyXu-HF, @shushanhf LA64 could use a similar approach.

Thanks so much for remind us! We will implement it next week as we will start a holiday tomorrow.
(Currently we left a TODO-LoongArch64 note for ProbeLoongArch64Quirks() as we temporarily not using this function. Anyway, we will need this sooner or later.)

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs
@SzpejnaDawid

Copy link
Copy Markdown
ContributorAuthor

How do you test this PR? Thank you.

It wasn't straightforward so i tested it manually. I crossgened four libraries (incl. System.Private.CoreLib.dll) for riscv64 and x64 and compared calle's names between r2rdumps. r2rdumps files for x64 have more comments than riscv64 because mov instructions are also labeled. I only compared call and jalr instructions.

auipc
addi
ld
jarl

@clamp03clamp03May 2, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update jarl to jalr.
Can you share code locations in runtime where you checked the patterns?

+ Please don't force-push. #100962 (comment)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no a strict line of code which checks this pattern.

Function ProbeRiscV64Quirks is looking for jalr instruction. If it finds it, then it goes back through the assembly code to calculate callee address. It is more analytical approach, than the fixed pattern. Unfortunately, instructions calculating this address do not always follow each other, sometimes unrelated instruction appears between them. Other problem was with multiple-wrapped calle, then more than one ld or lw are used to calculate callee address.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. you cannot give codes in runtime for the patterns.
However, in other archs, their implementation is different from yours. And it looks like they have some strict patterns.
And if this code should be checked manually without any tests, I cannot review whether this is correct implementation or not.
More, I don't know well about r2rdump. I am so sorry.

@jkotas@ivdiazsa Could you review this PR?
Thank you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know well about r2rdump

The point of this code in r2rdump is to make the disassembly output more human readable. Nothing in the rest of the runtime depends on it. There are no hard and fast rules for how it should behave.

@SzpejnaDawid Could you please share some examples for what the output looks like with this change, including the problematic cases like more than one ld or lw are used?

@SzpejnaDawidSzpejnaDawidMay 9, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that System.Private.CoreLib.dll has some interesting examples:

System.Exception Interop.GetExceptionForIoErrno(Interop+ErrorInfo, string, bool)
...
14811c: 00e00397 auipc t2, 3584
148120: f443b383 ld t2, -188(t2)
148124: 000380e7 jalr t2 // WRITE_BARRIER (HELPER)
...
148528: 00e0cf17 auipc t5, 3596
14852c: 550f0f13 addi t5, t5, 1360
148530: 00000593 li a1, 0
148534: 000f3603 ld a2, 0(t5)
148538: 000600e7 jalr a2 // System.Exception Interop.GetIOException(Interop+ErrorInfo, string) (METHOD_ENTRY_DEF_TOKEN)
...
148840: 00e10f17 auipc t5, 3600
148844: a20f0f13 addi t5, t5, -1504
148848: 000f3583 ld a1, 0(t5)
14884c: 000580e7 jalr a1 // string System.SR.GetResourceString(string) (METHOD_ENTRY_DEF_TOKEN)
...
int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // int Interop+Globalization.<GetCalendars>g____PInvoke|0_0(ushort*, System.Globalization.CalendarId*, int) (INDIRECT_PINVOKE_TARGET)

I know that my way of calculation callee address is not fixed as for arm. Nevertheless, the only way to be sure how jumps are generated is to read a code of coregen2 in order to see how it generates riscv instructions. But the profit and loss ratio of this approach is unfavorable, imo.

Comment threadsrc/coreclr/tools/r2rdump/CoreDisTools.cs Outdated
{
instr = BitConverter.ToUInt32(_reader.Image, imageOffset + currentInstrOffset);

if (IsRiscV64LdInstruction(instr) || IsRiscV64LwInstruction(instr))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am just curious. In your examples, check for lw instruction is not necessary. Could you give an example with lw instruction? Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i know there is no function call which uses lw to calculate jump address. However, this check for lw is necessary because this first if is trying to skip all ld and lw instructions which are used to push arguments (likely). For example

int Interop+Globalization.GetCalendars(string, System.Globalization.CalendarId[], int)
...
14935c: 00e22517 auipc a0, 3618
149360: c5450513 addi a0, a0, -940
149364: 00053503 ld a0, 0(a0)
149368: 00053683 ld a3, 0(a0)
14936c: fe443503 ld a0, -28(s0)
149370: fec42603 lw a2, -20(s0)
149374: fdc43583 ld a1, -36(s0)
149378: fd443f03 ld t5, -44(s0)
14937c: 000680e7 jalr a3 // <calle name>
....
bool Interop+Globalization.EnumCalendarInfo(IntPtr, string, System.Globalization.CalendarId, System.Globalization.CalendarDataType, IntPtr)n
...
149470: 00e22517 auipc a0, 3618
149474: b5050513 addi a0, a0, -1200
149478: 00053503 ld a0, 0(a0)
14947c: 00053783 ld a5, 0(a0)
149480: fe843583 ld a1, -24(s0)
149484: ff442603 lw a2, -12(s0)
149488: fe043503 ld a0, -32(s0)
14948c: fd843703 ld a4, -40(s0)
149490: ff042683 lw a3, -16(s0)
149494: fd043f03 ld t5, -48(s0)
149498: 000780e7 jalr a5 // <calle name>
...
void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>
...
int Interop+Globalization.CompareString(IntPtr, char*, int, char*, int, System.Globalization.CompareOptions)
...
149aa4: 00e21517 auipc a0, 3617
149aa8: 4bc50513 addi a0, a0, 1212
149aac: 00053503 ld a0, 0(a0)
149ab0: 00053803 ld a6, 0(a0)
149ab4: ffc42783 lw a5, -4(s0)
149ab8: fec43503 ld a0, -20(s0)
149abc: fe443583 ld a1, -28(s0)
149ac0: ff842603 lw a2, -8(s0)
149ac4: fdc43683 ld a3, -36(s0)
149ac8: ff442703 lw a4, -12(s0)
149acc: fd443f03 ld t5, -44(s0)
149ad0: 000800e7 jalr a6 // <calle name>

As you can see, the sequence of lw and ld instructions is not fixed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well. IMO, lw instructions can be skipped in line 1334 in StaticAnalyzeRiscV64Assembly. Am I wrong?

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;
if (rd == register)
{
return false;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we want to skip lw in StaticAnalyzeRiscV64Assembly, we will have to skip ld too. In other case, we would have a problem, for example, with this:

void Interop+Globalization.InitOrdinalCasingPage(int, char*)
...
149634: 00e22517 auipc a0, 3618
149638: 91c50513 addi a0, a0, -1764
14963c: 00053503 ld a0, 0(a0)
149640: 00053603 ld a2, 0(a0)
149644: ff443583 ld a1, -12(s0)
149648: ffc42503 lw a0, -4(s0)
14964c: fec43f03 ld t5, -20(s0)
149650: 000600e7 jalr a2 // <calle name>

@clamp03clamp03May 14, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. You are right. However, actually what I want are removing 'lw' and implementing simpler like #102146. Could you check loongarch PR and share your idea? Thank you.

@SzpejnaDawidSzpejnaDawidMay 14, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simplified code which calculates callee address

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no problem :D

else
{
// check if "register" is calculated using an unsupported instruction
uint rd = (instr >> 7) & 0b_11111U;

@clamp03clamp03May 13, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If instr is BType, JType or SType like sd which 11-7 bits are offset. It can return false when immediate value is same to register. I think this pattern is not produced in our runtime. I just want to check it is intended?
Thank you.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my honest opinion, i have never seen a situation when an instruction, like sd, would broke the pattern which is acceptable by ProbeRiscV64Quirks(...). So I assume that it is not produced in the runtime.

AnalyzeRiscV64Itype(instr, out rd, out rs1, out imm);
if (rd == register)
{
target =+ imm;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Have you seen a pattern which needs addition for addi instruction? IMO, it doesn't generate two addis for an address calculation. And it doesn't need both immediate values in ld and addi because ld and addi has the same bit size (signed 12 bits) for immediate value.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are patterns which use addi. You can find them here, link. As you can see, last three examples show patterns which use addi. Only the first one uses ld to add an immediate value instead of addi

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean you don't need target += imm. target = imm is enough because address is calculated with imm in auipc and one imm in ld or addi in patterns. If I am wrong, please let me know

@SzpejnaDawidSzpejnaDawidMay 16, 2024

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you that target = imm is enough. My explanation for target += imm is that i wanted to cover even those patterns which could exist and i didn't meet them. If you think that we shouldn't worry so much for the future I can change it to target = imm

@clamp03clamp03May 16, 2024

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, we don't need to worry such cases. If there are such cases, it is a bug we need to fix or optimization candidates. :)
If target already has a value when we check addi, it means a value is set from other addi or ld before.

  • We don't need to generate multiple addi for an address calculation.
  • And ld and addi have the same offset bits. So addi is redundant code in case of that target is set by ld before.

However, if you want, you can leave it. That is what I set it a Nit.
Thank you.

@jkotasjkotas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you

@jkotas
jkotas merged commit dafaf4a into dotnet:mainMay 16, 2024
Ruihan-Yin pushed a commit to Ruihan-Yin/runtime that referenced this pull request May 30, 2024
* [RISC-V] Add quirks for riscv
* [RISC-V] minimize code
@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jun 16, 2024
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

arch-riscvRelated to the RISC-V architecturearea-R2RDump-coreclrReady-to-run image dump toolcommunity-contributionIndicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@SzpejnaDawid@am11@LuckyXu-HF@tomeksowi@clamp03@jkotas