mirror of
https://github.com/golang/go.git
synced 2025-05-27 18:31:35 +00:00
Clean up the obj API by making Rconv (register pretty printer) a top-level function. This means that Dconv (operand pretty printer) doesn't need an Rconv argument. To do this, we make the register numbers, which are arbitrary inside an operand (obj.Addr), disjoint sets for each architecture. Each architecture registers (ha) a piece of the space and then the global Rconv knows which architecture-specific printer to use. Clean up all the code that uses Dconv. Now register numbers are large, so a couple of fields in Addr need to go from int8 to int16 because they sometimes hold register numbers. Clean up their uses, which meant regenerating the yacc grammars for the assemblers. There are changes in this CL triggered by earlier changes to yacc, which had not been run in this directory. There is still cleanup to do in Addr, but we're getting closer to that being easy to do. Change-Id: I9290ebee013b62f7d24e886743ea5a6b232990ab Reviewed-on: https://go-review.googlesource.com/6220 Reviewed-by: Russ Cox <rsc@golang.org>
422 lines
12 KiB
Go
422 lines
12 KiB
Go
// 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 arch
|
|
|
|
import (
|
|
"cmd/internal/obj"
|
|
"cmd/internal/obj/arm"
|
|
"cmd/internal/obj/i386" // == 386
|
|
"cmd/internal/obj/ppc64"
|
|
"cmd/internal/obj/x86" // == amd64
|
|
"fmt"
|
|
)
|
|
|
|
// Pseudo-registers whose names are the constant name without the leading R.
|
|
const (
|
|
RFP = -(iota + 1)
|
|
RSB
|
|
RSP
|
|
RPC
|
|
)
|
|
|
|
// Arch wraps the link architecture object with more architecture-specific information.
|
|
type Arch struct {
|
|
*obj.LinkArch
|
|
// Map of instruction names to enumeration.
|
|
Instructions map[string]int
|
|
// Map of register names to enumeration.
|
|
Register map[string]int16
|
|
// Table of register prefix names. These are things like R for R(0) and SPR for SPR(268).
|
|
RegisterPrefix map[string]bool
|
|
// RegisterNumber converts R(10) into arm.REG_R10.
|
|
RegisterNumber func(string, int16) (int16, bool)
|
|
// Instructions that take one operand whose result is a destination.
|
|
UnaryDestination map[int]bool
|
|
// Instruction is a jump.
|
|
IsJump func(word string) bool
|
|
// Aconv pretty-prints an instruction opcode for this architecture.
|
|
Aconv func(int) string
|
|
}
|
|
|
|
// nilRegisterNumber is the register number function for architectures
|
|
// that do not accept the R(N) notation. It always returns failure.
|
|
func nilRegisterNumber(name string, n int16) (int16, bool) {
|
|
return 0, false
|
|
}
|
|
|
|
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.
|
|
// It returns nil if GOARCH is not recognized.
|
|
func Set(GOARCH string) *Arch {
|
|
// TODO: Is this how to set this up?
|
|
switch GOARCH {
|
|
case "386":
|
|
return arch386()
|
|
case "amd64":
|
|
return archAmd64()
|
|
case "amd64p32":
|
|
a := archAmd64()
|
|
a.LinkArch = &x86.Linkamd64p32
|
|
return a
|
|
case "arm":
|
|
return archArm()
|
|
case "ppc64":
|
|
a := archPPC64()
|
|
a.LinkArch = &ppc64.Linkppc64
|
|
return a
|
|
case "ppc64le":
|
|
a := archPPC64()
|
|
a.LinkArch = &ppc64.Linkppc64le
|
|
return a
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func jump386(word string) bool {
|
|
return word[0] == 'J' || word == "CALL"
|
|
}
|
|
|
|
func arch386() *Arch {
|
|
register := make(map[string]int16)
|
|
// Create maps for easy lookup of instruction names etc.
|
|
// TODO: Should this be done in obj for us?
|
|
for i, s := range i386.Register {
|
|
register[s] = int16(i + i386.REG_AL)
|
|
}
|
|
// Pseudo-registers.
|
|
register["SB"] = RSB
|
|
register["FP"] = RFP
|
|
register["PC"] = RPC
|
|
// Prefixes not used on this architecture.
|
|
|
|
instructions := make(map[string]int)
|
|
for i, s := range i386.Anames {
|
|
instructions[s] = i
|
|
}
|
|
// Annoying aliases.
|
|
instructions["JA"] = i386.AJHI
|
|
instructions["JAE"] = i386.AJCC
|
|
instructions["JB"] = i386.AJCS
|
|
instructions["JBE"] = i386.AJLS
|
|
instructions["JC"] = i386.AJCS
|
|
instructions["JE"] = i386.AJEQ
|
|
instructions["JG"] = i386.AJGT
|
|
instructions["JHS"] = i386.AJCC
|
|
instructions["JL"] = i386.AJLT
|
|
instructions["JLO"] = i386.AJCS
|
|
instructions["JNA"] = i386.AJLS
|
|
instructions["JNAE"] = i386.AJCS
|
|
instructions["JNB"] = i386.AJCC
|
|
instructions["JNBE"] = i386.AJHI
|
|
instructions["JNC"] = i386.AJCC
|
|
instructions["JNG"] = i386.AJLE
|
|
instructions["JNGE"] = i386.AJLT
|
|
instructions["JNL"] = i386.AJGE
|
|
instructions["JNLE"] = i386.AJGT
|
|
instructions["JNO"] = i386.AJOC
|
|
instructions["JNP"] = i386.AJPC
|
|
instructions["JNS"] = i386.AJPL
|
|
instructions["JNZ"] = i386.AJNE
|
|
instructions["JO"] = i386.AJOS
|
|
instructions["JP"] = i386.AJPS
|
|
instructions["JPE"] = i386.AJPS
|
|
instructions["JPO"] = i386.AJPC
|
|
instructions["JS"] = i386.AJMI
|
|
instructions["JZ"] = i386.AJEQ
|
|
instructions["MASKMOVDQU"] = i386.AMASKMOVOU
|
|
instructions["MOVOA"] = i386.AMOVO
|
|
instructions["MOVNTDQ"] = i386.AMOVNTO
|
|
|
|
unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
|
|
// These instructions write to prog.To.
|
|
unaryDestination[i386.ABSWAPL] = true
|
|
unaryDestination[i386.ACMPXCHG8B] = true
|
|
unaryDestination[i386.ADECB] = true
|
|
unaryDestination[i386.ADECL] = true
|
|
unaryDestination[i386.ADECW] = true
|
|
unaryDestination[i386.AINCB] = true
|
|
unaryDestination[i386.AINCL] = true
|
|
unaryDestination[i386.AINCW] = true
|
|
unaryDestination[i386.ANEGB] = true
|
|
unaryDestination[i386.ANEGL] = true
|
|
unaryDestination[i386.ANEGW] = true
|
|
unaryDestination[i386.ANOTB] = true
|
|
unaryDestination[i386.ANOTL] = true
|
|
unaryDestination[i386.ANOTW] = true
|
|
unaryDestination[i386.APOPL] = true
|
|
unaryDestination[i386.APOPW] = true
|
|
unaryDestination[i386.ASETCC] = true
|
|
unaryDestination[i386.ASETCS] = true
|
|
unaryDestination[i386.ASETEQ] = true
|
|
unaryDestination[i386.ASETGE] = true
|
|
unaryDestination[i386.ASETGT] = true
|
|
unaryDestination[i386.ASETHI] = true
|
|
unaryDestination[i386.ASETLE] = true
|
|
unaryDestination[i386.ASETLS] = true
|
|
unaryDestination[i386.ASETLT] = true
|
|
unaryDestination[i386.ASETMI] = true
|
|
unaryDestination[i386.ASETNE] = true
|
|
unaryDestination[i386.ASETOC] = true
|
|
unaryDestination[i386.ASETOS] = true
|
|
unaryDestination[i386.ASETPC] = true
|
|
unaryDestination[i386.ASETPL] = true
|
|
unaryDestination[i386.ASETPS] = true
|
|
unaryDestination[i386.AFFREE] = true
|
|
unaryDestination[i386.AFLDENV] = true
|
|
unaryDestination[i386.AFSAVE] = true
|
|
unaryDestination[i386.AFSTCW] = true
|
|
unaryDestination[i386.AFSTENV] = true
|
|
unaryDestination[i386.AFSTSW] = true
|
|
|
|
return &Arch{
|
|
LinkArch: &i386.Link386,
|
|
Instructions: instructions,
|
|
Register: register,
|
|
RegisterPrefix: nil,
|
|
RegisterNumber: nilRegisterNumber,
|
|
UnaryDestination: unaryDestination,
|
|
IsJump: jump386,
|
|
Aconv: i386.Aconv,
|
|
}
|
|
}
|
|
|
|
func archAmd64() *Arch {
|
|
register := make(map[string]int16)
|
|
// Create maps for easy lookup of instruction names etc.
|
|
// TODO: Should this be done in obj for us?
|
|
for i, s := range x86.Register {
|
|
register[s] = int16(i + x86.REG_AL)
|
|
}
|
|
// Pseudo-registers.
|
|
register["SB"] = RSB
|
|
register["FP"] = RFP
|
|
register["PC"] = RPC
|
|
// Register prefix not used on this architecture.
|
|
|
|
instructions := make(map[string]int)
|
|
for i, s := range x86.Anames {
|
|
instructions[s] = i
|
|
}
|
|
// Annoying aliases.
|
|
instructions["JA"] = x86.AJHI
|
|
instructions["JAE"] = x86.AJCC
|
|
instructions["JB"] = x86.AJCS
|
|
instructions["JBE"] = x86.AJLS
|
|
instructions["JC"] = x86.AJCS
|
|
instructions["JE"] = x86.AJEQ
|
|
instructions["JG"] = x86.AJGT
|
|
instructions["JHS"] = x86.AJCC
|
|
instructions["JL"] = x86.AJLT
|
|
instructions["JLO"] = x86.AJCS
|
|
instructions["JNA"] = x86.AJLS
|
|
instructions["JNAE"] = x86.AJCS
|
|
instructions["JNB"] = x86.AJCC
|
|
instructions["JNBE"] = x86.AJHI
|
|
instructions["JNC"] = x86.AJCC
|
|
instructions["JNG"] = x86.AJLE
|
|
instructions["JNGE"] = x86.AJLT
|
|
instructions["JNL"] = x86.AJGE
|
|
instructions["JNLE"] = x86.AJGT
|
|
instructions["JNO"] = x86.AJOC
|
|
instructions["JNP"] = x86.AJPC
|
|
instructions["JNS"] = x86.AJPL
|
|
instructions["JNZ"] = x86.AJNE
|
|
instructions["JO"] = x86.AJOS
|
|
instructions["JP"] = x86.AJPS
|
|
instructions["JPE"] = x86.AJPS
|
|
instructions["JPO"] = x86.AJPC
|
|
instructions["JS"] = x86.AJMI
|
|
instructions["JZ"] = x86.AJEQ
|
|
instructions["MASKMOVDQU"] = x86.AMASKMOVOU
|
|
instructions["MOVD"] = x86.AMOVQ
|
|
instructions["MOVDQ2Q"] = x86.AMOVQ
|
|
instructions["MOVNTDQ"] = x86.AMOVNTO
|
|
instructions["MOVOA"] = x86.AMOVO
|
|
instructions["MOVOA"] = x86.AMOVO
|
|
instructions["PF2ID"] = x86.APF2IL
|
|
instructions["PI2FD"] = x86.API2FL
|
|
instructions["PSLLDQ"] = x86.APSLLO
|
|
instructions["PSRLDQ"] = x86.APSRLO
|
|
|
|
unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
|
|
// These instructions write to prog.To.
|
|
unaryDestination[x86.ABSWAPL] = true
|
|
unaryDestination[x86.ABSWAPQ] = true
|
|
unaryDestination[x86.ACMPXCHG8B] = true
|
|
unaryDestination[x86.ADECB] = true
|
|
unaryDestination[x86.ADECL] = true
|
|
unaryDestination[x86.ADECQ] = true
|
|
unaryDestination[x86.ADECW] = true
|
|
unaryDestination[x86.AINCB] = true
|
|
unaryDestination[x86.AINCL] = true
|
|
unaryDestination[x86.AINCQ] = true
|
|
unaryDestination[x86.AINCW] = true
|
|
unaryDestination[x86.ANEGB] = true
|
|
unaryDestination[x86.ANEGL] = true
|
|
unaryDestination[x86.ANEGQ] = true
|
|
unaryDestination[x86.ANEGW] = true
|
|
unaryDestination[x86.ANOTB] = true
|
|
unaryDestination[x86.ANOTL] = true
|
|
unaryDestination[x86.ANOTQ] = true
|
|
unaryDestination[x86.ANOTW] = true
|
|
unaryDestination[x86.APOPL] = true
|
|
unaryDestination[x86.APOPQ] = true
|
|
unaryDestination[x86.APOPW] = true
|
|
unaryDestination[x86.ASETCC] = true
|
|
unaryDestination[x86.ASETCS] = true
|
|
unaryDestination[x86.ASETEQ] = true
|
|
unaryDestination[x86.ASETGE] = true
|
|
unaryDestination[x86.ASETGT] = true
|
|
unaryDestination[x86.ASETHI] = true
|
|
unaryDestination[x86.ASETLE] = true
|
|
unaryDestination[x86.ASETLS] = true
|
|
unaryDestination[x86.ASETLT] = true
|
|
unaryDestination[x86.ASETMI] = true
|
|
unaryDestination[x86.ASETNE] = true
|
|
unaryDestination[x86.ASETOC] = true
|
|
unaryDestination[x86.ASETOS] = true
|
|
unaryDestination[x86.ASETPC] = true
|
|
unaryDestination[x86.ASETPL] = true
|
|
unaryDestination[x86.ASETPS] = true
|
|
unaryDestination[x86.AFFREE] = true
|
|
unaryDestination[x86.AFLDENV] = true
|
|
unaryDestination[x86.AFSAVE] = true
|
|
unaryDestination[x86.AFSTCW] = true
|
|
unaryDestination[x86.AFSTENV] = true
|
|
unaryDestination[x86.AFSTSW] = true
|
|
unaryDestination[x86.AFXSAVE] = true
|
|
unaryDestination[x86.AFXSAVE64] = true
|
|
unaryDestination[x86.ASTMXCSR] = true
|
|
|
|
return &Arch{
|
|
LinkArch: &x86.Linkamd64,
|
|
Instructions: instructions,
|
|
Register: register,
|
|
RegisterPrefix: nil,
|
|
RegisterNumber: nilRegisterNumber,
|
|
UnaryDestination: unaryDestination,
|
|
IsJump: jump386,
|
|
Aconv: x86.Aconv,
|
|
}
|
|
}
|
|
|
|
func archArm() *Arch {
|
|
register := make(map[string]int16)
|
|
// Create maps for easy lookup of instruction names etc.
|
|
// TODO: Should this be done in obj for us?
|
|
// Note that there is no list of names as there is for 386 and amd64.
|
|
// TODO: Are there aliases we need to add?
|
|
for i := arm.REG_R0; i < arm.REG_SPSR; i++ {
|
|
register[obj.Rconv(i)] = int16(i)
|
|
}
|
|
// Avoid unintentionally clobbering g using R10.
|
|
delete(register, "R10")
|
|
register["g"] = arm.REG_R10
|
|
for i := 0; i < 16; i++ {
|
|
register[fmt.Sprintf("C%d", i)] = int16(i)
|
|
}
|
|
|
|
// Pseudo-registers.
|
|
register["SB"] = RSB
|
|
register["FP"] = RFP
|
|
register["PC"] = RPC
|
|
register["SP"] = RSP
|
|
registerPrefix := map[string]bool{
|
|
"F": true,
|
|
"R": true,
|
|
}
|
|
|
|
instructions := make(map[string]int)
|
|
for i, s := range arm.Anames {
|
|
instructions[s] = i
|
|
}
|
|
// Annoying aliases.
|
|
instructions["B"] = obj.AJMP
|
|
instructions["BL"] = obj.ACALL
|
|
|
|
unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
|
|
// These instructions write to prog.To.
|
|
// TODO: These are silly. Fix once C assembler is gone.
|
|
unaryDestination[arm.ASWI] = true
|
|
unaryDestination[arm.AWORD] = true
|
|
|
|
return &Arch{
|
|
LinkArch: &arm.Linkarm,
|
|
Instructions: instructions,
|
|
Register: register,
|
|
RegisterPrefix: registerPrefix,
|
|
RegisterNumber: armRegisterNumber,
|
|
UnaryDestination: unaryDestination,
|
|
IsJump: jumpArm,
|
|
Aconv: arm.Aconv,
|
|
}
|
|
}
|
|
|
|
func archPPC64() *Arch {
|
|
register := make(map[string]int16)
|
|
// Create maps for easy lookup of instruction names etc.
|
|
// TODO: Should this be done in obj for us?
|
|
// Note that there is no list of names as there is for 386 and amd64.
|
|
for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ {
|
|
register[obj.Rconv(i)] = int16(i)
|
|
}
|
|
for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
|
|
register[obj.Rconv(i)] = int16(i)
|
|
}
|
|
for i := ppc64.REG_C0; i <= ppc64.REG_C7; i++ {
|
|
// TODO: Rconv prints these as C7 but the input syntax requires CR7.
|
|
register[fmt.Sprintf("CR%d", i-ppc64.REG_C0)] = int16(i)
|
|
}
|
|
for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ {
|
|
register[obj.Rconv(i)] = int16(i)
|
|
}
|
|
register["CR"] = ppc64.REG_CR
|
|
register["XER"] = ppc64.REG_XER
|
|
register["LR"] = ppc64.REG_LR
|
|
register["CTR"] = ppc64.REG_CTR
|
|
register["FPSCR"] = ppc64.REG_FPSCR
|
|
register["MSR"] = ppc64.REG_MSR
|
|
// Pseudo-registers.
|
|
register["SB"] = RSB
|
|
register["FP"] = RFP
|
|
register["PC"] = RPC
|
|
// Avoid unintentionally clobbering g using R30.
|
|
delete(register, "R30")
|
|
register["g"] = ppc64.REG_R30
|
|
registerPrefix := map[string]bool{
|
|
"CR": true,
|
|
"F": true,
|
|
"R": true,
|
|
"SPR": true,
|
|
}
|
|
|
|
instructions := make(map[string]int)
|
|
for i, s := range ppc64.Anames {
|
|
instructions[s] = i
|
|
}
|
|
// Annoying aliases.
|
|
instructions["BR"] = ppc64.ABR
|
|
instructions["BL"] = ppc64.ABL
|
|
instructions["RETURN"] = ppc64.ARETURN
|
|
|
|
return &Arch{
|
|
LinkArch: &ppc64.Linkppc64,
|
|
Instructions: instructions,
|
|
Register: register,
|
|
RegisterPrefix: registerPrefix,
|
|
RegisterNumber: ppc64RegisterNumber,
|
|
UnaryDestination: nil,
|
|
IsJump: jumpPPC64,
|
|
Aconv: ppc64.Aconv,
|
|
}
|
|
}
|