whatcanGOwrong
This commit is contained in:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user