// 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) }