aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/asm/internal/arch
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2015-02-18 20:30:55 -0800
committerRob Pike <r@golang.org>2015-02-19 05:12:20 +0000
commite559c5cce2f5bc48ad3c7ff75dec6cfa002115f1 (patch)
tree96d78e9cdf1c3a4e48514533790c060e90e6b0a4 /src/cmd/asm/internal/arch
parent6acd5a65b2c8a27326528f5a9bb109e194c82258 (diff)
downloadgo-e559c5cce2f5bc48ad3c7ff75dec6cfa002115f1.tar.xz
[dev.cc] cmd/asm: add ppc64
Fairly straightforward. A couple of unusual addressing tricks. Also added the ability to write R(10) to mean R10. PPC64 uses this for a couple of large register spaces. It appears for ARM now as well, since I saw some uses of that before, although I rewrote them in our source. I could put it in for 386 and amd64 but it's not worth it. Change-Id: I3ffd7ffa62d511b95b92c3c75b9f1d621f5393b6 Reviewed-on: https://go-review.googlesource.com/5282 Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/cmd/asm/internal/arch')
-rw-r--r--src/cmd/asm/internal/arch/arch.go135
-rw-r--r--src/cmd/asm/internal/arch/arm.go13
-rw-r--r--src/cmd/asm/internal/arch/ppc64.go63
3 files changed, 187 insertions, 24 deletions
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 740bb1e2e7..a7bffee4fa 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -8,7 +8,8 @@ import (
"cmd/internal/obj"
"cmd/internal/obj/arm"
"cmd/internal/obj/i386" // == 386
- "cmd/internal/obj/x86" // == amd64
+ "cmd/internal/obj/ppc64"
+ "cmd/internal/obj/x86" // == amd64
"fmt"
)
@@ -26,7 +27,11 @@ type Arch struct {
// Map of instruction names to enumeration.
Instructions map[string]int
// Map of register names to enumeration.
- Registers map[string]int16
+ 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.
@@ -37,6 +42,12 @@ type Arch struct {
Dconv func(p *obj.Prog, flag int, a *obj.Addr) 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,
@@ -60,6 +71,10 @@ func Set(GOARCH string) *Arch {
return a
case "arm":
return archArm()
+ case "ppc64":
+ a := archPPC64()
+ a.LinkArch = &ppc64.Linkppc64
+ return a
}
return nil
}
@@ -69,16 +84,17 @@ func jump386(word string) bool {
}
func arch386() *Arch {
- registers := make(map[string]int16)
+ 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 {
- registers[s] = int16(i + i386.REG_AL)
+ register[s] = int16(i + i386.REG_AL)
}
// Pseudo-registers.
- registers["SB"] = RSB
- registers["FP"] = RFP
- registers["PC"] = RPC
+ 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 {
@@ -162,7 +178,9 @@ func arch386() *Arch {
return &Arch{
LinkArch: &i386.Link386,
Instructions: instructions,
- Registers: registers,
+ Register: register,
+ RegisterPrefix: nil,
+ RegisterNumber: nilRegisterNumber,
UnaryDestination: unaryDestination,
IsJump: jump386,
Aconv: i386.Aconv,
@@ -171,16 +189,17 @@ func arch386() *Arch {
}
func archAmd64() *Arch {
- registers := make(map[string]int16)
+ 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 {
- registers[s] = int16(i + x86.REG_AL)
+ register[s] = int16(i + x86.REG_AL)
}
// Pseudo-registers.
- registers["SB"] = RSB
- registers["FP"] = RFP
- registers["PC"] = RPC
+ 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 {
@@ -271,7 +290,9 @@ func archAmd64() *Arch {
return &Arch{
LinkArch: &x86.Linkamd64,
Instructions: instructions,
- Registers: registers,
+ Register: register,
+ RegisterPrefix: nil,
+ RegisterNumber: nilRegisterNumber,
UnaryDestination: unaryDestination,
IsJump: jump386,
Aconv: x86.Aconv,
@@ -280,26 +301,30 @@ func archAmd64() *Arch {
}
func archArm() *Arch {
- registers := make(map[string]int16)
+ 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++ {
- registers[arm.Rconv(i)] = int16(i)
+ register[arm.Rconv(i)] = int16(i)
}
// Avoid unintentionally clobbering g using R10.
- delete(registers, "R10")
- registers["g"] = arm.REG_R10
+ delete(register, "R10")
+ register["g"] = arm.REG_R10
for i := 0; i < 16; i++ {
- registers[fmt.Sprintf("C%d", i)] = int16(i)
+ register[fmt.Sprintf("C%d", i)] = int16(i)
}
// Pseudo-registers.
- registers["SB"] = RSB
- registers["FP"] = RFP
- registers["PC"] = RPC
- registers["SP"] = RSP
+ 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 {
@@ -318,10 +343,72 @@ func archArm() *Arch {
return &Arch{
LinkArch: &arm.Linkarm,
Instructions: instructions,
- Registers: registers,
+ Register: register,
+ RegisterPrefix: registerPrefix,
+ RegisterNumber: armRegisterNumber,
UnaryDestination: unaryDestination,
IsJump: jumpArm,
Aconv: arm.Aconv,
Dconv: arm.Dconv,
}
}
+
+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[ppc64.Rconv(i)] = int16(i)
+ }
+ for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
+ register[ppc64.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[ppc64.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,
+ Dconv: ppc64.Dconv,
+ }
+}
diff --git a/src/cmd/asm/internal/arch/arm.go b/src/cmd/asm/internal/arch/arm.go
index 4ac13f0289..75bb0be168 100644
--- a/src/cmd/asm/internal/arch/arm.go
+++ b/src/cmd/asm/internal/arch/arm.go
@@ -188,3 +188,16 @@ func parseARMCondition(cond string) (uint8, bool) {
}
return bits, true
}
+
+func armRegisterNumber(name string, n int16) (int16, bool) {
+ if n < 0 || 15 < n {
+ return 0, false
+ }
+ switch name {
+ case "R":
+ return arm.REG_R0 + n, true
+ case "F":
+ return arm.REG_F0 + n, true
+ }
+ return 0, false
+}
diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go
new file mode 100644
index 0000000000..7fb9f7dd2e
--- /dev/null
+++ b/src/cmd/asm/internal/arch/ppc64.go
@@ -0,0 +1,63 @@
+// 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.
+
+// This file encapsulates some of the odd characteristics of the ARM
+// instruction set, to minimize its interaction with the core of the
+// assembler.
+
+package arch
+
+import "cmd/internal/obj/ppc64"
+
+func jumpPPC64(word string) bool {
+ switch word {
+ case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL":
+ return true
+ }
+ return false
+}
+
+// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
+// one of the RLD-like instructions that require special handling.
+func IsPPC64RLD(op int) bool {
+ switch op {
+ case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
+ ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
+ ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
+ return true
+ }
+ return false
+}
+
+// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
+// one of the CMP instructions that require special handling.
+func IsPPC64CMP(op int) bool {
+ switch op {
+ case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU:
+ return true
+ }
+ return false
+}
+
+func ppc64RegisterNumber(name string, n int16) (int16, bool) {
+ switch name {
+ case "CR":
+ if 0 <= n && n <= 7 {
+ return ppc64.REG_C0 + n, true
+ }
+ case "F":
+ if 0 <= n && n <= 31 {
+ return ppc64.REG_F0 + n, true
+ }
+ case "R":
+ if 0 <= n && n <= 31 {
+ return ppc64.REG_R0 + n, true
+ }
+ case "SPR":
+ if 0 <= n && n <= 1024 {
+ return ppc64.REG_SPR0 + n, true
+ }
+ }
+ return 0, false
+}