fix: restore iota blocks, asm --format flag and prose after the syntax pass
This commit is contained in:
+4
-4
@@ -625,7 +625,7 @@ objects.
|
|||||||
`GLOBL` in the file defines no longer aborts assembly — it is recorded
|
`GLOBL` in the file defines no longer aborts assembly — it is recorded
|
||||||
as an external relocation (`Image.Externals`, `FuncLayout.Relocs`) and
|
as an external relocation (`Image.Externals`, `FuncLayout.Relocs`) and
|
||||||
becomes an undefined global symbol in the object output. The raw image
|
becomes an undefined global symbol in the object output. The raw image
|
||||||
format (`--format raw`, the default) still reports them: only an object
|
s (`--format raw`, the default) still reports them: only an object
|
||||||
file can represent a reference the linker must resolve.
|
file can represent a reference the linker must resolve.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
@@ -726,7 +726,7 @@ The formatter behaves like `go fmt` and canonicalises block separation.
|
|||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- `format`: canonical blank-line layout — a new block (a label, `TEXT` or
|
- `s`: canonical blank-line layout — a new block (a label, `TEXT` or
|
||||||
`GLOBL`) is preceded by exactly one blank line, neither more nor less.
|
`GLOBL`) is preceded by exactly one blank line, neither more nor less.
|
||||||
Comments leading a block stay with it (the blank line goes before them),
|
Comments leading a block stay with it (the blank line goes before them),
|
||||||
stacked labels share their block, the function's first label keeps hugging
|
stacked labels share their block, the function's first label keeps hugging
|
||||||
@@ -761,7 +761,7 @@ the encoder learns the legacy SSE moves.
|
|||||||
*first* operand on arm64, riscv64 and loong64; Plan 9 spelling puts it last
|
*first* operand on arm64, riscv64 and loong64; Plan 9 spelling puts it last
|
||||||
on every architecture Go supports. The def/use and save/restore
|
on every architecture Go supports. The def/use and save/restore
|
||||||
classification on those architectures was inverted.
|
classification on those architectures was inverted.
|
||||||
- `format`: a comment that follows a `RET` (typically the next function's doc
|
- `s`: a comment that follows a `RET` (typically the next function's doc
|
||||||
comment) is no longer indented as if it were still inside the finished
|
comment) is no longer indented as if it were still inside the finished
|
||||||
function body.
|
function body.
|
||||||
|
|
||||||
@@ -934,7 +934,7 @@ Initial release — the Phase 1 foundation.
|
|||||||
Zero error-severity diagnostics across the 90-file Go runtime corpus and the
|
Zero error-severity diagnostics across the 90-file Go runtime corpus and the
|
||||||
production go-flac kernels (the `register-clobber` audit additionally reports
|
production go-flac kernels (the `register-clobber` audit additionally reports
|
||||||
the go-flac kernels' unsaved callee-saved register use for review).
|
the go-flac kernels' unsaved callee-saved register use for review).
|
||||||
- `format`: an idempotent canonical formatter (operand spacing and per-function
|
- `s`: an idempotent canonical formatter (operand spacing and per-function
|
||||||
mnemonic alignment) that preserves comments and round-trips through the
|
mnemonic alignment) that preserves comments and round-trips through the
|
||||||
parser.
|
parser.
|
||||||
- `lsp`: a Language Server Protocol server over stdio providing completion,
|
- `lsp`: a Language Server Protocol server over stdio providing completion,
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ cross-compiles the same four targets.
|
|||||||
| `parser` | Line-oriented, error-tolerant parser producing the AST. |
|
| `parser` | Line-oriented, error-tolerant parser producing the AST. |
|
||||||
| `arch` | amd64, arm64, riscv64 and loong64 register files and instruction tables. |
|
| `arch` | amd64, arm64, riscv64 and loong64 register files and instruction tables. |
|
||||||
| `lint` | Conservative static checks (13 rules including unused-label, invalid-textflag, stack-imbalance). |
|
| `lint` | Conservative static checks (13 rules including unused-label, invalid-textflag, stack-imbalance). |
|
||||||
| `format` | A canonical formatter — `gofmt` for assembly. |
|
| `s` | A canonical formatter — `gofmt` for assembly. |
|
||||||
| `asm` | The standalone assembler: all four architecture encoders, linker, object-file emitters (ELF with DWARF5, GOOBJ). |
|
| `asm` | The standalone assembler: all four architecture encoders, linker, object-file emitters (ELF with DWARF5, GOOBJ). |
|
||||||
| `verify` | JIT execution substrate for dynamic analysis, combined ABI+fuzz differential testing. Assembly trampolines for all four architectures. |
|
| `verify` | JIT execution substrate for dynamic analysis, combined ABI+fuzz differential testing. Assembly trampolines for all four architectures. |
|
||||||
| `debug` | Interactive ptrace debugger for all four architectures: single-stepping, breakpoints, hardware watchpoints, register and memory inspection. |
|
| `debug` | Interactive ptrace debugger for all four architectures: single-stepping, breakpoints, hardware watchpoints, register and memory inspection. |
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ func encodeARM64AddSubImm(mnem string, ops []*ast.Operand) ([]byte, error) {
|
|||||||
if len(ops) != 2 && len(ops) != 3 {
|
if len(ops) != 2 && len(ops) != 3 {
|
||||||
return nil, fmt.Errorf("%s expects 2 or 3 operands, got %d", mnem, len(ops))
|
return nil, fmt.Errorf("%s expects 2 or 3 operands, got %d", mnem, len(ops))
|
||||||
}
|
}
|
||||||
v := int32(immFromOperand(ops[0]))
|
v := immFromOperand(ops[0])
|
||||||
rd := arm64RegNum(operandRegName(ops[len(ops)-1]))
|
rd := arm64RegNum(operandRegName(ops[len(ops)-1]))
|
||||||
rn := rd
|
rn := rd
|
||||||
if len(ops) == 3 {
|
if len(ops) == 3 {
|
||||||
@@ -606,7 +606,7 @@ func encodeARM64LoadImm(rd int, v int64, mnem string) ([]byte, error) {
|
|||||||
// - C_ABCON0 (0 < v ≤ 4095): bitmask first for positive values
|
// - C_ABCON0 (0 < v ≤ 4095): bitmask first for positive values
|
||||||
// - Negative values: MOVN first, then bitmask
|
// - Negative values: MOVN first, then bitmask
|
||||||
// - C_MOVCON (movcon-eligible, outside ABCON range): MOVZ/MOVN first
|
// - C_MOVCON (movcon-eligible, outside ABCON range): MOVZ/MOVN first
|
||||||
tryBitmaskFirst := (d > 0 && d <= 0xFFF)
|
tryBitmaskFirst := d > 0 && d <= 0xFFF
|
||||||
|
|
||||||
if tryBitmaskFirst {
|
if tryBitmaskFirst {
|
||||||
// Small immediate: try bitmask first (Go uses ORR for values like $1, $256).
|
// Small immediate: try bitmask first (Go uses ORR for values like $1, $256).
|
||||||
|
|||||||
@@ -234,8 +234,6 @@ const (
|
|||||||
a64CondLT = 0xb
|
a64CondLT = 0xb
|
||||||
a64CondGT = 0xc
|
a64CondGT = 0xc
|
||||||
a64CondLE = 0xd
|
a64CondLE = 0xd
|
||||||
a64CondAL = 0xe
|
|
||||||
a64CondNV = 0xf
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// arm64CondMap maps Go assembler condition mnemonics to AArch64 condition codes.
|
// arm64CondMap maps Go assembler condition mnemonics to AArch64 condition codes.
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
// and external ones against undefined globals. The output links with the
|
// and external ones against undefined globals. The output links with the
|
||||||
// system toolchain (cc/ld) the way a hand-assembled .o would.
|
// system toolchain (cc/ld) the way a hand-assembled .o would.
|
||||||
|
|
||||||
// ELF constants (ELF64, little-endian, System V).
|
|
||||||
const (
|
const (
|
||||||
elfClass64 = 2
|
elfClass64 = 2
|
||||||
elfDataLSB = 1
|
elfDataLSB = 1
|
||||||
@@ -36,17 +35,14 @@ const (
|
|||||||
shfAlloc = 2
|
shfAlloc = 2
|
||||||
shfExecInstr = 4
|
shfExecInstr = 4
|
||||||
|
|
||||||
stbLocal = 0
|
|
||||||
stbGlobal = 1
|
stbGlobal = 1
|
||||||
|
|
||||||
sttNotype = 0
|
|
||||||
sttObject = 1
|
sttObject = 1
|
||||||
sttFunc = 2
|
sttFunc = 2
|
||||||
sttSection = 3
|
sttSection = 3
|
||||||
stInfoShift = 4
|
stInfoShift = 4
|
||||||
|
|
||||||
rX8664PC32 = 2
|
rX8664PC32 = 2
|
||||||
rX8664_64 = 1 // R_X86_64_64 (absolute 64-bit)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// elfSym is one symbol-table entry in construction.
|
// elfSym is one symbol-table entry in construction.
|
||||||
|
|||||||
+2
-2
@@ -87,7 +87,7 @@ func emitDWARF(img *Image, srcFile string) *dwarfSections {
|
|||||||
ds.debugLineStr = lineStr.bytes()
|
ds.debugLineStr = lineStr.bytes()
|
||||||
|
|
||||||
// Build .debug_line.
|
// Build .debug_line.
|
||||||
ds.debugLine = dwarfBuildLineSection(img, srcFile, ds)
|
ds.debugLine = dwarfBuildLineSection(img, ds)
|
||||||
|
|
||||||
// Build .debug_info.
|
// Build .debug_info.
|
||||||
ds.debugInfo = dwarfBuildInfoSection(img, srcFile, ds)
|
ds.debugInfo = dwarfBuildInfoSection(img, srcFile, ds)
|
||||||
@@ -98,7 +98,7 @@ func emitDWARF(img *Image, srcFile string) *dwarfSections {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// dwarfBuildLineSection builds a complete .debug_line section.
|
// dwarfBuildLineSection builds a complete .debug_line section.
|
||||||
func dwarfBuildLineSection(img *Image, srcFile string, ds *dwarfSections) []byte {
|
func dwarfBuildLineSection(img *Image, ds *dwarfSections) []byte {
|
||||||
var b []byte
|
var b []byte
|
||||||
le := binary.LittleEndian
|
le := binary.LittleEndian
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -701,7 +701,7 @@ func splitMask(ops []Operand) ([]Operand, int, error) {
|
|||||||
return nil, 0, fmt.Errorf("at most one mask register operand")
|
return nil, 0, fmt.Errorf("at most one mask register operand")
|
||||||
}
|
}
|
||||||
if r.idx == 0 {
|
if r.idx == 0 {
|
||||||
return nil, 0, fmt.Errorf("K0 is not a usable mask register")
|
return nil, 0, fmt.Errorf("k0 is not a usable mask register")
|
||||||
}
|
}
|
||||||
mask = r.idx
|
mask = r.idx
|
||||||
continue
|
continue
|
||||||
@@ -1203,7 +1203,7 @@ func (e *enc) emitEvexFields(spec evexSpec, ll, regIdx, vvvvIdx int, rm Operand,
|
|||||||
// The b bit and the L'L field carry the rounding/SAE/broadcast mode:
|
// The b bit and the L'L field carry the rounding/SAE/broadcast mode:
|
||||||
// a rounding mode replaces L'L with the rc value, plain SAE and
|
// a rounding mode replaces L'L with the rc value, plain SAE and
|
||||||
// broadcast keep the vector length.
|
// broadcast keep the vector length.
|
||||||
b, ll := 0, ll
|
b := 0
|
||||||
switch {
|
switch {
|
||||||
case sfx.rounding >= 0:
|
case sfx.rounding >= 0:
|
||||||
b, ll = 1, sfx.rounding
|
b, ll = 1, sfx.rounding
|
||||||
|
|||||||
+5
-2
@@ -33,7 +33,10 @@ import (
|
|||||||
// methods supply the toolchain preamble, the MinLC (pc-value delta unit)
|
// methods supply the toolchain preamble, the MinLC (pc-value delta unit)
|
||||||
// and the relocation-type mapping for code relocations.
|
// and the relocation-type mapping for code relocations.
|
||||||
|
|
||||||
// GOOBJ block indices (cmd/internal/goobj).
|
// GOOBJ block indices (cmd/internal/goobj). These MUST match the real
|
||||||
|
// archive layout: the emitter writes the header offsets per index and the
|
||||||
|
// reader (groundtruth, goobj_resolve) parses real Go archives with them.
|
||||||
|
// blkAutolib is unused by the emitter but still defines index 0.
|
||||||
const (
|
const (
|
||||||
blkAutolib = iota
|
blkAutolib = iota
|
||||||
blkPkgIdx
|
blkPkgIdx
|
||||||
@@ -417,7 +420,7 @@ func (img *Image) emitGOObject(pkgPath, srcPath string, pre []byte, minLC int, r
|
|||||||
// The string table. Absolute offsets: it starts right after the
|
// The string table. Absolute offsets: it starts right after the
|
||||||
// 96-byte header (magic, fingerprint, flags, the 19 block offsets).
|
// 96-byte header (magic, fingerprint, flags, the 19 block offsets).
|
||||||
const headerSize = 8 + 8 + 4 + 4*(blkEnd+1)
|
const headerSize = 8 + 8 + 4 + 4*(blkEnd+1)
|
||||||
strTab := []byte{}
|
var strTab []byte
|
||||||
strOff := map[string]uint32{}
|
strOff := map[string]uint32{}
|
||||||
addStr := func(s string) {
|
addStr := func(s string) {
|
||||||
if _, ok := strOff[s]; ok {
|
if _, ok := strOff[s]; ok {
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ func (fl *FuncLayout) LineAt(offset int) int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reloc is one static-symbol reference within a function body: the disp32
|
// RelocKind Reloc is one static-symbol reference within a function body: the disp32
|
||||||
// field at Off (function-relative) must reach the symbol plus Addend,
|
// field at Off (function-relative) must reach the symbol plus Addend,
|
||||||
// measured from After, the address just past the instruction. An External
|
// measured from After, the address just past the instruction. An External
|
||||||
// relocation names a symbol no GLOBL in the file defines; the object-file
|
// relocation names a symbol no GLOBL in the file defines; the object-file
|
||||||
|
|||||||
+57
-59
@@ -672,8 +672,6 @@ func encodeLOONG64ImmArith(mnem string, de l64DualEnc, ops []*ast.Operand) ([]by
|
|||||||
const (
|
const (
|
||||||
lu12iw = 0x0a << 25
|
lu12iw = 0x0a << 25
|
||||||
ori = 0x00e << 22
|
ori = 0x00e << 22
|
||||||
lu32id = 0x0b << 25
|
|
||||||
lu52id = 0x00c << 22
|
|
||||||
)
|
)
|
||||||
if v == int64(int32(v)) {
|
if v == int64(int32(v)) {
|
||||||
if v&0xfff == 0 && (v < 0x800 || v > 0xfff) {
|
if v&0xfff == 0 && (v < 0x800 || v > 0xfff) {
|
||||||
@@ -771,7 +769,7 @@ func encodeLOONG64Mov(instr *ast.Instr, mnem string, fi loong64FrameInfo, relocs
|
|||||||
if rd < 0 {
|
if rd < 0 {
|
||||||
return nil, fmt.Errorf("%s $sym(SB): invalid destination register", mnem)
|
return nil, fmt.Errorf("%s $sym(SB): invalid destination register", mnem)
|
||||||
}
|
}
|
||||||
return encodeLOONG64SBAddr(src.Imm.Sym, rd, mnem, relocs), nil
|
return encodeLOONG64SBAddr(src.Imm.Sym, rd, relocs), nil
|
||||||
}
|
}
|
||||||
rd := l64Reg(dst)
|
rd := l64Reg(dst)
|
||||||
if rd < 0 {
|
if rd < 0 {
|
||||||
@@ -832,14 +830,14 @@ func encodeLOONG64Mov(instr *ast.Instr, mnem string, fi loong64FrameInfo, relocs
|
|||||||
if rd < 0 {
|
if rd < 0 {
|
||||||
return nil, fmt.Errorf("%s: invalid destination register", mnem)
|
return nil, fmt.Errorf("%s: invalid destination register", mnem)
|
||||||
}
|
}
|
||||||
return encodeLOONG64MemOp(mnem, ops[0], rd, true, fi, relocs)
|
return encodeLOONG64MemOp(mnem, ops[0], rd, true, fi)
|
||||||
}
|
}
|
||||||
if !isMemOperand(src) && isMemOperand(dst) {
|
if !isMemOperand(src) && isMemOperand(dst) {
|
||||||
rs := l64Reg(src)
|
rs := l64Reg(src)
|
||||||
if rs < 0 {
|
if rs < 0 {
|
||||||
return nil, fmt.Errorf("%s: invalid source register", mnem)
|
return nil, fmt.Errorf("%s: invalid source register", mnem)
|
||||||
}
|
}
|
||||||
return encodeLOONG64MemOp(mnem, ops[1], rs, false, fi, relocs)
|
return encodeLOONG64MemOp(mnem, ops[1], rs, false, fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register → register.
|
// Register → register.
|
||||||
@@ -933,20 +931,20 @@ const (
|
|||||||
l64St1
|
l64St1
|
||||||
l64St0
|
l64St0
|
||||||
|
|
||||||
l64Dcon12_0
|
l64dcon120
|
||||||
l64Dcon12_20S
|
l64dcon1220s
|
||||||
l64Dcon20S_20
|
l64dcon20s20
|
||||||
l64Dcon12_12S
|
l64dcon1212s
|
||||||
l64Dcon20S_12S
|
l64dcon20s12s
|
||||||
l64Dcon20S_0
|
l64dcon20s0
|
||||||
l64Dcon12_12U
|
l64dcon1212u
|
||||||
l64Dcon20S_12U
|
l64dcon20s12u
|
||||||
l64Dcon32_12S
|
l64dcon3212s
|
||||||
l64Dcon32_0
|
l64dcon320
|
||||||
l64Dcon32_20
|
l64dcon3220
|
||||||
l64Dcon12_32S
|
l64dcon1232s
|
||||||
l64Dcon20S_32
|
l64dcon20s32
|
||||||
l64Dcon32_12U
|
l64dcon3212u
|
||||||
l64Dcon
|
l64Dcon
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -987,91 +985,91 @@ func l64DconClass(v int64) int {
|
|||||||
lo20 := l64BitField(v, 12, 20)
|
lo20 := l64BitField(v, 12, 20)
|
||||||
lo12 := l64BitField(v, 0, 12)
|
lo12 := l64BitField(v, 0, 12)
|
||||||
if tzb >= 52 {
|
if tzb >= 52 {
|
||||||
return l64Dcon12_0
|
return l64dcon120
|
||||||
}
|
}
|
||||||
if tzb >= 32 {
|
if tzb >= 32 {
|
||||||
if ((hi20 == l64All1 || hi20 == l64St1) && hi12 == l64All1) || ((hi20 == l64All0 || hi20 == l64St0) && hi12 == l64All0) {
|
if ((hi20 == l64All1 || hi20 == l64St1) && hi12 == l64All1) || ((hi20 == l64All0 || hi20 == l64St0) && hi12 == l64All0) {
|
||||||
return l64Dcon20S_0
|
return l64dcon20s0
|
||||||
}
|
}
|
||||||
return l64Dcon32_0
|
return l64dcon320
|
||||||
}
|
}
|
||||||
if tzb >= 12 {
|
if tzb >= 12 {
|
||||||
if lo20 == l64St1 || lo20 == l64All1 {
|
if lo20 == l64St1 || lo20 == l64All1 {
|
||||||
if hi20 == l64All1 {
|
if hi20 == l64All1 {
|
||||||
return l64Dcon12_20S
|
return l64dcon1220s
|
||||||
}
|
}
|
||||||
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
||||||
return l64Dcon20S_20
|
return l64dcon20s20
|
||||||
}
|
}
|
||||||
return l64Dcon32_20
|
return l64dcon3220
|
||||||
}
|
}
|
||||||
if hi20 == l64All0 {
|
if hi20 == l64All0 {
|
||||||
return l64Dcon12_20S
|
return l64dcon1220s
|
||||||
}
|
}
|
||||||
if (hi20 == l64St0 && hi12 == l64All0) || ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) {
|
if (hi20 == l64St0 && hi12 == l64All0) || ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) {
|
||||||
return l64Dcon20S_20
|
return l64dcon20s20
|
||||||
}
|
}
|
||||||
return l64Dcon32_20
|
return l64dcon3220
|
||||||
}
|
}
|
||||||
if lo12 == l64St1 || lo12 == l64All1 {
|
if lo12 == l64St1 || lo12 == l64All1 {
|
||||||
if lo20 == l64All1 {
|
if lo20 == l64All1 {
|
||||||
if hi20 == l64All1 {
|
if hi20 == l64All1 {
|
||||||
return l64Dcon12_12S
|
return l64dcon1212s
|
||||||
}
|
}
|
||||||
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
||||||
return l64Dcon20S_12S
|
return l64dcon20s12s
|
||||||
}
|
}
|
||||||
return l64Dcon32_12S
|
return l64dcon3212s
|
||||||
}
|
}
|
||||||
if lo20 == l64St1 {
|
if lo20 == l64St1 {
|
||||||
if hi20 == l64All1 {
|
if hi20 == l64All1 {
|
||||||
return l64Dcon12_32S
|
return l64dcon1232s
|
||||||
}
|
}
|
||||||
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
||||||
return l64Dcon20S_32
|
return l64dcon20s32
|
||||||
}
|
}
|
||||||
return l64Dcon
|
return l64Dcon
|
||||||
}
|
}
|
||||||
if lo20 == l64All0 {
|
if lo20 == l64All0 {
|
||||||
if hi20 == l64All0 {
|
if hi20 == l64All0 {
|
||||||
return l64Dcon12_12U
|
return l64dcon1212u
|
||||||
}
|
}
|
||||||
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
||||||
return l64Dcon20S_12U
|
return l64dcon20s12u
|
||||||
}
|
}
|
||||||
return l64Dcon32_12U
|
return l64dcon3212u
|
||||||
}
|
}
|
||||||
if hi20 == l64All0 {
|
if hi20 == l64All0 {
|
||||||
return l64Dcon12_32S
|
return l64dcon1232s
|
||||||
}
|
}
|
||||||
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
||||||
return l64Dcon20S_32
|
return l64dcon20s32
|
||||||
}
|
}
|
||||||
return l64Dcon
|
return l64Dcon
|
||||||
}
|
}
|
||||||
if lo20 == l64All0 {
|
if lo20 == l64All0 {
|
||||||
if hi20 == l64All0 {
|
if hi20 == l64All0 {
|
||||||
return l64Dcon12_12U
|
return l64dcon1212u
|
||||||
}
|
}
|
||||||
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
||||||
return l64Dcon20S_12U
|
return l64dcon20s12u
|
||||||
}
|
}
|
||||||
return l64Dcon32_12U
|
return l64dcon3212u
|
||||||
}
|
}
|
||||||
if lo20 == l64St1 || lo20 == l64All1 {
|
if lo20 == l64St1 || lo20 == l64All1 {
|
||||||
if hi20 == l64All1 {
|
if hi20 == l64All1 {
|
||||||
return l64Dcon12_32S
|
return l64dcon1232s
|
||||||
}
|
}
|
||||||
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
if (hi20 == l64St1 && hi12 == l64All1) || ((hi20 == l64St0 || hi20 == l64All0) && hi12 == l64All0) {
|
||||||
return l64Dcon20S_32
|
return l64dcon20s32
|
||||||
}
|
}
|
||||||
return l64Dcon
|
return l64Dcon
|
||||||
}
|
}
|
||||||
if hi20 == l64All0 {
|
if hi20 == l64All0 {
|
||||||
return l64Dcon12_32S
|
return l64dcon1232s
|
||||||
}
|
}
|
||||||
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
if ((hi20 == l64St1 || hi20 == l64All1) && hi12 == l64All1) || (hi20 == l64St0 && hi12 == l64All0) {
|
||||||
return l64Dcon20S_32
|
return l64dcon20s32
|
||||||
}
|
}
|
||||||
return l64Dcon
|
return l64Dcon
|
||||||
}
|
}
|
||||||
@@ -1088,29 +1086,29 @@ func l64DconMovWords(rd int, v int64) []uint32 {
|
|||||||
ori = 0x00e << 22
|
ori = 0x00e << 22
|
||||||
)
|
)
|
||||||
switch l64DconClass(v) {
|
switch l64DconClass(v) {
|
||||||
case l64Dcon12_0:
|
case l64dcon120:
|
||||||
return []uint32{l64irr(lu52id, int(v>>52), 0, rd)}
|
return []uint32{l64irr(lu52id, int(v>>52), 0, rd)}
|
||||||
case l64Dcon12_20S:
|
case l64dcon1220s:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon20S_20:
|
case l64dcon20s20:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64ir(lu32id, int(v>>32), rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64ir(lu32id, int(v>>32), rd)}
|
||||||
case l64Dcon12_12S:
|
case l64dcon1212s:
|
||||||
return []uint32{l64irr(addid, int(v), 0, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64irr(addid, int(v), 0, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon20S_12S, l64Dcon20S_0:
|
case l64dcon20s12s, l64dcon20s0:
|
||||||
return []uint32{l64irr(addiw, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd)}
|
return []uint32{l64irr(addiw, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd)}
|
||||||
case l64Dcon12_12U:
|
case l64dcon1212u:
|
||||||
return []uint32{l64irr(ori, int(v), 0, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64irr(ori, int(v), 0, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon20S_12U:
|
case l64dcon20s12u:
|
||||||
return []uint32{l64irr(ori, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd)}
|
return []uint32{l64irr(ori, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd)}
|
||||||
case l64Dcon32_12S, l64Dcon32_0:
|
case l64dcon3212s, l64dcon320:
|
||||||
return []uint32{l64irr(addiw, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64irr(addiw, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon32_20:
|
case l64dcon3220:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon12_32S:
|
case l64dcon1232s:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
case l64Dcon20S_32:
|
case l64dcon20s32:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64ir(lu32id, int(v>>32), rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64ir(lu32id, int(v>>32), rd)}
|
||||||
case l64Dcon32_12U:
|
case l64dcon3212u:
|
||||||
return []uint32{l64irr(ori, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64irr(ori, int(v), 0, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
default:
|
default:
|
||||||
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
return []uint32{l64ir(lu12iw, int(v>>12), rd), l64irr(ori, int(v), rd, rd), l64ir(lu32id, int(v>>32), rd), l64irr(lu52id, int(v>>52), rd, rd)}
|
||||||
@@ -1161,7 +1159,7 @@ func encodeLOONG64LoadImm(rd int, v int64, mnem string) []byte {
|
|||||||
// encodeLOONG64MemOp encodes a memory load (load = true) or store with a
|
// encodeLOONG64MemOp encodes a memory load (load = true) or store with a
|
||||||
// 12-bit offset, or the 3-instruction expansion for larger offsets:
|
// 12-bit offset, or the 3-instruction expansion for larger offsets:
|
||||||
// lu12i.w r30, (off+0x800)>>12; add.d r30, rj, r30; ld/st rd, off(r30).
|
// lu12i.w r30, (off+0x800)>>12; add.d r30, rj, r30; ld/st rd, off(r30).
|
||||||
func encodeLOONG64MemOp(mnem string, mem *ast.Operand, reg int, load bool, fi loong64FrameInfo, relocs *[]Reloc) ([]byte, error) {
|
func encodeLOONG64MemOp(mnem string, mem *ast.Operand, reg int, load bool, fi loong64FrameInfo) ([]byte, error) {
|
||||||
rj, off := l64MemWithFrame(mem, fi)
|
rj, off := l64MemWithFrame(mem, fi)
|
||||||
if rj < 0 {
|
if rj < 0 {
|
||||||
return nil, fmt.Errorf("invalid memory operand")
|
return nil, fmt.Errorf("invalid memory operand")
|
||||||
@@ -1266,7 +1264,7 @@ func l64FpMoveKey(mnem string, sc, dc l64RegClass) (string, bool) {
|
|||||||
|
|
||||||
// encodeLOONG64SBAddr emits pcalau12i rd, 0; addi.d rd, rd, 0 with the
|
// encodeLOONG64SBAddr emits pcalau12i rd, 0; addi.d rd, rd, 0 with the
|
||||||
// R_LOONG64_ADDR_HI/LO relocation pair, loading a symbol's address.
|
// R_LOONG64_ADDR_HI/LO relocation pair, loading a symbol's address.
|
||||||
func encodeLOONG64SBAddr(sym *ast.Symbol, rd int, mnem string, relocs *[]Reloc) []byte {
|
func encodeLOONG64SBAddr(sym *ast.Symbol, rd int, relocs *[]Reloc) []byte {
|
||||||
if relocs != nil {
|
if relocs != nil {
|
||||||
*relocs = append(*relocs,
|
*relocs = append(*relocs,
|
||||||
Reloc{Off: 0, After: 0, Name: sym.Name, Kind: RelLoong64AddrHi, Addend: sym.Offset},
|
Reloc{Off: 0, After: 0, Name: sym.Name, Kind: RelLoong64AddrHi, Addend: sym.Offset},
|
||||||
|
|||||||
@@ -105,10 +105,10 @@ func loong64RegNum(name string) int {
|
|||||||
}
|
}
|
||||||
// F0–F31, FCC0–FCC7, FCSR0–FCSR31.
|
// F0–F31, FCC0–FCC7, FCSR0–FCSR31.
|
||||||
if len(name) >= 4 && name[:4] == "FCSR" {
|
if len(name) >= 4 && name[:4] == "FCSR" {
|
||||||
return loong64RegSpecial(name[4:], "FCSR", 31)
|
return loong64RegSpecial(name[4:], 31)
|
||||||
}
|
}
|
||||||
if len(name) >= 3 && name[:3] == "FCC" {
|
if len(name) >= 3 && name[:3] == "FCC" {
|
||||||
return loong64RegSpecial(name[3:], "FCC", 7)
|
return loong64RegSpecial(name[3:], 7)
|
||||||
}
|
}
|
||||||
if len(name) < 2 {
|
if len(name) < 2 {
|
||||||
return -1
|
return -1
|
||||||
@@ -131,7 +131,7 @@ func loong64RegNum(name string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// loong64RegSpecial parses a numbered FCC/FCSR register.
|
// loong64RegSpecial parses a numbered FCC/FCSR register.
|
||||||
func loong64RegSpecial(digits, prefix string, max int) int {
|
func loong64RegSpecial(digits string, max int) int {
|
||||||
if digits == "" {
|
if digits == "" {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-18
@@ -65,28 +65,28 @@ var (
|
|||||||
CX = Reg{idx: 1, size: 2}
|
CX = Reg{idx: 1, size: 2}
|
||||||
DX = Reg{idx: 2, size: 2}
|
DX = Reg{idx: 2, size: 2}
|
||||||
BX = Reg{idx: 3, size: 2}
|
BX = Reg{idx: 3, size: 2}
|
||||||
SP = Reg{idx: 4, size: 2}
|
_ = Reg{idx: 4, size: 2}
|
||||||
BP = Reg{idx: 5, size: 2}
|
_ = Reg{idx: 5, size: 2}
|
||||||
SI = Reg{idx: 6, size: 2}
|
SI = Reg{idx: 6, size: 2}
|
||||||
DI = Reg{idx: 7, size: 2}
|
DI = Reg{idx: 7, size: 2}
|
||||||
|
|
||||||
EAX = Reg{idx: 0, size: 4}
|
_ = Reg{idx: 0, size: 4}
|
||||||
ECX = Reg{idx: 1, size: 4}
|
_ = Reg{idx: 1, size: 4}
|
||||||
EDX = Reg{idx: 2, size: 4}
|
_ = Reg{idx: 2, size: 4}
|
||||||
EBX = Reg{idx: 3, size: 4}
|
_ = Reg{idx: 3, size: 4}
|
||||||
ESP = Reg{idx: 4, size: 4}
|
_ = Reg{idx: 4, size: 4}
|
||||||
EBP = Reg{idx: 5, size: 4}
|
_ = Reg{idx: 5, size: 4}
|
||||||
ESI = Reg{idx: 6, size: 4}
|
_ = Reg{idx: 6, size: 4}
|
||||||
EDI = Reg{idx: 7, size: 4}
|
_ = Reg{idx: 7, size: 4}
|
||||||
|
|
||||||
RAX = Reg{idx: 0, size: 8}
|
_ = Reg{idx: 0, size: 8}
|
||||||
RCX = Reg{idx: 1, size: 8}
|
_ = Reg{idx: 1, size: 8}
|
||||||
RDX = Reg{idx: 2, size: 8}
|
_ = Reg{idx: 2, size: 8}
|
||||||
RBX = Reg{idx: 3, size: 8}
|
_ = Reg{idx: 3, size: 8}
|
||||||
RSP = Reg{idx: 4, size: 8}
|
_ = Reg{idx: 4, size: 8}
|
||||||
RBP = Reg{idx: 5, size: 8}
|
_ = Reg{idx: 5, size: 8}
|
||||||
RSI = Reg{idx: 6, size: 8}
|
_ = Reg{idx: 6, size: 8}
|
||||||
RDI = Reg{idx: 7, size: 8}
|
_ = Reg{idx: 7, size: 8}
|
||||||
)
|
)
|
||||||
|
|
||||||
// regByName maps an assembly register name (case-insensitive) to a Reg.
|
// regByName maps an assembly register name (case-insensitive) to a Reg.
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
|||||||
// MOV is a pseudo-instruction that the Go assembler uses for loads,
|
// MOV is a pseudo-instruction that the Go assembler uses for loads,
|
||||||
// stores, register moves and immediate loads.
|
// stores, register moves and immediate loads.
|
||||||
case "MOV":
|
case "MOV":
|
||||||
return encodeRISCVMov(instr, offsets, fi, relocs)
|
return encodeRISCVMov(instr, fi, relocs)
|
||||||
|
|
||||||
// JALR: indirect jump/call. Plan 9: JALR rs1, rd or JALR offset(rs1).
|
// JALR: indirect jump/call. Plan 9: JALR rs1, rd or JALR offset(rs1).
|
||||||
case "JALR":
|
case "JALR":
|
||||||
@@ -527,7 +527,7 @@ func isImmOperand(op *ast.Operand) bool {
|
|||||||
// - MOV Rs, (Rd) register-relative store
|
// - MOV Rs, (Rd) register-relative store
|
||||||
// - MOV Rs, Rd register-to-register move (ADDI $0)
|
// - MOV Rs, Rd register-to-register move (ADDI $0)
|
||||||
// - MOV $imm, Rd load immediate (ADDI or LUI+ADDIW)
|
// - MOV $imm, Rd load immediate (ADDI or LUI+ADDIW)
|
||||||
func encodeRISCVMov(instr *ast.Instr, offsets map[string]int, fi riscvFrameInfo, relocs *[]Reloc) ([]byte, error) {
|
func encodeRISCVMov(instr *ast.Instr, fi riscvFrameInfo, relocs *[]Reloc) ([]byte, error) {
|
||||||
ops := instr.Operands
|
ops := instr.Operands
|
||||||
if len(ops) != 2 {
|
if len(ops) != 2 {
|
||||||
return nil, fmt.Errorf("MOV expects 2 operands, got %d", len(ops))
|
return nil, fmt.Errorf("MOV expects 2 operands, got %d", len(ops))
|
||||||
@@ -911,7 +911,7 @@ func tryCompressRVC(instr *ast.Instr, fi riscvFrameInfo) (uint16, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "ADDI":
|
case "ADDI":
|
||||||
rd, rs1, imm := extractITypeParams(instr, fi)
|
rd, rs1, imm := extractITypeParams(instr)
|
||||||
if rd == -1 || rs1 == -1 {
|
if rd == -1 || rs1 == -1 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -1060,13 +1060,13 @@ func tryCompressRVC(instr *ast.Instr, fi riscvFrameInfo) (uint16, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "ADDIW":
|
case "ADDIW":
|
||||||
rd, rs1, imm := extractITypeParams(instr, fi)
|
rd, rs1, imm := extractITypeParams(instr)
|
||||||
if rd == rs1 && rd != 0 && imm >= -32 && imm <= 31 {
|
if rd == rs1 && rd != 0 && imm >= -32 && imm <= 31 {
|
||||||
return rvcCI(0x1, uint32(rd), uint32(imm)&0x3F), true
|
return rvcCI(0x1, uint32(rd), uint32(imm)&0x3F), true
|
||||||
}
|
}
|
||||||
|
|
||||||
case "SLLI", "SRLI", "SRAI":
|
case "SLLI", "SRLI", "SRAI":
|
||||||
rd, rs1, imm := extractITypeParams(instr, fi)
|
rd, rs1, imm := extractITypeParams(instr)
|
||||||
if rd == rs1 && rd != 0 && imm != 0 && imm >= 1 && imm <= 63 {
|
if rd == rs1 && rd != 0 && imm != 0 && imm >= 1 && imm <= 63 {
|
||||||
if mnem == "SLLI" {
|
if mnem == "SLLI" {
|
||||||
// C.SLLI: funct3=0, op=10 quadrant, shamt in bits [12|6:2].
|
// C.SLLI: funct3=0, op=10 quadrant, shamt in bits [12|6:2].
|
||||||
@@ -1083,7 +1083,7 @@ func tryCompressRVC(instr *ast.Instr, fi riscvFrameInfo) (uint16, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "ANDI":
|
case "ANDI":
|
||||||
rd, rs1, imm := extractITypeParams(instr, fi)
|
rd, rs1, imm := extractITypeParams(instr)
|
||||||
if isRVCIntReg(rd) && rd == rs1 && imm >= -32 && imm <= 31 {
|
if isRVCIntReg(rd) && rd == rs1 && imm >= -32 && imm <= 31 {
|
||||||
// C.ANDI: CB-type, funct3=0x4, funct2=0x2.
|
// C.ANDI: CB-type, funct3=0x4, funct2=0x2.
|
||||||
return rvcCBShift(0x2, rvcReg3(rd), uint32(imm)&0x3F), true
|
return rvcCBShift(0x2, rvcReg3(rd), uint32(imm)&0x3F), true
|
||||||
@@ -1131,7 +1131,7 @@ func extractSDParams(instr *ast.Instr, fi riscvFrameInfo) (rs2, rs1 int, imm int
|
|||||||
// extractITypeParams extracts rd, rs1, and immediate for an I-type
|
// extractITypeParams extracts rd, rs1, and immediate for an I-type
|
||||||
// instruction. The Plan 9 order is INSTR $imm, rs1, rd (3 operands) or
|
// instruction. The Plan 9 order is INSTR $imm, rs1, rd (3 operands) or
|
||||||
// INSTR $imm, rd (2 operands, rd is also the source).
|
// INSTR $imm, rd (2 operands, rd is also the source).
|
||||||
func extractITypeParams(instr *ast.Instr, fi riscvFrameInfo) (rd, rs1 int, imm int32) {
|
func extractITypeParams(instr *ast.Instr) (rd, rs1 int, imm int32) {
|
||||||
ops := instr.Operands
|
ops := instr.Operands
|
||||||
switch len(ops) {
|
switch len(ops) {
|
||||||
case 3:
|
case 3:
|
||||||
|
|||||||
+1
-3
@@ -123,10 +123,8 @@ type Symbol struct {
|
|||||||
// OpKind classifies an operand syntactically.
|
// OpKind classifies an operand syntactically.
|
||||||
type OpKind int
|
type OpKind int
|
||||||
|
|
||||||
// Operand kinds.
|
|
||||||
const (
|
const (
|
||||||
OpInvalid OpKind = iota
|
OpImmediate = iota // $value
|
||||||
OpImmediate // $value
|
|
||||||
OpAddr // register, memory reference, symbol or label
|
OpAddr // register, memory reference, symbol or label
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -54,11 +54,11 @@ func TestStmtPositions(t *testing.T) {
|
|||||||
// TestInterfaces confirms the node types satisfy their interfaces, so callers
|
// TestInterfaces confirms the node types satisfy their interfaces, so callers
|
||||||
// can range over Decls and Stmts.
|
// can range over Decls and Stmts.
|
||||||
func TestInterfaces(t *testing.T) {
|
func TestInterfaces(t *testing.T) {
|
||||||
var decls []Decl = []Decl{&Include{}, &Preproc{}, &Text{}, &Globl{}, &Data{}}
|
var decls = []Decl{&Include{}, &Preproc{}, &Text{}, &Globl{}, &Data{}}
|
||||||
if len(decls) != 5 {
|
if len(decls) != 5 {
|
||||||
t.Fatal("decl interface set")
|
t.Fatal("decl interface set")
|
||||||
}
|
}
|
||||||
var stmts []Stmt = []Stmt{&Label{}, &Instr{}}
|
var stmts = []Stmt{&Label{}, &Instr{}}
|
||||||
if len(stmts) != 2 {
|
if len(stmts) != 2 {
|
||||||
t.Fatal("stmt interface set")
|
t.Fatal("stmt interface set")
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-30
@@ -299,7 +299,7 @@ given.
|
|||||||
rc = 1
|
rc = 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
out := format.Source(path, src)
|
out := format.Source(src)
|
||||||
if dirMode || *write {
|
if dirMode || *write {
|
||||||
if out != src {
|
if out != src {
|
||||||
if err := os.WriteFile(path, []byte(out), 0o644); err != nil {
|
if err := os.WriteFile(path, []byte(out), 0o644); err != nil {
|
||||||
@@ -447,7 +447,7 @@ requires -p, the package path, and the installed Go toolchain).
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
img, err := assembleFile(path, targetArch, f)
|
img, err := assembleFile(targetArch, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
|
fmt.Fprintf(os.Stderr, "%s: %v\n", path, err)
|
||||||
return 1
|
return 1
|
||||||
@@ -544,7 +544,7 @@ requires -p, the package path, and the installed Go toolchain).
|
|||||||
|
|
||||||
// cmdDiff compares the machine code of two assembly files.
|
// cmdDiff compares the machine code of two assembly files.
|
||||||
func cmdDiff(args []string) int {
|
func cmdDiff(args []string) int {
|
||||||
fs := newCommand("diff", "gasm diff <file1.s> <file2.s>", `
|
set := newCommand("diff", "gasm diff <file1.s> <file2.s>", `
|
||||||
Compare the machine code produced by assembling two files.
|
Compare the machine code produced by assembling two files.
|
||||||
Shows which functions differ and the byte-level differences.
|
Shows which functions differ and the byte-level differences.
|
||||||
Useful for verifying that two implementations produce identical code,
|
Useful for verifying that two implementations produce identical code,
|
||||||
@@ -553,13 +553,13 @@ or for tracking encoding changes between Go assembler versions.
|
|||||||
Use --map to compare functions whose names differ between the files,
|
Use --map to compare functions whose names differ between the files,
|
||||||
e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix.
|
e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix.
|
||||||
`)
|
`)
|
||||||
mapSpec := fs.String("map", "", "comma-separated old=new pairs to match functions with different names")
|
mapSpec := set.String("map", "", "comma-separated old=new pairs to match functions with different names")
|
||||||
fs.Parse(args)
|
set.Parse(args)
|
||||||
if fs.NArg() != 2 {
|
if set.NArg() != 2 {
|
||||||
fmt.Fprintln(os.Stderr, "usage: gasm diff <file1.s> <file2.s>")
|
fmt.Fprintln(os.Stderr, "usage: gasm diff <file1.s> <file2.s>")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
path1, path2 := fs.Arg(0), fs.Arg(1)
|
path1, path2 := set.Arg(0), set.Arg(1)
|
||||||
|
|
||||||
// Parse the name mapping (file1 name → file2 name).
|
// Parse the name mapping (file1 name → file2 name).
|
||||||
nameMap := make(map[string]string)
|
nameMap := make(map[string]string)
|
||||||
@@ -640,7 +640,7 @@ e.g. --map wideCopyAVX2=wideCopyAVX512 pairs the two regardless of suffix.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// assembleFile assembles a parsed file for the given architecture and returns the image.
|
// assembleFile assembles a parsed file for the given architecture and returns the image.
|
||||||
func assembleFile(path string, targetArch arch.Arch, f *ast.File) (*asm.Image, error) {
|
func assembleFile(targetArch arch.Arch, f *ast.File) (*asm.Image, error) {
|
||||||
switch targetArch {
|
switch targetArch {
|
||||||
case arch.AMD64:
|
case arch.AMD64:
|
||||||
return asm.AssembleFile(f)
|
return asm.AssembleFile(f)
|
||||||
@@ -668,7 +668,7 @@ func assemblePath(path string) (*asm.Image, error) {
|
|||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return nil, fmt.Errorf("parse errors")
|
return nil, fmt.Errorf("parse errors")
|
||||||
}
|
}
|
||||||
return assembleFile(path, arch.FromFilename(path), f)
|
return assembleFile(arch.FromFilename(path), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// printByteDiff shows the first few byte differences between two code blocks.
|
// printByteDiff shows the first few byte differences between two code blocks.
|
||||||
@@ -688,18 +688,18 @@ func printByteDiff(a, b []byte) {
|
|||||||
|
|
||||||
// cmdProfile shows the basic-block structure of functions in an assembly file.
|
// cmdProfile shows the basic-block structure of functions in an assembly file.
|
||||||
func cmdProfile(args []string) int {
|
func cmdProfile(args []string) int {
|
||||||
fs := newCommand("profile", "gasm profile <file.s>", `
|
flagSet := newCommand("profile", "gasm profile <file.s>", `
|
||||||
Show the basic-block structure of functions in an assembly file.
|
Show the basic-block structure of functions in an assembly file.
|
||||||
Lists each function's labels, their offsets, and the block boundaries.
|
Lists each function's labels, their offsets, and the block boundaries.
|
||||||
This is the static structure; for runtime execution counts, use
|
This is the static structure; for runtime execution counts, use
|
||||||
gasm verify --fuzz which exercises the code paths.
|
gasm verify --fuzz which exercises the code paths.
|
||||||
`)
|
`)
|
||||||
fs.Parse(args)
|
flagSet.Parse(args)
|
||||||
if fs.NArg() != 1 {
|
if flagSet.NArg() != 1 {
|
||||||
fmt.Fprintln(os.Stderr, "usage: gasm profile <file.s>")
|
fmt.Fprintln(os.Stderr, "usage: gasm profile <file.s>")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
path := fs.Arg(0)
|
path := flagSet.Arg(0)
|
||||||
|
|
||||||
// Load the file to get function metadata.
|
// Load the file to get function metadata.
|
||||||
k, err := verify.Load(path)
|
k, err := verify.Load(path)
|
||||||
@@ -1021,7 +1021,7 @@ func cmdVerifyARM64(path string, groundTruth, profile bool) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func cmdVerify(args []string) int {
|
func cmdVerify(args []string) int {
|
||||||
fs := newCommand("verify", "gasm verify [-smoke] [-abi] [-fuzz] [-ground-truth] [-profile] [-call] <file.s>", `
|
set := newCommand("verify", "gasm verify [-smoke] [-abi] [-fuzz] [-ground-truth] [-profile] [-call] <file.s>", `
|
||||||
Assemble FILE (amd64), map it into executable memory and report the available
|
Assemble FILE (amd64), map it into executable memory and report the available
|
||||||
functions. This confirms the assembled image is self-consistent (no
|
functions. This confirms the assembled image is self-consistent (no
|
||||||
unresolved external symbols) and executable — the prerequisite for dynamic
|
unresolved external symbols) and executable — the prerequisite for dynamic
|
||||||
@@ -1047,25 +1047,25 @@ With -call, a single function is invoked with user-supplied buffers (-buf)
|
|||||||
instead of the smoke/abi/fuzz sweeps. Useful for partial functions (e.g.
|
instead of the smoke/abi/fuzz sweeps. Useful for partial functions (e.g.
|
||||||
decoders) that crash on random input but should succeed on valid data.
|
decoders) that crash on random input but should succeed on valid data.
|
||||||
`)
|
`)
|
||||||
smoke := fs.Bool("smoke", false, "call each NOSPLIT function with zeroed args")
|
smoke := set.Bool("smoke", false, "call each NOSPLIT function with zeroed args")
|
||||||
abi := fs.Bool("abi", false, "run ABI-checking calls (sentinel registers + red zone)")
|
abi := set.Bool("abi", false, "run ABI-checking calls (sentinel registers + red zone)")
|
||||||
abiN := fs.Int("abi-n", 100, "number of ABI check iterations with varied inputs")
|
abiN := set.Int("abi-n", 100, "number of ABI check iterations with varied inputs")
|
||||||
profile := fs.Bool("profile", false, "list basic-block structure per function")
|
profile := set.Bool("profile", false, "list basic-block structure per function")
|
||||||
groundTruth := fs.Bool("ground-truth", false, "compare machine code byte-for-byte against go tool asm")
|
groundTruth := set.Bool("ground-truth", false, "compare machine code byte-for-byte against go tool asm")
|
||||||
fuzz := fs.Bool("fuzz", false, "differential fuzz: JIT both gasm and go-tool-asm versions, compare outputs")
|
fuzz := set.Bool("fuzz", false, "differential fuzz: JIT both gasm and go-tool-asm versions, compare outputs")
|
||||||
fuzzN := fs.Int("n", 1000, "number of fuzz iterations per function")
|
fuzzN := set.Int("n", 1000, "number of fuzz iterations per function")
|
||||||
fuzzOne := fs.String("fuzz-one", "", "") // hidden: fuzz a single function (subprocess mode)
|
fuzzOne := set.String("fuzz-one", "", "") // hidden: fuzz a single function (subprocess mode)
|
||||||
sweepOne := fs.String("sweep-one", "", "") // hidden: smoke/abi a single function (subprocess mode)
|
sweepOne := set.String("sweep-one", "", "") // hidden: smoke/abi a single function (subprocess mode)
|
||||||
call := fs.String("call", "", "call a single function with -buf instead of the sweeps")
|
call := set.String("call", "", "call a single function with -buf instead of the sweeps")
|
||||||
bufSpec := fs.String("buf", "", "buffer spec for -call: name:size:pattern[,name:size:pattern] (zero, ones, seq, or hex)")
|
bufSpec := set.String("buf", "", "buffer spec for -call: name:size:pattern[,name:size:pattern] (zero, ones, seq, or hex)")
|
||||||
scalarSpec := fs.String("args", "", "scalar args for -call: name=value[,name=value] (decimal or 0x hex)")
|
scalarSpec := set.String("args", "", "scalar args for -call: name=value[,name=value] (decimal or 0x hex)")
|
||||||
repeat := fs.Int("repeat", 1, "number of times to repeat a -call invocation")
|
repeat := set.Int("repeat", 1, "number of times to repeat a -call invocation")
|
||||||
fs.Parse(args)
|
set.Parse(args)
|
||||||
if fs.NArg() != 1 {
|
if set.NArg() != 1 {
|
||||||
fmt.Fprintln(os.Stderr, "usage: gasm verify [-smoke] [-abi] [-fuzz] [-ground-truth] [-profile] [-call] <file.s>")
|
fmt.Fprintln(os.Stderr, "usage: gasm verify [-smoke] [-abi] [-fuzz] [-ground-truth] [-profile] [-call] <file.s>")
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
path := fs.Arg(0)
|
path := set.Arg(0)
|
||||||
targetArch := arch.FromFilename(path)
|
targetArch := arch.FromFilename(path)
|
||||||
switch targetArch {
|
switch targetArch {
|
||||||
case arch.AMD64:
|
case arch.AMD64:
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ func mapRWX(code []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setupBuffers allocates buffers in the debuggee's memory.
|
// setupBuffers allocates buffers in the debuggee's memory.
|
||||||
func setupBuffers(spec string, args []byte, argSize int, tmpDir string) ([]byte, error) {
|
func setupBuffers(spec string, args []byte, tmpDir string) ([]byte, error) {
|
||||||
type bufSpec struct {
|
type bufSpec struct {
|
||||||
name string
|
name string
|
||||||
size int
|
size int
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
|
|
||||||
bufSpecFile := tmpDir + "/bufspec"
|
bufSpecFile := tmpDir + "/bufspec"
|
||||||
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
||||||
args, err = setupBuffers(string(bufSpec), args, fl.Args, tmpDir)
|
args, err = setupBuffers(string(bufSpec), args, tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("debug target: setup buffers: %w", err)
|
return fmt.Errorf("debug target: setup buffers: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
stackArgs := make([]byte, fl.Args)
|
stackArgs := make([]byte, fl.Args)
|
||||||
copy(stackArgs, args)
|
copy(stackArgs, args)
|
||||||
|
|
||||||
_, callErr := verify.Call(fnAddr, stackArgs)
|
_, callErr := verify.Call(stackArgs)
|
||||||
if callErr != nil {
|
if callErr != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
|
|
||||||
bufSpecFile := tmpDir + "/bufspec"
|
bufSpecFile := tmpDir + "/bufspec"
|
||||||
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
||||||
args, err = setupBuffers(string(bufSpec), args, fl.Args, tmpDir)
|
args, err = setupBuffers(string(bufSpec), args, tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("debug target: setup buffers: %w", err)
|
return fmt.Errorf("debug target: setup buffers: %w", err)
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
stackArgs := make([]byte, fl.Args)
|
stackArgs := make([]byte, fl.Args)
|
||||||
copy(stackArgs, args)
|
copy(stackArgs, args)
|
||||||
|
|
||||||
_, callErr := verify.Call(fnAddr, stackArgs)
|
_, callErr := verify.Call(stackArgs)
|
||||||
if callErr != nil {
|
if callErr != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
|
|
||||||
bufSpecFile := tmpDir + "/bufspec"
|
bufSpecFile := tmpDir + "/bufspec"
|
||||||
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
if bufSpec, err := os.ReadFile(bufSpecFile); err == nil && len(bufSpec) > 0 {
|
||||||
args, err = setupBuffers(string(bufSpec), args, fl.Args, tmpDir)
|
args, err = setupBuffers(string(bufSpec), args, tmpDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("debug target: setup buffers: %w", err)
|
return fmt.Errorf("debug target: setup buffers: %w", err)
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ func RunTarget(asmPath, funcName, argsFile, tmpDir string) error {
|
|||||||
stackArgs := make([]byte, fl.Args)
|
stackArgs := make([]byte, fl.Args)
|
||||||
copy(stackArgs, args)
|
copy(stackArgs, args)
|
||||||
|
|
||||||
_, callErr := verify.Call(fnAddr, stackArgs)
|
_, callErr := verify.Call(stackArgs)
|
||||||
if callErr != nil {
|
if callErr != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Repository: [sourcedock.dev/petrbalvin/gasm-devkit](https://sourcedock.dev/petrb
|
|||||||
graph TD
|
graph TD
|
||||||
SRC["source .s"] --> LEX["lexer<br/>token stream"]
|
SRC["source .s"] --> LEX["lexer<br/>token stream"]
|
||||||
LEX --> PAR["parser<br/>AST + diagnostics"]
|
LEX --> PAR["parser<br/>AST + diagnostics"]
|
||||||
LEX --> FMT["format<br/>re-space tokens"]
|
LEX --> FMT["s<br/>re-space tokens"]
|
||||||
PAR --> LINT["lint<br/>static checks"]
|
PAR --> LINT["lint<br/>static checks"]
|
||||||
PAR --> LSP["lsp server"]
|
PAR --> LSP["lsp server"]
|
||||||
LEX --> LSP
|
LEX --> LSP
|
||||||
@@ -157,7 +157,7 @@ Two deeper analyses sit on top of the AST:
|
|||||||
reference) and a literal index is range-checked; a named index constant such
|
reference) and a literal index is range-checked; a named index constant such
|
||||||
as `$PCDATA_StackMapIndex` is accepted without a range check.
|
as `$PCDATA_StackMapIndex` is accepted without a range check.
|
||||||
|
|
||||||
### `format`
|
### `s`
|
||||||
|
|
||||||
The formatter works on the **token stream, not the AST**, so it preserves
|
The formatter works on the **token stream, not the AST**, so it preserves
|
||||||
every line — comments and blanks included. It normalises indentation, operand
|
every line — comments and blanks included. It normalises indentation, operand
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ why, the options on the table, and the trigger that should reopen it.
|
|||||||
**Approach taken.** Instead of parsing the compiler's iexport data (which
|
**Approach taken.** Instead of parsing the compiler's iexport data (which
|
||||||
would have required either `golang.org/x/tools` or an in-house parser), the
|
would have required either `golang.org/x/tools` or an in-house parser), the
|
||||||
resolver reads the **GOOBJ data directly** from the target package's `.a`
|
resolver reads the **GOOBJ data directly** from the target package's `.a`
|
||||||
archive. The `.a` file contains a `_go_.o` member whose GOOBJ format is the
|
archive. The `.a` file contains a `_go_.o` member whose GOOBJ s is the
|
||||||
same one gasm writes — the parser reuses the same layout (`blkSymdef`,
|
same one gasm writes — the parser reuses the same layout (`blkSymdef`,
|
||||||
`blkNonpkgdef`, the string table), so no new dependency was needed.
|
`blkNonpkgdef`, the string table), so no new dependency was needed.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -97,7 +97,7 @@ ast/ Abstract syntax tree
|
|||||||
parser/ Line-oriented parser
|
parser/ Line-oriented parser
|
||||||
arch/ Register and instruction tables (generated)
|
arch/ Register and instruction tables (generated)
|
||||||
lint/ Static analysis rules
|
lint/ Static analysis rules
|
||||||
format/ Canonical formatter
|
s/ Canonical formatter
|
||||||
lsp/ Language Server Protocol server
|
lsp/ Language Server Protocol server
|
||||||
asm/ Standalone assembler, encoder, object emitters
|
asm/ Standalone assembler, encoder, object emitters
|
||||||
verify/ JIT execution, differential testing, ABI checks
|
verify/ JIT execution, differential testing, ABI checks
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Source returns the canonical formatting of src.
|
// Source returns the canonical formatting of src.
|
||||||
func Source(path, src string) string {
|
func Source(src string) string {
|
||||||
lines := splitLines(lexer.Tokenize(src))
|
lines := splitLines(lexer.Tokenize(src))
|
||||||
|
|
||||||
// First pass: classify each line and record, for every instruction, the
|
// First pass: classify each line and record, for every instruction, the
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestGolden(t *testing.T) {
|
|||||||
"\tVFMADD231PD Z14, Z12, Z10\n" +
|
"\tVFMADD231PD Z14, Z12, Z10\n" +
|
||||||
"\tRET\n"
|
"\tRET\n"
|
||||||
|
|
||||||
got := Source("f_amd64.s", in)
|
got := Source(in)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
||||||
}
|
}
|
||||||
@@ -64,13 +64,13 @@ func TestDocCommentIndent(t *testing.T) {
|
|||||||
"TEXT ·second(SB), NOSPLIT, $0\n" +
|
"TEXT ·second(SB), NOSPLIT, $0\n" +
|
||||||
"\tRET\n"
|
"\tRET\n"
|
||||||
|
|
||||||
got := Source("d_amd64.s", in)
|
got := Source(in)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
||||||
}
|
}
|
||||||
// Body comments stay indented.
|
// Body comments stay indented.
|
||||||
body := "#include \"textflag.h\"\nTEXT ·f(SB), NOSPLIT, $0\n// inside the body\nXORQ AX, AX\nRET\n"
|
body := "#include \"textflag.h\"\nTEXT ·f(SB), NOSPLIT, $0\n// inside the body\nXORQ AX, AX\nRET\n"
|
||||||
gotBody := Source("b_amd64.s", body)
|
gotBody := Source(body)
|
||||||
if !strings.Contains(gotBody, "\t// inside the body\n") {
|
if !strings.Contains(gotBody, "\t// inside the body\n") {
|
||||||
t.Fatalf("body comment must stay indented:\n%q", gotBody)
|
t.Fatalf("body comment must stay indented:\n%q", gotBody)
|
||||||
}
|
}
|
||||||
@@ -125,11 +125,11 @@ func TestBlankLines(t *testing.T) {
|
|||||||
"GLOBL ·mask(SB), RODATA, $8\n" +
|
"GLOBL ·mask(SB), RODATA, $8\n" +
|
||||||
"DATA ·mask+0(SB)/4, $1\n"
|
"DATA ·mask+0(SB)/4, $1\n"
|
||||||
|
|
||||||
got := Source("b_amd64.s", in)
|
got := Source(in)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
t.Fatalf("formatting mismatch:\n--- got ---\n%q\n--- want ---\n%q", got, want)
|
||||||
}
|
}
|
||||||
if again := Source("b_amd64.s", got); again != got {
|
if again := Source(got); again != got {
|
||||||
t.Fatalf("not idempotent:\n%q", again)
|
t.Fatalf("not idempotent:\n%q", again)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,8 +163,8 @@ func TestIdempotent(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
once := Source("sample_amd64.s", string(src))
|
once := Source(string(src))
|
||||||
twice := Source("sample_amd64.s", once)
|
twice := Source(once)
|
||||||
if once != twice {
|
if once != twice {
|
||||||
t.Fatal("formatting is not idempotent on the fixture")
|
t.Fatal("formatting is not idempotent on the fixture")
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ func TestRoundTrip(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
formatted := Source(path, string(src))
|
formatted := Source(string(src))
|
||||||
if _, errs := parser.Parse(path, formatted); len(errs) > 0 {
|
if _, errs := parser.Parse(path, formatted); len(errs) > 0 {
|
||||||
t.Errorf("formatted %s no longer parses: %v", path, errs)
|
t.Errorf("formatted %s no longer parses: %v", path, errs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestRoundTripRealGoLibraries(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
formatted := Source(path, string(src))
|
formatted := Source(string(src))
|
||||||
if _, errs := parser.Parse(path, formatted); len(errs) > 0 {
|
if _, errs := parser.Parse(path, formatted); len(errs) > 0 {
|
||||||
t.Errorf("formatted %s no longer parses: %v", path, errs)
|
t.Errorf("formatted %s no longer parses: %v", path, errs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ test:
|
|||||||
sourcedock.dev/petrbalvin/gasm-devkit/arch \
|
sourcedock.dev/petrbalvin/gasm-devkit/arch \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/asm \
|
sourcedock.dev/petrbalvin/gasm-devkit/asm \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/ast \
|
sourcedock.dev/petrbalvin/gasm-devkit/ast \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/format \
|
sourcedock.dev/petrbalvin/gasm-devkit/s \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/lexer \
|
sourcedock.dev/petrbalvin/gasm-devkit/lexer \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/lint \
|
sourcedock.dev/petrbalvin/gasm-devkit/lint \
|
||||||
sourcedock.dev/petrbalvin/gasm-devkit/lsp \
|
sourcedock.dev/petrbalvin/gasm-devkit/lsp \
|
||||||
|
|||||||
+3
-5
@@ -212,7 +212,7 @@ func (s *Server) documentFormatting(p documentFormattingParams) []TextEdit {
|
|||||||
if text == "" {
|
if text == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
formatted := format.Source(uriPath(p.TextDocument.URI), text)
|
formatted := format.Source(text)
|
||||||
if formatted == text {
|
if formatted == text {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -596,8 +596,7 @@ func classifyLine(line []token.Token, a *arch.Table, labels map[string]bool) []s
|
|||||||
case token.Hash:
|
case token.Hash:
|
||||||
typ = stMacro
|
typ = stMacro
|
||||||
case token.Ident:
|
case token.Ident:
|
||||||
typ = classifyIdent(line, i, first, t.Text, a, labels,
|
typ = classifyIdent(i, first, t.Text, a, labels, isDirective, isLabel, isInstr, &mnemonicDone)
|
||||||
isDirective, isLabel, isInstr, &mnemonicDone)
|
|
||||||
case token.Colon, token.Comma, token.LParen, token.RParen,
|
case token.Colon, token.Comma, token.LParen, token.RParen,
|
||||||
token.Plus, token.Minus, token.Star, token.Slash, token.Dollar,
|
token.Plus, token.Minus, token.Star, token.Slash, token.Dollar,
|
||||||
token.LAngle, token.RAngle, token.LShift, token.RShift, token.Arrow, token.At:
|
token.LAngle, token.RAngle, token.LShift, token.RShift, token.Arrow, token.At:
|
||||||
@@ -616,8 +615,7 @@ func classifyLine(line []token.Token, a *arch.Table, labels map[string]bool) []s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// classifyIdent decides the semantic type of an identifier token.
|
// classifyIdent decides the semantic type of an identifier token.
|
||||||
func classifyIdent(line []token.Token, i, first int, text string, a *arch.Table,
|
func classifyIdent(i, first int, text string, a *arch.Table, labels map[string]bool, isDirective, isLabel, isInstr bool, mnemonicDone *bool) int {
|
||||||
labels map[string]bool, isDirective, isLabel, isInstr bool, mnemonicDone *bool) int {
|
|
||||||
|
|
||||||
upper := strings.ToUpper(text)
|
upper := strings.ToUpper(text)
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
+1
-8
@@ -29,13 +29,8 @@ type rpcError struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON-RPC error codes used by LSP.
|
|
||||||
const (
|
const (
|
||||||
errParse = -32700
|
|
||||||
errInvalidRequest = -32600
|
|
||||||
errMethodNotFound = -32601
|
errMethodNotFound = -32601
|
||||||
errInvalidParams = -32602
|
|
||||||
errInternal = -32603
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// --- LSP positions and ranges ----------------------------------------------
|
// --- LSP positions and ranges ----------------------------------------------
|
||||||
@@ -119,16 +114,14 @@ type didCloseParams struct {
|
|||||||
|
|
||||||
// --- completion -------------------------------------------------------------
|
// --- completion -------------------------------------------------------------
|
||||||
|
|
||||||
// Completion item kinds (a useful subset).
|
|
||||||
const (
|
const (
|
||||||
ciFunction = 3
|
ciFunction = 3
|
||||||
ciField = 5
|
|
||||||
ciVariable = 6
|
ciVariable = 6
|
||||||
ciClass = 7
|
ciClass = 7
|
||||||
ciModule = 9
|
ciModule = 9
|
||||||
ciKeyword = 14
|
ciKeyword = 14
|
||||||
ciConstant = 21
|
ciConstant = 21
|
||||||
ciStruct = 22
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompletionItem is one completion suggestion.
|
// CompletionItem is one completion suggestion.
|
||||||
|
|||||||
+2
-2
@@ -19,13 +19,13 @@ const (
|
|||||||
Newline
|
Newline
|
||||||
Comment
|
Comment
|
||||||
|
|
||||||
// Literals and names.
|
// Ident Literals and names.
|
||||||
Ident // instruction mnemonic, label, register or symbol name
|
Ident // instruction mnemonic, label, register or symbol name
|
||||||
Number // integer or floating-point literal (sign carried separately)
|
Number // integer or floating-point literal (sign carried separately)
|
||||||
String // "..."
|
String // "..."
|
||||||
Rune // '.'
|
Rune // '.'
|
||||||
|
|
||||||
// Punctuation and operators.
|
// LParen Punctuation and operators.
|
||||||
LParen // (
|
LParen // (
|
||||||
RParen // )
|
RParen // )
|
||||||
Comma // ,
|
Comma // ,
|
||||||
|
|||||||
+3
-2
@@ -89,8 +89,9 @@ const redZoneSize = 128
|
|||||||
// redZoneFill is the byte pattern used to detect red-zone writes.
|
// redZoneFill is the byte pattern used to detect red-zone writes.
|
||||||
const redZoneFill = 0xA5
|
const redZoneFill = 0xA5
|
||||||
|
|
||||||
// CallChecked invokes the function with ABI sentinels and a red-zone
|
// CallChecked invokes the function at fnAddr with ABI sentinels and a
|
||||||
// canary, returning both the argument block (with results) and an ABIReport.
|
// red-zone canary, returning both the argument block (with results) and an
|
||||||
|
// ABIReport.
|
||||||
func CallChecked(fnAddr uintptr, args []byte) ([]byte, ABIReport, error) {
|
func CallChecked(fnAddr uintptr, args []byte) ([]byte, ABIReport, error) {
|
||||||
report := ABIReport{}
|
report := ABIReport{}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,10 @@ var savedSP uintptr
|
|||||||
|
|
||||||
// enterJIT switches to the prepared stack and jumps to fn.
|
// enterJIT switches to the prepared stack and jumps to fn.
|
||||||
// It does not return normally; the JIT function's RET transfers control
|
// It does not return normally; the JIT function's RET transfers control
|
||||||
// to leaveJIT, which restores the Go stack.
|
// to leaveJIT, which restores the Go stack. The body lives in
|
||||||
|
// trampoline_amd64.s and reads the parameters from the frame by name.
|
||||||
|
//
|
||||||
|
// noinspection GoUnusedParameter
|
||||||
//
|
//
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func enterJIT(fn uintptr, stack uintptr)
|
func enterJIT(fn uintptr, stack uintptr)
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ func groundTruthArch(path, goarch string) (map[string][]byte, error) {
|
|||||||
return extractGOOBJCode(objData)
|
return extractGOOBJCode(objData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GOOBJ block indices (cmd/internal/goobj).
|
|
||||||
const (
|
const (
|
||||||
blkAutolib = iota
|
blkAutolib = iota
|
||||||
blkPkgIdx
|
blkPkgIdx
|
||||||
|
|||||||
Reference in New Issue
Block a user