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).
|
||||
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
|
||||
// the local-exec sequence: LUI + ADDIW carry the offset against TP,
|
||||
// the ADD folds the thread pointer in, the access reads through TMP.
|
||||
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] {
|
||||
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
|
||||
}
|
||||
rs1, off := memFromOperandWithFrame(src, fi)
|
||||
if rd < 0 || rs1 < 0 {
|
||||
return nil, fmt.Errorf("MOV load: invalid operand")
|
||||
if err := riscvWantMemBase(mnem, "rs1", src); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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).
|
||||
@@ -2234,6 +2237,9 @@ func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc, lits *
|
||||
}
|
||||
return encodeRISCVSBStore(dst.Addr.Sym, rs2, relocs), nil
|
||||
}
|
||||
if err := riscvWantMemBase(mnem, "rs1", dst); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rs1, off := memFromOperandWithFrame(dst, fi)
|
||||
if rs1 < 0 {
|
||||
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
|
||||
// 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)
|
||||
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 {
|
||||
case "MOVF", "MOVD":
|
||||
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
|
||||
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
|
||||
if mnem == "MOVD" {
|
||||
op = uint32(0x79) << 25 // FMV.D.X
|
||||
}
|
||||
return wordLE(op | uint32(rs1)<<15 | uint32(rd)<<7 | 0x53), nil
|
||||
case srcF && !dstF:
|
||||
if _, err := riscvWantMovReg("MOV", "rd", dst); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
op := uint32(0x70) << 25 // FMV.X.W
|
||||
if mnem == "MOVD" {
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if op.Imm.HasVal {
|
||||
v := op.Imm.Val
|
||||
|
||||
Reference in new issue
Block a user