...

Source file src/golang.org/x/arch/ppc64/ppc64util/util.go

Documentation: golang.org/x/arch/ppc64/ppc64util

     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  }
   150  

View as plain text