Joel Sing would like Meng Zhuo and Mark Ryan to review this change.
cmd/internal/obj/riscv: use compressed control transfer instructions
Where possible, make use of compressed control transfer instructions
with immediate encodings (CBEQZ, CBNEZ, CJ). Since the use of these
instructions is conditioned on the size of the offset, we need to
compute the offsets earlier than we do currently. Additionally, if
the offsets change during processing, then we need to rescan as
additional compressed control transfer instructions may be used.
Fixes #71105
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 1175e0e..bb67af0a 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -676,6 +676,37 @@
big = true
}
+ if ctxt.CompressInstructions {
+ for p := cursym.Func().Text; p != nil; p = p.Link {
+ switch p.As {
+ case ABEQZ, ABNEZ:
+ if p.To.Type == obj.TYPE_BRANCH {
+ offset := p.To.Target().Pc - p.Pc
+ if offset != p.To.Offset {
+ rescan = true
+ }
+ p.To.Offset = offset
+ }
+
+ case AJAL:
+ if p.To.Target() != nil {
+ offset := p.To.Target().Pc - p.Pc
+ if offset != p.To.Offset {
+ rescan = true
+ }
+ p.To.Offset = offset
+ }
+ }
+ }
+
+ if ctxt.Errors > 0 {
+ return
+ }
+ if rescan {
+ continue
+ }
+ }
+
for p := cursym.Func().Text; p != nil; p = p.Link {
switch p.As {
case ABEQ, ABEQZ, ABGE, ABGEU, ABGEZ, ABGT, ABGTU, ABGTZ, ABLE, ABLEU, ABLEZ, ABLT, ABLTU, ABLTZ, ABNE, ABNEZ, ACBEQZ, ACBNEZ, ACJ:
@@ -3569,6 +3600,13 @@
ins.as, ins.rd, ins.rs1, ins.rs2 = ACFSD, obj.REG_NONE, ins.rd, ins.rs1
}
+ case AJAL:
+ if ins.imm != 0 && isScaledImmI(ins.imm, 12, 2) {
+ if ins.rd == REG_X0 {
+ ins.as = ACJ
+ }
+ }
+
case AJALR:
if ins.rs1 != REG_X0 && ins.imm == 0 {
if ins.rd == REG_X0 {
@@ -3578,6 +3616,16 @@
}
}
+ case ABEQ:
+ if ins.rs1 == REG_X0 && isIntPrimeReg(ins.rs2) && ins.imm != 0 && isScaledImmI(ins.imm, 9, 2) {
+ ins.as, ins.rs1, ins.rs2 = ACBEQZ, ins.rs2, obj.REG_NONE
+ }
+
+ case ABNE:
+ if ins.rs1 == REG_X0 && isIntPrimeReg(ins.rs2) && ins.imm != 0 && isScaledImmI(ins.imm, 9, 2) {
+ ins.as, ins.rs1, ins.rs2 = ACBNEZ, ins.rs2, obj.REG_NONE
+ }
+
case AADDI:
if ins.rd == REG_SP && ins.rs1 == REG_SP && ins.imm != 0 && isScaledImmI(ins.imm, 10, 16) {
ins.as = ACADDI16SP
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Removed LUCI-TryBot-Result-1 by Go LUCI <golang...@luci-project-accounts.iam.gserviceaccount.com>
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
case ABEQZ, ABNEZ:I think we might need an explicit check for
```
BEQ rs1, x0, offset
```
and
```
BNE rs1, x0, offset
```
here. I'm seeing an error assembling the following function.
https://github.com/golang/go/blob/master/src/runtime/sys_linux_riscv64.s#L379
```
TEXT runtime.sigtramp.abi0(SB) /Users/home/code/go/src/runtime/sys_linux_riscv64.s
sys_linux_riscv64.s:379 0x813d0 fa113c23 MOV X1, -72(X2)
sys_linux_riscv64.s:379 0x813d4 fb810113 ADDI $-72, X2, X2
sys_linux_riscv64.s:379 0x813d8 06e0 MOV X1, (X2)
sys_linux_riscv64.s:380 0x813da 2ac4 MOVW X10, 8(X2)
sys_linux_riscv64.s:381 0x813dc 2ee8 MOV X11, 16(X2)
sys_linux_riscv64.s:382 0x813de 32ec MOV X12, 24(X2)
sys_linux_riscv64.s:386 0x813e0 002a5517 AUIPC $677, X10
sys_linux_riscv64.s:386 0x813e4 3e454503 MOVBU 996(X10), X10
sys_linux_riscv64.s:387 0x813e8 01c5 BEQZ X10, 2(PC)
sys_linux_riscv64.s:387 0x813ea 0000 UNIMP
sys_linux_riscv64.s:388 0x813ec 164000ef CALL runtime.load_g.abi0(SB)
sys_linux_riscv64.s:390 0x813f0 00000517 AUIPC $0, X10
sys_linux_riscv64.s:390 0x813f4 4e050513 ADDI $1248, X10, X10
sys_linux_riscv64.s:391 0x813f8 0295 CALL (X10)
sys_linux_riscv64.s:392 0x813fa 8260 MOV (X2), X1
sys_linux_riscv64.s:392 0x813fc 04810113 ADDI $72, X2, X2
sys_linux_riscv64.s:392 0x81400 8280 RET
```
Notice the UNIMP.
If I modify the original assembly code (https://github.com/golang/go/blob/master/src/runtime/sys_linux_riscv64.s#L387) to change
```
BEQ A0, ZERO, 2(PC)
```
to
```
BEQZ A0, 2(PC)
```
Then I get
```
TEXT runtime.sigtramp.abi0(SB) /Users/home/code/go/src/runtime/sys_linux_riscv64.s
sys_linux_riscv64.s:379 0x813d0 fa113c23 MOV X1, -72(X2)
sys_linux_riscv64.s:379 0x813d4 fb810113 ADDI $-72, X2, X2
sys_linux_riscv64.s:379 0x813d8 06e0 MOV X1, (X2)
sys_linux_riscv64.s:380 0x813da 2ac4 MOVW X10, 8(X2)
sys_linux_riscv64.s:381 0x813dc 2ee8 MOV X11, 16(X2)
sys_linux_riscv64.s:382 0x813de 32ec MOV X12, 24(X2)
sys_linux_riscv64.s:386 0x813e0 002a5517 AUIPC $677, X10
sys_linux_riscv64.s:386 0x813e4 3e454503 MOVBU 996(X10), X10
sys_linux_riscv64.s:387 0x813e8 19c1 BEQZ X10, 1(PC)
sys_linux_riscv64.s:388 0x813ea 15e000ef CALL runtime.load_g.abi0(SB)
sys_linux_riscv64.s:390 0x813ee 00000517 AUIPC $0, X10
sys_linux_riscv64.s:390 0x813f2 4da50513 ADDI $1242, X10, X10
sys_linux_riscv64.s:391 0x813f6 0295 CALL (X10)
sys_linux_riscv64.s:392 0x813f8 8260 MOV (X2), X1
sys_linux_riscv64.s:392 0x813fa 04810113 ADDI $72, X2, X2
sys_linux_riscv64.s:392 0x813fe 8280 RET
```
and everything looks good.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Well I say everything looks good but actually the disassembly isn't quite right. We see BEQZ X10, 1(PC) instead of BEQZ X10, 2(PC). The generated machine code looks fine. So there may be a little bit of work to do on the disassembler after all.
case AJAL:Any reason to disallow the compression if the offset is 0? I don't see anything in the specs prohibiting this. Same comment for the branches.