2015-06-06 16:03:33 -07:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
// The gen command generates Go code (in the parent directory) for all
|
|
|
|
|
// the architecture-specific opcodes, blocks, and rewrites.
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"fmt"
|
|
|
|
|
"go/format"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
2015-07-28 16:04:50 -07:00
|
|
|
"regexp"
|
2015-06-06 16:03:33 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type arch struct {
|
2015-06-11 15:52:08 -07:00
|
|
|
name string
|
|
|
|
|
ops []opData
|
|
|
|
|
blocks []blockData
|
|
|
|
|
regnames []string
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type opData struct {
|
|
|
|
|
name string
|
|
|
|
|
reg regInfo
|
2015-06-16 13:33:32 -07:00
|
|
|
asm string
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type blockData struct {
|
|
|
|
|
name string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type regInfo struct {
|
|
|
|
|
inputs []regMask
|
|
|
|
|
clobbers regMask
|
|
|
|
|
outputs []regMask
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type regMask uint64
|
|
|
|
|
|
2015-06-11 15:52:08 -07:00
|
|
|
func (a arch) regMaskComment(r regMask) string {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
for i := uint64(0); r != 0; i++ {
|
|
|
|
|
if r&1 != 0 {
|
|
|
|
|
if buf.Len() == 0 {
|
|
|
|
|
buf.WriteString(" //")
|
|
|
|
|
}
|
|
|
|
|
buf.WriteString(" ")
|
|
|
|
|
buf.WriteString(a.regnames[i])
|
|
|
|
|
}
|
|
|
|
|
r >>= 1
|
|
|
|
|
}
|
|
|
|
|
return buf.String()
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
var archs []arch
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
genOp()
|
|
|
|
|
genLower()
|
|
|
|
|
}
|
2015-06-16 11:11:16 -07:00
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
func genOp() {
|
|
|
|
|
w := new(bytes.Buffer)
|
|
|
|
|
fmt.Fprintf(w, "// autogenerated: do not edit!\n")
|
|
|
|
|
fmt.Fprintf(w, "// generated from gen/*Ops.go\n")
|
|
|
|
|
fmt.Fprintln(w, "package ssa")
|
|
|
|
|
|
2015-06-16 11:11:16 -07:00
|
|
|
fmt.Fprintln(w, "import \"cmd/internal/obj/x86\"")
|
|
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
// generate Block* declarations
|
|
|
|
|
fmt.Fprintln(w, "const (")
|
|
|
|
|
fmt.Fprintln(w, "blockInvalid BlockKind = iota")
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
|
for _, d := range a.blocks {
|
|
|
|
|
fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, ")")
|
|
|
|
|
|
|
|
|
|
// generate block kind string method
|
|
|
|
|
fmt.Fprintln(w, "var blockString = [...]string{")
|
|
|
|
|
fmt.Fprintln(w, "blockInvalid:\"BlockInvalid\",")
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
|
for _, b := range a.blocks {
|
|
|
|
|
fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, "}")
|
|
|
|
|
fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
|
|
|
|
|
|
|
|
|
|
// generate Op* declarations
|
|
|
|
|
fmt.Fprintln(w, "const (")
|
|
|
|
|
fmt.Fprintln(w, "OpInvalid Op = iota")
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
|
for _, v := range a.ops {
|
|
|
|
|
fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, ")")
|
|
|
|
|
|
|
|
|
|
// generate OpInfo table
|
|
|
|
|
fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
|
|
|
|
|
fmt.Fprintln(w, " { name: \"OpInvalid\" },")
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
|
for _, v := range a.ops {
|
|
|
|
|
fmt.Fprintln(w, "{")
|
|
|
|
|
fmt.Fprintf(w, "name:\"%s\",\n", v.name)
|
2015-07-21 07:10:56 -07:00
|
|
|
if a.name == "generic" {
|
|
|
|
|
fmt.Fprintln(w, "generic:true,")
|
|
|
|
|
fmt.Fprintln(w, "},") // close op
|
|
|
|
|
// generic ops have no reg info or asm
|
|
|
|
|
continue
|
|
|
|
|
}
|
2015-06-16 13:33:32 -07:00
|
|
|
if v.asm != "" {
|
|
|
|
|
fmt.Fprintf(w, "asm: x86.A%s,\n", v.asm)
|
2015-06-16 11:11:16 -07:00
|
|
|
}
|
2015-06-06 16:03:33 -07:00
|
|
|
fmt.Fprintln(w, "reg:regInfo{")
|
2015-07-21 07:10:56 -07:00
|
|
|
// reg inputs
|
|
|
|
|
if len(v.reg.inputs) > 0 {
|
|
|
|
|
fmt.Fprintln(w, "inputs: []regMask{")
|
|
|
|
|
for _, r := range v.reg.inputs {
|
|
|
|
|
fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r))
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, "},")
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
2015-07-21 07:10:56 -07:00
|
|
|
if v.reg.clobbers > 0 {
|
|
|
|
|
fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
2015-07-21 07:10:56 -07:00
|
|
|
// reg outputs
|
|
|
|
|
if len(v.reg.outputs) > 0 {
|
|
|
|
|
fmt.Fprintln(w, "outputs: []regMask{")
|
|
|
|
|
for _, r := range v.reg.outputs {
|
|
|
|
|
fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r))
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, "},")
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
2015-07-21 07:10:56 -07:00
|
|
|
fmt.Fprintln(w, "},") // close reg info
|
|
|
|
|
fmt.Fprintln(w, "},") // close op
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, "}")
|
|
|
|
|
|
2015-06-16 11:11:16 -07:00
|
|
|
fmt.Fprintln(w, "func (o Op) Asm() int {return opcodeTable[o].asm}")
|
|
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
// generate op string method
|
|
|
|
|
fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
|
|
|
|
|
|
|
|
|
|
// gofmt result
|
|
|
|
|
b := w.Bytes()
|
|
|
|
|
var err error
|
|
|
|
|
b, err = format.Source(b)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = ioutil.WriteFile("../opGen.go", b, 0666)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't write output: %v\n", err)
|
|
|
|
|
}
|
2015-07-28 16:04:50 -07:00
|
|
|
|
|
|
|
|
// Check that ../gc/ssa.go handles all the arch-specific opcodes.
|
|
|
|
|
// This is very much a hack, but it is better than nothing.
|
|
|
|
|
ssa, err := ioutil.ReadFile("../../gc/ssa.go")
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't read ../../gc/ssa.go: %v", err)
|
|
|
|
|
}
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
if a.name == "generic" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
for _, v := range a.ops {
|
|
|
|
|
pattern := fmt.Sprintf("\\Wssa[.]Op%s%s\\W", a.name, v.name)
|
|
|
|
|
match, err := regexp.Match(pattern, ssa)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("bad opcode regexp %s: %v", pattern, err)
|
|
|
|
|
}
|
|
|
|
|
if !match {
|
|
|
|
|
log.Fatalf("Op%s%s has no code generation in ../../gc/ssa.go", a.name, v.name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Name returns the name of the architecture for use in Op* and Block* enumerations.
|
|
|
|
|
func (a arch) Name() string {
|
|
|
|
|
s := a.name
|
|
|
|
|
if s == "generic" {
|
|
|
|
|
s = ""
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func genLower() {
|
|
|
|
|
for _, a := range archs {
|
|
|
|
|
genRules(a)
|
|
|
|
|
}
|
|
|
|
|
}
|