fix(asm): read the MOV family registers against their banks
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
4ff47fe17a
commit
86cb785e58
1 file changed
+53
-14
+53
-14
@@ -2195,24 +2195,27 @@ func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc, lits *
|
|||||||
|
|
||||||
// Memory → register (load).
|
// Memory → register (load).
|
||||||
if isMemOperand(src) && !isMemOperand(dst) {
|
if isMemOperand(src) && !isMemOperand(dst) {
|
||||||
rd := regFromOperand(dst)
|
rd, err := riscvWantMovReg(mnem, "rd", dst)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// MOV sym(SB), rd, load from static data. A TLSBSS symbol takes
|
// MOV sym(SB), rd, load from static data. A TLSBSS symbol takes
|
||||||
// the local-exec sequence: LUI + ADDIW carry the offset against TP,
|
// the local-exec sequence: LUI + ADDIW carry the offset against TP,
|
||||||
// the ADD folds the thread pointer in, the access reads through TMP.
|
// the ADD folds the thread pointer in, the access reads through TMP.
|
||||||
if src.Addr.Sym != nil && src.Addr.Sym.Pseudo == "SB" {
|
if src.Addr.Sym != nil && src.Addr.Sym.Pseudo == "SB" {
|
||||||
if rd < 0 {
|
|
||||||
return nil, fmt.Errorf("MOV sym(SB): invalid destination register")
|
|
||||||
}
|
|
||||||
if tlsSyms[src.Addr.Sym.Name] {
|
if tlsSyms[src.Addr.Sym.Name] {
|
||||||
return riscvTLSBytes(riscvMovEnc(strings.ToUpper(instr.Mnemonic.Text), false), false, rd, src.Addr.Sym, relocs), nil
|
return riscvTLSBytes(riscvMovEnc(mnem, false), false, rd, src.Addr.Sym, relocs), nil
|
||||||
}
|
}
|
||||||
return encodeRISCVSBLoad(src.Addr.Sym, rd, relocs), nil
|
return encodeRISCVSBLoad(src.Addr.Sym, rd, relocs), nil
|
||||||
}
|
}
|
||||||
rs1, off := memFromOperandWithFrame(src, fi)
|
if err := riscvWantMemBase(mnem, "rs1", src); err != nil {
|
||||||
if rd < 0 || rs1 < 0 {
|
return nil, err
|
||||||
return nil, fmt.Errorf("MOV load: invalid operand")
|
|
||||||
}
|
}
|
||||||
return riscvFrameMemOp(riscvMovEnc(strings.ToUpper(instr.Mnemonic.Text), false), false, rd, rs1, off), nil
|
rs1, off := memFromOperandWithFrame(src, fi)
|
||||||
|
if rs1 < 0 {
|
||||||
|
return nil, fmt.Errorf("%s: expected integer register in rs1 position", mnem)
|
||||||
|
}
|
||||||
|
return riscvFrameMemOp(riscvMovEnc(mnem, false), false, rd, rs1, off), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register → memory (store).
|
// Register → memory (store).
|
||||||
@@ -2234,6 +2237,9 @@ func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc, lits *
|
|||||||
}
|
}
|
||||||
return encodeRISCVSBStore(dst.Addr.Sym, rs2, relocs), nil
|
return encodeRISCVSBStore(dst.Addr.Sym, rs2, relocs), nil
|
||||||
}
|
}
|
||||||
|
if err := riscvWantMemBase(mnem, "rs1", dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
rs1, off := memFromOperandWithFrame(dst, fi)
|
rs1, off := memFromOperandWithFrame(dst, fi)
|
||||||
if rs1 < 0 {
|
if rs1 < 0 {
|
||||||
return nil, fmt.Errorf("%s: expected integer register in rs1 position", mnem)
|
return nil, fmt.Errorf("%s: expected integer register in rs1 position", mnem)
|
||||||
@@ -2248,13 +2254,25 @@ func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc, lits *
|
|||||||
// MOVWU zero-extend through SLLI+SRLI; bare MOV is ADDI $0, which the
|
// MOVWU zero-extend through SLLI+SRLI; bare MOV is ADDI $0, which the
|
||||||
// RVC pass compresses.
|
// RVC pass compresses.
|
||||||
{
|
{
|
||||||
|
srcF, dstF := riscvIsFloatRegOperand(src), riscvIsFloatRegOperand(dst)
|
||||||
|
if mnem == "MOVF" || mnem == "MOVD" {
|
||||||
|
if !srcF && !dstF {
|
||||||
|
return nil, fmt.Errorf("%s: expected float register in rd position but got non-float register %s",
|
||||||
|
mnem, operandRegName(dst))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The integer widths move through the integer file alone: a
|
||||||
|
// float or vector register in either slot is the toolchain's
|
||||||
|
// bank rejection, the destination reported first.
|
||||||
|
if _, err := riscvWantMovReg(mnem, "rd", dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := riscvWantMovReg(mnem, "rs1", src); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
rs1 := regFromOperand(src)
|
rs1 := regFromOperand(src)
|
||||||
rd := regFromOperand(dst)
|
rd := regFromOperand(dst)
|
||||||
if rd < 0 || rs1 < 0 {
|
|
||||||
return nil, fmt.Errorf("MOV: invalid register operand")
|
|
||||||
}
|
|
||||||
mnem := strings.ToUpper(instr.Mnemonic.Text)
|
|
||||||
srcF, dstF := riscvIsFloatRegOperand(src), riscvIsFloatRegOperand(dst)
|
|
||||||
switch mnem {
|
switch mnem {
|
||||||
case "MOVF", "MOVD":
|
case "MOVF", "MOVD":
|
||||||
switch {
|
switch {
|
||||||
@@ -2265,12 +2283,21 @@ func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc, lits *
|
|||||||
}
|
}
|
||||||
return wordLE(op | uint32(rs1)<<15 | uint32(rs1)<<20 | uint32(rd)<<7), nil
|
return wordLE(op | uint32(rs1)<<15 | uint32(rs1)<<20 | uint32(rd)<<7), nil
|
||||||
case dstF && !srcF:
|
case dstF && !srcF:
|
||||||
|
// The FMV spellings move the bit pattern through the
|
||||||
|
// integer file: a vector register in the source slot
|
||||||
|
// names no integer register.
|
||||||
|
if _, err := riscvWantMovReg("MOV", "rs1", src); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
op := uint32(0x78) << 25 // FMV.W.X
|
op := uint32(0x78) << 25 // FMV.W.X
|
||||||
if mnem == "MOVD" {
|
if mnem == "MOVD" {
|
||||||
op = uint32(0x79) << 25 // FMV.D.X
|
op = uint32(0x79) << 25 // FMV.D.X
|
||||||
}
|
}
|
||||||
return wordLE(op | uint32(rs1)<<15 | uint32(rd)<<7 | 0x53), nil
|
return wordLE(op | uint32(rs1)<<15 | uint32(rd)<<7 | 0x53), nil
|
||||||
case srcF && !dstF:
|
case srcF && !dstF:
|
||||||
|
if _, err := riscvWantMovReg("MOV", "rd", dst); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
op := uint32(0x70) << 25 // FMV.X.W
|
op := uint32(0x70) << 25 // FMV.X.W
|
||||||
if mnem == "MOVD" {
|
if mnem == "MOVD" {
|
||||||
op = uint32(0x71) << 25 // FMV.X.D
|
op = uint32(0x71) << 25 // FMV.X.D
|
||||||
@@ -5533,6 +5560,18 @@ func riscvWantBaseReg(mnem, pos, descr string, op *ast.Operand, bank riscvRegBan
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// riscvWantMemBase validates the base register of a memory operand that is
|
||||||
|
// not a frame reference: the addressing forms take integer registers only.
|
||||||
|
func riscvWantMemBase(mnem, pos string, op *ast.Operand) error {
|
||||||
|
if op.Addr.Base == "" || (op.Addr.Sym != nil && op.Addr.Sym.Pseudo != "") {
|
||||||
|
return nil // a frame-pseudo or symbol reference names no register
|
||||||
|
}
|
||||||
|
if _, b := riscvBankedRegNum(op.Addr.Base); b != riscvBankInt {
|
||||||
|
return fmt.Errorf("%s: expected integer register in %s position but got non-integer register %s", mnem, pos, op.Addr.Base)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func immFromOperand(op *ast.Operand) int32 {
|
func immFromOperand(op *ast.Operand) int32 {
|
||||||
if op.Imm.HasVal {
|
if op.Imm.HasVal {
|
||||||
v := op.Imm.Val
|
v := op.Imm.Val
|
||||||
|
|||||||
Reference in new issue
Block a user