golang.org/x/arch@v0.17.0/ppc64/ppc64util/util.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build ignore 6 7 // Generate interesting test cases from ppc64 objdump via 8 // go run util.go 9 // 10 // This requires powerpc64le-linux-gnu-gcc and powerpc64le-linux-gnu-objdump be in 11 // the PATH this command is run. 12 // 13 // These tools can be acquired from the IBM advance toolchain for amd64 hosts too. 14 15 package main 16 17 import ( 18 "bufio" 19 "fmt" 20 "io" 21 "os" 22 "os/exec" 23 "regexp" 24 "strconv" 25 "strings" 26 ) 27 28 // Generator for branch on spr (bclr, bctar, bcctr) 29 func emitBSpr(bo, bi, l uint32, out io.Writer) { 30 var insn [3]uint32 = [3]uint32{19<<26 | 16<<1, 19<<26 | 528<<1, 19<<26 | 560<<1} 31 for bh := uint32(0); bh < 3; bh++ { 32 for _, m := range insn { 33 m |= bo << 21 34 m |= bi << 16 35 m |= bh << 11 36 m |= l << 0 37 fmt.Fprintf(out, "\t.long 0x%08x\n", m) 38 } 39 } 40 } 41 42 // Generator for bc 43 func emitBc(bo, bi, l uint32, out io.Writer) { 44 for aa := uint32(0); aa < 2; aa++ { 45 m := uint32(16 << 26) 46 m |= bo << 21 47 m |= bi << 16 48 m |= l << 0 49 m |= aa << 1 50 m |= 128 51 fmt.Fprintf(out, "\t.long 0x%08x\n", m) 52 } 53 } 54 55 // Generator all interesting conditional branch type instructions 56 func emitBranches(out io.Writer) { 57 fmt.Fprintf(out, ".text\n") 58 for bo := 0; bo < 0x20; bo++ { 59 // objdump behaves strangely on some cases when a z bit is set. 60 // Ignore these, they should never show up in correct code. 61 if bo&0x15 == 0x1 { 62 // skip 0b0.0.z cases where z != 0 63 continue 64 } 65 if bo&0x14 == 0x14 && bo != 14 { 66 // skip 0b1z1zz cases where z != 0 67 continue 68 } 69 // skip at == 1 cases. objdump doesn't handle these well either. 70 reserved_at := map[int]bool{5: true, 13: true, 17: true, 19: true} 71 if reserved_at[bo] { 72 continue 73 } 74 // only test cr0/cr1 bits. cr2-cr7 cases are basically identical to cr1. 75 for bi := 0; bi < 0x8; bi++ { 76 for l := 0; l < 2; l++ { 77 emitBSpr(uint32(bo), uint32(bi), uint32(l), out) 78 emitBc(uint32(bo), uint32(bi), uint32(l), out) 79 } 80 } 81 } 82 } 83 84 // Emit a test file using the generator called name.txt. This requires 85 // a GCC toolchain which supports -mcpu=power10. 86 func genOutput(name, tcPfx string, generator func(io.Writer)) { 87 // Generate object code from gcc 88 cmd := exec.Command(tcPfx+"gcc", "-c", "-mbig", "-mcpu=power10", "-x", "assembler-with-cpp", "-o", name+".o", "-") 89 input, _ := cmd.StdinPipe() 90 cmd.Stderr = os.Stderr 91 go func() { 92 defer input.Close() 93 generator(input.(io.Writer)) 94 }() 95 if cmd.Run() != nil { 96 fmt.Printf("Failed running gcc for: %s\n", name) 97 return 98 } 99 defer os.Remove(name + ".o") 100 cmd = exec.Command(tcPfx+"objdump", "-d", name+".o") 101 102 // Run objdump and parse output into test format 103 output, _ := cmd.StdoutPipe() 104 defer output.Close() 105 scanner := bufio.NewScanner(output) 106 spacere := regexp.MustCompile("[[:space:]]+") 107 outf, _ := os.Create(name + ".txt") 108 defer outf.Close() 109 if cmd.Start() != nil { 110 fmt.Printf("Failed running objdump for: %s\n", name) 111 return 112 } 113 114 pfx := "" 115 dec := "" 116 for scanner.Scan() { 117 ln := spacere.Split(scanner.Text(), -1) 118 if len(ln) >= 7 { 119 opc := strings.Join(ln[2:6], "") 120 if len(pfx) == 0 { 121 dec = strings.Join(ln[6:], " ") 122 } 123 if v, _ := strconv.ParseInt(ln[2], 16, 16); v&0xFC == 0x04 { 124 pfx = opc 125 continue 126 } 127 fmt.Fprintf(outf, "%s%s|\tgnu\t%s\n", pfx, opc, dec) 128 pfx = "" 129 } 130 131 } 132 cmd.Wait() 133 } 134 135 // Generate representative instructions for all[1] instructions in pp64.csv. 136 // 137 // [1] See hack.h for a few minor, exceptional workarounds. 138 func emitGenerated(out io.Writer) { 139 cmd := exec.Command("go", "run", "../ppc64map/map.go", "-fmt=asm", "../pp64.csv") 140 cmdout, _ := cmd.Output() 141 out.Write(cmdout) 142 } 143 144 // Produce generated test outputs. This should be run every so often with 145 // new versions of objdump to ensure we stay up to date. 146 func main() { 147 genOutput("decode_branch", "powerpc64le-linux-gnu-", emitBranches) 148 genOutput("decode_generated", "powerpc64le-linux-gnu-", emitGenerated) 149 }