whatcanGOwrong

This commit is contained in:
2024-09-19 21:38:24 -04:00
commit d0ae4d841d
17908 changed files with 4096831 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
// Copyright 2014 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 ppc64asm
import (
"encoding/binary"
"fmt"
"log"
)
const debugDecode = false
const prefixOpcode = 1
// instFormat is a decoding rule for one specific instruction form.
// an instruction ins matches the rule if ins&Mask == Value
// DontCare bits should be zero, but the machine might not reject
// ones in those bits, they are mainly reserved for future expansion
// of the instruction set.
// The Args are stored in the same order as the instruction manual.
//
// Prefixed instructions are stored as:
//
// prefix << 32 | suffix,
//
// Regular instructions are:
//
// inst << 32
type instFormat struct {
Op Op
Mask uint64
Value uint64
DontCare uint64
Args [6]*argField
}
// argField indicate how to decode an argument to an instruction.
// First parse the value from the BitFields, shift it left by Shift
// bits to get the actual numerical value.
type argField struct {
Type ArgType
Shift uint8
BitFields
}
// Parse parses the Arg out from the given binary instruction i.
func (a argField) Parse(i [2]uint32) Arg {
switch a.Type {
default:
return nil
case TypeUnknown:
return nil
case TypeReg:
return R0 + Reg(a.BitFields.Parse(i))
case TypeCondRegBit:
return Cond0LT + CondReg(a.BitFields.Parse(i))
case TypeCondRegField:
return CR0 + CondReg(a.BitFields.Parse(i))
case TypeFPReg:
return F0 + Reg(a.BitFields.Parse(i))
case TypeVecReg:
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:
return Imm(a.BitFields.ParseSigned(i) << a.Shift)
case TypeImmUnsigned:
return Imm(a.BitFields.Parse(i) << a.Shift)
case TypePCRel:
return PCRel(a.BitFields.ParseSigned(i) << a.Shift)
case TypeLabel:
return Label(a.BitFields.ParseSigned(i) << a.Shift)
case TypeOffset:
return Offset(a.BitFields.ParseSigned(i) << a.Shift)
case TypeNegOffset:
// An oddball encoding of offset for hashchk and similar.
// e.g hashchk offset is 0b1111111000000000 | DX << 8 | D << 3
off := a.BitFields.ParseSigned(i) << a.Shift
neg := int64(-1) << (int(a.Shift) + a.BitFields.NumBits())
return Offset(neg | off)
}
}
type ArgType int8
const (
TypeUnknown ArgType = iota
TypePCRel // PC-relative address
TypeLabel // absolute address
TypeReg // integer register
TypeCondRegBit // conditional register bit (0-31)
TypeCondRegField // conditional register field (0-7)
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
TypeOffset // signed offset in load/store
TypeNegOffset // A negative 16 bit value 0b1111111xxxxx000 encoded as 0bxxxxx (e.g in the hashchk instruction)
TypeLast // must be the last one
)
func (t ArgType) String() string {
switch t {
default:
return fmt.Sprintf("ArgType(%d)", int(t))
case TypeUnknown:
return "Unknown"
case TypeReg:
return "Reg"
case TypeCondRegBit:
return "CondRegBit"
case TypeCondRegField:
return "CondRegField"
case TypeFPReg:
return "FPReg"
case TypeVecReg:
return "VecReg"
case TypeVecSReg:
return "VecSReg"
case TypeVecSpReg:
return "VecSpReg"
case TypeMMAReg:
return "MMAReg"
case TypeSpReg:
return "SpReg"
case TypeImmSigned:
return "ImmSigned"
case TypeImmUnsigned:
return "ImmUnsigned"
case TypePCRel:
return "PCRel"
case TypeLabel:
return "Label"
case TypeOffset:
return "Offset"
case TypeNegOffset:
return "NegOffset"
}
}
func (t ArgType) GoString() string {
s := t.String()
if t > 0 && t < TypeLast {
return "Type" + s
}
return s
}
var (
// Errors
errShort = fmt.Errorf("truncated instruction")
errUnknown = fmt.Errorf("unknown instruction")
)
var decoderCover []bool
// Decode decodes the leading bytes in src as a single instruction using
// byte order ord.
func Decode(src []byte, ord binary.ByteOrder) (inst Inst, err error) {
if len(src) < 4 {
return inst, errShort
}
if decoderCover == nil {
decoderCover = make([]bool, len(instFormats))
}
inst.Len = 4
ui_extn := [2]uint32{ord.Uint32(src[:inst.Len]), 0}
ui := uint64(ui_extn[0]) << 32
inst.Enc = ui_extn[0]
opcode := inst.Enc >> 26
if opcode == prefixOpcode {
// This is a prefixed instruction
inst.Len = 8
if len(src) < 8 {
return inst, errShort
}
// Merge the suffixed word.
ui_extn[1] = ord.Uint32(src[4:inst.Len])
ui |= uint64(ui_extn[1])
inst.SuffixEnc = ui_extn[1]
}
for i, iform := range instFormats {
if ui&iform.Mask != iform.Value {
continue
}
if ui&iform.DontCare != 0 {
if debugDecode {
log.Printf("Decode(%#x): unused bit is 1 for Op %s", ui, iform.Op)
}
// to match GNU objdump (libopcodes), we ignore don't care bits
}
for i, argfield := range iform.Args {
if argfield == nil {
break
}
inst.Args[i] = argfield.Parse(ui_extn)
}
inst.Op = iform.Op
if debugDecode {
log.Printf("%#x: search entry %d", ui, i)
continue
}
break
}
if inst.Op == 0 && inst.Enc != 0 {
return inst, errUnknown
}
return inst, nil
}
@@ -0,0 +1,98 @@
// Copyright 2014 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 ppc64asm
import (
"encoding/binary"
"encoding/hex"
"io/ioutil"
"path"
"strings"
"testing"
)
func TestDecode(t *testing.T) {
files, err := ioutil.ReadDir("testdata")
if err != nil {
t.Fatal(err)
}
for _, f := range files {
if !strings.HasPrefix(f.Name(), "decode") {
continue
}
filename := path.Join("testdata", f.Name())
data, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatal(err)
}
decode(data, t, filename)
}
}
// Provide a fake symbol to verify PCrel argument decoding.
func symlookup(pc uint64) (string, uint64) {
foopc := uint64(0x100000)
if pc >= foopc && pc < foopc+0x10 {
return "foo", foopc
}
return "", 0
}
func decode(data []byte, t *testing.T, filename string) {
all := string(data)
// Simulate PC based on number of instructions found in the test file.
pc := uint64(0)
for strings.Contains(all, "\t\t") {
all = strings.Replace(all, "\t\t", "\t", -1)
}
for _, line := range strings.Split(all, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.SplitN(line, "\t", 3)
i := strings.Index(f[0], "|")
if i < 0 {
t.Errorf("%s: parsing %q: missing | separator", filename, f[0])
continue
}
if i%2 != 0 {
t.Errorf("%s: parsing %q: misaligned | separator", filename, f[0])
}
size := i / 2
code, err := hex.DecodeString(f[0][:i] + f[0][i+1:])
if err != nil {
t.Errorf("%s: parsing %q: %v", filename, f[0], err)
continue
}
syntax, asm := f[1], f[2]
inst, err := Decode(code, binary.BigEndian)
var out string
if err != nil {
out = "error: " + err.Error()
} else {
switch syntax {
case "gnu":
out = GNUSyntax(inst, pc)
case "plan9":
pc := pc
// Hack: Setting PC to 0 effectively transforms the PC relative address
// of CALL (bl) into an absolute address when decoding in GoSyntax. This
// simplifies the testing of symbol lookups via symlookup above.
if inst.Op == BL {
pc = 0
}
out = GoSyntax(inst, pc, symlookup)
default:
t.Errorf("unknown syntax %q", syntax)
continue
}
}
pc += uint64(size)
if out != asm || inst.Len != size {
t.Errorf("%s: Decode(%s) [%s] = %s want %s", filename, f[0], syntax, out, asm)
}
}
}
@@ -0,0 +1,6 @@
// Copyright 2014 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 ppc64asm implements decoding of 64-bit PowerPC machine code.
package ppc64asm
@@ -0,0 +1,541 @@
// Copyright 2014 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.
// Support for testing against external disassembler program.
// Copied and simplified from rsc.io/arm/armasm/ext_test.go.
package ppc64asm
import (
"bufio"
"bytes"
"encoding/binary"
"encoding/hex"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"testing"
"time"
)
var (
printTests = flag.Bool("printtests", false, "print test cases that exercise new code paths")
dumpTest = flag.Bool("dump", false, "dump all encodings")
mismatch = flag.Bool("mismatch", false, "log allowed mismatches")
longTest = flag.Bool("long", false, "long test")
keep = flag.Bool("keep", false, "keep object files around")
debug = false
)
// An ExtInst represents a single decoded instruction parsed
// from an external disassembler's output.
type ExtInst struct {
addr uint32
enc [8]byte
nenc int
text string
}
func (r ExtInst) String() string {
return fmt.Sprintf("%#x: % x: %s", r.addr, r.enc, r.text)
}
// An ExtDis is a connection between an external disassembler and a test.
type ExtDis struct {
Dec chan ExtInst
File *os.File
Size int
KeepFile bool
Cmd *exec.Cmd
}
// Run runs the given command - the external disassembler - and returns
// a buffered reader of its standard output.
func (ext *ExtDis) Run(cmd ...string) (*bufio.Reader, error) {
if *keep {
log.Printf("%s\n", strings.Join(cmd, " "))
}
ext.Cmd = exec.Command(cmd[0], cmd[1:]...)
out, err := ext.Cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("stdoutpipe: %v", err)
}
if err := ext.Cmd.Start(); err != nil {
return nil, fmt.Errorf("exec: %v", err)
}
b := bufio.NewReaderSize(out, 1<<20)
return b, nil
}
// Wait waits for the command started with Run to exit.
func (ext *ExtDis) Wait() error {
return ext.Cmd.Wait()
}
// testExtDis tests a set of byte sequences against an external disassembler.
// The disassembler is expected to produce the given syntax and be run
// in the given architecture mode (16, 32, or 64-bit).
// The extdis function must start the external disassembler
// and then parse its output, sending the parsed instructions on ext.Dec.
// The generate function calls its argument f once for each byte sequence
// to be tested. The generate function itself will be called twice, and it must
// make the same sequence of calls to f each time.
// When a disassembly does not match the internal decoding,
// allowedMismatch determines whether this mismatch should be
// allowed, or else considered an error.
func testExtDis(
t *testing.T,
syntax string,
extdis func(ext *ExtDis) error,
generate func(f func([]byte)),
allowedMismatch func(text string, size int, inst *Inst, dec ExtInst) bool,
) {
start := time.Now()
ext := &ExtDis{
Dec: make(chan ExtInst),
}
errc := make(chan error)
// First pass: write instructions to input file for external disassembler.
file, f, size, err := writeInst(generate)
if err != nil {
t.Fatal(err)
}
ext.Size = size
ext.File = f
defer func() {
f.Close()
if !*keep {
os.Remove(file)
}
}()
// Second pass: compare disassembly against our decodings.
var (
totalTests = 0
totalSkips = 0
totalErrors = 0
errors = make([]string, 0, 100) // sampled errors, at most cap
)
go func() {
errc <- extdis(ext)
}()
generate(func(enc []byte) {
dec, ok := <-ext.Dec
if !ok {
t.Errorf("decoding stream ended early")
return
}
inst, text := disasm(syntax, pad(enc))
totalTests++
if *dumpTest {
fmt.Printf("%x -> %s [%d]\n", enc[:len(enc)], dec.text, dec.nenc)
}
if text != dec.text || inst.Len != dec.nenc {
suffix := ""
if allowedMismatch(text, size, &inst, dec) {
totalSkips++
if !*mismatch {
return
}
suffix += " (allowed mismatch)"
}
totalErrors++
if len(errors) >= cap(errors) {
j := rand.Intn(totalErrors)
if j >= cap(errors) {
return
}
errors = append(errors[:j], errors[j+1:]...)
}
errors = append(errors, fmt.Sprintf("decode(%x) = %q, %d, want %q, %d%s", enc, text, inst.Len, dec.text, dec.nenc, suffix))
}
})
if *mismatch {
totalErrors -= totalSkips
}
for _, b := range errors {
t.Log(b)
}
if totalErrors > 0 {
t.Fail()
}
t.Logf("%d test cases, %d expected mismatches, %d failures; %.0f cases/second", totalTests, totalSkips, totalErrors, float64(totalTests)/time.Since(start).Seconds())
if err := <-errc; err != nil {
t.Fatalf("external disassembler: %v", err)
}
}
const start = 0x8000 // start address of text
// writeInst writes the generated byte sequences to a new file
// starting at offset start. That file is intended to be the input to
// the external disassembler.
func writeInst(generate func(func([]byte))) (file string, f *os.File, size int, err error) {
f, err = ioutil.TempFile("", "ppc64asm")
if err != nil {
return
}
file = f.Name()
f.Seek(start, io.SeekStart)
w := bufio.NewWriter(f)
defer w.Flush()
size = 0
generate(func(x []byte) {
if len(x) != 4 && len(x) != 8 {
panic(fmt.Sprintf("Unexpected instruction %v\n", x))
}
izeros := zeros
if len(x) == 4 {
// Only pad to 4 bytes for a 4 byte instruction word.
izeros = izeros[4:]
}
if debug {
fmt.Printf("%#x: %x%x\n", start+size, x, izeros[len(x):])
}
w.Write(x)
w.Write(izeros[len(x):])
size += len(izeros)
})
return file, f, size, nil
}
var zeros = []byte{0, 0, 0, 0, 0, 0, 0, 0}
// pad pads the code sequence with pops.
func pad(enc []byte) []byte {
if len(enc) < 4 {
enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
}
return enc
}
// disasm returns the decoded instruction and text
// for the given source bytes, using the given syntax and mode.
func disasm(syntax string, src []byte) (inst Inst, text string) {
// If printTests is set, we record the coverage value
// before and after, and we write out the inputs for which
// coverage went up, in the format expected in testdata/decode.text.
// This produces a fairly small set of test cases that exercise nearly
// all the code.
var cover float64
if *printTests {
cover -= coverage()
}
inst, err := Decode(src, binary.BigEndian)
if err != nil {
text = "error: " + err.Error()
} else {
text = inst.String()
switch syntax {
//case "arm":
// text = ARMSyntax(inst)
case "gnu":
text = GNUSyntax(inst, 0)
//case "plan9":
// text = GoSyntax(inst, 0, nil)
default:
text = "error: unknown syntax " + syntax
}
}
if *printTests {
cover += coverage()
if cover > 0 {
max := len(src)
if max > 4 && inst.Len <= 4 {
max = 4
}
fmt.Printf("%x|%x\t%s\t%s\n", src[:inst.Len], src[inst.Len:max], syntax, text)
}
}
return
}
// coverage returns a floating point number denoting the
// test coverage until now. The number increases when new code paths are exercised,
// both in the Go program and in the decoder byte code.
func coverage() float64 {
var f float64
f += testing.Coverage()
f += decodeCoverage()
return f
}
func decodeCoverage() float64 {
n := 0
for _, t := range decoderCover {
if t {
n++
}
}
return float64(1+n) / float64(1+len(decoderCover))
}
// Helpers for writing disassembler output parsers.
// hasPrefix reports whether any of the space-separated words in the text s
// begins with any of the given prefixes.
func hasPrefix(s string, prefixes ...string) bool {
for _, prefix := range prefixes {
for s := s; s != ""; {
if strings.HasPrefix(s, prefix) {
return true
}
i := strings.Index(s, " ")
if i < 0 {
break
}
s = s[i+1:]
}
}
return false
}
// contains reports whether the text s contains any of the given substrings.
func contains(s string, substrings ...string) bool {
for _, sub := range substrings {
if strings.Contains(s, sub) {
return true
}
}
return false
}
// isHex reports whether b is a hexadecimal character (0-9A-Fa-f).
func isHex(b byte) bool { return b == '0' || unhex[b] > 0 }
// parseHex parses the hexadecimal byte dump in hex,
// appending the parsed bytes to raw and returning the updated slice.
// The returned bool signals whether any invalid hex was found.
// Spaces and tabs between bytes are okay but any other non-hex is not.
func parseHex(hex []byte, raw []byte) ([]byte, bool) {
hex = trimSpace(hex)
for j := 0; j < len(hex); {
for hex[j] == ' ' || hex[j] == '\t' {
j++
}
if j >= len(hex) {
break
}
if j+2 > len(hex) || !isHex(hex[j]) || !isHex(hex[j+1]) {
return nil, false
}
raw = append(raw, unhex[hex[j]]<<4|unhex[hex[j+1]])
j += 2
}
return raw, true
}
var unhex = [256]byte{
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
'A': 10,
'B': 11,
'C': 12,
'D': 13,
'E': 14,
'F': 15,
'a': 10,
'b': 11,
'c': 12,
'd': 13,
'e': 14,
'f': 15,
}
// index is like bytes.Index(s, []byte(t)) but avoids the allocation.
func index(s []byte, t string) int {
i := 0
for {
j := bytes.IndexByte(s[i:], t[0])
if j < 0 {
return -1
}
i = i + j
if i+len(t) > len(s) {
return -1
}
for k := 1; k < len(t); k++ {
if s[i+k] != t[k] {
goto nomatch
}
}
return i
nomatch:
i++
}
}
// fixSpace rewrites runs of spaces, tabs, and newline characters into single spaces in s.
// If s must be rewritten, it is rewritten in place.
func fixSpace(s []byte) []byte {
s = trimSpace(s)
for i := 0; i < len(s); i++ {
if s[i] == '\t' || s[i] == '\n' || i > 0 && s[i] == ' ' && s[i-1] == ' ' {
goto Fix
}
}
return s
Fix:
b := s
w := 0
for i := 0; i < len(s); i++ {
c := s[i]
if c == '\t' || c == '\n' {
c = ' '
}
if c == ' ' && w > 0 && b[w-1] == ' ' {
continue
}
b[w] = c
w++
}
if w > 0 && b[w-1] == ' ' {
w--
}
return b[:w]
}
// trimSpace trims leading and trailing space from s, returning a subslice of s.
func trimSpace(s []byte) []byte {
j := len(s)
for j > 0 && (s[j-1] == ' ' || s[j-1] == '\t' || s[j-1] == '\n') {
j--
}
i := 0
for i < j && (s[i] == ' ' || s[i] == '\t') {
i++
}
return s[i:j]
}
// pcrel matches instructions using relative addressing mode.
var (
pcrel = regexp.MustCompile(`^((?:.* )?(?:b|bc)[^ac ]* (?:(?:[0-9]{1,2},)|(?:[0-7]\*)|\+|lt|gt|eq|so|cr[0-7]|,)*)0x([0-9a-f]+)$`)
)
// Generators.
//
// The test cases are described as functions that invoke a callback repeatedly,
// with a new input sequence each time. These helpers make writing those
// a little easier.
// randomCases generates random instructions.
func randomCases(t *testing.T) func(func([]byte)) {
return func(try func([]byte)) {
// All the strides are relatively prime to 2 and therefore to 2²⁸,
// so we will not repeat any instructions until we have tried all 2²⁸.
// Using a stride other than 1 is meant to visit the instructions in a
// pseudorandom order, which gives better variety in the set of
// test cases chosen by -printtests.
stride := uint32(10007)
n := 1 << 28 / 7
if testing.Short() {
stride = 100003
n = 1 << 28 / 1001
} else if *longTest {
stride = 2000033
n = 1 << 29
}
x := uint32(0)
for i := 0; i < n; i++ {
enc := (x%15)<<28 | x&(1<<28-1)
try([]byte{byte(enc), byte(enc >> 8), byte(enc >> 16), byte(enc >> 24)})
x += stride
}
}
}
// hexCases generates the cases written in hexadecimal in the encoded string.
// Spaces in 'encoded' separate entire test cases, not individual bytes.
func hexCases(t *testing.T, encoded string) func(func([]byte)) {
return func(try func([]byte)) {
for _, x := range strings.Fields(encoded) {
src, err := hex.DecodeString(x)
if err != nil {
t.Errorf("parsing %q: %v", x, err)
}
try(src)
}
}
}
// testdataCases generates the test cases recorded in testdata/decode.txt.
// It only uses the inputs; it ignores the answers recorded in that file.
func testdataCases(t *testing.T) func(func([]byte)) {
var codes [][]byte
data, err := ioutil.ReadFile("testdata/decode.txt")
if err != nil {
t.Fatal(err)
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.Fields(line)[0]
i := strings.Index(f, "|")
if i < 0 {
t.Errorf("parsing %q: missing | separator", f)
continue
}
if i%2 != 0 {
t.Errorf("parsing %q: misaligned | separator", f)
}
code, err := hex.DecodeString(f[:i] + f[i+1:])
if err != nil {
t.Errorf("parsing %q: %v", f, err)
continue
}
codes = append(codes, code)
}
return func(try func([]byte)) {
for _, code := range codes {
try(code)
}
}
}
func caller(skip int) string {
pc, _, _, _ := runtime.Caller(skip)
f := runtime.FuncForPC(pc)
name := "?"
if f != nil {
name = f.Name()
if i := strings.LastIndex(name, "."); i >= 0 {
name = name[i+1:]
}
}
return name
}
@@ -0,0 +1,97 @@
// Copyright 2014 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 ppc64asm
import (
"fmt"
"strings"
)
// A BitField is a bit-field in a 32-bit word.
// Bits are counted from 0 from the MSB to 31 as the LSB.
type BitField struct {
Offs uint8 // the offset of the left-most bit.
Bits uint8 // length in bits.
// This instruction word holding this field.
// It is always 0 for ISA < 3.1 instructions. It is
// in decoding order. (0 == prefix, 1 == suffix on ISA 3.1)
Word uint8
}
func (b BitField) String() string {
if b.Bits > 1 {
return fmt.Sprintf("[%d:%d]", b.Offs, int(b.Offs+b.Bits)-1)
} else if b.Bits == 1 {
return fmt.Sprintf("[%d]", b.Offs)
} else {
return fmt.Sprintf("[%d, len=0]", b.Offs)
}
}
// Parse extracts the bitfield b from i, and return it as an unsigned integer.
// Parse will panic if b is invalid.
func (b BitField) Parse(i [2]uint32) uint32 {
if b.Bits > 32 || b.Bits == 0 || b.Offs > 31 || b.Offs+b.Bits > 32 {
panic(fmt.Sprintf("invalid bitfiled %v", b))
}
return (i[b.Word] >> (32 - b.Offs - b.Bits)) & ((1 << b.Bits) - 1)
}
// ParseSigned extracts the bitfield b from i, and return it as a signed integer.
// ParseSigned will panic if b is invalid.
func (b BitField) ParseSigned(i [2]uint32) int32 {
u := int32(b.Parse(i))
return u << (32 - b.Bits) >> (32 - b.Bits)
}
// BitFields is a series of BitFields representing a single number.
type BitFields []BitField
func (bs BitFields) String() string {
ss := make([]string, len(bs))
for i, bf := range bs {
ss[i] = bf.String()
}
return fmt.Sprintf("<%s>", strings.Join(ss, "|"))
}
func (bs *BitFields) Append(b BitField) {
*bs = append(*bs, b)
}
// parse extracts the bitfields from i, concatenate them and return the result
// as an unsigned integer and the total length of all the bitfields.
// parse will panic if any bitfield in b is invalid, but it doesn't check if
// the sequence of bitfields is reasonable.
func (bs BitFields) parse(i [2]uint32) (u uint64, Bits uint8) {
for _, b := range bs {
u = (u << b.Bits) | uint64(b.Parse(i))
Bits += b.Bits
}
return u, Bits
}
// Parse extracts the bitfields from i, concatenate them and return the result
// as an unsigned integer. Parse will panic if any bitfield in b is invalid.
func (bs BitFields) Parse(i [2]uint32) uint64 {
u, _ := bs.parse(i)
return u
}
// ParseSigned extracts the bitfields from i, concatenate them and return the result
// as a signed integer. Parse will panic if any bitfield in b is invalid.
func (bs BitFields) ParseSigned(i [2]uint32) int64 {
u, l := bs.parse(i)
return int64(u) << (64 - l) >> (64 - l)
}
// Count the number of bits in the aggregate BitFields
func (bs BitFields) NumBits() int {
num := 0
for _, b := range bs {
num += int(b.Bits)
}
return num
}
@@ -0,0 +1,109 @@
// Copyright 2014 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 ppc64asm
import (
"testing"
)
func panicOrNot(f func()) (panicked bool) {
defer func() {
if err := recover(); err != nil {
panicked = true
}
}()
f()
return false
}
func TestBitField(t *testing.T) {
var tests = []struct {
b BitField
i uint32 // input
u uint32 // unsigned output
s int32 // signed output
fail bool // if the check should panic
}{
{BitField{0, 0, 0}, 0, 0, 0, true},
{BitField{31, 2, 0}, 0, 0, 0, true},
{BitField{31, 1, 0}, 1, 1, -1, false},
{BitField{29, 2, 0}, 0 << 1, 0, 0, false},
{BitField{29, 2, 0}, 1 << 1, 1, 1, false},
{BitField{29, 2, 0}, 2 << 1, 2, -2, false},
{BitField{29, 2, 0}, 3 << 1, 3, -1, false},
{BitField{0, 32, 0}, 1<<32 - 1, 1<<32 - 1, -1, false},
{BitField{16, 3, 0}, 1 << 15, 4, -4, false},
}
for i, tst := range tests {
var (
ou uint32
os int32
)
failed := panicOrNot(func() {
ou = tst.b.Parse([2]uint32{tst.i})
os = tst.b.ParseSigned([2]uint32{tst.i})
})
if failed != tst.fail {
t.Errorf("case %d: %v: fail test failed, got %v, expected %v", i, tst.b, failed, tst.fail)
continue
}
if ou != tst.u {
t.Errorf("case %d: %v.Parse(%d) returned %d, expected %d", i, tst.b, tst.i, ou, tst.u)
continue
}
if os != tst.s {
t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
}
}
}
func TestBitFields(t *testing.T) {
var tests = []struct {
b BitFields
i [2]uint32 // input
u uint64 // unsigned output
s int64 // signed output
nb int // Total number of bits in BitField
fail bool // if the check should panic
}{
{BitFields{{0, 0, 1}}, [2]uint32{0, 0}, 0, 0, 0, true},
{BitFields{{31, 2, 1}}, [2]uint32{0, 0}, 0, 0, 2, true},
{BitFields{{31, 1, 1}}, [2]uint32{0, 1}, 1, -1, 1, false},
{BitFields{{29, 2, 1}}, [2]uint32{0, 0 << 1}, 0, 0, 2, false},
{BitFields{{29, 2, 1}}, [2]uint32{0, 1 << 1}, 1, 1, 2, false},
{BitFields{{29, 2, 1}}, [2]uint32{0, 2 << 1}, 2, -2, 2, false},
{BitFields{{29, 2, 1}}, [2]uint32{0, 3 << 1}, 3, -1, 2, false},
{BitFields{{0, 32, 1}}, [2]uint32{0, 1<<32 - 1}, 1<<32 - 1, -1, 32, false},
{BitFields{{16, 3, 1}}, [2]uint32{0, 1 << 15}, 4, -4, 3, false},
{BitFields{{16, 16, 0}, {16, 16, 1}}, [2]uint32{0x8016, 0x32}, 0x80160032, -0x7FE9FFCE, 32, false},
{BitFields{{14, 18, 0}, {16, 16, 1}}, [2]uint32{0x38016, 0x32}, 0x380160032, -0x07FE9FFCE, 34, false},
}
for i, tst := range tests {
var (
ou uint64
os int64
onb int
)
failed := panicOrNot(func() {
onb = tst.b.NumBits()
ou = tst.b.Parse(tst.i)
os = tst.b.ParseSigned(tst.i)
})
if failed != tst.fail {
t.Errorf("case %d: %v: fail test failed, got %v, expected %v", i, tst.b, failed, tst.fail)
continue
}
if ou != tst.u {
t.Errorf("case %d: %v.Parse(%d) returned %d, expected %d", i, tst.b, tst.i, ou, tst.u)
continue
}
if os != tst.s {
t.Errorf("case %d: %v.ParseSigned(%d) returned %d, expected %d", i, tst.b, tst.i, os, tst.s)
}
if onb != tst.nb {
t.Errorf("case %d: %v.NumBits() returned %d, expected %d", i, tst.b, onb, tst.nb)
}
}
}
@@ -0,0 +1,471 @@
// Copyright 2014 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 ppc64asm
import (
"bytes"
"fmt"
"strings"
)
var (
// bit 3 of index is a negated check.
condBit = [8]string{
"lt", "gt", "eq", "so",
"ge", "le", "ne", "ns"}
)
// GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
// This form typically matches the syntax defined in the Power ISA Reference Manual.
func GNUSyntax(inst Inst, pc uint64) string {
var buf bytes.Buffer
// When there are all 0s, identify them as the disassembler
// in binutils would.
if inst.Enc == 0 {
return ".long 0x0"
} else if inst.Op == 0 {
return "error: unknown instruction"
}
PC := pc
// Special handling for some ops
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:]
bo := int(inst.Args[0].(Imm))
bi := inst.Args[1].(CondReg)
atsfx := [4]string{"", "?", "-", "+"}
decsfx := [2]string{"dnz", "dz"}
//BO field is... complicated (z == ignored bit, at == prediction hint)
//Paraphrased from ISA 3.1 Book I Section 2.4:
//
//0000z -> decrement ctr, b if ctr != 0 and CRbi == 0
//0001z -> decrement ctr, b if ctr == 0 and CRbi == 0
//001at -> b if CRbi == 0
//0100z -> decrement ctr, b if ctr != 0 and CRbi == 1
//0101z -> decrement ctr, b if ctr == 0 and CRbi == 1
//011at -> b if CRbi == 1
//1a00t -> decrement ctr, b if ctr != 0
//1a01t -> decrement ctr, b if ctr == 0
//1z1zz -> b always
// Decoding (in this order) we get
// BO & 0b00100 == 0b00000 -> dz if BO[1], else dnz (not simplified for bcctrl forms)
// BO & 0b10000 == 0b10000 -> (bc and bca forms not simplified), at = B[4]B[0] if B[2] != 0, done
// BO & 0b10000 == 0b00000 -> t if BO[3], else f
// BO & 0b10100 == 0b00100 -> at = B[0:1]
// BI fields rename as follows:
// less than : lt BI%4==0 && test == t
// less than or equal : le BI%4==1 && test == f
// equal : eq BI%4==2 && test == t
// greater than or equal: ge BI%4==0 && test == f
// greater than : gt BI%4==1 && test == t
// not less than : nl BI%4==0 && test == f
// not equal : ne BI%4==2 && test == f
// not greater than : ng BI%4==1 && test == f
// summary overflow : so BI%4==3 && test == t
// not summary overflow : ns BI%4==3 && test == f
// unordered : un BI%4==3 && test == t
// not unordered : nu BI%4==3 && test == f
//
// Note, there are only 8 possible tests, but quite a few more
// ways to name fields. For simplicity, we choose those in condBit.
at := 0 // 0 == no hint, 1 == reserved, 2 == not likely, 3 == likely
form := 1 // 1 == n/a, 0 == cr bit not set, 4 == cr bit set
cr := (bi - Cond0LT) / 4
bh := -1 // Only for lr/tar/ctr variants.
switch opName {
case "bclr", "bclrl", "bcctr", "bcctrl", "bctar", "bctarl":
bh = int(inst.Args[2].(Imm))
}
if bo&0x14 == 0x14 {
if bo == 0x14 && bi == Cond0LT { // preferred form of unconditional branch
// Likewise, avoid printing fake b/ba/bl/bla
if opName != "bc" && opName != "bca" && opName != "bcl" && opName != "bcla" {
startArg = 2
}
}
} else if bo&0x04 == 0 { // ctr is decremented
if opName != "bcctr" && opName != "bcctrl" {
startArg = 1
tf := ""
if bo&0x10 == 0x00 {
tf = "f"
if bo&0x08 == 0x08 {
tf = "t"
}
}
sfx = decsfx[(bo>>1)&1] + tf + sfx
}
if bo&0x10 == 0x10 {
if opName != "bcctr" && opName != "bcctrl" {
startArg = 2
}
if bi != Cond0LT {
// A non-zero BI bit was encoded, but ignored by BO
startArg = 0
}
at = ((bo & 0x8) >> 2) | (bo & 0x1)
} else if bo&0x4 == 0x4 {
at = bo & 0x3
}
} else if bo&0x10 == 0x10 { // BI field is not used
if opName != "bca" && opName != "bc" {
at = ((bo & 0x8) >> 2) | (bo & 0x1)
startArg = 2
}
// If BI is encoded as a bit other than 0, no mnemonic.
if bo&0x14 == 0x14 {
startArg = 0
}
} else {
form = (bo & 0x8) >> 1
startArg = 2
if bo&0x14 == 0x04 {
at = bo & 0x3
}
}
sfx += atsfx[at]
if form != 1 {
bit := int((bi-Cond0LT)%4) | (^form)&0x4
sfx = condBit[bit] + sfx
}
if at != 1 && startArg > 0 && bh <= 0 {
str := fmt.Sprintf("b%s", sfx)
if startArg > 1 && (cr != 0 || bh > 0) {
str += fmt.Sprintf(" cr%d", cr)
sep = ","
}
buf.WriteString(str)
if startArg < 2 && bh == 0 {
str := fmt.Sprintf(" %s",
gnuArg(&inst, 1, inst.Args[1], PC))
buf.WriteString(str)
startArg = 3
} else if bh == 0 {
startArg = 3
}
} else {
if startArg == 0 || bh > 0 || at == 1 {
buf.WriteString(inst.Op.String())
buf.WriteString(atsfx[at])
startArg = 0
} else {
buf.WriteString("b" + sfx)
}
if bh == 0 {
str := fmt.Sprintf(" %d,%s", bo, gnuArg(&inst, 1, inst.Args[1], PC))
buf.WriteString(str)
startArg = 3
}
}
case "mtspr":
opcode := inst.Op.String()
buf.WriteString(opcode[0:2])
switch spr := inst.Args[0].(type) {
case SpReg:
switch spr {
case 1:
buf.WriteString("xer")
startArg = 1
case 8:
buf.WriteString("lr")
startArg = 1
case 9:
buf.WriteString("ctr")
startArg = 1
default:
buf.WriteString("spr")
}
default:
buf.WriteString("spr")
}
case "mfspr":
opcode := inst.Op.String()
buf.WriteString(opcode[0:2])
arg := inst.Args[0]
switch spr := inst.Args[1].(type) {
case SpReg:
switch spr {
case 1:
buf.WriteString("xer ")
buf.WriteString(gnuArg(&inst, 0, arg, PC))
startArg = 2
case 8:
buf.WriteString("lr ")
buf.WriteString(gnuArg(&inst, 0, arg, PC))
startArg = 2
case 9:
buf.WriteString("ctr ")
buf.WriteString(gnuArg(&inst, 0, arg, PC))
startArg = 2
case 268:
buf.WriteString("tb ")
buf.WriteString(gnuArg(&inst, 0, arg, PC))
startArg = 2
default:
buf.WriteString("spr")
}
default:
buf.WriteString("spr")
}
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
}
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())
case "paddi":
// There are several extended mnemonics. Notably, "pla" is
// the only valid mnemonic for paddi (R=1), In this case, RA must
// always be 0. Otherwise it is invalid.
r := inst.Args[3].(Imm)
ra := inst.Args[1].(Reg)
str := opName
if ra == R0 {
name := []string{"pli", "pla"}
str = fmt.Sprintf("%s %s,%s",
name[r&1],
gnuArg(&inst, 0, inst.Args[0], PC),
gnuArg(&inst, 2, inst.Args[2], PC))
startArg = 4
} else {
str = fmt.Sprintf("%s %s,%s,%s", opName,
gnuArg(&inst, 0, inst.Args[0], PC),
gnuArg(&inst, 1, inst.Args[1], PC),
gnuArg(&inst, 2, inst.Args[2], PC))
startArg = 4
if r == 1 {
// This is an illegal encoding (ra != 0 && r == 1) on ISA 3.1.
v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
return fmt.Sprintf(".quad 0x%x", v)
}
}
buf.WriteString(str)
default:
// Prefixed load/stores do not print the displacement register when R==1 (they are PCrel).
// This also implies RA should be 0. Likewise, when R==0, printing of R can be omitted.
if strings.HasPrefix(opName, "pl") || strings.HasPrefix(opName, "pst") {
r := inst.Args[3].(Imm)
ra := inst.Args[2].(Reg)
d := inst.Args[1].(Offset)
if r == 1 && ra == R0 {
str := fmt.Sprintf("%s %s,%d", opName, gnuArg(&inst, 0, inst.Args[0], PC), d)
buf.WriteString(str)
startArg = 4
} else {
str := fmt.Sprintf("%s %s,%d(%s)", opName,
gnuArg(&inst, 0, inst.Args[0], PC),
d,
gnuArg(&inst, 2, inst.Args[2], PC))
if r == 1 {
// This is an invalid encoding (ra != 0 && r == 1) on ISA 3.1.
v := uint64(inst.Enc)<<32 | uint64(inst.SuffixEnc)
return fmt.Sprintf(".quad 0x%x", v)
}
buf.WriteString(str)
startArg = 4
}
} else {
buf.WriteString(opName)
}
}
for i, arg := range argList {
if arg == nil {
break
}
if i < startArg {
continue
}
text := gnuArg(&inst, i, arg, PC)
if text == "" {
continue
}
buf.WriteString(sep)
sep = ","
buf.WriteString(text)
}
return buf.String()
}
// gnuArg formats arg (which is the argIndex's arg in inst) according to GNU rules.
// NOTE: because GNUSyntax is the only caller of this func, and it receives a copy
// of inst, it's ok to modify inst.Args here.
func gnuArg(inst *Inst, argIndex int, arg Arg, pc uint64) string {
// special cases for load/store instructions
if _, ok := arg.(Offset); ok {
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
panic(fmt.Errorf("wrong table: offset not followed by register"))
}
}
switch arg := arg.(type) {
case Reg:
if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
return "0"
}
return arg.String()
case CondReg:
// The CondReg can either be found in a CMP, where the
// condition register field is being set, or in an instruction
// like a branch or isel that is testing a bit in a condition
// register field.
if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
return "" // don't show cr0 for cmp instructions
} else if arg >= CR0 {
return fmt.Sprintf("cr%d", int(arg-CR0))
}
bit := condBit[(arg-Cond0LT)%4]
if arg <= Cond0SO {
return bit
}
return fmt.Sprintf("4*cr%d+%s", int(arg-Cond0LT)/4, bit)
case Imm:
return fmt.Sprintf("%d", arg)
case SpReg:
switch int(arg) {
case 1:
return "xer"
case 8:
return "lr"
case 9:
return "ctr"
case 268:
return "tb"
default:
return fmt.Sprintf("%d", int(arg))
}
case PCRel:
// If the arg is 0, use the relative address format.
// Otherwise the pc is meaningful, use absolute address.
if int(arg) == 0 {
return fmt.Sprintf(".%+#x", int(arg))
}
addr := pc + uint64(int64(arg))
return fmt.Sprintf("%#x", addr)
case Label:
return fmt.Sprintf("%#x", uint32(arg))
case Offset:
reg := inst.Args[argIndex+1].(Reg)
removeArg(inst, argIndex+1)
if reg == R0 {
return fmt.Sprintf("%d(0)", int(arg))
}
return fmt.Sprintf("%d(r%d)", int(arg), reg-R0)
}
return fmt.Sprintf("???(%v)", arg)
}
// removeArg removes the arg in inst.Args[index].
func removeArg(inst *Inst, index int) {
for i := index; i < len(inst.Args); i++ {
if i+1 < len(inst.Args) {
inst.Args[i] = inst.Args[i+1]
} else {
inst.Args[i] = nil
}
}
}
// isLoadStoreOp returns true if op is a load or store instruction
func isLoadStoreOp(op Op) bool {
switch op {
case LBZ, LBZU, LBZX, LBZUX:
return true
case LHZ, LHZU, LHZX, LHZUX:
return true
case LHA, LHAU, LHAX, LHAUX:
return true
case LWZ, LWZU, LWZX, LWZUX:
return true
case LWA, LWAX, LWAUX:
return true
case LD, LDU, LDX, LDUX:
return true
case LQ:
return true
case STB, STBU, STBX, STBUX:
return true
case STH, STHU, STHX, STHUX:
return true
case STW, STWU, STWX, STWUX:
return true
case STD, STDU, STDX, STDUX:
return true
case STQ:
return true
case LHBRX, LWBRX, STHBRX, STWBRX:
return true
case LBARX, LWARX, LHARX, LDARX:
return true
}
return false
}
@@ -0,0 +1,355 @@
// Copyright 2014 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 ppc64asm
import (
"bytes"
"fmt"
)
type Inst struct {
Op Op // Opcode mnemonic
Enc uint32 // Raw encoding bits (if Len == 8, this is the prefix word)
Len int // Length of encoding in bytes.
SuffixEnc uint32 // Raw encoding bits of second word (if Len == 8)
Args Args // Instruction arguments, in Power ISA manual order.
}
func (i Inst) String() string {
var buf bytes.Buffer
buf.WriteString(i.Op.String())
for j, arg := range i.Args {
if arg == nil {
break
}
if j == 0 {
buf.WriteString(" ")
} else {
buf.WriteString(", ")
}
buf.WriteString(arg.String())
}
return buf.String()
}
// An Op is an instruction operation.
type Op uint16
func (o Op) String() string {
if int(o) >= len(opstr) || opstr[o] == "" {
return fmt.Sprintf("Op(%d)", int(o))
}
return opstr[o]
}
// An Arg is a single instruction argument, one of these types: Reg, CondReg, SpReg, Imm, PCRel, Label, or Offset.
type Arg interface {
IsArg()
String() string
}
// An Args holds the instruction arguments.
// If an instruction has fewer than 6 arguments,
// the final elements in the array are nil.
type Args [6]Arg
// A Reg is a single register. The zero value means R0, not the absence of a register.
// It also includes special registers.
type Reg uint16
const (
_ Reg = iota
R0
R1
R2
R3
R4
R5
R6
R7
R8
R9
R10
R11
R12
R13
R14
R15
R16
R17
R18
R19
R20
R21
R22
R23
R24
R25
R26
R27
R28
R29
R30
R31
F0
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F11
F12
F13
F14
F15
F16
F17
F18
F19
F20
F21
F22
F23
F24
F25
F26
F27
F28
F29
F30
F31
V0 // VSX extension, F0 is V0[0:63].
V1
V2
V3
V4
V5
V6
V7
V8
V9
V10
V11
V12
V13
V14
V15
V16
V17
V18
V19
V20
V21
V22
V23
V24
V25
V26
V27
V28
V29
V30
V31
VS0
VS1
VS2
VS3
VS4
VS5
VS6
VS7
VS8
VS9
VS10
VS11
VS12
VS13
VS14
VS15
VS16
VS17
VS18
VS19
VS20
VS21
VS22
VS23
VS24
VS25
VS26
VS27
VS28
VS29
VS30
VS31
VS32
VS33
VS34
VS35
VS36
VS37
VS38
VS39
VS40
VS41
VS42
VS43
VS44
VS45
VS46
VS47
VS48
VS49
VS50
VS51
VS52
VS53
VS54
VS55
VS56
VS57
VS58
VS59
VS60
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() {}
func (r Reg) String() string {
switch {
case R0 <= r && r <= R31:
return fmt.Sprintf("r%d", int(r-R0))
case F0 <= r && r <= F31:
return fmt.Sprintf("f%d", int(r-F0))
case V0 <= r && r <= V31:
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))
}
}
// CondReg is a bit or field in the condition register.
type CondReg int8
const (
_ CondReg = iota
// Condition Regster bits
Cond0LT
Cond0GT
Cond0EQ
Cond0SO
Cond1LT
Cond1GT
Cond1EQ
Cond1SO
Cond2LT
Cond2GT
Cond2EQ
Cond2SO
Cond3LT
Cond3GT
Cond3EQ
Cond3SO
Cond4LT
Cond4GT
Cond4EQ
Cond4SO
Cond5LT
Cond5GT
Cond5EQ
Cond5SO
Cond6LT
Cond6GT
Cond6EQ
Cond6SO
Cond7LT
Cond7GT
Cond7EQ
Cond7SO
// Condition Register Fields
CR0
CR1
CR2
CR3
CR4
CR5
CR6
CR7
)
func (CondReg) IsArg() {}
func (c CondReg) String() string {
switch {
default:
return fmt.Sprintf("CondReg(%d)", int(c))
case c >= CR0:
return fmt.Sprintf("CR%d", int(c-CR0))
case c >= Cond0LT && c < CR0:
return fmt.Sprintf("Cond%d%s", int((c-Cond0LT)/4), [4]string{"LT", "GT", "EQ", "SO"}[(c-Cond0LT)%4])
}
}
// SpReg is a special register, its meaning depends on Op.
type SpReg uint16
const (
SpRegZero SpReg = 0
)
func (SpReg) IsArg() {}
func (s SpReg) String() string {
return fmt.Sprintf("SpReg(%d)", int(s))
}
// PCRel is a PC-relative offset, used only in branch instructions.
type PCRel int32
func (PCRel) IsArg() {}
func (r PCRel) String() string {
return fmt.Sprintf("PC%+#x", int32(r))
}
// A Label is a code (text) address, used only in absolute branch instructions.
type Label uint32
func (Label) IsArg() {}
func (l Label) String() string {
return fmt.Sprintf("%#x", uint32(l))
}
// Imm represents an immediate number.
type Imm int64
func (Imm) IsArg() {}
func (i Imm) String() string {
return fmt.Sprintf("%d", int32(i))
}
// Offset represents a memory offset immediate.
type Offset int64
func (Offset) IsArg() {}
func (o Offset) String() string {
return fmt.Sprintf("%+d", int32(o))
}
@@ -0,0 +1,61 @@
// Copyright 2014 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 ppc64asm
import (
"encoding/binary"
"strings"
"testing"
)
func TestObjdumpPowerTestdata(t *testing.T) { testObjdump(t, testdataCases(t)) }
func TestObjdumpPowerManual(t *testing.T) { testObjdump(t, hexCases(t, objdumpManualTests)) }
// Disable this for now since generating all possible bit combinations within a word
// generates lots of ppc64x instructions not possible with golang so not worth supporting..
//func TestObjdumpPowerRandom(t *testing.T) { testObjdump(t, randomCases(t)) }
// objdumpManualTests holds test cases that will be run by TestObjdumpPowerManual.
// If you are debugging a few cases that turned up in a longer run, it can be useful
// to list them here and then use -run=Manual, particularly with tracing enabled.
// Note that these are byte sequences, so they must be reversed from the usual
// word presentation.
var objdumpManualTests = `
6d746162
4c040000
88000017
`
// allowedMismatchObjdump reports whether the mismatch between text and dec
// should be allowed by the test.
func allowedMismatchObjdump(text string, size int, inst *Inst, dec ExtInst) bool {
// we support more instructions than binutils
if strings.Contains(dec.text, ".long") {
return true
}
switch inst.Op {
case BC: // We don't print PC relative branches the same way.
return true
case DCBF, DCBT: // We only support extended mnemonics, and may not print 0 where R0 == 0.
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
case BL:
// TODO: Ignore these for now. The output format from gnu objdump is dependent on more than the
// instruction itself e.g: decode(48100009) = "bl 0x100008", 4, want "bl .+0x100008", 4
return true
}
if len(dec.enc) >= 4 {
_ = binary.BigEndian.Uint32(dec.enc[:4])
}
return false
}
@@ -0,0 +1,271 @@
// Copyright 2014 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.
// Copied and simplified from rsc.io/arm/armasm/objdumpext_test.go.
package ppc64asm
import (
"bytes"
"debug/elf"
"encoding/binary"
"fmt"
"io"
"log"
"os"
"os/exec"
"runtime"
"strconv"
"strings"
"testing"
)
var objdumpPath = "objdump"
var objdumpCrossNames = [...]string{"powerpc64-linux-gnu-objdump", "powerpc64le-linux-gnu-objdump"}
func testObjdump(t *testing.T, generate func(func([]byte))) {
if testing.Short() {
t.Skip("skipping objdump test in short mode")
}
if runtime.GOARCH != "ppc64le" && runtime.GOARCH != "ppc64" {
found := false
for _, c := range objdumpCrossNames {
if _, err := exec.LookPath(c); err == nil {
objdumpPath = c
found = true
break
}
}
if !found {
t.Skip("skipping; test requires host tool objdump for ppc64 or ppc64le")
}
} else if _, err := exec.LookPath(objdumpPath); err != nil {
t.Skip(err)
}
testExtDis(t, "gnu", objdump, generate, allowedMismatchObjdump)
}
func objdump(ext *ExtDis) error {
// File already written with instructions; add ELF header.
if err := writeELF64(ext.File, ext.Size); err != nil {
return err
}
b, err := ext.Run(objdumpPath, "-d", "-z", ext.File.Name())
if err != nil {
return err
}
var (
nmatch int
reading bool
next uint32 = start
addr uint32
encbuf [8]byte
enc []byte
text string
)
flush := func() {
if addr == next {
if m := pcrel.FindStringSubmatch(text); m != nil {
targ, _ := strconv.ParseUint(m[2], 16, 64)
text = fmt.Sprintf("%s.%+#x", m[1], int32(uint32(targ)-addr))
}
if strings.HasPrefix(text, "stmia") {
text = "stm" + text[5:]
}
if strings.HasPrefix(text, "stmfd") {
text = "stmdb" + text[5:]
}
if strings.HasPrefix(text, "ldmfd") {
text = "ldm" + text[5:]
}
text = strings.Replace(text, "#0.0", "#0", -1)
if text == "undefined" && len(enc) == 4 {
text = "error: unknown instruction"
enc = nil
}
// Prefixed instructions may not decode as expected if
// they are an invalid form. Some are tested in decode.txt.
// objdump treats these like two instructions.
//
// Look for primary opcode 1 and advance an exta 4 bytes if
// this failed to decode.
if strings.HasPrefix(text, ".long") && enc[0]>>2 == 1 {
next += 4
}
ext.Dec <- ExtInst{addr, encbuf, len(enc), text}
encbuf = [8]byte{}
next += uint32(len(enc))
enc = nil
}
}
var textangle = []byte("<.text>:")
for {
line, err := b.ReadSlice('\n')
if err != nil {
if err == io.EOF {
break
}
return fmt.Errorf("reading objdump output: %v", err)
}
if bytes.Contains(line, textangle) {
reading = true
continue
}
if !reading {
continue
}
if debug {
os.Stdout.Write(line)
}
if enc1 := parseContinuation(line, encbuf[:len(enc)]); enc1 != nil {
enc = enc1
continue
}
flush()
nmatch++
addr, enc, text = parseLine(line, encbuf[:0])
if addr > next {
return fmt.Errorf("address out of sync expected <= %#x at %q in:\n%s", next, line, line)
}
}
flush()
if next != start+uint32(ext.Size) {
return fmt.Errorf("not enough results found [%d %d]", next, start+ext.Size)
}
if err := ext.Wait(); err != nil {
return fmt.Errorf("exec: %v", err)
}
return nil
}
var (
undefined = []byte("<UNDEFINED>")
unpredictable = []byte("<UNPREDICTABLE>")
illegalShifter = []byte("<illegal shifter operand>")
)
func parseLine(line []byte, encstart []byte) (addr uint32, enc []byte, text string) {
oline := line
i := index(line, ":\t")
if i < 0 {
log.Fatalf("cannot parse disassembly: %q", oline)
}
x, err := strconv.ParseUint(string(trimSpace(line[:i])), 16, 32)
if err != nil {
log.Fatalf("cannot parse disassembly: %q", oline)
}
addr = uint32(x)
line = line[i+2:]
i = bytes.IndexByte(line, '\t')
if i < 0 {
log.Fatalf("cannot parse disassembly: %q", oline)
}
enc, ok := parseHex(line[:i], encstart)
if !ok {
log.Fatalf("cannot parse disassembly: %q", oline)
}
line = trimSpace(line[i:])
if bytes.Contains(line, undefined) {
text = "undefined"
return
}
if bytes.Contains(line, illegalShifter) {
text = "undefined"
return
}
if false && bytes.Contains(line, unpredictable) {
text = "unpredictable"
return
}
if i := bytes.IndexByte(line, ';'); i >= 0 {
line = trimSpace(line[:i])
}
text = string(fixSpace(line))
return
}
func parseContinuation(line []byte, enc []byte) []byte {
i := index(line, ":\t")
if i < 0 {
return nil
}
line = line[i+1:]
enc, _ = parseHex(line, enc)
return enc
}
// writeELF64 writes an ELF64 header to the file,
// describing a text segment that starts at start
// and extends for size bytes.
func writeELF64(f *os.File, size int) error {
f.Seek(0, io.SeekStart)
var hdr elf.Header64
var prog elf.Prog64
var sect elf.Section64
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, &hdr)
off1 := buf.Len()
binary.Write(&buf, binary.BigEndian, &prog)
off2 := buf.Len()
binary.Write(&buf, binary.BigEndian, &sect)
off3 := buf.Len()
buf.Reset()
data := byte(elf.ELFDATA2MSB)
hdr = elf.Header64{
Ident: [16]byte{0x7F, 'E', 'L', 'F', 2, data, 1},
Type: 2,
Machine: uint16(elf.EM_PPC64),
Version: 1,
Entry: start,
Phoff: uint64(off1),
Shoff: uint64(off2),
Flags: 0x05000002,
Ehsize: uint16(off1),
Phentsize: uint16(off2 - off1),
Phnum: 1,
Shentsize: uint16(off3 - off2),
Shnum: 3,
Shstrndx: 2,
}
binary.Write(&buf, binary.BigEndian, &hdr)
prog = elf.Prog64{
Type: 1,
Off: start,
Vaddr: start,
Paddr: start,
Filesz: uint64(size),
Memsz: uint64(size),
Flags: 5,
Align: start,
}
binary.Write(&buf, binary.BigEndian, &prog)
binary.Write(&buf, binary.BigEndian, &sect) // NULL section
sect = elf.Section64{
Name: 1,
Type: uint32(elf.SHT_PROGBITS),
Addr: start,
Off: start,
Size: uint64(size),
Flags: uint64(elf.SHF_ALLOC | elf.SHF_EXECINSTR),
Addralign: 4,
}
binary.Write(&buf, binary.BigEndian, &sect) // .text
sect = elf.Section64{
Name: uint32(len("\x00.text\x00")),
Type: uint32(elf.SHT_STRTAB),
Addr: 0,
Off: uint64(off2 + (off3-off2)*3),
Size: uint64(len("\x00.text\x00.shstrtab\x00")),
Addralign: 1,
}
binary.Write(&buf, binary.BigEndian, &sect)
buf.WriteString("\x00.text\x00.shstrtab\x00")
f.Write(buf.Bytes())
return nil
}
@@ -0,0 +1,379 @@
// 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 ppc64asm
import (
"fmt"
"strings"
)
// GoSyntax returns the Go assembler syntax for the instruction.
// The pc is the program counter of the first instruction, used for expanding
// PC-relative addresses into absolute ones.
// The symname function queries the symbol table for the program
// being disassembled. It returns the name and base address of the symbol
// containing the target, if any; otherwise it returns "", 0.
func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
if symname == nil {
symname = func(uint64) (string, uint64) { return "", 0 }
}
if inst.Op == 0 && inst.Enc == 0 {
return "WORD $0"
} else if inst.Op == 0 {
return "?"
}
var args []string
for i, a := range inst.Args[:] {
if a == nil {
break
}
if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
args = append(args, s)
}
}
var op string
op = plan9OpMap[inst.Op]
if op == "" {
op = strings.ToUpper(inst.Op.String())
if op[len(op)-1] == '.' {
op = op[:len(op)-1] + "CC"
}
}
// laid out the instruction
switch inst.Op {
default: // dst, sA, sB, ...
switch len(args) {
case 0:
return op
case 1:
return fmt.Sprintf("%s %s", op, args[0])
case 2:
if inst.Op == COPY || inst.Op == PASTECC {
return op + " " + args[0] + "," + args[1]
}
return op + " " + args[1] + "," + args[0]
case 3:
if reverseOperandOrder(inst.Op) {
return op + " " + args[2] + "," + args[1] + "," + args[0]
}
case 4:
if reverseMiddleOps(inst.Op) {
return op + " " + args[1] + "," + args[3] + "," + args[2] + "," + args[0]
}
}
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"
}
return "HWSYNC"
case ISEL:
return "ISEL " + args[3] + "," + args[1] + "," + args[2] + "," + args[0]
// store instructions always have the memory operand at the end, no need to reorder
// indexed stores handled separately
case STB, STBU,
STH, STHU,
STW, STWU,
STD, STDU,
STFD, STFDU,
STFS, STFSU,
STQ, HASHST, HASHSTP:
return op + " " + strings.Join(args, ",")
case FCMPU, FCMPO, CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
crf := int(inst.Args[0].(CondReg) - CR0)
cmpstr := op + " " + args[1] + "," + args[2]
if crf != 0 { // print CRx as the final operand if not implied (i.e BF != 0)
cmpstr += "," + args[0]
}
return cmpstr
case LIS:
return "ADDIS $0," + args[1] + "," + args[0]
// store instructions with index registers
case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
STHBRX, STWBRX, STDBRX, STSWX, STFIWX:
return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STXVX, STXVD2X, STXVW4X, STXVH8X, STXVB16X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STXV:
return op + " " + args[0] + "," + args[1]
case STXVL, STXVLL:
return op + " " + args[0] + "," + args[1] + "," + args[2]
case LWAX, LWAUX, LWZX, LHZX, LBZX, LDX, LHAX, LHAUX, LDARX, LWARX, LHARX, LBARX, LFDX, LFDUX, LFSX, LFSUX, LDBRX, LWBRX, LHBRX, LDUX, LWZUX, LHZUX, LBZUX:
if args[1] == "0" {
return op + " (" + args[2] + ")," + args[0]
}
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
case LXVX, LXVD2X, LXVW4X, LXVH8X, LXVB16X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
case LXV:
return op + " " + args[1] + "," + args[0]
case LXVL, LXVLL:
return op + " " + args[1] + "," + args[2] + "," + args[0]
case DCBT, DCBTST, DCBZ, DCBST, ICBI:
if args[0] == "0" || args[0] == "R0" {
return op + " (" + args[1] + ")"
}
return op + " (" + args[1] + ")(" + args[0] + ")"
// branch instructions needs additional handling
case BCLR:
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
return "RET"
}
return op + " " + strings.Join(args, ", ")
case BC:
bo := int(inst.Args[0].(Imm))
bi := int(inst.Args[1].(CondReg) - Cond0LT)
bcname := condName[((bo&0x8)>>1)|(bi&0x3)]
if bo&0x17 == 4 { // jump only a CR bit set/unset, no hints (at bits) set.
if bi >= 4 {
return fmt.Sprintf("B%s CR%d,%s", bcname, bi>>2, args[2])
} else {
return fmt.Sprintf("B%s %s", bcname, args[2])
}
}
return op + " " + strings.Join(args, ",")
case BCCTR:
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
return "BR (CTR)"
}
return op + " " + strings.Join(args, ", ")
case BCCTRL:
if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
return "BL (CTR)"
}
return op + " " + strings.Join(args, ",")
case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
return op + " " + strings.Join(args, ",")
}
}
// plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
//
// NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
// of inst, it's ok to modify inst.Args here.
func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
// special cases for load/store instructions
if _, ok := arg.(Offset); ok {
if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
panic(fmt.Errorf("wrong table: offset not followed by register"))
}
}
switch arg := arg.(type) {
case Reg:
if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
return "0"
}
if arg == R30 {
return "g"
}
return strings.ToUpper(arg.String())
case CondReg:
// This op is left as its numerical value, not mapped onto CR + condition
if inst.Op == ISEL {
return fmt.Sprintf("$%d", (arg - Cond0LT))
}
bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
if arg <= Cond0SO {
return bit
} else if arg > Cond0SO && arg <= Cond7SO {
return fmt.Sprintf("CR%d%s", int(arg-Cond0LT)/4, bit)
} else {
return fmt.Sprintf("CR%d", int(arg-CR0))
}
case Imm:
return fmt.Sprintf("$%d", arg)
case SpReg:
switch arg {
case 8:
return "LR"
case 9:
return "CTR"
}
return fmt.Sprintf("SPR(%d)", int(arg))
case PCRel:
addr := pc + uint64(int64(arg))
s, base := symname(addr)
if s != "" && addr == base {
return fmt.Sprintf("%s(SB)", s)
}
if inst.Op == BL && s != "" && (addr-base) == 8 {
// When decoding an object built for PIE, a CALL targeting
// a global entry point will be adjusted to the local entry
// if any. For now, assume any symname+8 PC is a local call.
return fmt.Sprintf("%s+%d(SB)", s, addr-base)
}
return fmt.Sprintf("%#x", addr)
case Label:
return fmt.Sprintf("%#x", int(arg))
case Offset:
reg := inst.Args[argIndex+1].(Reg)
removeArg(inst, argIndex+1)
if reg == R0 {
return fmt.Sprintf("%d(0)", int(arg))
}
return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
}
return fmt.Sprintf("???(%v)", arg)
}
func reverseMiddleOps(op Op) bool {
switch op {
case FMADD, FMADDCC, FMADDS, FMADDSCC, FMSUB, FMSUBCC, FMSUBS, FMSUBSCC, FNMADD, FNMADDCC, FNMADDS, FNMADDSCC, FNMSUB, FNMSUBCC, FNMSUBS, FNMSUBSCC, FSEL, FSELCC:
return true
}
return false
}
func reverseOperandOrder(op Op) bool {
switch op {
// Special case for SUBF, SUBFC: not reversed
case ADD, ADDC, ADDE, ADDCC, ADDCCC:
return true
case MULLW, MULLWCC, MULHW, MULHWCC, MULLD, MULLDCC, MULHD, MULHDCC, MULLWO, MULLWOCC, MULHWU, MULHWUCC, MULLDO, MULLDOCC:
return true
case DIVD, DIVDCC, DIVDU, DIVDUCC, DIVDE, DIVDECC, DIVDEU, DIVDEUCC, DIVDO, DIVDOCC, DIVDUO, DIVDUOCC:
return true
case MODUD, MODSD, MODUW, MODSW:
return true
case FADD, FADDS, FSUB, FSUBS, FMUL, FMULS, FDIV, FDIVS, FMADD, FMADDS, FMSUB, FMSUBS, FNMADD, FNMADDS, FNMSUB, FNMSUBS, FMULSCC:
return true
case FADDCC, FADDSCC, FSUBCC, FMULCC, FDIVCC, FDIVSCC:
return true
case OR, ORCC, ORC, ORCCC, AND, ANDCC, ANDC, ANDCCC, XOR, XORCC, NAND, NANDCC, EQV, EQVCC, NOR, NORCC:
return true
case SLW, SLWCC, SLD, SLDCC, SRW, SRAW, SRWCC, SRAWCC, SRD, SRDCC, SRAD, SRADCC:
return true
}
return false
}
// revCondMap maps a conditional register bit to its inverse, if possible.
var revCondMap = map[string]string{
"LT": "GE", "GT": "LE", "EQ": "NE",
}
// Lookup table to map BI[0:1] and BO[3] to an extended mnemonic for CR ops.
// Bits 0-1 map to a bit with a CR field, and bit 2 selects the inverted (0)
// or regular (1) extended mnemonic.
var condName = []string{
"GE",
"LE",
"NE",
"NSO",
"LT",
"GT",
"EQ",
"SO",
}
// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
var plan9OpMap = map[Op]string{
LWARX: "LWAR",
LDARX: "LDAR",
LHARX: "LHAR",
LBARX: "LBAR",
LWAX: "MOVW",
LHAX: "MOVH",
LWAUX: "MOVWU",
LHAU: "MOVHU",
LHAUX: "MOVHU",
LDX: "MOVD",
LDUX: "MOVDU",
LWZX: "MOVWZ",
LWZUX: "MOVWZU",
LHZX: "MOVHZ",
LHZUX: "MOVHZU",
LBZX: "MOVBZ",
LBZUX: "MOVBZU",
LDBRX: "MOVDBR",
LWBRX: "MOVWBR",
LHBRX: "MOVHBR",
MCRF: "MOVFL",
XORI: "XOR",
ORI: "OR",
ANDICC: "ANDCC",
ANDC: "ANDN",
ANDCCC: "ANDNCC",
ADDEO: "ADDEV",
ADDEOCC: "ADDEVCC",
ADDO: "ADDV",
ADDOCC: "ADDVCC",
ADDMEO: "ADDMEV",
ADDMEOCC: "ADDMEVCC",
ADDCO: "ADDCV",
ADDCOCC: "ADDCVCC",
ADDZEO: "ADDZEV",
ADDZEOCC: "ADDZEVCC",
SUBFME: "SUBME",
SUBFMECC: "SUBMECC",
SUBFZE: "SUBZE",
SUBFZECC: "SUBZECC",
SUBFZEO: "SUBZEV",
SUBFZEOCC: "SUBZEVCC",
SUBF: "SUB",
SUBFC: "SUBC",
SUBFCC: "SUBCC",
SUBFCCC: "SUBCCC",
ORC: "ORN",
ORCCC: "ORNCC",
MULLWO: "MULLWV",
MULLWOCC: "MULLWVCC",
MULLDO: "MULLDV",
MULLDOCC: "MULLDVCC",
DIVDO: "DIVDV",
DIVDOCC: "DIVDVCC",
DIVDUO: "DIVDUV",
DIVDUOCC: "DIVDUVCC",
ADDI: "ADD",
MULLI: "MULLD",
SRADI: "SRAD",
STBCXCC: "STBCCC",
STWCXCC: "STWCCC",
STDCXCC: "STDCCC",
LI: "MOVD",
LBZ: "MOVBZ", STB: "MOVB",
LBZU: "MOVBZU", STBU: "MOVBU",
LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
LHZU: "MOVHZU", STHU: "MOVHU",
LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
LWZU: "MOVWZU", STWU: "MOVWU",
LD: "MOVD", STD: "MOVD",
LDU: "MOVDU", STDU: "MOVDU",
LFD: "FMOVD", STFD: "FMOVD",
LFS: "FMOVS", STFS: "FMOVS",
LFDX: "FMOVD", STFDX: "FMOVD",
LFDU: "FMOVDU", STFDU: "FMOVDU",
LFDUX: "FMOVDU", STFDUX: "FMOVDU",
LFSX: "FMOVS", STFSX: "FMOVS",
LFSU: "FMOVSU", STFSU: "FMOVSU",
LFSUX: "FMOVSU", STFSUX: "FMOVSU",
CMPD: "CMP", CMPDI: "CMP",
CMPW: "CMPW", CMPWI: "CMPW",
CMPLD: "CMPU", CMPLDI: "CMPU",
CMPLW: "CMPWU", CMPLWI: "CMPWU",
MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
B: "BR",
BL: "CALL",
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,885 @@
6d746162| gnu xoris r20,r11,24930
6d746162| plan9 XORIS R11,$24930,R20
4c040000| gnu mcrf cr0,cr1
88a70002| gnu lbz r5,2(r7)
88a70002| plan9 MOVBZ 2(R7),R5
00000000| plan9 WORD $0
00010000| plan9 error: unknown instruction
00000000| gnu .long 0x0
00002000| gnu error: unknown instruction
a1841e80| gnu lhz r12,7808(r4)
a1841e80| plan9 MOVHZ 7808(R4),R12
42000004| gnu bdnz 0x30
e38d5b90| gnu lq r28,23440(r13)
84127a20| gnu lwzu r0,31264(r18)
84127a20| plan9 MOVWZU 31264(R18),R0
a8630000| gnu lha r3,0(r3)
a8630000| plan9 MOVH 0(R3),R3
ebb24fd1| gnu ldu r29,20432(r18)
ebb24fd1| plan9 MOVDU 20432(R18),R29
b1ce0612| gnu sth r14,1554(r14)
b1ce0612| plan9 MOVH R14,1554(R14)
945c62a2| gnu stwu r2,25250(r28)
f91b9c7a| gnu stq r8,-25480(r27)
2c030001| gnu cmpwi r3,1
2c030001| plan9 CMPW R3,$1
e8610032| gnu lwa r3,48(r1)
e8610032| plan9 MOVW 48(R1),R3
4320336b| gnu bdnzla+ 0x3368
7e40092e| gnu stwx r18,0,r1
7e40092e| plan9 MOVW R18,(R1)(0)
7c103c2c| gnu lwbrx r0,r16,r7
7c103c2c| plan9 MOVWBR (R7)(R16),R0
7c441d28| gnu stdbrx r2,r4,r3
7c441d28| plan9 MOVDBR R2,(R3)(R4)
3d220001| gnu addis r9,r2,1
3d220001| plan9 ADDIS R2,$1,R9
7ce628ae| gnu lbzx r7,r6,r5
7ce628ae| plan9 MOVBZ (R5)(R6),R7
7c0e1e99| gnu lxvd2x vs32,r14,r3
7c0e1e99| plan9 LXVD2X (R3)(R14),VS32
7c00422c| gnu dcbt r0,r8,0
7c00422c| plan9 DCBT (R8)
7fab3040| gnu cmpld cr7,r11,r6
7fab3040| plan9 CMPU R11,R6,CR7
2c030001| gnu cmpwi r3,1
2c030001| plan9 CMPW R3,$1
7c2b4840| gnu cmpld r11,r9
7c2b4840| plan9 CMPU R11,R9
7c6521ad| gnu stdcx. r3,r5,r4
7c6521ad| plan9 STDCCC R3,(R4)(R5)
fbe1ffd1| gnu stdu r31,-48(r1)
fbe1ffd1| plan9 MOVDU R31,-48(R1)
7c941f19| gnu stxvw4x vs36,r20,r3
7c941f19| plan9 STXVW4X VS36,(R3)(R20)
7c941f59| gnu stxvh8x vs36,r20,r3
7c941f59| plan9 STXVH8X VS36,(R3)(R20)
7c941fd9| gnu stxvb16x vs36,r20,r3
7c941fd9| plan9 STXVB16X VS36,(R3)(R20)
7c6520a8| gnu ldarx r3,r5,r4
7c6520a8| plan9 LDAR (R4)(R5),R3
7c6803a6| plan9 MOVD R3,LR
7c6802a6| plan9 MOVD LR,R3
7c6803a6| gnu mtlr r3
7c6802a6| gnu mflr r3
7c6903a6| plan9 MOVD R3,CTR
7c6902a6| plan9 MOVD CTR,R3
7c6903a6| gnu mtctr r3
7c6902a6| gnu mfctr r3
7c6c42a6| gnu mftb r3
7c6c42a6| plan9 MOVD SPR(268),R3
7c8202a6| plan9 MOVD SPR(2),R4
7c8202a6| gnu mfspr r4,2
41820010| plan9 BEQ 0x130
41820010| gnu beq 0x134
4086000c| plan9 BNE CR1,0x134
4086000c| gnu bne cr1,0x138
41880008| plan9 BLT CR2,0x138
41880008| gnu blt cr2,0x13c
418d0004| plan9 BGT CR3,0x13c
418d0004| gnu bgt cr3,0x140
e8830008| plan9 MOVD 8(R3),R4
7ca4182a| plan9 MOVD (R3)(R4),R5
e8830006| plan9 MOVW 4(R3),R4
7ca41aaa| plan9 MOVW (R3)(R4),R5
80830004| plan9 MOVWZ 4(R3),R4
7ca4182e| plan9 MOVWZ (R3)(R4),R5
a8830004| plan9 MOVH 4(R3),R4
7ca41aae| plan9 MOVH (R3)(R4),R5
a0830002| plan9 MOVHZ 2(R3),R4
7ca41a2e| plan9 MOVHZ (R3)(R4),R5
7ca418ae| plan9 MOVBZ (R3)(R4),R5
7ca41c28| plan9 MOVDBR (R3)(R4),R5
7ca41c2c| plan9 MOVWBR (R3)(R4),R5
7ca41e2c| plan9 MOVHBR (R3)(R4),R5
e8830009| plan9 MOVDU 8(R3),R4
7ca4186a| plan9 MOVDU (R3)(R4),R5
7ca41aea| plan9 MOVWU (R3)(R4),R5
84830004| plan9 MOVWZU 4(R3),R4
7ca4186e| plan9 MOVWZU (R3)(R4),R5
ac830002| plan9 MOVHU 2(R3),R4
7ca41aee| plan9 MOVHU (R3)(R4),R5
a4830002| plan9 MOVHZU 2(R3),R4
7ca41a6e| plan9 MOVHZU (R3)(R4),R5
8c830001| plan9 MOVBZU 1(R3),R4
7ca418ee| plan9 MOVBZU (R3)(R4),R5
f8830008| plan9 MOVD R4,8(R3)
7ca4192a| plan9 MOVD R5,(R3)(R4)
90830004| plan9 MOVW R4,4(R3)
7ca4192e| plan9 MOVW R5,(R3)(R4)
b0830002| plan9 MOVH R4,2(R3)
7ca41b2e| plan9 MOVH R5,(R3)(R4)
98830001| plan9 MOVB R4,1(R3)
7ca419ae| plan9 MOVB R5,(R3)(R4)
7ca41d28| plan9 MOVDBR R5,(R3)(R4)
7ca41d2c| plan9 MOVWBR R5,(R3)(R4)
7ca41f2c| plan9 MOVHBR R5,(R3)(R4)
f8830009| plan9 MOVDU R4,8(R3)
7ca4196a| plan9 MOVDU R5,(R3)(R4)
94830004| plan9 MOVWU R4,4(R3)
7ca4196e| plan9 MOVWU R5,(R3)(R4)
b4830002| plan9 MOVHU R4,2(R3)
7ca41b6e| plan9 MOVHU R5,(R3)(R4)
9c830001| plan9 MOVBU R4,1(R3)
7ca419ee| plan9 MOVBU R5,(R3)(R4)
7c232040| plan9 CMPU R3,R4
7c032000| plan9 CMPW R3,R4
7c032040| plan9 CMPWU R3,R4
7ca41a14| plan9 ADD R3,R4,R5
7ca41a15| plan9 ADDCC R3,R4,R5
7ca41814| plan9 ADDC R3,R4,R5
7ca41815| plan9 ADDCCC R3,R4,R5
7c851838| plan9 AND R3,R4,R5
7c851839| plan9 ANDCC R3,R4,R5
7c851878| plan9 ANDN R3,R4,R5
7c851879| plan9 ANDNCC R3,R4,R5
7c851b78| plan9 OR R3,R4,R5
7c851b79| plan9 ORCC R3,R4,R5
7c851b38| plan9 ORN R3,R4,R5
7c851b39| plan9 ORNCC R3,R4,R5
7c851a78| plan9 XOR R3,R4,R5
7c851a79| plan9 XORCC R3,R4,R5
7c851bb8| plan9 NAND R3,R4,R5
7c851bb9| plan9 NANDCC R3,R4,R5
7c851a38| plan9 EQV R3,R4,R5
7c851a39| plan9 EQVCC R3,R4,R5
7c8300d0| plan9 NEG R3,R4
7c8300d1| plan9 NEGCC R3,R4
7c8518f8| plan9 NOR R3,R4,R5
7c8518f9| plan9 NORCC R3,R4,R5
7ca32050| plan9 SUB R3,R4,R5
7ca32051| plan9 SUBCC R3,R4,R5
7ca32010| plan9 SUBC R3,R4,R5
7ca32011| plan9 SUBCCC R3,R4,R5
7ca419d6| plan9 MULLW R3,R4,R5
7ca419d7| plan9 MULLWCC R3,R4,R5
7ca41896| plan9 MULHW R3,R4,R5
7ca41816| plan9 MULHWU R3,R4,R5
7ca421d2| plan9 MULLD R4,R4,R5
1c63000a| plan9 MULLD R3,$10,R3
7ca419d3| plan9 MULLDCC R3,R4,R5
7ca41892| plan9 MULHD R3,R4,R5
7ca41893| plan9 MULHDCC R3,R4,R5
7ca41dd6| plan9 MULLWV R3,R4,R5
7ca41dd7| plan9 MULLWVCC R3,R4,R5
7ca41817| plan9 MULHWUCC R3,R4,R5
7ca41dd2| plan9 MULLDV R3,R4,R5
7ca41dd3| plan9 MULLDVCC R3,R4,R5
7ca41bd2| plan9 DIVD R3,R4,R5
7ca41bd3| plan9 DIVDCC R3,R4,R5
7ca41b92| plan9 DIVDU R3,R4,R5
7ca41fd2| plan9 DIVDV R3,R4,R5
7ca41b93| plan9 DIVDUCC R3,R4,R5
7ca41fd3| plan9 DIVDVCC R3,R4,R5
7ca41f92| plan9 DIVDUV R3,R4,R5
7ca41f93| plan9 DIVDUVCC R3,R4,R5
7ca41b52| plan9 DIVDE R3,R4,R5
7ca41b53| plan9 DIVDECC R3,R4,R5
7ca41b12| plan9 DIVDEU R3,R4,R5
7ca41b13| plan9 DIVDEUCC R3,R4,R5
7ca41a12| plan9 MODUD R3,R4,R5
7ca41a16| plan9 MODUW R3,R4,R5
7ca41e12| plan9 MODSD R3,R4,R5
7ca41e16| plan9 MODSW R3,R4,R5
7c851830| plan9 SLW R3,R4,R5
7c851836| plan9 SLD R3,R4,R5
7c851c30| plan9 SRW R3,R4,R5
7c851e30| plan9 SRAW R3,R4,R5
7c851c36| plan9 SRD R3,R4,R5
7c851e34| plan9 SRAD R3,R4,R5
7c631ef4| plan9 EXTSWSLI R3,$3,R3
7c6400f4| plan9 POPCNTB R3,R4
7c6402f4| plan9 POPCNTW R3,R4
7c6403f4| plan9 POPCNTD R3,R4
7c23270d| plan9 PASTECC R3,R4,$1
7c23260c| plan9 COPY R3,R4
7ca01868| plan9 LBAR (R3),R5
7ca018e8| plan9 LHAR (R3),R5
7ca01828| plan9 LWAR (R3),R5
7ca018a8| plan9 LDAR (R3),R5
7c65256d| plan9 STBCCC R3,(R4)(R5)
7c65212d| plan9 STWCCC R3,(R4)(R5)
7c6521ad| plan9 STDCCC R3,(R4)(R5)
7c0004ac| plan9 HWSYNC
4c00012c| plan9 ISYNC
7c2004ac| plan9 LWSYNC
7c04186c| plan9 DCBST (R3)(R4)
7c041fec| plan9 DCBZ (R3)(R4)
7c041a2c| plan9 DCBT (R3)(R4)
7c041fac| plan9 ICBI (R3)(R4)
c8230008| plan9 FMOVD 8(R3),F1
7c241cae| plan9 FMOVD (R3)(R4),F1
cc230008| plan9 FMOVDU 8(R3),F1
7c241cee| plan9 FMOVDU (R3)(R4),F1
c0230004| plan9 FMOVS 4(R3),F1
7c241c2e| plan9 FMOVS (R3)(R4),F1
c4230004| plan9 FMOVSU 4(R3),F1
7c241c6e| plan9 FMOVSU (R3)(R4),F1
d8230008| plan9 FMOVD F1,8(R3)
7c241dae| plan9 FMOVD F1,(R3)(R4)
dc230008| plan9 FMOVDU F1,8(R3)
7c241dee| plan9 FMOVDU F1,(R3)(R4)
d0230004| plan9 FMOVS F1,4(R3)
7c241d2e| plan9 FMOVS F1,(R3)(R4)
d4230004| plan9 FMOVSU F1,4(R3)
7c241d6e| plan9 FMOVSU F1,(R3)(R4)
fc62082a| plan9 FADD F1,F2,F3
fc62082b| plan9 FADDCC F1,F2,F3
ec62082a| plan9 FADDS F1,F2,F3
ec62082b| plan9 FADDSCC F1,F2,F3
fc620828| plan9 FSUB F1,F2,F3
fc620829| plan9 FSUBCC F1,F2,F3
ec620828| plan9 FSUBS F1,F2,F3
fc620829| plan9 FSUBCC F1,F2,F3
fc620072| plan9 FMUL F1,F2,F3
fc620073| plan9 FMULCC F1,F2,F3
ec620072| plan9 FMULS F1,F2,F3
ec620073| plan9 FMULSCC F1,F2,F3
fc620824| plan9 FDIV F1,F2,F3
fc620825| plan9 FDIVCC F1,F2,F3
ec620824| plan9 FDIVS F1,F2,F3
ec620825| plan9 FDIVSCC F1,F2,F3
fc8110fa| plan9 FMADD F1,F2,F3,F4
fc8110fb| plan9 FMADDCC F1,F2,F3,F4
ec8110fa| plan9 FMADDS F1,F2,F3,F4
ec8110fb| plan9 FMADDSCC F1,F2,F3,F4
fc8110f8| plan9 FMSUB F1,F2,F3,F4
fc8110f9| plan9 FMSUBCC F1,F2,F3,F4
ec8110f8| plan9 FMSUBS F1,F2,F3,F4
ec8110f9| plan9 FMSUBSCC F1,F2,F3,F4
fc8110fe| plan9 FNMADD F1,F2,F3,F4
fc8110ff| plan9 FNMADDCC F1,F2,F3,F4
ec8110fe| plan9 FNMADDS F1,F2,F3,F4
ec8110ff| plan9 FNMADDSCC F1,F2,F3,F4
fc8110fc| plan9 FNMSUB F1,F2,F3,F4
fc8110fd| plan9 FNMSUBCC F1,F2,F3,F4
ec8110fc| plan9 FNMSUBS F1,F2,F3,F4
ec8110fd| plan9 FNMSUBSCC F1,F2,F3,F4
fc8110ee| plan9 FSEL F1,F2,F3,F4
fc8110ef| plan9 FSELCC F1,F2,F3,F4
fc400a10| plan9 FABS F1,F2
fc400a11| plan9 FABSCC F1,F2
fc400850| plan9 FNEG F1,F2
fc400a11| plan9 FABSCC F1,F2
fc400818| plan9 FRSP F1,F2
fc400819| plan9 FRSPCC F1,F2
fc40081c| plan9 FCTIW F1,F2
fc40081d| plan9 FCTIWCC F1,F2
fc40081e| plan9 FCTIWZ F1,F2
fc40081f| plan9 FCTIWZCC F1,F2
fc400e5c| plan9 FCTID F1,F2
fc400e5d| plan9 FCTIDCC F1,F2
fc400e5e| plan9 FCTIDZ F1,F2
fc400e5f| plan9 FCTIDZCC F1,F2
fc400e9c| plan9 FCFID F1,F2
fc400e9d| plan9 FCFIDCC F1,F2
fc400f9c| plan9 FCFIDU F1,F2
fc400f9d| plan9 FCFIDUCC F1,F2
ec400e9c| plan9 FCFIDS F1,F2
ec400e9d| plan9 FCFIDSCC F1,F2
ec400830| plan9 FRES F1,F2
ec400831| plan9 FRESCC F1,F2
fc400bd0| plan9 FRIM F1,F2
fc400bd1| plan9 FRIMCC F1,F2
fc400b90| plan9 FRIP F1,F2
fc400b91| plan9 FRIPCC F1,F2
fc400b50| plan9 FRIZ F1,F2
fc400b51| plan9 FRIZCC F1,F2
fc400b10| plan9 FRIN F1,F2
fc400b11| plan9 FRINCC F1,F2
fc400834| plan9 FRSQRTE F1,F2
fc400835| plan9 FRSQRTECC F1,F2
fc40082c| plan9 FSQRT F1,F2
fc40082d| plan9 FSQRTCC F1,F2
ec40082c| plan9 FSQRTS F1,F2
ec40082d| plan9 FSQRTSCC F1,F2
fc011040| plan9 FCMPO F1,F2
fc011000| plan9 FCMPU F1,F2
7c2418ce| plan9 LVX (R3)(R4),V1
7c241ace| plan9 LVXL (R3)(R4),V1
7c24180c| plan9 LVSL (R3)(R4),V1
7c24184c| plan9 LVSR (R3)(R4),V1
7c24180e| plan9 LVEBX (R3)(R4),V1
7c24184e| plan9 LVEHX (R3)(R4),V1
7c24188e| plan9 LVEWX (R3)(R4),V1
7c2419ce| plan9 STVX V1,(R3)(R4)
7c241bce| plan9 STVXL V1,(R3)(R4)
7c24190e| plan9 STVEBX V1,(R3)(R4)
7c24194e| plan9 STVEHX V1,(R3)(R4)
7c24198e| plan9 STVEWX V1,(R3)(R4)
10611404| plan9 VAND V1,V2,V3
10611444| plan9 VANDC V1,V2,V3
10611584| plan9 VNAND V1,V2,V3
10611484| plan9 VOR V1,V2,V3
10611544| plan9 VORC V1,V2,V3
106114c4| plan9 VXOR V1,V2,V3
10611504| plan9 VNOR V1,V2,V3
10611684| plan9 VEQV V1,V2,V3
10611000| plan9 VADDUBM V1,V2,V3
10611040| plan9 VADDUHM V1,V2,V3
10611080| plan9 VADDUWM V1,V2,V3
106110c0| plan9 VADDUDM V1,V2,V3
10611100| plan9 VADDUQM V1,V2,V3
10611140| plan9 VADDCUQ V1,V2,V3
10611180| plan9 VADDCUW V1,V2,V3
10611200| plan9 VADDUBS V1,V2,V3
10611240| plan9 VADDUHS V1,V2,V3
10611280| plan9 VADDUWS V1,V2,V3
10611400| plan9 VSUBUBM V1,V2,V3
10611440| plan9 VSUBUHM V1,V2,V3
10611480| plan9 VSUBUWM V1,V2,V3
106114c0| plan9 VSUBUDM V1,V2,V3
10611500| plan9 VSUBUQM V1,V2,V3
10611540| plan9 VSUBCUQ V1,V2,V3
10611580| plan9 VSUBCUW V1,V2,V3
10611600| plan9 VSUBUBS V1,V2,V3
10611640| plan9 VSUBUHS V1,V2,V3
10611680| plan9 VSUBUWS V1,V2,V3
10611700| plan9 VSUBSBS V1,V2,V3
10611740| plan9 VSUBSHS V1,V2,V3
10611780| plan9 VSUBSWS V1,V2,V3
108110fe| plan9 VSUBEUQM V1,V2,V3,V4
108110ff| plan9 VSUBECUQ V1,V2,V3,V4
10611308| plan9 VMULESB V1,V2,V3
10611108| plan9 VMULOSB V1,V2,V3
10611208| plan9 VMULEUB V1,V2,V3
10611008| plan9 VMULOUB V1,V2,V3
10611348| plan9 VMULESH V1,V2,V3
10611148| plan9 VMULOSH V1,V2,V3
10611248| plan9 VMULEUH V1,V2,V3
10611048| plan9 VMULOUH V1,V2,V3
10611348| plan9 VMULESH V1,V2,V3
10611188| plan9 VMULOSW V1,V2,V3
10611288| plan9 VMULEUW V1,V2,V3
10611088| plan9 VMULOUW V1,V2,V3
10611089| plan9 VMULUWM V1,V2,V3
10611408| plan9 VPMSUMB V1,V2,V3
10611448| plan9 VPMSUMH V1,V2,V3
10611488| plan9 VPMSUMW V1,V2,V3
106114c8| plan9 VPMSUMD V1,V2,V3
108110e3| plan9 VMSUMUDM V1,V2,V3,V4
10611004| plan9 VRLB V1,V2,V3
10611044| plan9 VRLH V1,V2,V3
10611084| plan9 VRLW V1,V2,V3
106110c4| plan9 VRLD V1,V2,V3
10611104| plan9 VSLB V1,V2,V3
10611144| plan9 VSLH V1,V2,V3
10611184| plan9 VSLW V1,V2,V3
106111c4| plan9 VSL V1,V2,V3
1061140c| plan9 VSLO V1,V2,V3
10611204| plan9 VSRB V1,V2,V3
10611244| plan9 VSRH V1,V2,V3
10611284| plan9 VSRW V1,V2,V3
106112c4| plan9 VSR V1,V2,V3
1061144c| plan9 VSRO V1,V2,V3
106115c4| plan9 VSLD V1,V2,V3
10611304| plan9 VSRAB V1,V2,V3
10611344| plan9 VSRAH V1,V2,V3
10611384| plan9 VSRAW V1,V2,V3
106113c4| plan9 VSRAD V1,V2,V3
10400f02| plan9 VCLZB V1,V2
10400f42| plan9 VCLZH V1,V2
10400f82| plan9 VCLZW V1,V2
10400fc2| plan9 VCLZD V1,V2
10400f03| plan9 VPOPCNTB V1,V2
10400f43| plan9 VPOPCNTH V1,V2
10400f83| plan9 VPOPCNTW V1,V2
10400fc3| plan9 VPOPCNTD V1,V2
10611006| plan9 VCMPEQUB V1,V2,V3
10611406| plan9 VCMPEQUBCC V1,V2,V3
10611046| plan9 VCMPEQUH V1,V2,V3
10611446| plan9 VCMPEQUHCC V1,V2,V3
10611086| plan9 VCMPEQUW V1,V2,V3
10611486| plan9 VCMPEQUWCC V1,V2,V3
106110c7| plan9 VCMPEQUD V1,V2,V3
106114c7| plan9 VCMPEQUDCC V1,V2,V3
10611206| plan9 VCMPGTUB V1,V2,V3
10611606| plan9 VCMPGTUBCC V1,V2,V3
10611246| plan9 VCMPGTUH V1,V2,V3
10611646| plan9 VCMPGTUHCC V1,V2,V3
10611286| plan9 VCMPGTUW V1,V2,V3
10611686| plan9 VCMPGTUWCC V1,V2,V3
106112c7| plan9 VCMPGTUD V1,V2,V3
106116c7| plan9 VCMPGTUDCC V1,V2,V3
10611306| plan9 VCMPGTSB V1,V2,V3
10611706| plan9 VCMPGTSBCC V1,V2,V3
10611346| plan9 VCMPGTSH V1,V2,V3
10611746| plan9 VCMPGTSHCC V1,V2,V3
10611386| plan9 VCMPGTSW V1,V2,V3
10611786| plan9 VCMPGTSWCC V1,V2,V3
106113c7| plan9 VCMPGTSD V1,V2,V3
106117c7| plan9 VCMPGTSDCC V1,V2,V3
10611107| plan9 VCMPNEZB V1,V2,V3
10611507| plan9 VCMPNEZBCC V1,V2,V3
10611007| plan9 VCMPNEB V1,V2,V3
10611407| plan9 VCMPNEBCC V1,V2,V3
10611047| plan9 VCMPNEH V1,V2,V3
10611447| plan9 VCMPNEHCC V1,V2,V3
10611087| plan9 VCMPNEW V1,V2,V3
10611487| plan9 VCMPNEWCC V1,V2,V3
108110eb| plan9 VPERM V1,V2,V3,V4
108110fb| plan9 VPERMR V1,V2,V3,V4
108110ed| plan9 VPERMXOR V1,V2,V3,V4
1061154c| plan9 VBPERMQ V1,V2,V3
106115cc| plan9 VBPERMD V1,V2,V3
108110ea| plan9 VSEL V1,V2,V3,V4
10611508| plan9 VCIPHER V1,V2,V3
10611509| plan9 VCIPHERLAST V1,V2,V3
10611548| plan9 VNCIPHER V1,V2,V3
10611549| plan9 VNCIPHERLAST V1,V2,V3
104105c8| plan9 VSBOX V1,V2
7c241e98| plan9 LXVD2X (R3)(R4),VS1
7c241e18| plan9 LXVW4X (R3)(R4),VS1
7c241e58| plan9 LXVH8X (R3)(R4),VS1
7c241ed8| plan9 LXVB16X (R3)(R4),VS1
f4230011| plan9 LXV 16(R3),VS1
7c23221a| plan9 LXVL R3,R4,VS1
7c23225a| plan9 LXVLL R3,R4,VS1
7c241a18| plan9 LXVX (R3)(R4),VS1
7c241c98| plan9 LXSDX (R3)(R4),VS1
7c241f98| plan9 STXVD2X VS1,(R3)(R4)
f4230015| plan9 STXV VS1,16(R3)
7c23231a| plan9 STXVL VS1,R3,R4
7c23235a| plan9 STXVLL VS1,R3,R4
7c241b18| plan9 STXVX VS1,(R3)(R4)
7c241d98| plan9 STXSDX VS1,(R3)(R4)
7c241898| plan9 LXSIWAX (R3)(R4),VS1
7c241918| plan9 STXSIWX VS1,(R3)(R4)
7c230066| plan9 MFVSRD VS1,R3
7c230166| plan9 MTVSRD R3,VS1
f0611410| plan9 XXLAND VS1,VS2,VS3
f0611490| plan9 XXLOR VS1,VS2,VS3
f0611550| plan9 XXLORC VS1,VS2,VS3
f06114d0| plan9 XXLXOR VS1,VS2,VS3
f08110f0| plan9 XXSEL VS1,VS2,VS3,VS4
f0570f6c| plan9 XXBRD VS1,VS2
f04f0f6c| plan9 XXBRW VS1,VS2
f0470f6c| plan9 XXBRH VS1,VS2
f0611090| plan9 XXMRGHW VS1,VS2,VS3
f0410a90| plan9 XXSPLTW VS1,$1,VS2
f06110d0| plan9 XXPERM VS1,VS2,VS3
f0611110| plan9 XXSLDWI VS1,VS2,$1,VS3
f0400c24| plan9 XSCVDPSP VS1,VS2
f0400e24| plan9 XVCVDPSP VS1,VS2
f0400de0| plan9 XSCVSXDDP VS1,VS2
f0400f60| plan9 XVCVDPSXDS VS1,VS2
f0400fe0| plan9 XVCVSXDDP VS1,VS2
7c6803a6| plan9 MOVD R3,LR
7c6903a6| plan9 MOVD R3,CTR
7c6802a6| plan9 MOVD LR,R3
7c6902a6| plan9 MOVD CTR,R3
4c8c0000| plan9 MOVFL CR3,CR1
48100001| plan9 CALL foo(SB)
48100009| plan9 CALL foo+8(SB)
4810000d| plan9 CALL 0x10000c
7c6803a6| gnu mtlr r3
7c6802a6| gnu mflr r3
7c6903a6| gnu mtctr r3
7c6902a6| gnu mfctr r3
7c6c42a6| gnu mftb r3
7c8202a6| gnu mfspr r4,2
e8830008| gnu ld r4,8(r3)
7ca4182a| gnu ldx r5,r4,r3
e8830006| gnu lwa r4,4(r3)
7ca41aaa| gnu lwax r5,r4,r3
80830004| gnu lwz r4,4(r3)
7ca4182e| gnu lwzx r5,r4,r3
a8830004| gnu lha r4,4(r3)
7ca41aae| gnu lhax r5,r4,r3
a0830002| gnu lhz r4,2(r3)
7ca41a2e| gnu lhzx r5,r4,r3
7ca418ae| gnu lbzx r5,r4,r3
7ca41c28| gnu ldbrx r5,r4,r3
7ca41c2c| gnu lwbrx r5,r4,r3
7ca41e2c| gnu lhbrx r5,r4,r3
e8830009| gnu ldu r4,8(r3)
7ca4186a| gnu ldux r5,r4,r3
7ca41aea| gnu lwaux r5,r4,r3
84830004| gnu lwzu r4,4(r3)
7ca4186e| gnu lwzux r5,r4,r3
ac830002| gnu lhau r4,2(r3)
7ca41aee| gnu lhaux r5,r4,r3
a4830002| gnu lhzu r4,2(r3)
7ca41a6e| gnu lhzux r5,r4,r3
8c830001| gnu lbzu r4,1(r3)
7ca418ee| gnu lbzux r5,r4,r3
f8830008| gnu std r4,8(r3)
7ca4192a| gnu stdx r5,r4,r3
90830004| gnu stw r4,4(r3)
7ca4192e| gnu stwx r5,r4,r3
b0830002| gnu sth r4,2(r3)
7ca41b2e| gnu sthx r5,r4,r3
98830001| gnu stb r4,1(r3)
7ca419ae| gnu stbx r5,r4,r3
7ca41d28| gnu stdbrx r5,r4,r3
7ca41d2c| gnu stwbrx r5,r4,r3
7ca41f2c| gnu sthbrx r5,r4,r3
f8830009| gnu stdu r4,8(r3)
7ca4196a| gnu stdux r5,r4,r3
94830004| gnu stwu r4,4(r3)
7ca4196e| gnu stwux r5,r4,r3
b4830002| gnu sthu r4,2(r3)
7ca41b6e| gnu sthux r5,r4,r3
9c830001| gnu stbu r4,1(r3)
7ca419ee| gnu stbux r5,r4,r3
7c232040| gnu cmpld r3,r4
7c032000| gnu cmpw r3,r4
7c032040| gnu cmplw r3,r4
7ca41a14| gnu add r5,r4,r3
7ca41814| gnu addc r5,r4,r3
7ca41815| gnu addc. r5,r4,r3
7c851838| gnu and r5,r4,r3
7c851878| gnu andc r5,r4,r3
7c851839| gnu and. r5,r4,r3
7c851b78| gnu or r5,r4,r3
7c851b38| gnu orc r5,r4,r3
7c851b79| gnu or. r5,r4,r3
7c851a78| gnu xor r5,r4,r3
7c851a79| gnu xor. r5,r4,r3
7c851bb8| gnu nand r5,r4,r3
7c851bb9| gnu nand. r5,r4,r3
7c851a38| gnu eqv r5,r4,r3
7c851a39| gnu eqv. r5,r4,r3
7c8518f8| gnu nor r5,r4,r3
7c8518f9| gnu nor. r5,r4,r3
7ca32050| gnu subf r5,r3,r4
7ca32010| gnu subfc r5,r3,r4
7ca419d6| gnu mullw r5,r4,r3
7ca419d7| gnu mullw. r5,r4,r3
7ca41896| gnu mulhw r5,r4,r3
7ca41816| gnu mulhwu r5,r4,r3
7ca421d2| gnu mulld r5,r4,r4
7ca419d3| gnu mulld. r5,r4,r3
7ca41892| gnu mulhd r5,r4,r3
7ca41893| gnu mulhd. r5,r4,r3
7ca41dd6| gnu mullwo r5,r4,r3
7ca41dd7| gnu mullwo. r5,r4,r3
7ca41817| gnu mulhwu. r5,r4,r3
7ca41dd2| gnu mulldo r5,r4,r3
7ca41dd3| gnu mulldo. r5,r4,r3
7ca41bd2| gnu divd r5,r4,r3
7ca41bd3| gnu divd. r5,r4,r3
7ca41b92| gnu divdu r5,r4,r3
7ca41fd2| gnu divdo r5,r4,r3
7ca41b93| gnu divdu. r5,r4,r3
7ca41fd3| gnu divdo. r5,r4,r3
7ca41f92| gnu divduo r5,r4,r3
7ca41f93| gnu divduo. r5,r4,r3
7ca41b52| gnu divde r5,r4,r3
7ca41b53| gnu divde. r5,r4,r3
7ca41b12| gnu divdeu r5,r4,r3
7ca41b13| gnu divdeu. r5,r4,r3
7ca41a12| gnu modud r5,r4,r3
7ca41a16| gnu moduw r5,r4,r3
7ca41e12| gnu modsd r5,r4,r3
7ca41e16| gnu modsw r5,r4,r3
7c851830| gnu slw r5,r4,r3
7c851836| gnu sld r5,r4,r3
7c851c30| gnu srw r5,r4,r3
7c851e30| gnu sraw r5,r4,r3
7c851c36| gnu srd r5,r4,r3
7c851e34| gnu srad r5,r4,r3
7c6400f4| gnu popcntb r4,r3
7c6402f4| gnu popcntw r4,r3
7c6403f4| gnu popcntd r4,r3
7c23270d| gnu paste. r3,r4
7c23260c| gnu copy r3,r4
7ca01868| gnu lbarx r5,0,r3
7ca018e8| gnu lharx r5,0,r3
7ca01828| gnu lwarx r5,0,r3
7ca018a8| gnu ldarx r5,0,r3
7c65256d| gnu stbcx. r3,r5,r4
7c65212d| gnu stwcx. r3,r5,r4
7c6521ad| gnu stdcx. r3,r5,r4
4c00012c| gnu isync
7c0004ac| gnu hwsync
7c2004ac| gnu lwsync
7c04186c| gnu dcbst r4,r3
7c041fec| gnu dcbz r4,r3
7c041a2c| gnu dcbt r4,r3,0
7c041fac| gnu icbi r4,r3
c8230008| gnu lfd f1,8(r3)
7c241cae| gnu lfdx f1,r4,r3
cc230008| gnu lfdu f1,8(r3)
7c241cee| gnu lfdux f1,r4,r3
c0230004| gnu lfs f1,4(r3)
7c241c2e| gnu lfsx f1,r4,r3
c4230004| gnu lfsu f1,4(r3)
7c241c6e| gnu lfsux f1,r4,r3
d8230008| gnu stfd f1,8(r3)
7c241dae| gnu stfdx f1,r4,r3
dc230008| gnu stfdu f1,8(r3)
7c241dee| gnu stfdux f1,r4,r3
d0230004| gnu stfs f1,4(r3)
7c241d2e| gnu stfsx f1,r4,r3
d4230004| gnu stfsu f1,4(r3)
7c241d6e| gnu stfsux f1,r4,r3
fc62082a| gnu fadd f3,f2,f1
fc62082b| gnu fadd. f3,f2,f1
ec62082a| gnu fadds f3,f2,f1
ec62082b| gnu fadds. f3,f2,f1
fc620828| gnu fsub f3,f2,f1
fc620829| gnu fsub. f3,f2,f1
ec620828| gnu fsubs f3,f2,f1
fc620829| gnu fsub. f3,f2,f1
fc620072| gnu fmul f3,f2,f1
fc620073| gnu fmul. f3,f2,f1
ec620072| gnu fmuls f3,f2,f1
ec620073| gnu fmuls. f3,f2,f1
fc620824| gnu fdiv f3,f2,f1
fc620825| gnu fdiv. f3,f2,f1
ec620824| gnu fdivs f3,f2,f1
ec620825| gnu fdivs. f3,f2,f1
fc8110fa| gnu fmadd f4,f1,f3,f2
fc8110fb| gnu fmadd. f4,f1,f3,f2
ec8110fa| gnu fmadds f4,f1,f3,f2
ec8110fb| gnu fmadds. f4,f1,f3,f2
fc8110f8| gnu fmsub f4,f1,f3,f2
fc8110f9| gnu fmsub. f4,f1,f3,f2
ec8110f8| gnu fmsubs f4,f1,f3,f2
ec8110f9| gnu fmsubs. f4,f1,f3,f2
fc8110fe| gnu fnmadd f4,f1,f3,f2
fc8110ff| gnu fnmadd. f4,f1,f3,f2
ec8110fe| gnu fnmadds f4,f1,f3,f2
ec8110ff| gnu fnmadds. f4,f1,f3,f2
fc8110fc| gnu fnmsub f4,f1,f3,f2
fc8110fd| gnu fnmsub. f4,f1,f3,f2
ec8110fc| gnu fnmsubs f4,f1,f3,f2
ec8110fd| gnu fnmsubs. f4,f1,f3,f2
fc8110ee| gnu fsel f4,f1,f3,f2
fc8110ef| gnu fsel. f4,f1,f3,f2
fc400a10| gnu fabs f2,f1
fc400a11| gnu fabs. f2,f1
fc400850| gnu fneg f2,f1
fc400a11| gnu fabs. f2,f1
fc400818| gnu frsp f2,f1
fc400819| gnu frsp. f2,f1
fc40081c| gnu fctiw f2,f1
fc40081d| gnu fctiw. f2,f1
fc40081e| gnu fctiwz f2,f1
fc40081f| gnu fctiwz. f2,f1
fc400e5c| gnu fctid f2,f1
fc400e5d| gnu fctid. f2,f1
fc400e5e| gnu fctidz f2,f1
fc400e5f| gnu fctidz. f2,f1
fc400e9c| gnu fcfid f2,f1
fc400e9d| gnu fcfid. f2,f1
fc400f9c| gnu fcfidu f2,f1
fc400f9d| gnu fcfidu. f2,f1
ec400e9c| gnu fcfids f2,f1
ec400e9d| gnu fcfids. f2,f1
ec400830| gnu fres f2,f1
ec400831| gnu fres. f2,f1
fc400bd0| gnu frim f2,f1
fc400bd1| gnu frim. f2,f1
fc400b90| gnu frip f2,f1
fc400b91| gnu frip. f2,f1
fc400b50| gnu friz f2,f1
fc400b51| gnu friz. f2,f1
fc400b10| gnu frin f2,f1
fc400b11| gnu frin. f2,f1
fc400834| gnu frsqrte f2,f1
fc400835| gnu frsqrte. f2,f1
fc40082c| gnu fsqrt f2,f1
fc40082d| gnu fsqrt. f2,f1
ec40082c| gnu fsqrts f2,f1
ec40082d| gnu fsqrts. f2,f1
fc011040| gnu fcmpo cr0,f1,f2
fc011000| gnu fcmpu cr0,f1,f2
7c2418ce| gnu lvx v1,r4,r3
7c241ace| gnu lvxl v1,r4,r3
7c24180c| gnu lvsl v1,r4,r3
7c24184c| gnu lvsr v1,r4,r3
7c24180e| gnu lvebx v1,r4,r3
7c24184e| gnu lvehx v1,r4,r3
7c24188e| gnu lvewx v1,r4,r3
7c2419ce| gnu stvx v1,r4,r3
7c241bce| gnu stvxl v1,r4,r3
7c24190e| gnu stvebx v1,r4,r3
7c24194e| gnu stvehx v1,r4,r3
7c24198e| gnu stvewx v1,r4,r3
10611404| gnu vand v3,v1,v2
10611444| gnu vandc v3,v1,v2
10611584| gnu vnand v3,v1,v2
10611484| gnu vor v3,v1,v2
10611544| gnu vorc v3,v1,v2
106114c4| gnu vxor v3,v1,v2
10611504| gnu vnor v3,v1,v2
10611684| gnu veqv v3,v1,v2
10611000| gnu vaddubm v3,v1,v2
10611040| gnu vadduhm v3,v1,v2
10611080| gnu vadduwm v3,v1,v2
106110c0| gnu vaddudm v3,v1,v2
10611100| gnu vadduqm v3,v1,v2
10611140| gnu vaddcuq v3,v1,v2
10611180| gnu vaddcuw v3,v1,v2
10611200| gnu vaddubs v3,v1,v2
10611240| gnu vadduhs v3,v1,v2
10611280| gnu vadduws v3,v1,v2
10611400| gnu vsububm v3,v1,v2
10611440| gnu vsubuhm v3,v1,v2
10611480| gnu vsubuwm v3,v1,v2
106114c0| gnu vsubudm v3,v1,v2
10611500| gnu vsubuqm v3,v1,v2
10611540| gnu vsubcuq v3,v1,v2
10611580| gnu vsubcuw v3,v1,v2
10611600| gnu vsububs v3,v1,v2
10611640| gnu vsubuhs v3,v1,v2
10611680| gnu vsubuws v3,v1,v2
10611700| gnu vsubsbs v3,v1,v2
10611740| gnu vsubshs v3,v1,v2
10611780| gnu vsubsws v3,v1,v2
108110fe| gnu vsubeuqm v4,v1,v2,v3
108110ff| gnu vsubecuq v4,v1,v2,v3
10611308| gnu vmulesb v3,v1,v2
10611108| gnu vmulosb v3,v1,v2
10611208| gnu vmuleub v3,v1,v2
10611008| gnu vmuloub v3,v1,v2
10611348| gnu vmulesh v3,v1,v2
10611148| gnu vmulosh v3,v1,v2
10611248| gnu vmuleuh v3,v1,v2
10611048| gnu vmulouh v3,v1,v2
10611348| gnu vmulesh v3,v1,v2
10611188| gnu vmulosw v3,v1,v2
10611288| gnu vmuleuw v3,v1,v2
10611088| gnu vmulouw v3,v1,v2
10611089| gnu vmuluwm v3,v1,v2
10611408| gnu vpmsumb v3,v1,v2
10611448| gnu vpmsumh v3,v1,v2
10611488| gnu vpmsumw v3,v1,v2
106114c8| gnu vpmsumd v3,v1,v2
108110e3| gnu vmsumudm v4,v1,v2,v3
10611004| gnu vrlb v3,v1,v2
10611044| gnu vrlh v3,v1,v2
10611084| gnu vrlw v3,v1,v2
106110c4| gnu vrld v3,v1,v2
10611104| gnu vslb v3,v1,v2
10611144| gnu vslh v3,v1,v2
10611184| gnu vslw v3,v1,v2
106111c4| gnu vsl v3,v1,v2
1061140c| gnu vslo v3,v1,v2
10611204| gnu vsrb v3,v1,v2
10611244| gnu vsrh v3,v1,v2
10611284| gnu vsrw v3,v1,v2
106112c4| gnu vsr v3,v1,v2
1061144c| gnu vsro v3,v1,v2
106115c4| gnu vsld v3,v1,v2
10611304| gnu vsrab v3,v1,v2
10611344| gnu vsrah v3,v1,v2
10611384| gnu vsraw v3,v1,v2
106113c4| gnu vsrad v3,v1,v2
10400f02| gnu vclzb v2,v1
10400f42| gnu vclzh v2,v1
10400f82| gnu vclzw v2,v1
10400fc2| gnu vclzd v2,v1
10400f03| gnu vpopcntb v2,v1
10400f43| gnu vpopcnth v2,v1
10400f83| gnu vpopcntw v2,v1
10400fc3| gnu vpopcntd v2,v1
10611006| gnu vcmpequb v3,v1,v2
10611406| gnu vcmpequb. v3,v1,v2
10611046| gnu vcmpequh v3,v1,v2
10611446| gnu vcmpequh. v3,v1,v2
10611086| gnu vcmpequw v3,v1,v2
10611486| gnu vcmpequw. v3,v1,v2
106110c7| gnu vcmpequd v3,v1,v2
106114c7| gnu vcmpequd. v3,v1,v2
10611206| gnu vcmpgtub v3,v1,v2
10611606| gnu vcmpgtub. v3,v1,v2
10611246| gnu vcmpgtuh v3,v1,v2
10611646| gnu vcmpgtuh. v3,v1,v2
10611286| gnu vcmpgtuw v3,v1,v2
10611686| gnu vcmpgtuw. v3,v1,v2
106112c7| gnu vcmpgtud v3,v1,v2
106116c7| gnu vcmpgtud. v3,v1,v2
10611306| gnu vcmpgtsb v3,v1,v2
10611706| gnu vcmpgtsb. v3,v1,v2
10611346| gnu vcmpgtsh v3,v1,v2
10611746| gnu vcmpgtsh. v3,v1,v2
10611386| gnu vcmpgtsw v3,v1,v2
10611786| gnu vcmpgtsw. v3,v1,v2
106113c7| gnu vcmpgtsd v3,v1,v2
106117c7| gnu vcmpgtsd. v3,v1,v2
10611107| gnu vcmpnezb v3,v1,v2
10611507| gnu vcmpnezb. v3,v1,v2
10611007| gnu vcmpneb v3,v1,v2
10611407| gnu vcmpneb. v3,v1,v2
10611047| gnu vcmpneh v3,v1,v2
10611447| gnu vcmpneh. v3,v1,v2
10611087| gnu vcmpnew v3,v1,v2
10611487| gnu vcmpnew. v3,v1,v2
108110eb| gnu vperm v4,v1,v2,v3
108110fb| gnu vpermr v4,v1,v2,v3
108110ed| gnu vpermxor v4,v1,v2,v3
1061154c| gnu vbpermq v3,v1,v2
106115cc| gnu vbpermd v3,v1,v2
108110ea| gnu vsel v4,v1,v2,v3
10611508| gnu vcipher v3,v1,v2
10611509| gnu vcipherlast v3,v1,v2
10611548| gnu vncipher v3,v1,v2
10611549| gnu vncipherlast v3,v1,v2
104105c8| gnu vsbox v2,v1
7c241e98| gnu lxvd2x vs1,r4,r3
f4230011| gnu lxv vs1,16(r3)
7c23221a| gnu lxvl vs1,r3,r4
7c23225a| gnu lxvll vs1,r3,r4
7c241c98| gnu lxsdx vs1,r4,r3
7c241a18| gnu lxvx vs1,r4,r3
7c241b18| gnu stxvx vs1,r4,r3
7c241f98| gnu stxvd2x vs1,r4,r3
f4230015| gnu stxv vs1,16(r3)
7c23231a| gnu stxvl vs1,r3,r4
7c23235a| gnu stxvll vs1,r3,r4
7c241d98| gnu stxsdx vs1,r4,r3
7c241898| gnu lxsiwax vs1,r4,r3
7c241918| gnu stxsiwx vs1,r4,r3
7c230066| gnu mfvsrd r3,vs1
7c230166| gnu mtvsrd vs1,r3
f0611410| gnu xxland vs3,vs1,vs2
f0611490| gnu xxlor vs3,vs1,vs2
f0611550| gnu xxlorc vs3,vs1,vs2
f06114d0| gnu xxlxor vs3,vs1,vs2
f08110f0| gnu xxsel vs4,vs1,vs2,vs3
f0611090| gnu xxmrghw vs3,vs1,vs2
f0410a90| gnu xxspltw vs2,vs1,1
f06110d0| gnu xxperm vs3,vs1,vs2
f0611110| gnu xxsldwi vs3,vs1,vs2,1
f0400c24| gnu xscvdpsp vs2,vs1
f0400e24| gnu xvcvdpsp vs2,vs1
f0400de0| gnu xscvsxddp vs2,vs1
f0400f60| gnu xvcvdpsxds vs2,vs1
f0400fe0| gnu xvcvsxddp vs2,vs1
7c6803a6| gnu mtlr r3
7c6903a6| gnu mtctr r3
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
0602000138800007| gnu pli r4,-8589869049
7c5b03c0| plan9 SETNBCR CR6SO,R2
fc811000| plan9 FCMPU F1,F2,CR1
7c220176| plan9 BRD R1,R2
7c2201b6| plan9 BRH R1,R2
7c220136| plan9 BRW R1,R2
7c2311b8| plan9 CFUGED R1,R2,R3
04100016e4820032| gnu .quad 0x4100016e4820032
0612000138820007| gnu .quad 0x612000138820007
7fe20de5| plan9 HASHCHK -8(R2),R1
7fe20da5| plan9 HASHST R1,-8(R2)
7c020de4| plan9 HASHCHK -512(R2),R1
7c020da4| plan9 HASHST R1,-512(R2)
7c020de5| plan9 HASHCHK -256(R2),R1
7c020da5| plan9 HASHST R1,-256(R2)
7fe115a5| plan9 HASHST R2,-8(R1)
7fe11525| plan9 HASHSTP R2,-8(R1)
7fe115e5| plan9 HASHCHK -8(R1),R2
7fe11565| plan9 HASHCHKP -8(R1),R2
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,503 @@
// Copyright 2014 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.
// Power64spec reads the “Power ISA V2.07” Manual
// to collect instruction encoding details and writes those details to standard output
// in CSV format.
//
// Usage:
//
// ppc64spec PowerISA_V2.07_PUBLIC.pdf >ppc64.csv
//
// Each CSV line contains four fields:
//
// instruction
// The instruction heading, such as "AAD imm8".
// mnemonic
// The instruction mnemonics, separated by | symbols.
// encoding
// The instruction encoding, a sequence of name@startbit| describing each bit field in turn.
// tags
// For now, empty.
//
// For more on the exact meaning of these fields, see the Power manual.
package main
import (
"bufio"
"fmt"
"log"
"math"
"os"
"regexp"
"sort"
"strconv"
"strings"
"rsc.io/pdf"
)
type Inst struct {
Name string
Text string
Enc string
}
const debugPage = 0
var stdout *bufio.Writer
func main() {
log.SetFlags(0)
log.SetPrefix("ppc64spec: ")
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "usage: ppc64spec file.pdf\n")
os.Exit(2)
}
f, err := pdf.Open(os.Args[1])
if err != nil {
log.Fatal(err)
}
// Find instruction set reference in outline, to build instruction list.
instList := instHeadings(f.Outline())
if len(instList) < 200 {
log.Fatalf("only found %d instructions in table of contents", len(instList))
}
var all = []Inst{
// Split across multiple columns and pages!
{"Count Leading Zeros Word X-form", "cntlzw RA, RS (Rc=0)\ncntlzw. RA, RS (Rc=1)", "31@0|RS@6|RA@11|///@16|26@21|Rc@31|"},
}
for j, headline := range instList {
for _, inst := range all {
if headline == inst.Name {
instList[j] = ""
break
}
}
}
// Scan document looking for instructions.
// Must find exactly the ones in the outline.
n := f.NumPage()
for pageNum := 1; pageNum <= n; pageNum++ {
if debugPage > 0 && pageNum != debugPage {
continue
}
p := f.Page(pageNum)
table := parsePage(pageNum, p)
if len(table) == 0 {
continue
}
InstLoop:
for _, inst := range table {
for j, headline := range instList {
if inst.Name == headline {
instList[j] = ""
continue InstLoop
}
}
fmt.Fprintf(os.Stderr, "page %d: unexpected instruction %q\n", pageNum, inst.Name)
}
all = append(all, table...)
}
if debugPage == 0 {
for _, headline := range instList {
if headline != "" {
switch headline {
default:
fmt.Fprintf(os.Stderr, "missing instruction %q\n", headline)
case "CHKA": // ThumbEE
case "CPS": // system instruction
case "CPY": // synonym for MOV
case "ENTERX": // ThumbEE
case "F* (former VFP instruction mnemonics)": // synonyms
case "HB, HBL, HBLP, HBP": // ThumbEE
case "LEAVEX": // ThumbEE
case "MOV (shifted register)": // pseudo instruction for ASR, LSL, LSR, ROR, and RRX
case "NEG": // synonym for RSB
case "RFE": // system instruction
case "SMC (previously SMI)": // system instruction
case "SRS": // system instruction
case "SUBS PC, LR and related instructions": // system instruction
case "VAND (immediate)": // pseudo instruction
case "VCLE (register)": // pseudo instruction
case "VCLT (register)": // pseudo instruction
case "VORN (immediate)": // pseudo instruction
}
}
}
}
stdout = bufio.NewWriter(os.Stdout)
for _, inst := range all {
fmt.Fprintf(stdout, "%q,%q,%q,%q\n", inst.Name, strings.Replace(inst.Text, "\n", "|", -1), inst.Enc, "")
}
stdout.Flush()
}
func instHeadings(outline pdf.Outline) []string {
return appendInstHeadings(outline, nil)
}
var instRE = regexp.MustCompile(` ([A-Z0-9]+-form|Byte|Word|Doubleword|Halfword)($| \[)`)
var sectionRE = regexp.MustCompile(`^[0-9A-Z]+\.[0-9]`)
func appendInstHeadings(outline pdf.Outline, list []string) []string {
if strings.Contains(outline.Title, "Variable Length Encoding (VLE) Encoding") {
for _, child := range outline.Child {
vle = appendInstHeadings(child, vle)
}
return list
}
if instRE.MatchString(outline.Title) && !sectionRE.MatchString(outline.Title) {
list = append(list, outline.Title)
}
if outline.Title == "Transaction Abort Word Conditional" {
list = append(list, outline.Title+" X-form")
}
for _, child := range outline.Child {
list = appendInstHeadings(child, list)
}
return list
}
const inch = 72.0
func parsePage(num int, p pdf.Page) []Inst {
content := p.Content()
var text []pdf.Text
for _, t := range content.Text {
text = append(text, t)
}
text = findWords(text)
if debugPage > 0 {
for _, t := range text {
fmt.Println(t)
}
for _, r := range content.Rect {
fmt.Println(r)
}
}
// Look for instruction encodings.
// Some begin with a Helvetica-BoldOblique size 11 headline like "AND X-Form",
// is followed by Helvetica 9 mnemonic, and then a bit box with
// Helvetica 9 fields and Helvetica 7 bit offsets.
// Others use Arial,BoldItalic 11 for the headline,
// Arial 8 for the mnemonic, and Arial 4.2 for the bit offsets.
var insts []Inst
for {
// Heading
for len(text) > 0 && !match(text[0], "Helvetica-BoldOblique", 11, "") && !match(text[0], "Arial,BoldItalic", 11, "") && !match(text[0], "Arial,BoldItalic", 10, "") {
text = text[1:]
}
if len(text) == 0 {
break
}
heading := text[0].S
text = text[1:]
for len(text) > 0 && (match(text[0], "Helvetica-BoldOblique", 11, "") || match(text[0], "Arial,BoldItalic", 11, "") || match(text[0], "Arial,BoldItalic", 10, "")) {
heading += " " + text[0].S
text = text[1:]
}
heading = strings.Replace(heading, "]", "] ", -1)
heading = strings.Replace(heading, " ", " ", -1)
heading = strings.Replace(heading, "rEVX-form", "r EVX-form", -1)
heading = strings.Replace(heading, "eX-form", "e X-form", -1)
heading = strings.Replace(heading, "mSD4-form", "m SD4-form", -1)
heading = strings.Replace(heading, "eSCI8-form", "e SCI8-form", -1)
heading = strings.TrimSpace(heading)
if isVLE(heading) {
continue
}
// Mnemonic
if len(text) == 0 || (!match(text[0], "Helvetica", 9, "") && !match(text[0], "Helvetica-BoldOblique", 9, "") && !match(text[0], "Arial", 9, "") && !match(text[0], "Arial", 10, "")) {
continue
}
mnemonic := ""
y := text[0].Y
x0 := text[0].X
for len(text) > 0 && (match(text[0], "Helvetica", 9, "") || match(text[0], "Helvetica-BoldOblique", 9, "") || match(text[0], "Arial", 9, "") || match(text[0], "Courier", 8, "") || match(text[0], "LucidaConsole", 7.17, "") || text[0].Y == y) {
if text[0].Y != y {
if math.Abs(text[0].X-x0) > 4 {
break
}
mnemonic += "\n"
y = text[0].Y
} else if mnemonic != "" {
mnemonic += " "
}
mnemonic += text[0].S
text = text[1:]
}
// Encoding
bits, i := readBitBox(heading, content, text, num)
if i == 0 {
continue
}
insts = append(insts, Inst{heading, mnemonic, bits})
}
return insts
}
var vle = []string{
"System Call C-form,ESC-form",
}
func isVLE(s string) bool {
for _, v := range vle {
if s == v {
return true
}
}
return false
}
func readBitBox(headline string, content pdf.Content, text []pdf.Text, pageNum int) (string, int) {
// fields
i := 0
if len(text) == 0 || (!match(text[i], "Helvetica", 9, "") && !match(text[i], "Helvetica", 7.26, "") && !match(text[i], "Arial", 9, "") && !match(text[i], "Arial", 7.98, "") && !match(text[i], "Arial", 7.2, "")) {
fmt.Fprintf(os.Stderr, "page %d: no bit fields for %q\n", pageNum, headline)
if len(text) > 0 {
fmt.Fprintf(os.Stderr, "\tlast text: %v\n", text[0])
}
return "", 0
}
sz := text[i].FontSize
y2 := text[i].Y
x2 := 0.0
for i < len(text) && text[i].Y == y2 {
if x2 < text[i].X+text[i].W {
x2 = text[i].X + text[i].W
}
i++
}
y2 += sz / 2
// bit numbers
if i >= len(text) || text[i].S != "0" {
if headline == "Transaction Abort Doubleword Conditional X-form" {
// Split across the next page.
return "31@0|TO@6|RA@11|RB@16|814@21|1@31|", i
}
if headline == "Add Scaled Immediate SCI8-form" {
// Very strange fonts.
return "06@0|RT@6|RA@11|8@16|Rc@20|F@21|SCL@22|UI8@24|", i
}
fmt.Fprintf(os.Stderr, "page %d: no bit numbers for %s\n", pageNum, headline)
if i < len(text) {
fmt.Fprintf(os.Stderr, "\tlast text: %v\n", text[i])
}
return "", 0
}
sz = text[i].FontSize
y1 := text[i].Y
x1 := text[i].X
for i < len(text) && text[i].Y == y1 {
if x2 < text[i].X+text[i].W {
x2 = text[i].X + text[i].W
}
i++
}
if debugPage > 0 {
fmt.Println("encoding box", x1, y1, x2, y2, i, text[0], text[i])
}
// Find lines (thin rectangles) separating bit fields.
var bottom, top pdf.Rect
const (
yMargin = 0.25 * 72
xMargin = 1 * 72
)
for _, r := range content.Rect {
// Only consider lines in the same column.
if (x1 < 306) != (r.Max.X < 306) {
continue
}
if r.Max.Y-r.Min.Y < 2 && x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
if y1-yMargin < r.Min.Y && r.Min.Y < y1 {
bottom = r
}
if y2 < r.Min.Y && r.Min.Y < y2+8 {
top = r
}
}
}
if bottom.Min.X == 0 {
// maybe bit numbers are outside box; see doze, nap, sleep, rvwinkle.
for _, r := range content.Rect {
// Only consider lines in the same column.
if (x1 < 306) != (r.Max.X < 306) {
continue
}
if r.Max.Y-r.Min.Y < 2 && x1-xMargin < r.Min.X && r.Min.X < x1 && x2 < r.Max.X && r.Max.X < x2+xMargin {
if y1+sz/2 < r.Min.Y && r.Min.Y < y2 {
bottom = r
}
}
}
}
if debugPage > 0 {
fmt.Println("top", top, "bottom", bottom)
}
const ε = 0.1 * 72
var bars []pdf.Rect
for _, r := range content.Rect {
if r.Max.X-r.Min.X < 2 && math.Abs(r.Min.Y-bottom.Min.Y) < ε && math.Abs(r.Max.Y-top.Min.Y) < ε && (bottom.Min.X < 306) == (r.Max.X < 306) {
bars = append(bars, r)
}
}
sort.Sort(RectHorizontal(bars))
out := ""
for i := 0; i < len(bars)-1; i++ {
var sub []pdf.Text
x1, x2 := bars[i].Min.X, bars[i+1].Min.X
for _, t := range content.Text {
tx := t.X + t.W/2
ty := t.Y + t.FontSize/4
if x1 < tx && tx < x2 && y1 < ty && ty < y2 {
sub = append(sub, t)
}
}
var str []string
for _, t := range findWords(sub) {
str = append(str, t.S)
}
s := strings.Join(str, "@")
out += s + "|"
}
if out == "" {
fmt.Fprintf(os.Stderr, "page %d: no bit encodings for %s\n", pageNum, headline)
}
return out, i
}
type RectHorizontal []pdf.Rect
func (x RectHorizontal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x RectHorizontal) Less(i, j int) bool { return x[i].Min.X < x[j].Min.X }
func (x RectHorizontal) Len() int { return len(x) }
func checkNoEncodings(num int, text []pdf.Text) {
for _, t := range text {
if match(t, "Helvetica-Bold", 9, "Encoding") {
fmt.Fprintf(os.Stderr, "page %d: unexpected encoding: %s\n", num, t.S)
}
}
}
func match(t pdf.Text, font string, size float64, substr string) bool {
return t.Font == font && (size == 0 || math.Abs(t.FontSize-size) < 0.1) && strings.Contains(t.S, substr)
}
func findWords(chars []pdf.Text) (words []pdf.Text) {
// Sort by Y coordinate and normalize.
const nudge = 1.5
sort.Sort(pdf.TextVertical(chars))
old := -100000.0
for i, c := range chars {
if c.Y != old && math.Abs(old-c.Y) < nudge {
chars[i].Y = old
} else {
old = c.Y
}
}
// Sort by Y coordinate, breaking ties with X.
// This will bring letters in a single word together.
sort.Sort(pdf.TextVertical(chars))
// Loop over chars.
for i := 0; i < len(chars); {
// Find all chars on line.
j := i + 1
for j < len(chars) && chars[j].Y == chars[i].Y {
j++
}
var end float64
// Split line into words (really, phrases).
for k := i; k < j; {
ck := &chars[k]
s := ck.S
end = ck.X + ck.W
charSpace := ck.FontSize / 6
wordSpace := ck.FontSize * 2 / 3
l := k + 1
for l < j {
// Grow word.
cl := &chars[l]
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+charSpace {
s += cl.S
end = cl.X + cl.W
l++
continue
}
// Add space to phrase before next word.
if sameFont(cl.Font, ck.Font) && math.Abs(cl.FontSize-ck.FontSize) < 0.1 && cl.X <= end+wordSpace {
s += " " + cl.S
end = cl.X + cl.W
l++
continue
}
break
}
f := ck.Font
f = strings.TrimSuffix(f, ",Italic")
f = strings.TrimSuffix(f, "-Italic")
words = append(words, pdf.Text{f, ck.FontSize, ck.X, ck.Y, end - ck.X, s})
k = l
}
i = j
}
// Split into two columns.
var col1, col2 []pdf.Text
for _, w := range words {
if w.X > 306 {
col2 = append(col2, w)
} else {
col1 = append(col1, w)
}
}
return append(col1, col2...)
}
func sameFont(f1, f2 string) bool {
f1 = strings.TrimSuffix(f1, ",Italic")
f1 = strings.TrimSuffix(f1, "-Italic")
f2 = strings.TrimSuffix(f1, ",Italic")
f2 = strings.TrimSuffix(f1, "-Italic")
return strings.TrimSuffix(f1, ",Italic") == strings.TrimSuffix(f2, ",Italic") || f1 == "Symbol" || f2 == "Symbol" || f1 == "TimesNewRoman" || f2 == "TimesNewRoman"
}
var jsFix = strings.NewReplacer(
// `\u003c`, `<`,
// `\u003e`, `>`,
// `\u0026`, `&`,
// `\u0009`, `\t`,
)
func printTable(name string, table []Inst) {
_ = strconv.Atoi
}
@@ -0,0 +1,163 @@
// 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
// A valid displacement value for the hash check and hash store instructions.
#define offset -128
// 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
@@ -0,0 +1,149 @@
// 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.
//go:build ignore
// Generate interesting test cases from ppc64 objdump via
// go run util.go
//
// This requires powerpc64le-linux-gnu-gcc and powerpc64le-linux-gnu-objdump be in
// the PATH this command is run.
//
// These tools can be acquired from the IBM advance toolchain for amd64 hosts too.
package main
import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
// Generator for branch on spr (bclr, bctar, bcctr)
func emitBSpr(bo, bi, l uint32, out io.Writer) {
var insn [3]uint32 = [3]uint32{19<<26 | 16<<1, 19<<26 | 528<<1, 19<<26 | 560<<1}
for bh := uint32(0); bh < 3; bh++ {
for _, m := range insn {
m |= bo << 21
m |= bi << 16
m |= bh << 11
m |= l << 0
fmt.Fprintf(out, "\t.long 0x%08x\n", m)
}
}
}
// Generator for bc
func emitBc(bo, bi, l uint32, out io.Writer) {
for aa := uint32(0); aa < 2; aa++ {
m := uint32(16 << 26)
m |= bo << 21
m |= bi << 16
m |= l << 0
m |= aa << 1
m |= 128
fmt.Fprintf(out, "\t.long 0x%08x\n", m)
}
}
// Generator all interesting conditional branch type instructions
func emitBranches(out io.Writer) {
fmt.Fprintf(out, ".text\n")
for bo := 0; bo < 0x20; bo++ {
// objdump behaves strangely on some cases when a z bit is set.
// Ignore these, they should never show up in correct code.
if bo&0x15 == 0x1 {
// skip 0b0.0.z cases where z != 0
continue
}
if bo&0x14 == 0x14 && bo != 14 {
// skip 0b1z1zz cases where z != 0
continue
}
// skip at == 1 cases. objdump doesn't handle these well either.
reserved_at := map[int]bool{5: true, 13: true, 17: true, 19: true}
if reserved_at[bo] {
continue
}
// only test cr0/cr1 bits. cr2-cr7 cases are basically identical to cr1.
for bi := 0; bi < 0x8; bi++ {
for l := 0; l < 2; l++ {
emitBSpr(uint32(bo), uint32(bi), uint32(l), out)
emitBc(uint32(bo), uint32(bi), uint32(l), out)
}
}
}
}
// 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=power10", "-x", "assembler-with-cpp", "-o", name+".o", "-")
input, _ := cmd.StdinPipe()
cmd.Stderr = os.Stderr
go func() {
defer input.Close()
generator(input.(io.Writer))
}()
if cmd.Run() != nil {
fmt.Printf("Failed running gcc for: %s\n", name)
return
}
defer os.Remove(name + ".o")
cmd = exec.Command(tcPfx+"objdump", "-d", name+".o")
// Run objdump and parse output into test format
output, _ := cmd.StdoutPipe()
defer output.Close()
scanner := bufio.NewScanner(output)
spacere := regexp.MustCompile("[[:space:]]+")
outf, _ := os.Create(name + ".txt")
defer outf.Close()
if cmd.Start() != nil {
fmt.Printf("Failed running objdump for: %s\n", name)
return
}
pfx := ""
dec := ""
for scanner.Scan() {
ln := spacere.Split(scanner.Text(), -1)
if len(ln) >= 7 {
opc := strings.Join(ln[2:6], "")
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)
}