ppc64asm,ppc64map: update for ISA 3.1

Likewise, add all missing ISA 3.0 instructions.

This table is generated in a two-step process.

1. Parse ISA 3.1 Appendix F.
2. Scan ISA for descriptions
3. Sort to match old ISA (and check for bugs)
   and append new insn to bottom

A second patch will reformat these instructions into
a sorting order of the ISA 3.1 appendix F, that is
by version then alphabetically. This intermediate
patch ensures we don't regress, and helped catch
quite a few ISA 3.1 typos.

The tooling is left in another repo, and is loosely
based on the spec.go tooling for ppc64.

Notably, transaction memory instructions are effectively
removed in ISA 3.1, and some shuffling of descriptions
has result in cmp*/li/lis becoming extended mnemonics
instead, thus they go away. VLE/SPE/embedded instructions
are also removed. They were never used, and have been
removed since ISA 3.0.

Similarly, the new ISA introduces prefixed instructions
using opcode 1. They are encoded like two instruction
words. However, it should be noted prefixes cannot be
applied to any instruction, only those specifically
enumerated in the documentation. Likewise, what would
be the primary opcode of the suffixed instruction is
not always identical to it's non-prefixed counterpart.

A number of small changes have been made to the parser
to accomodate new instructions and minor changes to
existing ones.

Note, DCBI was a book iii-e instruction in ISA 2.07, and
only emulated on P8, and the opcode is reserved in newer
ISAs.

Note, isel BI decoding is slightly different than gnu.
It is much more readable to decode like other condition
register BI fields. Similarly, paste. and mtfsf* like
instruction decoding is improved to match the newer ISA.

Note, book ii extended mnemonics are mostly ignored.
These are inconsistently described in the documentation,
and most should never appear in golang compiled code.
We do handle the exceptional cases for some, such as the
hwsync/lwsync and the l*arx instructions.

Change-Id: I41711807a5fbdbdd22a2bde4159a09dad5382691
Reviewed-on: https://go-review.googlesource.com/c/arch/+/298793
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
Reviewed-by: Carlos Eduardo Seo <carlos.seo@linaro.org>
Trust: Carlos Eduardo Seo <carlos.seo@linaro.org>
This commit is contained in:
Paul E. Murphy 2020-12-01 11:50:12 -06:00 коммит произвёл Lynn Boger
Родитель ea130f1b0a
Коммит d48d9c4a19
12 изменённых файлов: 5887 добавлений и 3866 удалений

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -54,6 +54,10 @@ func (a argField) Parse(i uint32) Arg {
return V0 + Reg(a.BitFields.Parse(i))
case TypeVecSReg:
return VS0 + Reg(a.BitFields.Parse(i))
case TypeVecSpReg:
return VS0 + Reg(a.BitFields.Parse(i))*2
case TypeMMAReg:
return A0 + Reg(a.BitFields.Parse(i))
case TypeSpReg:
return SpReg(a.BitFields.Parse(i))
case TypeImmSigned:
@ -81,6 +85,8 @@ const (
TypeFPReg // floating point register
TypeVecReg // vector register
TypeVecSReg // VSX register
TypeVecSpReg // VSX register pair (even only encoding)
TypeMMAReg // MMA register
TypeSpReg // special register (depends on Op)
TypeImmSigned // signed immediate
TypeImmUnsigned // unsigned immediate/flag/mask, this is the catch-all type
@ -106,6 +112,10 @@ func (t ArgType) String() string {
return "VecReg"
case TypeVecSReg:
return "VecSReg"
case TypeVecSpReg:
return "VecSpReg"
case TypeMMAReg:
return "MMAReg"
case TypeSpReg:
return "SpReg"
case TypeImmSigned:

Просмотреть файл

@ -34,6 +34,8 @@ func GNUSyntax(inst Inst, pc uint64) string {
startArg := 0
sep := " "
opName := inst.Op.String()
argList := inst.Args[:]
switch opName {
case "bc", "bcl", "bca", "bcla", "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
sfx := inst.Op.String()[2:]
@ -223,23 +225,68 @@ func GNUSyntax(inst Inst, pc uint64) string {
buf.WriteString("spr")
}
case "sync":
switch arg := inst.Args[0].(type) {
case Imm:
switch arg {
case 0:
buf.WriteString("hwsync")
case 1:
buf.WriteString("lwsync")
case 2:
buf.WriteString("ptesync")
}
case "mtfsfi", "mtfsfi.":
buf.WriteString(opName)
l := inst.Args[2].(Imm)
if l == 0 {
// L == 0 is an extended mnemonic for the same.
asm := fmt.Sprintf(" %s,%s",
gnuArg(&inst, 0, inst.Args[0], PC),
gnuArg(&inst, 1, inst.Args[1], PC))
buf.WriteString(asm)
startArg = 3
}
startArg = 2
case "paste.":
buf.WriteString(opName)
l := inst.Args[2].(Imm)
if l == 1 {
// L == 1 is an extended mnemonic for the same.
asm := fmt.Sprintf(" %s,%s",
gnuArg(&inst, 0, inst.Args[0], PC),
gnuArg(&inst, 1, inst.Args[1], PC))
buf.WriteString(asm)
startArg = 3
}
case "mtfsf", "mtfsf.":
buf.WriteString(opName)
l := inst.Args[3].(Imm)
if l == 0 {
// L == 0 is an extended mnemonic for the same.
asm := fmt.Sprintf(" %s,%s,%s",
gnuArg(&inst, 0, inst.Args[0], PC),
gnuArg(&inst, 1, inst.Args[1], PC),
gnuArg(&inst, 2, inst.Args[2], PC))
buf.WriteString(asm)
startArg = 4
}
case "sync":
lsc := inst.Args[0].(Imm)<<4 | inst.Args[1].(Imm)
switch lsc {
case 0x00:
buf.WriteString("hwsync")
startArg = 2
case 0x10:
buf.WriteString("lwsync")
startArg = 2
default:
buf.WriteString(opName)
}
case "lbarx", "lharx", "lwarx", "ldarx":
// If EH == 0, omit printing EH.
eh := inst.Args[3].(Imm)
if eh == 0 {
argList = inst.Args[:3]
}
buf.WriteString(inst.Op.String())
default:
buf.WriteString(inst.Op.String())
}
for i, arg := range inst.Args[:] {
for i, arg := range argList {
if arg == nil {
break
}

Просмотреть файл

@ -220,6 +220,14 @@ const (
VS61
VS62
VS63
A0 // MMA registers. These are effectively shadow registers of four adjacent VSR's [An*4,An*4+3]
A1
A2
A3
A4
A5
A6
A7
)
func (Reg) IsArg() {}
@ -233,6 +241,8 @@ func (r Reg) String() string {
return fmt.Sprintf("v%d", int(r-V0))
case VS0 <= r && r <= VS63:
return fmt.Sprintf("vs%d", int(r-VS0))
case A0 <= r && r <= A7:
return fmt.Sprintf("a%d", int(r-A0))
default:
return fmt.Sprintf("Reg(%d)", int(r))
}

Просмотреть файл

@ -43,6 +43,10 @@ func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool
return true
case MTVSRWA, MTVSRWZ, MFVSRWZ, MFVSRD, MTVSRD: // We don't support extended mnemonics using VRs or FPRs
return true
case ISEL: // We decode the BI similar to conditional branch insn, objdump doesn't.
return true
case SYNC, WAIT, RFEBB: // ISA 3.1 adds more bits and extended mnemonics for these book ii instructions.
return true
}
if len(dec.enc) >= 4 {

Просмотреть файл

@ -76,6 +76,9 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
}
args = append(args, args[0])
return op + " " + strings.Join(args[1:], ",")
case PASTECC:
// paste. has two input registers, and an L field, unlike other 3 operand instructions.
return op + " " + args[0] + "," + args[1] + "," + args[2]
case SYNC:
if args[0] == "$1" {
return "LWSYNC"
@ -136,7 +139,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
case LXVL, LXVLL:
return op + " " + args[1] + "," + args[2] + "," + args[0]
case DCBT, DCBTST, DCBZ, DCBST, DCBI, ICBI:
case DCBT, DCBTST, DCBZ, DCBST, ICBI:
if args[0] == "0" || args[0] == "R0" {
return op + " (" + args[1] + ")"
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

14
ppc64/ppc64asm/testdata/decode.txt поставляемый
Просмотреть файл

@ -184,7 +184,7 @@ b4830002| plan9 MOVHU R4,2(R3)
7c6400f4| plan9 POPCNTB R3,R4
7c6402f4| plan9 POPCNTW R3,R4
7c6403f4| plan9 POPCNTD R3,R4
7c23270d| plan9 PASTECC R3,R4
7c23270d| plan9 PASTECC R3,R4,$1
7c23260c| plan9 COPY R3,R4
7ca01868| plan9 LBAR (R3),R5
7ca018e8| plan9 LHAR (R3),R5
@ -196,7 +196,6 @@ b4830002| plan9 MOVHU R4,2(R3)
7c0004ac| plan9 HWSYNC
4c00012c| plan9 ISYNC
7c2004ac| plan9 LWSYNC
7c041bac| plan9 DCBI (R3)(R4)
7c04186c| plan9 DCBST (R3)(R4)
7c041fec| plan9 DCBZ (R3)(R4)
7c041a2c| plan9 DCBT (R3)(R4)
@ -585,7 +584,6 @@ b4830002| gnu sthu r4,2(r3)
4c00012c| gnu isync
7c0004ac| gnu hwsync
7c2004ac| gnu lwsync
7c041bac| gnu dcbi r4,r3
7c04186c| gnu dcbst r4,r3
7c041fec| gnu dcbz r4,r3
7c041a2c| gnu dcbt r4,r3,0
@ -846,3 +844,13 @@ f0400fe0| gnu xvcvsxddp vs2,vs1
7c6802a6| gnu mflr r3
7c6902a6| gnu mfctr r3
4c8c0000| gnu mcrf cr1,cr3
7c2101a7| gnu mtvsrwa vs33,r1
7c2101e7| gnu mtvsrwz vs33,r1
7ce10067| gnu mfvsrd r1,vs39
7ce100e7| gnu mfvsrwz r1,vs39
7c210167| gnu mtvsrd vs33,r1
7c8112de| gnu isel r4,r1,r2,4*cr2+so
7c2104ac| gnu sync 1,1
7c2110ac| gnu dcbf r1,r2,1
7c20003c| gnu wait 1,0
4c000924| gnu rfebb 1

1365
ppc64/ppc64asm/testdata/decode_generated.txt поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -14,15 +14,16 @@
package main
import (
"bufio"
"bytes"
"encoding/csv"
"flag"
"fmt"
gofmt "go/format"
"log"
"math/bits"
"os"
"regexp"
"sort"
"strconv"
"strings"
"text/template"
@ -30,7 +31,7 @@ import (
asm "golang.org/x/arch/ppc64/ppc64asm"
)
var format = flag.String("fmt", "text", "output format: text, decoder")
var format = flag.String("fmt", "text", "output format: text, decoder, asm")
var debug = flag.Bool("debug", false, "enable debugging output")
var inputFile string
@ -60,13 +61,15 @@ func main() {
print = printText
case "decoder":
print = printDecoder
case "asm":
print = printASM
}
p, err := readCSV(flag.Arg(0))
log.Printf("Parsed %d instruction forms.", len(p.Insts))
if err != nil {
log.Fatal(err)
}
log.Printf("Parsed %d instruction forms.", len(p.Insts))
print(p)
}
@ -79,23 +82,9 @@ func readCSV(file string) (*Prog, error) {
if err != nil {
return nil, err
}
b := bufio.NewReader(f)
for {
c, err := b.ReadByte()
if err != nil {
break
}
if c == '\n' {
continue
}
if c == '#' {
b.ReadBytes('\n')
continue
}
b.UnreadByte()
break
}
table, err := csv.NewReader(b).ReadAll()
csvReader := csv.NewReader(f)
csvReader.Comment = '#'
table, err := csvReader.ReadAll()
if err != nil {
return nil, fmt.Errorf("parsing %s: %v", file, err)
}
@ -108,6 +97,10 @@ func readCSV(file string) (*Prog, error) {
p := &Prog{}
for _, row := range table {
// TODO: add support for prefixed instructions. Ignore for now.
if row[2][0] == ',' {
continue
}
add(p, row[0], row[1], row[2], row[3])
}
return p, nil
@ -200,14 +193,25 @@ func (a Arg) isDontCare() bool {
return a.Name[0] == '/' && a.Name == strings.Repeat("/", len(a.Name))
}
type instArray []Inst
func (i instArray) Len() int {
return len(i)
}
func (i instArray) Swap(j, k int) {
i[j], i[k] = i[k], i[j]
}
// Sort by decreasing number of mask bits to ensure extended mnemonics
// are always found first when scanning the table.
func (i instArray) Less(j, k int) bool {
return bits.OnesCount32(i[j].Mask) > bits.OnesCount32(i[k].Mask)
}
// add adds the entry from the CSV described by text, mnemonics, encoding, and tags
// to the program p.
func add(p *Prog, text, mnemonics, encoding, tags string) {
if strings.HasPrefix(mnemonics, "e_") || strings.HasPrefix(mnemonics, "se_") {
// TODO(minux): VLE instructions are ignored.
return
}
// Parse encoding, building size and offset of each field.
// The first field in the encoding is the smallest offset.
// And note the MSB is bit 0, not bit 31.
@ -313,6 +317,7 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
// split mnemonics into individual instructions
// example: "b target_addr (AA=0 LK=0)|ba target_addr (AA=1 LK=0)|bl target_addr (AA=0 LK=1)|bla target_addr (AA=1 LK=1)"
insts := strings.Split(categoryRe.ReplaceAllString(mnemonics, ""), "|")
foundInst := []Inst{}
for _, inst := range insts {
value, mask := value, mask
args := args.Clone()
@ -351,6 +356,7 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
typ := asm.TypeUnknown
var shift uint8
opr2 := ""
opr3 := ""
switch opr {
case "target_addr":
shift = 2
@ -364,11 +370,17 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
} else {
opr = "BD"
}
case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "UIM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DCMX", "DGM", "RMC", "R", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY":
case "UI", "BO", "BH", "TH", "LEV", "NB", "L", "TO", "FXM", "FC", "U", "W", "FLM", "UIM", "IMM8", "RIC", "PRS", "SHB", "SHW", "ST", "SIX", "PS", "DCM", "DGM", "RMC", "R", "SP", "S", "DM", "CT", "EH", "E", "MO", "WC", "A", "IH", "OC", "DUI", "DUIS", "CY", "SC", "PL", "MP", "N", "IMM", "DRM", "RM":
typ = asm.TypeImmUnsigned
if i := args.Find(opr); i < 0 {
opr = "D"
}
case "bm":
opr = "b0"
opr2 = "b1"
opr3 = "b2"
typ = asm.TypeImmUnsigned
case "SH":
typ = asm.TypeImmUnsigned
if args.Find("sh2") >= 0 { // sh2 || sh
@ -385,6 +397,16 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
if i := args.Find(opr); i < 0 {
opr = "D"
}
case "DCMX":
typ = asm.TypeImmUnsigned
// Some instructions encode this consecutively.
if i := args.Find(opr); i >= 0 {
break
}
typ = asm.TypeImmUnsigned
opr = "dc"
opr2 = "dm"
opr3 = "dx"
case "DS":
typ = asm.TypeOffset
shift = 2
@ -406,6 +428,13 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
opr = "SI"
break
}
if i := args.Find("d0"); i >= 0 {
typ = asm.TypeImmSigned
// DX-form
opr = "d0"
opr2 = "d1"
opr3 = "d2"
}
case "RA", "RB", "RC", "RS", "RSp", "RT", "RTp":
typ = asm.TypeReg
case "BT", "BA", "BB", "BC", "BI":
@ -428,6 +457,22 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
typ = asm.TypeVecSReg
opr2 = opr[1:]
opr = opr[1:] + "X"
case "XTp", "XSp": // 5-bit, split field
//XTp encodes 5 bits, VSR is XT*32 + TP<<1
typ = asm.TypeVecSpReg
opr2 = opr[1:2] + "p"
opr = opr[1:2] + "X"
case "XAp":
// XAp in MMA encodes a regular VSR, but is only valid
// if it is even, and does not overlap the accumulator.
typ = asm.TypeVecSReg
opr2 = opr[1:2] + "p"
opr = opr[1:2] + "X"
case "AT", "AS":
typ = asm.TypeMMAReg
case "VRA", "VRB", "VRC", "VRS", "VRT":
typ = asm.TypeVecReg
case "SPR", "DCRN", "BHRBE", "TBR", "SR", "TMR", "PMRN": // Note: if you add to this list and the register field needs special handling, add it to switch statement below
@ -445,8 +490,16 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
}
field.Type = typ
field.Shift = shift
var f1, f2 asm.BitField
var f1, f2, f3 asm.BitField
switch {
case opr3 != "":
b0 := args.Find(opr)
b1 := args.Find(opr2)
b2 := args.Find(opr3)
f1.Offs, f1.Bits = uint8(args[b0].Offs), uint8(args[b0].Bits)
f2.Offs, f2.Bits = uint8(args[b1].Offs), uint8(args[b1].Bits)
f3.Offs, f3.Bits = uint8(args[b2].Offs), uint8(args[b2].Bits)
case opr2 != "":
ext := args.Find(opr)
if ext < 0 {
@ -486,14 +539,22 @@ func add(p *Prog, text, mnemonics, encoding, tags string) {
if f2.Bits > 0 {
field.BitFields.Append(f2)
}
if f3.Bits > 0 {
field.BitFields.Append(f3)
}
inst.Fields = append(inst.Fields, field)
}
if *debug {
fmt.Printf("%v\n", inst)
}
p.Insts = append(p.Insts, inst)
foundInst = append(foundInst, inst)
}
// Sort mnemonics by bitcount. This ensures more specific mnemonics are picked
// up before generic ones (e.g li vs addi, or cmpld/cmplw vs cmpl)
sort.Sort(instArray(foundInst))
p.Insts = append(p.Insts, foundInst...)
}
// condRegexp is a regular expression that matches condition in mnemonics (e.g. "AA=1")
@ -516,6 +577,18 @@ func printText(p *Prog) {
log.Fatal("-fmt=text not implemented")
}
// printASM implements the -fmt=asm mode. This prints out a gnu assembler file
// which can be used to used to generate test output to verify the golang
// disassembler's gnu output matches gnu binutils. This is used as an input to
// ppc64util to generate the decode_generated.txt test case.
func printASM(p *Prog) {
fmt.Printf("#include \"hack.h\"\n")
fmt.Printf(".text\n")
for _, inst := range p.Insts {
fmt.Printf("\t%s\n", inst.Encoding)
}
}
// opName translate an opcode to a valid Go identifier all-cap op name.
func opName(op string) string {
return strings.ToUpper(strings.Replace(op, ".", "CC", 1))

160
ppc64/ppc64util/hack.h Normal file
Просмотреть файл

@ -0,0 +1,160 @@
// Copyright 2021 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 requires gcc and binutils with -mcpu=power10 support.
// ppc64util runs a series of commands like:
// go run map.go -fmt=asm ../pp64.csv > asm.S
// powerpc64le-linux-gnu-gcc -c asm.S -mcpu=power10 -mbig
// powerpc64le-linux-gnu-objdump -d asm.o
// to create the file decode_generated.txt used to verify the disassembler.
//
// Note, the golang disassembler is not expected to support every extended
// mnemonic, but it should support those which frequently show up in object
// files compiled by the golang toolchain.
#define RA 1
#define RB 2
#define RS 3
#define RT 4
#define RC 5
#define RSp 6
#define RTp 8
#define MB 1
#define ME 7
#define NB 2
#define CY 1
#define LEV 1
#define FRBp 2
#define FRAp 4
#define FRTp 6
#define FRSp 8
#define FRT 3
#define FRA 5
#define FRB 7
#define FRC 9
#define FRS 11
#define FLM 8
#define U 3
#define W 0
#define TE 15
#define SP 1
#define S 1
#define DRM 0x7
#define RM 0x3
#define BF 3
#define SH 7
#define XT 33
#define XA 35
#define XB 37
#define XS 39
#define XC 41
#define XAp 36
#define XTp 38
#define XSp 40
#define DM 1
#define SHW 2
#define VRA 1
#define VRB 2
#define VRC 3
#define VRT 4
#define VRS 5
#define SHB 3
#define SIX 1
#define ST 1
#define PS 0
#define MP 1
#define bm 0x45FF
#define N 3
#define AT 7
#define AS 6
#define RMC 3
#define UIM 1
#define DCMX 0x23
#define DCM 0x11
#define DGM 0x11
#define R 1
#define BA 1
#define BB 2
#define BT 3
#define BO 4
#define BI 6
#define BH 0
#define BFA 7
#define FXM 8
#define BC 11
#define L 1
#define EH 1
#define SPR 69
#define BHRBE 69
#define TO 0x11
#define TBR 268
#define CT 2
#define FC 2
#define TH 3
#define WC 1
#define PL 0
#define IH 4
#define RIC 1
#define PRS 1
#define SIM 6
#define IMM 13
#define IMM8 14
#define D 0x80
#define SC 1
#define target_addr 0x690
#define XMSK 0x9
#define YMSK 0x3
#define PMSK 0x2
#define IX 1
#define IMM32 0x1234567
#define Dpfx 0x160032
#define RApfx 0x0
#define Rpfx 1
#define SIpfx 0xFFFFFFFE00010007
// These decode as m.fpr* or m.vr*. This is a matter of preference. We
// don't support these mnemonics, and I don't think they improve reading
// disassembled code in most cases. so ignore.
//
// Likewise, if you add to this list, add tests to decode.txt to ensure we
// still test these, while ignoring the extended mnemonics which get
// generated.
#define mfvsrd xsrsp
#define mfvsrwz xsrsp
#define mtvsrd xsrsp
#define mtvsrwz xsrsp
#define mtvsrwa xsrsp
// isel BC bit is not decoded like other BC fields.
// A special test case is added to decode.txt to verify this.
// We decode it like other BC fields.
#define isel rldicl
// Likewise, these are obscure book ii instructions with extended mnemonics
// which are almost guaranteed never to show up in go code
#define dcbf add
#define sync xsrsp
#define wait xsrsp
#define rfebb sc
// sync 1,1 is the stncisync extended mnemonic. Similar to the above, but
// the lwsync/hwsync extended mnemonics are tested in decode.txt
#define sync xsrsp

Просмотреть файл

@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ignore
// +build ignore
// Generate interesting test cases from ppc64 objdump via
// go run util.go
//
@ -20,6 +22,7 @@ import (
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
@ -79,11 +82,13 @@ func emitBranches(out io.Writer) {
}
}
// Emit a test file using the generator called name.txt
// Emit a test file using the generator called name.txt. This requires
// a GCC toolchain which supports -mcpu=power10.
func genOutput(name, tcPfx string, generator func(io.Writer)) {
// Generate object code from gcc
cmd := exec.Command(tcPfx+"gcc", "-c", "-mbig", "-mcpu=power9", "-x", "assembler-with-cpp", "-o", name+".o", "-")
cmd := exec.Command(tcPfx+"gcc", "-c", "-mbig", "-mcpu=power10", "-x", "assembler-with-cpp", "-o", name+".o", "-")
input, _ := cmd.StdinPipe()
cmd.Stderr = os.Stderr
go func() {
defer input.Close()
generator(input.(io.Writer))
@ -107,20 +112,39 @@ func genOutput(name, tcPfx string, generator func(io.Writer)) {
return
}
pfx := ""
dec := ""
for scanner.Scan() {
ln := spacere.Split(scanner.Text(), -1)
if len(ln) >= 7 {
opc := strings.Join(ln[2:6], "")
dec := strings.Join(ln[6:], " ")
fmt.Fprintf(outf, "%s|\tgnu\t%s\n", opc, dec)
if len(pfx) == 0 {
dec = strings.Join(ln[6:], " ")
}
if v, _ := strconv.ParseInt(ln[2], 16, 16); v&0xFC == 0x04 {
pfx = opc
continue
}
fmt.Fprintf(outf, "%s%s|\tgnu\t%s\n", pfx, opc, dec)
pfx = ""
}
}
cmd.Wait()
}
// Generate representative instructions for all[1] instructions in pp64.csv.
//
// [1] See hack.h for a few minor, exceptional workarounds.
func emitGenerated(out io.Writer) {
cmd := exec.Command("go", "run", "../ppc64map/map.go", "-fmt=asm", "../pp64.csv")
cmdout, _ := cmd.Output()
out.Write(cmdout)
}
// Produce generated test outputs. This should be run every so often with
// new versions of objdump to ensure we stay up to date.
func main() {
genOutput("decode_branch", "powerpc64le-linux-gnu-", emitBranches)
genOutput("decode_generated", "powerpc64le-linux-gnu-", emitGenerated)
}