fix(asm): encode the loong64 64-bit-span 2RI14 offsets like the toolchain
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
41aa8edfd2
commit
b9dfb48d79
2 files changed
+30
-7
No files matched your search
+28
-4
@@ -825,6 +825,22 @@ func encodeLOONG64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi loo
|
|||||||
if off&3 != 0 {
|
if off&3 != 0 {
|
||||||
return nil, fmt.Errorf("%s: offset must be a multiple of 4", mnem)
|
return nil, fmt.Errorf("%s: offset must be a multiple of 4", mnem)
|
||||||
}
|
}
|
||||||
|
// The 64-bit span reproduces the toolchain's case 73/74 size-24
|
||||||
|
// expansion word for word, its missing load negation included: a
|
||||||
|
// MOVWP/MOVVP load emits the store opcode, because case 74 spells
|
||||||
|
// opirr(p.As) where the narrower spans spell opirr(-p.As), and the
|
||||||
|
// LL family has no unnegated opirr entry at all, so the toolchain
|
||||||
|
// refuses those loads with "bad irr opcode".
|
||||||
|
if off < -2147483650 || off >= 2147483646 {
|
||||||
|
if load {
|
||||||
|
switch mnem {
|
||||||
|
case "MOVWP", "MOVVP":
|
||||||
|
op += 1 << 24
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("bad irr opcode %s", mnem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return l64firr14Words(op, int(off), rj, rd), nil
|
return l64firr14Words(op, int(off), rj, rd), nil
|
||||||
|
|
||||||
case l64Fir20:
|
case l64Fir20:
|
||||||
@@ -1292,21 +1308,29 @@ func l64FmaOperands(ops []*ast.Operand) (fa, fk, fj, fd int, err error) {
|
|||||||
// l64MemOperands extracts (rd, rj, off, load) from a load/store instruction:
|
// l64MemOperands extracts (rd, rj, off, load) from a load/store instruction:
|
||||||
// INSTR mem, rd is a load, INSTR rd, mem a store.
|
// INSTR mem, rd is a load, INSTR rd, mem a store.
|
||||||
// l64MemOperands splits the two-operand load/store forms: the register and
|
// l64MemOperands splits the two-operand load/store forms: the register and
|
||||||
// the memory side, the memory's base and byte offset, and the direction.
|
// the memory side, the memory's base and full-width byte offset (64-bit
|
||||||
func l64MemOperands(ops []*ast.Operand, fi loong64FrameInfo) (rd, rj int, off int32, load bool, err error) {
|
// offsets reach the 2RI14 families' six-word span), and the direction.
|
||||||
|
func l64MemOperands(ops []*ast.Operand, fi loong64FrameInfo) (rd, rj int, off int64, load bool, err error) {
|
||||||
if len(ops) != 2 {
|
if len(ops) != 2 {
|
||||||
return 0, 0, 0, false, fmt.Errorf("expected 2 operands, got %d", len(ops))
|
return 0, 0, 0, false, fmt.Errorf("expected 2 operands, got %d", len(ops))
|
||||||
}
|
}
|
||||||
|
var mem *ast.Operand
|
||||||
if isMemOperand(ops[0]) {
|
if isMemOperand(ops[0]) {
|
||||||
rd = l64Reg(ops[1])
|
rd = l64Reg(ops[1])
|
||||||
rj, off = l64MemWithFrame(ops[0], fi)
|
mem = ops[0]
|
||||||
load = true
|
load = true
|
||||||
} else if isMemOperand(ops[1]) {
|
} else if isMemOperand(ops[1]) {
|
||||||
rd = l64Reg(ops[0])
|
rd = l64Reg(ops[0])
|
||||||
rj, off = l64MemWithFrame(ops[1], fi)
|
mem = ops[1]
|
||||||
} else {
|
} else {
|
||||||
return 0, 0, 0, false, fmt.Errorf("expected a memory operand")
|
return 0, 0, 0, false, fmt.Errorf("expected a memory operand")
|
||||||
}
|
}
|
||||||
|
if mem.Addr.Sym != nil && mem.Addr.Sym.Pseudo != "" {
|
||||||
|
pj, poff := loong64ResolvePseudo(mem.Addr.Sym, fi)
|
||||||
|
rj, off = pj, int64(poff)
|
||||||
|
} else {
|
||||||
|
rj, off = loong64RegNum(mem.Addr.Base), mem.Addr.Offset
|
||||||
|
}
|
||||||
if rd < 0 || rj < 0 {
|
if rd < 0 || rj < 0 {
|
||||||
return 0, 0, 0, false, fmt.Errorf("invalid operand")
|
return 0, 0, 0, false, fmt.Errorf("invalid operand")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,9 +264,8 @@ func l64WordsLE(ws ...uint32) []byte {
|
|||||||
// a 32-bit one (C_LOREG_32) splits between addu16i.d (bits 31:16, materialised
|
// a 32-bit one (C_LOREG_32) splits between addu16i.d (bits 31:16, materialised
|
||||||
// in R30, the assembler temp) and si14 (bits 15:2); anything wider
|
// in R30, the assembler temp) and si14 (bits 15:2); anything wider
|
||||||
// (C_LOREG_64) builds the whole constant in R30 through lu12i.w + ori +
|
// (C_LOREG_64) builds the whole constant in R30 through lu12i.w + ori +
|
||||||
// lu32i.d + lu52i.d and folds the base into it. The loong64 backend resolves
|
// lu32i.d + lu52i.d and folds the base into it. The caller adjusts the
|
||||||
// memory offsets as int32, so the third span answers nothing the encoder can
|
// opcode for the 64-bit span's load-direction quirks before arriving here.
|
||||||
// ask today: it stands so the mapping stays complete if that domain widens.
|
|
||||||
func l64firr14Words(op uint32, off, rj, rd int) []byte {
|
func l64firr14Words(op uint32, off, rj, rd int) []byte {
|
||||||
switch {
|
switch {
|
||||||
case off >= -32766 && off < 32766:
|
case off >= -32766 && off < 32766:
|
||||||
|
|||||||
Reference in new issue
Block a user