feat(asm): add RVC compression for branches, arithmetic, and FP

Assisted-by: DeepSeek V4 Pro
This commit is contained in:
2026-08-03 01:08:00 +02:00
parent 243b087116
commit 7721353d44
4 changed files with 237 additions and 20 deletions
+148
View File
@@ -426,3 +426,151 @@ TEXT ·`+tt.name+`(SB), NOSPLIT, $0
})
}
}
func TestRISCV_RVC_branch(t *testing.T) {
// BEQ rs, X0, target → C.BEQZ when rs is in prime regs and offset fits.
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cbeqz(SB), NOSPLIT, $0
ADDI X10, $1, X10
BEQ X10, X0, done
ADDI X10, $1, X10
done:
RET
`)
code := assembleRISCVHelper(t, fn)
// C.ADDI(2) + C.BEQZ(2) + C.ADDI(2) + C.JR(2) = 8 (all compress)
if len(code) != 8 {
t.Errorf("expected 8 bytes with C.BEQZ, got %d", len(code))
}
}
func TestRISCV_RVC_CJ(t *testing.T) {
// JMP target → C.J when offset fits.
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cj(SB), NOSPLIT, $0
JMP done
done:
RET
`)
code := assembleRISCVHelper(t, fn)
// C.J(2) + C.JR(2) = 4
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.J, got %d", len(code))
}
}
func TestRISCV_RVC_CADD(t *testing.T) {
// ADD where rd==rs1 and both in prime regs → C.ADD.
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cadd(SB), NOSPLIT, $0
ADD X10, X11, X10
RET
`)
code := assembleRISCVHelper(t, fn)
// C.ADD(2) + C.JR(2) = 4
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.ADD, got %d", len(code))
}
}
func TestRISCV_RVC_CADD_commute(t *testing.T) {
// ADD where rd==rs2 (commutative swap) → C.ADD.
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cadd2(SB), NOSPLIT, $0
ADD X11, X10, X10
RET
`)
code := assembleRISCVHelper(t, fn)
// C.ADD(2) + C.JR(2) = 4
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.ADD (commuted), got %d", len(code))
}
}
func TestRISCV_RVC_CSUB(t *testing.T) {
// SUB where rd==rs1 and both in prime regs → C.SUB.
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·csub(SB), NOSPLIT, $0
SUB X11, X10, X10
RET
`)
code := assembleRISCVHelper(t, fn)
// SUB X11,X10,X10 → rd=X10, rs1=X11 ≠ rd → no C.SUB.
// Plan9: INSTR src1, src2, dst. For C.SUB: rd must equal rs1.
// So: SUB X10, X11, X10 → rd=10, rs1=10, rs2=11 ✓
if len(code) == 4 {
return // compressed
}
// Try with correct operand order.
fn2 := firstTextRISCV(t, `#include "textflag.h"
TEXT ·csub2(SB), NOSPLIT, $0
SUB X10, X11, X10
RET
`)
code2 := assembleRISCVHelper(t, fn2)
if len(code2) != 4 {
t.Errorf("expected 4 bytes with C.SUB, got %d (% x)", len(code2), code2)
}
}
func TestRISCV_RVC_CXOR(t *testing.T) {
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cxor(SB), NOSPLIT, $0
XOR X10, X11, X10
RET
`)
code := assembleRISCVHelper(t, fn)
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.XOR, got %d", len(code))
}
}
func TestRISCV_RVC_COR(t *testing.T) {
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cor(SB), NOSPLIT, $0
OR X10, X11, X10
RET
`)
code := assembleRISCVHelper(t, fn)
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.OR, got %d", len(code))
}
}
func TestRISCV_RVC_CAND(t *testing.T) {
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cand(SB), NOSPLIT, $0
AND X10, X11, X10
RET
`)
code := assembleRISCVHelper(t, fn)
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.AND, got %d", len(code))
}
}
func TestRISCV_RVC_CFLDSP(t *testing.T) {
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cfldsp(SB), NOSPLIT, $0-8
FLD a+0(FP), F10
RET
`)
code := assembleRISCVHelper(t, fn)
// C.FLDSP(2) + C.JR(2) = 4
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.FLDSP, got %d", len(code))
}
}
func TestRISCV_RVC_CFSDSP(t *testing.T) {
fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·cfsdsp(SB), NOSPLIT, $0-8
FSD F10, ret+0(FP)
RET
`)
code := assembleRISCVHelper(t, fn)
// C.FSDSP(2) + C.JR(2) = 4
if len(code) != 4 {
t.Errorf("expected 4 bytes with C.FSDSP, got %d", len(code))
}
}