diff --git a/parser/parser.go b/parser/parser.go index 8771a3e..0601c2c 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -552,6 +552,20 @@ func parseAddress(g []token.Token) ast.Address { i = len(g) - len(rest) } } + // The same expression under a leading sign: -(24+8)(X6) puts the sign + // outside the fold. The base group must follow for the value to + // commit, exactly as in the unsigned branch above. + if i < len(g) && (g[i].Kind == token.Minus || g[i].Kind == token.Plus) && + i+1 < len(g) && g[i+1].Kind == token.LParen { + if v, rest, ok := foldExpr(g[i+1:]); ok && len(rest) > 0 && rest[0].Kind == token.LParen { + if g[i].Kind == token.Minus { + v = -v + } + addr.Offset = v + addr.HasOff = true + i = len(g) - len(rest) + } + } // Optional leading displacement before a '(' base group. A sign pushes // the parenthesis one token further out: -4(DX) has it at i+2. if isSignedNumber(g, i) { diff --git a/parser/parser_test.go b/parser/parser_test.go index 4c18551..8e4e4f4 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -634,3 +634,27 @@ func TestBareTrailingImmediate(t *testing.T) { t.Errorf("jump target = %+v, want label loop", jmp.Operands[0]) } } + +// TestSignedParenDisplacement pins a sign before a parenthesised +// displacement expression: -(24+8)(X6) negates the folded value and keeps +// the base group, the shape GOROOT's riscv64 and loong64 files use. +func TestSignedParenDisplacement(t *testing.T) { + file, errs := Parse("t.s", "TEXT \u00b7f(SB), NOSPLIT, $0-0\n\tMOV X7, -(24+8)(X6)\n\tMOV X7, +(16)(X6)\n\tRET\n") + if len(errs) > 0 { + t.Fatalf("parse: %v", errs) + } + text := file.Decls[0].(*ast.Text) + ins := text.Body[0].(*ast.Instr) + op := ins.Operands[1] // Plan 9 order: the destination address is last + if !op.Addr.HasOff || op.Addr.Offset != -32 { + t.Errorf("-(24+8): offset = %v hasOff=%v, want -32 true", op.Addr.Offset, op.Addr.HasOff) + } + if op.Addr.Base != "X6" { + t.Errorf("-(24+8): base = %q, want X6", op.Addr.Base) + } + ins = text.Body[1].(*ast.Instr) + op = ins.Operands[1] + if !op.Addr.HasOff || op.Addr.Offset != 16 || op.Addr.Base != "X6" { + t.Errorf("+(16): offset = %v hasOff=%v base=%q, want 16 true X6", op.Addr.Offset, op.Addr.HasOff, op.Addr.Base) + } +}