Commit cb19a201 authored by Rob Pike's avatar Rob Pike

[dev.cc] cmd/asm: rewrite to work with new obj API

Considerable rewriting of the parser and assembler (code generator)
but it's simpler and shorter now. The internal Addr type is gone; so
is the package that held it. Parsing of operands goes directly into
obj.Addrs now.

There is a horrible hack regarding register pairs. It uses the Class
field to store the second register since it needs _some_ place to
put it but none is provided in the API. An alternative would be nice
but this works for now.

Once again creates identical .6 and .8 files as the old assembler.

Change-Id: I8207d6dfdfdb5bbed0bd870cb34ee0fe61c2fbfd
Reviewed-on: https://go-review.googlesource.com/4062Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 1fc330d8
// +build ignore
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package addr holds the definition of an instruction address.
package addr
// Addr represents a parsed address.
type Addr struct {
IsStatic bool // symbol<>
IsImmediateConstant bool // $3
IsImmediateAddress bool // $main·main(SB)
IsIndirect bool // (R1)
HasRegister bool // register is set
HasRegister2 bool // register2 is set
HasFloat bool // float is set
HasOffset bool // offset is set
HasString bool // string is set
Symbol string // "main·main"
Register int16 // R1
Register2 int16 // R1 in R0:R1
Offset int64 // 3
Float float64 // 1.0e2 (floating constant)
String string // "hi" (string constant)
Index int16 // R1 in (R1*8)
Scale int8 // 8 in (R1*8)
}
const (
// IsStatic does not appear here; Is and Has methods ignore it.
ImmediateConstant = 1 << iota
ImmediateAddress
Indirect
Symbol
Register
Register2
Offset
Float
String
Index
Scale
)
// Has reports whether the address has any of the specified elements.
// Indirect and immediate are not checked.
func (a *Addr) Has(mask int) bool {
if mask&Symbol != 0 && a.Symbol != "" {
return true
}
if mask&Register != 0 && a.HasRegister {
return true
}
if mask&Register2 != 0 && a.HasRegister2 {
return true
}
if mask&Offset != 0 && a.HasOffset {
return true
}
if mask&Float != 0 && a.HasFloat {
return true
}
if mask&String != 0 && a.HasString {
return true
}
if mask&Index != 0 && a.Index != 0 {
return true
}
if mask&Scale != 0 && a.Scale != 0 {
return true
}
return false
}
// Is reports whether the address has all the specified elements.
// Indirect and immediate are checked.
func (a *Addr) Is(mask int) bool {
if (mask&ImmediateConstant == 0) != !a.IsImmediateConstant {
return false
}
if (mask&ImmediateAddress == 0) != !a.IsImmediateAddress {
return false
}
if (mask&Indirect == 0) != !a.IsIndirect {
return false
}
if (mask&Symbol == 0) != (a.Symbol == "") {
return false
}
if (mask&Register == 0) != !a.HasRegister {
return false
}
if (mask&Register2 == 0) != !a.HasRegister2 {
return false
}
if (mask&Offset == 0) != !a.HasOffset {
// $0 has the immediate bit but value 0.
return false
}
if (mask&Float == 0) != !a.HasFloat {
return false
}
if (mask&String == 0) != !a.HasString {
return false
}
if (mask&Index == 0) != (a.Index == 0) {
return false
}
if (mask&Scale == 0) != (a.Scale == 0) {
return false
}
return true
}
// +build ignore
// Copyright 2015 The Go Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -23,22 +21,22 @@ const ( ...@@ -23,22 +21,22 @@ const (
// Arch wraps the link architecture object with more architecture-specific information. // Arch wraps the link architecture object with more architecture-specific information.
type Arch struct { type Arch struct {
*obj.LinkArch *obj.LinkArch
D_INDIR int // TODO: why not in LinkArch?
D_CONST2 int // TODO: why not in LinkArch?
// Register number of hardware stack pointer.
SP int
// Encoding of non-address.
NoAddr obj.Addr
// Map of instruction names to enumeration. // Map of instruction names to enumeration.
Instructions map[string]int Instructions map[string]int
// Map of register names to enumeration. // Map of register names to enumeration.
Registers map[string]int Registers map[string]int16
// Map of pseudo-instructions (TEXT, DATA etc.) to enumeration.
Pseudos map[string]int
// Instructions that take one operand whose result is a destination. // Instructions that take one operand whose result is a destination.
UnaryDestination map[int]bool UnaryDestination map[int]bool
} }
var Pseudos = map[string]int{
"DATA": obj.ADATA,
"FUNCDATA": obj.AFUNCDATA,
"GLOBL": obj.AGLOBL,
"PCDATA": obj.APCDATA,
"TEXT": obj.ATEXT,
}
// Set configures the architecture specified by GOARCH and returns its representation. // Set configures the architecture specified by GOARCH and returns its representation.
// It returns nil if GOARCH is not recognized. // It returns nil if GOARCH is not recognized.
func Set(GOARCH string) *Arch { func Set(GOARCH string) *Arch {
...@@ -53,21 +51,16 @@ func Set(GOARCH string) *Arch { ...@@ -53,21 +51,16 @@ func Set(GOARCH string) *Arch {
} }
func arch386() *Arch { func arch386() *Arch {
noAddr := obj.Addr{
Type: i386.D_NONE,
Index: i386.D_NONE,
}
registers := make(map[string]int) registers := make(map[string]int16)
// Create maps for easy lookup of instruction names etc. // Create maps for easy lookup of instruction names etc.
// TODO: Should this be done in obj for us? // TODO: Should this be done in obj for us?
for i, s := range i386.Register { for i, s := range i386.Register {
registers[s] = i registers[s] = int16(i + i386.REG_AL)
} }
// Pseudo-registers. // Pseudo-registers.
registers["SB"] = RSB registers["SB"] = RSB
registers["FP"] = RFP registers["FP"] = RFP
registers["SP"] = RSP
registers["PC"] = RPC registers["PC"] = RPC
instructions := make(map[string]int) instructions := make(map[string]int)
...@@ -108,13 +101,6 @@ func arch386() *Arch { ...@@ -108,13 +101,6 @@ func arch386() *Arch {
instructions["MOVOA"] = i386.AMOVO instructions["MOVOA"] = i386.AMOVO
instructions["MOVNTDQ"] = i386.AMOVNTO instructions["MOVNTDQ"] = i386.AMOVNTO
pseudos := make(map[string]int) // TEXT, DATA etc.
pseudos["DATA"] = i386.ADATA
pseudos["FUNCDATA"] = i386.AFUNCDATA
pseudos["GLOBL"] = i386.AGLOBL
pseudos["PCDATA"] = i386.APCDATA
pseudos["TEXT"] = i386.ATEXT
unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination. unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
// These instructions write to prog.To. // These instructions write to prog.To.
unaryDestination[i386.ABSWAPL] = true unaryDestination[i386.ABSWAPL] = true
...@@ -158,33 +144,23 @@ func arch386() *Arch { ...@@ -158,33 +144,23 @@ func arch386() *Arch {
return &Arch{ return &Arch{
LinkArch: &i386.Link386, LinkArch: &i386.Link386,
D_INDIR: i386.D_INDIR,
D_CONST2: i386.D_CONST2,
SP: i386.D_SP,
NoAddr: noAddr,
Instructions: instructions, Instructions: instructions,
Registers: registers, Registers: registers,
Pseudos: pseudos,
UnaryDestination: unaryDestination, UnaryDestination: unaryDestination,
} }
} }
func archAmd64() *Arch { func archAmd64() *Arch {
noAddr := obj.Addr{
Type: x86.D_NONE,
Index: x86.D_NONE,
}
registers := make(map[string]int) registers := make(map[string]int16)
// Create maps for easy lookup of instruction names etc. // Create maps for easy lookup of instruction names etc.
// TODO: Should this be done in obj for us? // TODO: Should this be done in obj for us?
for i, s := range x86.Register { for i, s := range x86.Register {
registers[s] = i registers[s] = int16(i + x86.REG_AL)
} }
// Pseudo-registers. // Pseudo-registers.
registers["SB"] = RSB registers["SB"] = RSB
registers["FP"] = RFP registers["FP"] = RFP
registers["SP"] = RSP
registers["PC"] = RPC registers["PC"] = RPC
instructions := make(map[string]int) instructions := make(map[string]int)
...@@ -223,13 +199,6 @@ func archAmd64() *Arch { ...@@ -223,13 +199,6 @@ func archAmd64() *Arch {
instructions["MOVD"] = x86.AMOVQ instructions["MOVD"] = x86.AMOVQ
instructions["MOVDQ2Q"] = x86.AMOVQ instructions["MOVDQ2Q"] = x86.AMOVQ
pseudos := make(map[string]int) // TEXT, DATA etc.
pseudos["DATA"] = x86.ADATA
pseudos["FUNCDATA"] = x86.AFUNCDATA
pseudos["GLOBL"] = x86.AGLOBL
pseudos["PCDATA"] = x86.APCDATA
pseudos["TEXT"] = x86.ATEXT
unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination. unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
// These instructions write to prog.To. // These instructions write to prog.To.
unaryDestination[x86.ABSWAPL] = true unaryDestination[x86.ABSWAPL] = true
...@@ -282,13 +251,8 @@ func archAmd64() *Arch { ...@@ -282,13 +251,8 @@ func archAmd64() *Arch {
return &Arch{ return &Arch{
LinkArch: &x86.Linkamd64, LinkArch: &x86.Linkamd64,
D_INDIR: x86.D_INDIR,
D_CONST2: x86.D_NONE,
SP: x86.D_SP,
NoAddr: noAddr,
Instructions: instructions, Instructions: instructions,
Registers: registers, Registers: registers,
Pseudos: pseudos,
UnaryDestination: unaryDestination, UnaryDestination: unaryDestination,
} }
} }
This diff is collapsed.
This diff is collapsed.
...@@ -61,8 +61,9 @@ var ( ...@@ -61,8 +61,9 @@ var (
// HistLine reports the cumulative source line number of the token, // HistLine reports the cumulative source line number of the token,
// for use in the Prog structure for the linker. (It's always handling the // for use in the Prog structure for the linker. (It's always handling the
// instruction from the current lex line.) // instruction from the current lex line.)
func HistLine() int { // It returns int32 because that's what type ../asm prefers.
return histLine func HistLine() int32 {
return int32(histLine)
} }
// NewLexer returns a lexer for the named file and the given link context. // NewLexer returns a lexer for the named file and the given link context.
......
...@@ -22,13 +22,6 @@ func (s *Stack) Next() ScanToken { ...@@ -22,13 +22,6 @@ func (s *Stack) Next() ScanToken {
tok := tos.Next() tok := tos.Next()
for tok == scanner.EOF && len(s.tr) > 1 { for tok == scanner.EOF && len(s.tr) > 1 {
tos.Close() tos.Close()
/*
// If it's not a macro (a Slice at this point), pop the line history stack and close the file descriptor.
if _, isMacro := tos.(*Slice); !isMacro {
// TODO: close file descriptor.
obj.Linklinehist(linkCtxt, histLine, "<pop>", 0)
}
*/
// Pop the topmost item from the stack and resume with the next one down. // Pop the topmost item from the stack and resume with the next one down.
s.tr = s.tr[:len(s.tr)-1] s.tr = s.tr[:len(s.tr)-1]
tok = s.Next() tok = s.Next()
......
// +build ignore
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment