fix(asm): match RISC-V branch and jump encodings
This commit is contained in:
+11
-35
@@ -203,7 +203,8 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
word = riscvIType(riscvEnc{0x13, 0x0, 0x00}, 0, 0, 0)
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
case "JMP":
|
||||
// JMP = JAL X0, target. Try C.J compression.
|
||||
// JMP = JAL X0, target. The Go assembler never compresses this to
|
||||
// C.J, so always emit the 32-bit JAL.
|
||||
var target string
|
||||
if len(ops) >= 1 {
|
||||
target = labelFromOperand(ops[0])
|
||||
@@ -213,11 +214,6 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
return nil, fmt.Errorf("undefined label %q%s", target, suggestLabel(target, offsets))
|
||||
}
|
||||
offset := int32(targetOff - pc)
|
||||
// C.J: funct3=0x5, offset in ±2 KB, bit 0 must be 0.
|
||||
if offset >= -2048 && offset <= 2046 && offset%2 == 0 {
|
||||
c16 := rvcCJ(0x5, offset)
|
||||
return []byte{byte(c16), byte(c16 >> 8)}, nil
|
||||
}
|
||||
word = riscvJType(0, offset)
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
case "JAL":
|
||||
@@ -234,11 +230,6 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
return nil, fmt.Errorf("undefined label %q%s", target, suggestLabel(target, offsets))
|
||||
}
|
||||
offset := int32(targetOff - pc)
|
||||
// JAL X0, target → C.J when offset fits.
|
||||
if rd == 0 && offset >= -2048 && offset <= 2046 && offset%2 == 0 {
|
||||
c16 := rvcCJ(0x5, offset)
|
||||
return []byte{byte(c16), byte(c16 >> 8)}, nil
|
||||
}
|
||||
word = riscvJType(rd, offset)
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
|
||||
@@ -492,18 +483,7 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
return nil, fmt.Errorf("invalid register in %s", mnem)
|
||||
}
|
||||
|
||||
// Try C.BEQZ / C.BNEZ compression.
|
||||
if (mnem == "BEQ" || mnem == "BNE") && rs2 == 0 && isRVCIntReg(rs1) {
|
||||
if cOff := offset; cOff >= -256 && cOff <= 254 && cOff%2 == 0 {
|
||||
funct3 := uint32(0x6) // C.BEQZ
|
||||
if mnem == "BNE" {
|
||||
funct3 = 0x7 // C.BNEZ
|
||||
}
|
||||
c16 := rvcCB(funct3, rvcReg3(rs1), offset)
|
||||
return []byte{byte(c16), byte(c16 >> 8)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// The Go assembler never compresses branches to C.BEQZ/C.BNEZ.
|
||||
word = riscvBType(enc, rs1, rs2, offset)
|
||||
|
||||
// U-type: rd, imm.
|
||||
@@ -969,24 +949,19 @@ func tryCompressRVC(instr *ast.Instr, fi riscvFrameInfo) (uint16, bool) {
|
||||
}
|
||||
|
||||
case "JAL":
|
||||
// JAL X0, target → C.J when offset fits in ±2KB.
|
||||
if len(ops) >= 1 {
|
||||
// For JAL with implicit rd=0 (JMP alias), check target.
|
||||
// C.J: funct3=0x5
|
||||
// Offset is computed at encode time — we can't check it here.
|
||||
return 0, false
|
||||
}
|
||||
// JAL/JMP are never compressed to C.J by the Go assembler.
|
||||
return 0, false
|
||||
|
||||
case "JMP":
|
||||
// C.J — handled in encodeRISCVInstr with actual offset.
|
||||
// JAL/JMP are never compressed to C.J by the Go assembler.
|
||||
return 0, false
|
||||
|
||||
case "BEQ":
|
||||
// C.BEQZ — handled in encodeRISCVInstr with actual offset.
|
||||
// Branches are never compressed to C.BEQZ/C.BNEZ.
|
||||
return 0, false
|
||||
|
||||
case "BNE":
|
||||
// C.BNEZ — handled in encodeRISCVInstr with actual offset.
|
||||
// Branches are never compressed to C.BEQZ/C.BNEZ.
|
||||
return 0, false
|
||||
|
||||
case "ADD":
|
||||
@@ -1082,11 +1057,12 @@ func tryCompressRVC(instr *ast.Instr, fi riscvFrameInfo) (uint16, bool) {
|
||||
}
|
||||
|
||||
case "LUI":
|
||||
// LUI rd, imm → C.LUI when rd≠0, rd≠SP, imm nonzero and fits in 6 bits.
|
||||
// LUI rd, imm → C.LUI when rd≠0, rd≠SP, imm nonzero and fits in six
|
||||
// signed bits (matching the toolchain's compress pass).
|
||||
if len(ops) == 2 {
|
||||
rd := regFromOperand(ops[0])
|
||||
imm := immFromOperand(ops[1])
|
||||
if rd != -1 && rd != 0 && rd != 2 && imm != 0 && imm >= 1 && imm <= 63 {
|
||||
if rd != -1 && rd != 0 && rd != 2 && imm != 0 && imm >= -32 && imm <= 31 {
|
||||
return rvcCI(0x3, uint32(rd), uint32(imm)&0x3F), true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user