modernc.org/qbe@v0.0.9/cc/all_test.go (about)

     1  // Copyright 2021 The QBE 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  //TODO Csmith
     6  
     7  package cc // import "modernc.org/qbe/cc"
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"context"
    13  	"encoding/hex"
    14  	"flag"
    15  	"fmt"
    16  	"go/build"
    17  	"io"
    18  	"io/ioutil"
    19  	"math"
    20  	"os"
    21  	"os/exec"
    22  	"path"
    23  	"path/filepath"
    24  	"regexp"
    25  	"runtime"
    26  	"runtime/debug"
    27  	"sort"
    28  	"strconv"
    29  	"strings"
    30  	"sync"
    31  	"testing"
    32  	"time"
    33  
    34  	"github.com/pmezard/go-difflib/difflib"
    35  	"modernc.org/cc/v3"
    36  	"modernc.org/ccgo/v3/lib"
    37  	"modernc.org/ccorpus"
    38  	"modernc.org/qbe"
    39  )
    40  
    41  var (
    42  	fs                   = ccorpus.FileSystem()
    43  	includePaths         []string
    44  	initIncludePathsOnce sync.Once
    45  	oBenchO              = flag.Int("BO", 3, "")
    46  	oBestOf              = flag.Int("bestof", 5, "TestBenchmarksGame: best of N")
    47  	oCSmith              = flag.Duration("csmith", time.Minute, "")
    48  	oFF                  = flag.Bool("ff", false, "fail fast")
    49  	oFullPaths           = flag.Bool("full-paths", false, "")
    50  	oInstall             = flag.Bool("install", false, "install qbec and ecc binaries")
    51  	oKeepTmp             = flag.Bool("keep-tmp", false, "")
    52  	oMarch               = flag.String("march", "native", "")
    53  	oMtune               = flag.String("mtune", "native", "")
    54  	oO                   = flag.Int("O", 1, "")
    55  	oOpenmp              = flag.Bool("fopenmp", false, "")
    56  	oRE                  = flag.String("re", "", "")
    57  	oTrc                 = flag.Bool("trc", false, "")
    58  	oTrc2                = flag.Bool("trc2", false, "")
    59  	oTrco                = flag.Bool("trco", false, "")
    60  	overlayDir           string
    61  	predefined           string
    62  	re                   *regexp.Regexp
    63  	sysIncludePaths      []string
    64  	systemCC             string
    65  	systemCCVersion      string
    66  	tempDir              string
    67  )
    68  
    69  func init() {
    70  	use(use)
    71  }
    72  
    73  func use(...interface{}) {}
    74  
    75  func initIncludePaths(cpp string) error {
    76  	var err error
    77  	predefined, includePaths, sysIncludePaths, err = cc.HostConfig(cpp)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	includePaths = append(includePaths, "@")
    83  	includePaths = append(includePaths, sysIncludePaths...)
    84  	return nil
    85  }
    86  
    87  func TestMain(m *testing.M) {
    88  	fmt.Fprintf(os.Stderr, "qbe/cc: %v\n", os.Args)
    89  	oGCC := flag.String("gcc", "", "")
    90  	flag.BoolVar(&qbe.TraceC, "trcc", false, "")
    91  	flag.BoolVar(&oTrcw, "trcw", false, "")
    92  	flag.Parse()
    93  	if s := *oRE; s != "" {
    94  		re = regexp.MustCompile(s)
    95  	}
    96  	if *oGCC == "" {
    97  		var err error
    98  		initIncludePathsOnce.Do(func() { err = initIncludePaths("") })
    99  		if err != nil {
   100  			fmt.Println(err)
   101  			os.Exit(1)
   102  		}
   103  
   104  		if systemCC, err = exec.LookPath(env("QBEC_CC", env("CC", "gcc"))); err != nil {
   105  			fmt.Println(err)
   106  			os.Exit(1)
   107  		}
   108  
   109  		fmt.Fprintf(os.Stderr, "QBEC_CC=%s\n", systemCC)
   110  		out, err := exec.Command(systemCC, "--version").CombinedOutput()
   111  		if err == nil {
   112  			if a := strings.Split(string(out), "\n"); len(a) > 0 {
   113  				systemCCVersion = a[0]
   114  				fmt.Fprintf(os.Stderr, "%s\n", systemCCVersion)
   115  			}
   116  		}
   117  
   118  		os.Exit(testMain(m))
   119  	}
   120  
   121  	var args []string
   122  	for i, v := range os.Args {
   123  		if v == "-gcc" {
   124  			args = append(os.Args[:i], os.Args[i+2:]...)
   125  		}
   126  	}
   127  	a := strings.Split(*oGCC, ",")
   128  	rc := 0
   129  	for _, suffix := range a {
   130  		systemCC = fmt.Sprintf("gcc-%s", suffix)
   131  		systemCPP := fmt.Sprintf("cpp-%s", suffix)
   132  		var err error
   133  		if systemCC, err = exec.LookPath(systemCC); err != nil {
   134  			fmt.Fprintf(os.Stderr, "%s: %s\n", systemCC, err)
   135  			continue
   136  		}
   137  
   138  		if systemCPP, err = exec.LookPath(systemCPP); err != nil {
   139  			fmt.Fprintf(os.Stderr, "%s: %s\n", systemCPP, err)
   140  			continue
   141  		}
   142  
   143  		os.Setenv("QBEC_CC", systemCC)
   144  		os.Setenv("ECC_CPP", systemCPP)
   145  		cmd := exec.Command(args[0], args[1:]...)
   146  		cmd.Stdout = os.Stdout
   147  		cmd.Stderr = os.Stderr
   148  		if err := cmd.Run(); err != nil {
   149  			rc = 1
   150  		}
   151  	}
   152  	os.Exit(rc)
   153  
   154  }
   155  
   156  func testMain(m *testing.M) int {
   157  	var err error
   158  	tempDir, err = ioutil.TempDir("", "qbe-cc-test-")
   159  	if err != nil {
   160  		panic(err) //TODOOK
   161  	}
   162  
   163  	switch {
   164  	case *oKeepTmp:
   165  		fmt.Fprintf(os.Stderr, "keeping temporary directory %s\n", tempDir)
   166  	default:
   167  		defer os.RemoveAll(tempDir)
   168  	}
   169  
   170  	s := filepath.FromSlash("testdata/overlay")
   171  	if overlayDir, err = filepath.Abs(s); err != nil {
   172  		panic(err) //TODOOK
   173  	}
   174  
   175  	return m.Run()
   176  }
   177  
   178  func mustEmptyDir(t *testing.T, s string) {
   179  	if err := emptyDir(s); err != nil {
   180  		t.Fatal(err)
   181  	}
   182  }
   183  
   184  func emptyDir(s string) error {
   185  	m, err := filepath.Glob(filepath.FromSlash(s + "/*"))
   186  	if err != nil {
   187  		return err
   188  	}
   189  
   190  	for _, v := range m {
   191  		fi, err := os.Stat(v)
   192  		if err != nil {
   193  			return err
   194  		}
   195  
   196  		switch {
   197  		case fi.IsDir():
   198  			if err = os.RemoveAll(v); err != nil {
   199  				return err
   200  			}
   201  		default:
   202  			if err = os.Remove(v); err != nil {
   203  				return err
   204  			}
   205  		}
   206  	}
   207  	return nil
   208  }
   209  
   210  type runResult struct {
   211  	ccTime    time.Duration
   212  	csmithSrc []byte
   213  	eccTime   time.Duration
   214  	err       error
   215  	name      string
   216  	out       []byte
   217  }
   218  
   219  type skipErr string
   220  
   221  func (e skipErr) Error() string { return "skipped: " + string(e) }
   222  
   223  type runTask struct {
   224  	args      []string
   225  	c         chan *runResult
   226  	cmd       string
   227  	csmithSrc []byte
   228  	opts      []string
   229  	src       string
   230  
   231  	ccCanFail       bool
   232  	doNotExec       bool
   233  	hasBinaryOutput bool
   234  }
   235  
   236  func (t *runTask) run() {
   237  	r := &runResult{name: t.src}
   238  	r.out, r.err, r.ccTime, r.eccTime = t.run0()
   239  	t.c <- r
   240  }
   241  
   242  func (t *runTask) runCSmith() {
   243  	r := &runResult{name: t.src, csmithSrc: t.csmithSrc}
   244  	r.out, r.err, r.ccTime, r.eccTime = t.run0CSmith()
   245  	t.c <- r
   246  }
   247  
   248  func (t *runTask) run0() (_ []byte, err error, ccTime, eccTime time.Duration) {
   249  	const outLimit = 1 << 16
   250  	defer func() {
   251  		if e := recover(); e != nil {
   252  			switch {
   253  			case err == nil:
   254  				err = fmt.Errorf("PANIC: %v\n%s", e, debug.Stack())
   255  			default:
   256  				err = fmt.Errorf("%v\nPANIC: %v\n%s", err, e, debug.Stack())
   257  			}
   258  		}
   259  	}()
   260  
   261  	overlay := filepath.Join(overlayDir, t.src)
   262  	b, err := ioutil.ReadFile(overlay)
   263  	if err != nil {
   264  		if !os.IsNotExist(err) {
   265  			return nil, err, ccTime, eccTime
   266  		}
   267  
   268  		f, err := fs.Open(t.src)
   269  		if err != nil {
   270  			return nil, err, ccTime, eccTime
   271  		}
   272  
   273  		if b, err = ioutil.ReadAll(f); err != nil {
   274  			return nil, err, ccTime, eccTime
   275  		}
   276  
   277  		if err = f.Close(); err != nil {
   278  			return nil, err, ccTime, eccTime
   279  		}
   280  	}
   281  
   282  	overlay = filepath.Join(overlayDir, t.src+".expectrc")
   283  	b2, err := ioutil.ReadFile(overlay)
   284  	if err != nil {
   285  		f, err := fs.Open(t.src + ".expectrc")
   286  		if err == nil {
   287  			if b2, err = ioutil.ReadAll(f); err != nil {
   288  				return nil, err, ccTime, eccTime
   289  			}
   290  
   291  			if err = f.Close(); err != nil {
   292  				return nil, err, ccTime, eccTime
   293  			}
   294  		}
   295  	}
   296  	var expectRC int
   297  	if len(b2) != 0 {
   298  		s := strings.TrimSpace(string(b2))
   299  		n, err := strconv.ParseUint(s, 10, 32)
   300  		if err != nil {
   301  			return nil, err, ccTime, eccTime
   302  		}
   303  
   304  		expectRC = int(n)
   305  	}
   306  
   307  	baseName := filepath.Base(t.src)
   308  	if err := ioutil.WriteFile(baseName, b, 0600); err != nil {
   309  		return nil, err, ccTime, eccTime
   310  	}
   311  
   312  	args, err := getArgs(t.src)
   313  	if err != nil {
   314  		return nil, err, ccTime, eccTime
   315  	}
   316  
   317  	ccArgs := append([]string{"-lm"}, t.opts...)
   318  	ok := true
   319  	for _, v := range t.opts {
   320  		if strings.HasPrefix(v, "-O") {
   321  			ok = false
   322  			break
   323  		}
   324  	}
   325  	if ok {
   326  		if o := *oO; o >= 0 {
   327  			ccArgs = append(ccArgs, fmt.Sprintf("-O%d", o))
   328  		}
   329  	}
   330  	if t.doNotExec {
   331  		ccArgs = append(ccArgs, "-c")
   332  	}
   333  	binary, err := makeCCBinary(baseName, t.doNotExec, ccArgs...)
   334  	if err != nil {
   335  		return nil, skipErr(err.Error()), ccTime, eccTime
   336  	}
   337  
   338  	const (
   339  		ccOut  = "cc.out"
   340  		eccOut = "ecc.out"
   341  	)
   342  	var binaryBytes, binaryBytes2 int
   343  	var expected []byte
   344  	if !t.doNotExec {
   345  		ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
   346  		defer cancel()
   347  		if t.cmd != "" {
   348  			binary = t.cmd
   349  		}
   350  		if len(t.args) != 0 {
   351  			args = t.args
   352  		}
   353  		t0 := time.Now()
   354  		if *oTrc2 {
   355  			fmt.Fprintf(os.Stderr, "%v: started CC binary for %s: %v %v\n", t0, baseName, binary, args)
   356  		}
   357  		switch {
   358  		case t.hasBinaryOutput:
   359  			binaryBytes, err = execute(ctx, binary, ccOut, args)
   360  			defer os.Remove(ccOut)
   361  		default:
   362  			expected, err = exec.CommandContext(ctx, binary, args...).CombinedOutput()
   363  			if len(expected) > outLimit {
   364  				panic(todo("", t.src, len(expected)))
   365  			}
   366  		}
   367  		ccTime = time.Since(t0)
   368  		if *oTrc2 {
   369  			switch {
   370  			case t.hasBinaryOutput:
   371  				fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes, err)
   372  			default:
   373  				fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, expected)
   374  			}
   375  		}
   376  		if err != nil {
   377  			switch {
   378  			case t.ccCanFail:
   379  				expected = nil
   380  				expectRC = 0
   381  			default:
   382  				rc := err.(*exec.ExitError).ProcessState.ExitCode()
   383  				if rc != expectRC {
   384  					return nil, skipErr(fmt.Sprintf("executing CC binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, expected)), ccTime, eccTime
   385  				}
   386  
   387  				err = nil
   388  			}
   389  		}
   390  
   391  		if *oTrco {
   392  			switch {
   393  			case t.hasBinaryOutput:
   394  				fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", ccTime, args, binaryBytes)
   395  			default:
   396  				fmt.Fprintf(os.Stderr, "%v %q: %s\n", ccTime, args, expected)
   397  			}
   398  		}
   399  	}
   400  
   401  	if t.cmd == "" {
   402  		if err := os.Remove(binary); err != nil {
   403  			return nil, fmt.Errorf("removing %v: %v", binary, err), ccTime, eccTime
   404  		}
   405  	}
   406  
   407  	eccArgs := append([]string{"-lm"}, t.opts...)
   408  	ok = true
   409  	for _, v := range t.opts {
   410  		if strings.HasPrefix(v, "-O") {
   411  			ok = false
   412  			break
   413  		}
   414  	}
   415  	if ok {
   416  		if o := *oO; o >= 0 {
   417  			eccArgs = append(eccArgs, fmt.Sprintf("-O%d", o))
   418  		}
   419  	}
   420  	if *oFullPaths {
   421  		eccArgs = append(eccArgs, "-full-paths")
   422  	}
   423  	if *oKeepTmp {
   424  		eccArgs = append(eccArgs, "-keep-tmp")
   425  	}
   426  	if t.doNotExec {
   427  		eccArgs = append(ccArgs, "-c")
   428  	}
   429  	if binary, err = makeBinary(t.src, t.doNotExec, eccArgs...); err != nil {
   430  		return nil, err, ccTime, eccTime
   431  	}
   432  
   433  	var got []byte
   434  	if !t.doNotExec {
   435  		ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
   436  		defer cancel()
   437  		if t.cmd != "" {
   438  			binary = t.cmd
   439  		}
   440  		if len(t.args) != 0 {
   441  			args = t.args
   442  		}
   443  		t0 := time.Now()
   444  		if *oTrc2 {
   445  			fmt.Fprintf(os.Stderr, "%v: started ecc binary for %s: %v %v\n", t0, baseName, binary, args)
   446  		}
   447  		switch {
   448  		case t.hasBinaryOutput:
   449  			binaryBytes2, err = execute(ctx, binary, eccOut, args)
   450  			defer os.Remove(eccOut)
   451  		default:
   452  			got, err = exec.CommandContext(ctx, binary, args...).CombinedOutput()
   453  			if len(got) > outLimit {
   454  				panic(todo("", t.src, len(expected)))
   455  			}
   456  		}
   457  		eccTime = time.Since(t0)
   458  		if *oTrc2 {
   459  			switch {
   460  			case t.hasBinaryOutput:
   461  				fmt.Fprintf(os.Stderr, "%v: ecc binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes2, err)
   462  			default:
   463  				fmt.Fprintf(os.Stderr, "%v: ecc binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, got)
   464  			}
   465  		}
   466  		if err != nil {
   467  			rc := err.(*exec.ExitError).ProcessState.ExitCode()
   468  			if rc != expectRC {
   469  				return nil, fmt.Errorf("executing ecc binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, got), ccTime, eccTime
   470  			}
   471  
   472  			err = nil
   473  		}
   474  
   475  		if *oTrco {
   476  			switch {
   477  			case t.hasBinaryOutput:
   478  				fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", eccTime, args, binaryBytes2)
   479  			default:
   480  				fmt.Fprintf(os.Stderr, "%v %q: %s\n", eccTime, args, got)
   481  			}
   482  		}
   483  		switch {
   484  		case t.hasBinaryOutput:
   485  			if err := fileEqual(eccOut, ccOut); err != nil {
   486  				return nil, fmt.Errorf("binary output: %s", err), ccTime, eccTime
   487  			}
   488  		default:
   489  			got := string(got)
   490  			expected := string(expected)
   491  			got = strings.ReplaceAll(got, "\r", "")
   492  			got = lineTrim(strings.TrimSpace(got))
   493  			expected = strings.ReplaceAll(expected, "\r", "")
   494  			expected = lineTrim(strings.TrimSpace(expected))
   495  			if got != expected {
   496  				diff := difflib.UnifiedDiff{
   497  					A:        difflib.SplitLines(expected),
   498  					B:        difflib.SplitLines(got),
   499  					FromFile: "expected",
   500  					ToFile:   "got",
   501  					Context:  3,
   502  				}
   503  				text, _ := difflib.GetUnifiedDiffString(diff)
   504  				return nil, fmt.Errorf(
   505  					"%v: text output differs:\n%s\n---- x.c\ngot\n%s\nexp\n%s\ngot\n%s\nexp\n%s",
   506  					t.src, text,
   507  					hex.Dump([]byte(got)), hex.Dump([]byte(expected)),
   508  					got, expected,
   509  				), ccTime, eccTime
   510  			}
   511  		}
   512  	}
   513  	return got, err, ccTime, eccTime
   514  }
   515  
   516  func (t *runTask) run0CSmith() (_ []byte, err error, ccTime, eccTime time.Duration) {
   517  	timeLimit := 10 * time.Second
   518  	const outLimit = 1 << 16
   519  	defer func() {
   520  		if e := recover(); e != nil {
   521  			switch {
   522  			case err == nil:
   523  				err = fmt.Errorf("PANIC: %v\n%s", e, debug.Stack())
   524  			default:
   525  				err = fmt.Errorf("%v\nPANIC: %v\n%s", err, e, debug.Stack())
   526  			}
   527  		}
   528  	}()
   529  
   530  	baseName := filepath.Base(t.src)
   531  	ccArgs := append([]string(nil), t.opts...)
   532  	ok := true
   533  	for _, v := range t.opts {
   534  		if strings.HasPrefix(v, "-O") {
   535  			ok = false
   536  			break
   537  		}
   538  	}
   539  	if ok {
   540  		if o := *oO; o >= 0 {
   541  			ccArgs = append(ccArgs, fmt.Sprintf("-O%d", o))
   542  		}
   543  	}
   544  	binary, err := makeCCBinary(baseName, t.doNotExec, ccArgs...)
   545  	if err != nil {
   546  		return nil, skipErr(err.Error()), ccTime, eccTime
   547  	}
   548  
   549  	const (
   550  		ccOut  = "cc.out"
   551  		eccOut = "ecc.out"
   552  	)
   553  	var binaryBytes, binaryBytes2 int
   554  	var expected []byte
   555  	ctx, cancel := context.WithTimeout(context.Background(), timeLimit)
   556  	defer cancel()
   557  	t0 := time.Now()
   558  	if *oTrc2 {
   559  		fmt.Fprintf(os.Stderr, "%v: started CC binary for %s: %v\n", t0, baseName, binary)
   560  	}
   561  	switch {
   562  	case t.hasBinaryOutput:
   563  		binaryBytes, err = execute(ctx, binary, ccOut, nil)
   564  		defer os.Remove(ccOut)
   565  	default:
   566  		expected, err = exec.CommandContext(ctx, binary).CombinedOutput()
   567  		if len(expected) > outLimit {
   568  			panic(todo("", t.src, len(expected)))
   569  		}
   570  	}
   571  	ccTime = time.Since(t0)
   572  	if *oTrc2 {
   573  		switch {
   574  		case t.hasBinaryOutput:
   575  			fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes, err)
   576  		default:
   577  			fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, expected)
   578  		}
   579  	}
   580  	if err != nil {
   581  		return nil, skipErr(fmt.Sprintf("executing CC binary %v: %v\n%s", binary, err, expected)), ccTime, eccTime
   582  	}
   583  
   584  	if *oTrco {
   585  		fmt.Fprintf(os.Stderr, "%v: %s\n", ccTime, expected)
   586  	}
   587  
   588  	if err := os.Remove(binary); err != nil {
   589  		return nil, fmt.Errorf("removing %v: %v", binary, err), ccTime, eccTime
   590  	}
   591  
   592  	eccArgs := append([]string(nil), t.opts...)
   593  	ok = true
   594  	for _, v := range t.opts {
   595  		if strings.HasPrefix(v, "-O") {
   596  			ok = false
   597  			break
   598  		}
   599  	}
   600  	if ok {
   601  		if o := *oO; o >= 0 {
   602  			eccArgs = append(eccArgs, fmt.Sprintf("-O%d", o))
   603  		}
   604  	}
   605  	if *oFullPaths {
   606  		eccArgs = append(eccArgs, "-full-paths")
   607  	}
   608  	if *oKeepTmp {
   609  		eccArgs = append(eccArgs, "-keep-tmp")
   610  	}
   611  	if binary, err = makeBinary(t.src, t.doNotExec, eccArgs...); err != nil {
   612  		return nil, err, ccTime, eccTime
   613  	}
   614  
   615  	var got []byte
   616  	ctx, cancel = context.WithTimeout(context.Background(), timeLimit)
   617  	defer cancel()
   618  	t0 = time.Now()
   619  	if *oTrc2 {
   620  		fmt.Fprintf(os.Stderr, "%v: started ecc binary for %s: %v\n", t0, baseName, binary)
   621  	}
   622  	got, err = exec.CommandContext(ctx, binary).CombinedOutput()
   623  	if len(got) > outLimit {
   624  		panic(todo("", t.src, len(expected)))
   625  	}
   626  	eccTime = time.Since(t0)
   627  	if *oTrc2 {
   628  		switch {
   629  		case t.hasBinaryOutput:
   630  			fmt.Fprintf(os.Stderr, "%v: ecc binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes2, err)
   631  		default:
   632  			fmt.Fprintf(os.Stderr, "%v: ecc binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, got)
   633  		}
   634  	}
   635  	if err != nil {
   636  		return nil, fmt.Errorf("executing ecc binary %v: %v\n%s", binary, err, got), ccTime, eccTime
   637  	}
   638  
   639  	if *oTrco {
   640  		fmt.Fprintf(os.Stderr, "%v: %s\n", eccTime, got)
   641  	}
   642  	{
   643  		got := string(got)
   644  		expected := string(expected)
   645  		got = strings.ReplaceAll(got, "\r", "")
   646  		got = lineTrim(strings.TrimSpace(got))
   647  		expected = strings.ReplaceAll(expected, "\r", "")
   648  		expected = lineTrim(strings.TrimSpace(expected))
   649  		if got != expected {
   650  			diff := difflib.UnifiedDiff{
   651  				A:        difflib.SplitLines(expected),
   652  				B:        difflib.SplitLines(got),
   653  				FromFile: "expected",
   654  				ToFile:   "got",
   655  				Context:  3,
   656  			}
   657  			text, _ := difflib.GetUnifiedDiffString(diff)
   658  			return nil, fmt.Errorf(
   659  				"%v: text output differs:\n%s\n---- x.c\ngot\n%s\nexp\n%s\ngot\n%s\nexp\n%s",
   660  				t.src, text,
   661  				hex.Dump([]byte(got)), hex.Dump([]byte(expected)),
   662  				got, expected,
   663  			), ccTime, eccTime
   664  		}
   665  	}
   666  	return got, err, ccTime, eccTime
   667  }
   668  
   669  func fileEqual(g, e string) error {
   670  	fig, err := os.Stat(g)
   671  	if err != nil {
   672  		return err
   673  	}
   674  
   675  	fie, err := os.Stat(e)
   676  	if err != nil {
   677  		return err
   678  	}
   679  
   680  	if g, e := fig.Size(), fie.Size(); g != e {
   681  		return fmt.Errorf("files sizes differ, got %v, expected %v", g, e)
   682  	}
   683  
   684  	rem := fig.Size()
   685  	if rem == 0 {
   686  		return nil
   687  	}
   688  
   689  	var bg, be [4096]byte
   690  	fg, err := os.Open(g)
   691  	if err != nil {
   692  		return err
   693  	}
   694  
   695  	defer fg.Close()
   696  
   697  	fe, err := os.Open(e)
   698  	if err != nil {
   699  		return err
   700  	}
   701  
   702  	defer fe.Close()
   703  
   704  	for rem != 0 {
   705  		n, err := io.ReadFull(fg, bg[:])
   706  		if n == 0 {
   707  			if err == io.EOF {
   708  				err = nil
   709  			}
   710  			return err
   711  		}
   712  
   713  		n2, err := io.ReadFull(fe, be[:])
   714  		if n == 0 {
   715  			if err == io.EOF {
   716  				err = nil
   717  			}
   718  			return err
   719  		}
   720  
   721  		if n != n2 {
   722  			panic(todo("", n, n2))
   723  		}
   724  
   725  		if !bytes.Equal(bg[:n], be[:n]) {
   726  			return fmt.Errorf("files are different")
   727  		}
   728  
   729  		rem -= int64(n)
   730  	}
   731  	return nil
   732  }
   733  
   734  type countingWriter struct {
   735  	written int
   736  	w       *bufio.Writer
   737  }
   738  
   739  func (c *countingWriter) Write(b []byte) (int, error) {
   740  	n, err := c.w.Write(b)
   741  	c.written += n
   742  	return n, err
   743  }
   744  
   745  var _ io.Writer = (*countingWriter)(nil)
   746  
   747  // err = execute(ctx, executable, args, ccOut)
   748  func execute(ctx context.Context, executable, out string, args []string) (n int, err error) {
   749  	cmd := exec.CommandContext(ctx, executable, args...)
   750  	f, err := os.Create(out)
   751  	if err != nil {
   752  		return 0, err
   753  	}
   754  
   755  	defer func() {
   756  		if e := f.Close(); e != nil && err == nil {
   757  			err = e
   758  		}
   759  	}()
   760  
   761  	w := &countingWriter{w: bufio.NewWriter(f)}
   762  
   763  	defer func() {
   764  		if e := w.w.Flush(); e != nil && err == nil {
   765  			err = e
   766  		}
   767  	}()
   768  
   769  	cmd.Stdout = w
   770  	err = cmd.Run()
   771  	return w.written, err
   772  }
   773  
   774  func run(src string, binaryOut, ccCanFail, doNotExec bool, c chan *runResult, opts ...string) {
   775  	(&runTask{
   776  		c:               c,
   777  		ccCanFail:       ccCanFail,
   778  		doNotExec:       doNotExec,
   779  		hasBinaryOutput: binaryOut,
   780  		opts:            opts,
   781  		src:             src,
   782  	}).run()
   783  }
   784  
   785  func makeCCBinary(src string, obj bool, args ...string) (executable string, err error) {
   786  	ext := ""
   787  	if obj {
   788  		ext = ".o"
   789  	}
   790  	src = filepath.Base(src)
   791  	executable = "./" + src[:len(src)-len(filepath.Ext(src))]
   792  	if runtime.GOOS == "windows" && !obj {
   793  		ext = ".exe"
   794  	}
   795  	executable += ext
   796  	os.Remove(executable)
   797  	b, err := exec.Command(systemCC, append([]string{"-o", executable, src}, args...)...).CombinedOutput()
   798  	if err != nil {
   799  		return "", fmt.Errorf("%v %v -o %v %v: system C compiler: %v\n%s", systemCC, args, executable, src, err, b)
   800  	}
   801  
   802  	return executable, nil
   803  }
   804  
   805  func makeBinary(src string, obj bool, args ...string) (executable string, err error) {
   806  	ext := ""
   807  	if obj {
   808  		ext = ".o"
   809  	}
   810  	src = filepath.Base(src)
   811  	executable = "./" + src[:len(src)-len(filepath.Ext(src))]
   812  	if runtime.GOOS == "windows" {
   813  		ext = ".exe"
   814  	}
   815  	executable += ext
   816  	os.Remove(executable)
   817  	var out bytes.Buffer
   818  	task := NewTask("ecc", append([]string{"-o", executable, src}, args...), &out, &out)
   819  	if err := task.Main(); err != nil {
   820  		return "", fmt.Errorf("%v: ecc compiler: %v\n%s", src, err, out.Bytes())
   821  	}
   822  
   823  	if b := out.Bytes(); len(b) != 0 { //TODO-
   824  		s := string(b)
   825  		s = strings.ReplaceAll(s, "‘", "'")
   826  		s = strings.ReplaceAll(s, "’", "'")
   827  		switch {
   828  		case
   829  			strings.Contains(s, "warning: 'return' with no value, in function returning non-void"),
   830  			strings.Contains(s, "warning: conflicting types for built-in function '__fprintf_chk'"),
   831  			strings.Contains(s, "warning: conflicting types for built-in function '__printf_chk'"),
   832  			strings.Contains(s, "warning: conflicting types for built-in function '__vfprintf_chk'"),
   833  			strings.Contains(s, "warning: conflicting types for built-in function '__vprintf_chk'"),
   834  			strings.Contains(s, "warning: conflicting types for built-in function 'cbrtl'"),
   835  			strings.Contains(s, "warning: conflicting types for built-in function 'memcmp'"),
   836  			strings.Contains(s, "warning: conflicting types for built-in function 'rintf'"),
   837  			strings.Contains(s, "warning: floating constant exceeds range of 'long double'"),
   838  			strings.Contains(s, "warning:") && strings.Contains(s, "may not be initialized"):
   839  			// ok
   840  		default:
   841  			fmt.Printf("WARNING %s\n", s)
   842  		}
   843  	}
   844  	return executable, nil
   845  }
   846  
   847  func getArgs(src string) (args []string, err error) {
   848  	src = src[:len(src)-len(filepath.Ext(src))] + ".arg"
   849  	overlay := filepath.Join(overlayDir, src)
   850  	b, err := ioutil.ReadFile(overlay)
   851  	if err != nil {
   852  		if !os.IsNotExist(err) {
   853  			return nil, err
   854  		}
   855  
   856  		f, err := fs.Open(src)
   857  		if err != nil {
   858  			return nil, nil
   859  		}
   860  
   861  		if b, err = ioutil.ReadAll(f); err != nil {
   862  			return nil, err
   863  		}
   864  
   865  		if err = f.Close(); err != nil {
   866  			return nil, err
   867  		}
   868  	}
   869  
   870  	a := strings.Split(strings.TrimSpace(string(b)), "\n")
   871  	for _, v := range a {
   872  		switch {
   873  		case strings.HasPrefix(v, "\"") || strings.HasPrefix(v, "`"):
   874  			w, err := strconv.Unquote(v)
   875  			if err != nil {
   876  				return nil, fmt.Errorf("%s: %v: %v", src, v, err)
   877  			}
   878  
   879  			args = append(args, w)
   880  		default:
   881  			args = append(args, v)
   882  		}
   883  	}
   884  	return args, nil
   885  }
   886  
   887  func lineTrim(s string) string {
   888  	a := strings.Split(s, "\n")
   889  	for i, v := range a {
   890  		a[i] = strings.TrimSpace(v)
   891  	}
   892  	return strings.Join(a, "\n")
   893  }
   894  
   895  func walk(dir string, f func(pth string, fi os.FileInfo) error) error {
   896  	if !strings.HasSuffix(dir, "/") {
   897  		dir += "/"
   898  	}
   899  	root, err := fs.Open(dir)
   900  	if err != nil {
   901  		return err
   902  	}
   903  
   904  	fi, err := root.Stat()
   905  	if err != nil {
   906  		return err
   907  	}
   908  
   909  	if !fi.IsDir() {
   910  		return fmt.Errorf("%s: not a directory", fi.Name())
   911  	}
   912  
   913  	fis, err := root.Readdir(-1)
   914  	if err != nil {
   915  		return err
   916  	}
   917  
   918  	for _, v := range fis {
   919  		switch {
   920  		case v.IsDir():
   921  			if err = walk(v.Name(), f); err != nil {
   922  				return err
   923  			}
   924  		default:
   925  			if err = f(v.Name(), v); err != nil {
   926  				return err
   927  			}
   928  		}
   929  	}
   930  	return nil
   931  }
   932  
   933  func TestTCC(t *testing.T) {
   934  	const root = "/tcc-0.9.27/tests/tests2"
   935  	mustEmptyDir(t, tempDir)
   936  	wd, err := os.Getwd()
   937  	if err != nil {
   938  		t.Fatal(err)
   939  	}
   940  
   941  	if err := os.Chdir(tempDir); err != nil {
   942  		t.Fatal(err)
   943  	}
   944  
   945  	defer func() {
   946  		if err := os.Chdir(wd); err != nil {
   947  			t.Fatal(err)
   948  		}
   949  	}()
   950  
   951  	needFiles(t, root, []string{
   952  		"18_include.h",
   953  		"95_bitfields.c",
   954  	})
   955  	blacklist := map[string]struct{}{
   956  		"60_errors_and_warnings.c":  {}, // no main
   957  		"73_arm64.c":                {}, // does not work properly on any gcc tested (7-11)
   958  		"77_push_pop_macro.c":       {}, // unsupported push/pop macro
   959  		"78_vla_label.c":            {}, //MAYBE
   960  		"79_vla_continue.c":         {}, //MAYBE
   961  		"80_flexarray.c":            {}, //MAYBE
   962  		"83_utf8_in_identifiers.c":  {}, // No support before gcc 10.
   963  		"85_asm-outside-function.c": {}, // asm
   964  		"90_struct-init.c":          {}, // 90_struct-init.c:168:25: `...`: expected ]
   965  		"94_generic.c":              {}, // 94_generic.c:36:18: `int`: expected primary-expression
   966  		"96_nodata_wanted.c":        {}, // no main
   967  		"98_al_ax_extend.c":         {}, // asm
   968  		"99_fastcall.c":             {}, // asm
   969  
   970  		"95_bitfields_ms.c": {}, //TODO
   971  	}
   972  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
   973  		blacklist["95_bitfields.c"] = struct{}{} //TODO
   974  	}
   975  	var rq, res, ok int
   976  	limit := runtime.GOMAXPROCS(0)
   977  	limiter := make(chan struct{}, limit)
   978  	results := make(chan *runResult, limit)
   979  	failed := map[string]struct{}{}
   980  	err = walk(root, func(pth string, fi os.FileInfo) error {
   981  		if !strings.HasSuffix(pth, ".c") {
   982  			return nil
   983  		}
   984  
   985  		switch {
   986  		case re != nil:
   987  			if !re.MatchString(pth) {
   988  				return nil
   989  			}
   990  		default:
   991  			if _, ok := blacklist[filepath.Base(pth)]; ok {
   992  				return nil
   993  			}
   994  		}
   995  
   996  	more:
   997  		select {
   998  		case r := <-results:
   999  			res++
  1000  			<-limiter
  1001  			switch r.err.(type) {
  1002  			case nil:
  1003  				ok++
  1004  				delete(failed, r.name)
  1005  			case skipErr:
  1006  				delete(failed, r.name)
  1007  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1008  			default:
  1009  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1010  			}
  1011  			goto more
  1012  		case limiter <- struct{}{}:
  1013  			rq++
  1014  			if *oTrc {
  1015  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1016  			}
  1017  			failed[pth] = struct{}{}
  1018  			go run(pth, false, false, false, results)
  1019  		}
  1020  		return nil
  1021  	})
  1022  	if err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  	for res != rq {
  1026  		r := <-results
  1027  		res++
  1028  		<-limiter
  1029  		switch r.err.(type) {
  1030  		case nil:
  1031  			ok++
  1032  			delete(failed, r.name)
  1033  		case skipErr:
  1034  			delete(failed, r.name)
  1035  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1036  		default:
  1037  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1038  		}
  1039  	}
  1040  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1041  	if len(failed) == 0 {
  1042  		return
  1043  	}
  1044  
  1045  	var a []string
  1046  	for k := range failed {
  1047  		a = append(a, k)
  1048  	}
  1049  	sort.Strings(a)
  1050  	for _, v := range a {
  1051  		t.Logf("FAIL %s", v)
  1052  	}
  1053  }
  1054  
  1055  func needFiles(t *testing.T, root string, a []string) {
  1056  	for _, v := range a {
  1057  		overlay := filepath.Join(overlayDir, filepath.FromSlash(root), v)
  1058  		b, err := ioutil.ReadFile(overlay)
  1059  		if err != nil {
  1060  			if !os.IsNotExist(err) {
  1061  				t.Fatal(err)
  1062  			}
  1063  
  1064  			f, err := fs.Open(path.Join(root, v))
  1065  			if err != nil {
  1066  				t.Fatal(err)
  1067  			}
  1068  
  1069  			if b, err = ioutil.ReadAll(f); err != nil {
  1070  				t.Fatal(err)
  1071  			}
  1072  
  1073  			if err = f.Close(); err != nil {
  1074  				t.Fatal(err)
  1075  			}
  1076  		}
  1077  		if dir, _ := filepath.Split(v); dir != "" {
  1078  			if err := os.MkdirAll(dir, 0700); err != nil {
  1079  				t.Fatal(err)
  1080  			}
  1081  		}
  1082  
  1083  		if err := ioutil.WriteFile(v, b, 0600); err != nil {
  1084  			t.Fatal(err)
  1085  		}
  1086  	}
  1087  }
  1088  
  1089  func TestCCGo(t *testing.T) {
  1090  	const root = "/ccgo/bug"
  1091  	mustEmptyDir(t, tempDir)
  1092  	wd, err := os.Getwd()
  1093  	if err != nil {
  1094  		t.Fatal(err)
  1095  	}
  1096  
  1097  	if err := os.Chdir(tempDir); err != nil {
  1098  		t.Fatal(err)
  1099  	}
  1100  
  1101  	defer func() {
  1102  		if err := os.Chdir(wd); err != nil {
  1103  			t.Fatal(err)
  1104  		}
  1105  	}()
  1106  
  1107  	blacklist := map[string]struct{}{}
  1108  	var rq, res, ok int
  1109  	limit := runtime.GOMAXPROCS(0)
  1110  	limiter := make(chan struct{}, limit)
  1111  	results := make(chan *runResult, limit)
  1112  	failed := map[string]struct{}{}
  1113  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1114  		if !strings.HasSuffix(pth, ".c") {
  1115  			return nil
  1116  		}
  1117  
  1118  		switch {
  1119  		case re != nil:
  1120  			if !re.MatchString(pth) {
  1121  				return nil
  1122  			}
  1123  		default:
  1124  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1125  				return nil
  1126  			}
  1127  		}
  1128  
  1129  	more:
  1130  		select {
  1131  		case r := <-results:
  1132  			res++
  1133  			<-limiter
  1134  			switch r.err.(type) {
  1135  			case nil:
  1136  				ok++
  1137  				delete(failed, r.name)
  1138  			case skipErr:
  1139  				delete(failed, r.name)
  1140  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1141  			default:
  1142  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1143  			}
  1144  			goto more
  1145  		case limiter <- struct{}{}:
  1146  			rq++
  1147  			if *oTrc {
  1148  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1149  			}
  1150  			failed[pth] = struct{}{}
  1151  			go run(pth, false, false, false, results)
  1152  		}
  1153  		return nil
  1154  	})
  1155  	if err != nil {
  1156  		t.Fatal(err)
  1157  	}
  1158  	for res != rq {
  1159  		r := <-results
  1160  		res++
  1161  		<-limiter
  1162  		switch r.err.(type) {
  1163  		case nil:
  1164  			ok++
  1165  			delete(failed, r.name)
  1166  		case skipErr:
  1167  			delete(failed, r.name)
  1168  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1169  		default:
  1170  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1171  		}
  1172  	}
  1173  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1174  	if len(failed) == 0 {
  1175  		return
  1176  	}
  1177  
  1178  	var a []string
  1179  	for k := range failed {
  1180  		a = append(a, k)
  1181  	}
  1182  	sort.Strings(a)
  1183  	for _, v := range a {
  1184  		t.Logf("FAIL %s", v)
  1185  	}
  1186  }
  1187  
  1188  func TestMirBenchmarks(t *testing.T) {
  1189  	const root = "/github.com/vnmakarov/mir/c-benchmarks"
  1190  	mustEmptyDir(t, tempDir)
  1191  	wd, err := os.Getwd()
  1192  	if err != nil {
  1193  		t.Fatal(err)
  1194  	}
  1195  
  1196  	if err := os.Chdir(tempDir); err != nil {
  1197  		t.Fatal(err)
  1198  	}
  1199  
  1200  	defer func() {
  1201  		if err := os.Chdir(wd); err != nil {
  1202  			t.Fatal(err)
  1203  		}
  1204  	}()
  1205  
  1206  	needFiles(t, root, []string{
  1207  		"simple_hash.h",
  1208  	})
  1209  	blacklist := map[string]struct{}{}
  1210  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  1211  		blacklist["except.c"] = struct{}{} //TODO
  1212  	}
  1213  	binary := map[string]bool{
  1214  		"mandelbrot.c": true,
  1215  	}
  1216  	var rq, res, ok int
  1217  	limit := runtime.GOMAXPROCS(0)
  1218  	limiter := make(chan struct{}, limit)
  1219  	results := make(chan *runResult, limit)
  1220  	failed := map[string]struct{}{}
  1221  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1222  		if !strings.HasSuffix(pth, ".c") {
  1223  			return nil
  1224  		}
  1225  
  1226  		switch {
  1227  		case re != nil:
  1228  			if !re.MatchString(pth) {
  1229  				return nil
  1230  			}
  1231  		default:
  1232  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1233  				return nil
  1234  			}
  1235  		}
  1236  
  1237  	more:
  1238  		select {
  1239  		case r := <-results:
  1240  			res++
  1241  			<-limiter
  1242  			switch r.err.(type) {
  1243  			case nil:
  1244  				ok++
  1245  				delete(failed, r.name)
  1246  			case skipErr:
  1247  				delete(failed, r.name)
  1248  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1249  			default:
  1250  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1251  			}
  1252  			goto more
  1253  		case limiter <- struct{}{}:
  1254  			rq++
  1255  			if *oTrc {
  1256  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1257  			}
  1258  			failed[pth] = struct{}{}
  1259  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1260  		}
  1261  		return nil
  1262  	})
  1263  	if err != nil {
  1264  		t.Fatal(err)
  1265  	}
  1266  	for res != rq {
  1267  		r := <-results
  1268  		res++
  1269  		<-limiter
  1270  		switch r.err.(type) {
  1271  		case nil:
  1272  			ok++
  1273  			delete(failed, r.name)
  1274  		case skipErr:
  1275  			delete(failed, r.name)
  1276  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1277  		default:
  1278  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1279  		}
  1280  	}
  1281  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1282  	if len(failed) == 0 {
  1283  		return
  1284  	}
  1285  
  1286  	var a []string
  1287  	for k := range failed {
  1288  		a = append(a, k)
  1289  	}
  1290  	sort.Strings(a)
  1291  	for _, v := range a {
  1292  		t.Logf("FAIL %s", v)
  1293  	}
  1294  }
  1295  
  1296  func TestMirAndrewChambers(t *testing.T) {
  1297  	const root = "/github.com/vnmakarov/mir/c-tests/andrewchambers_c"
  1298  	mustEmptyDir(t, tempDir)
  1299  	wd, err := os.Getwd()
  1300  	if err != nil {
  1301  		t.Fatal(err)
  1302  	}
  1303  
  1304  	if err := os.Chdir(tempDir); err != nil {
  1305  		t.Fatal(err)
  1306  	}
  1307  
  1308  	defer func() {
  1309  		if err := os.Chdir(wd); err != nil {
  1310  			t.Fatal(err)
  1311  		}
  1312  	}()
  1313  
  1314  	blacklist := map[string]struct{}{}
  1315  	binary := map[string]bool{}
  1316  	var rq, res, ok int
  1317  	limit := runtime.GOMAXPROCS(0)
  1318  	limiter := make(chan struct{}, limit)
  1319  	results := make(chan *runResult, limit)
  1320  	failed := map[string]struct{}{}
  1321  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1322  		if !strings.HasSuffix(pth, ".c") {
  1323  			return nil
  1324  		}
  1325  
  1326  		switch {
  1327  		case re != nil:
  1328  			if !re.MatchString(pth) {
  1329  				return nil
  1330  			}
  1331  		default:
  1332  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1333  				return nil
  1334  			}
  1335  		}
  1336  
  1337  	more:
  1338  		select {
  1339  		case r := <-results:
  1340  			res++
  1341  			<-limiter
  1342  			switch r.err.(type) {
  1343  			case nil:
  1344  				ok++
  1345  				delete(failed, r.name)
  1346  			case skipErr:
  1347  				delete(failed, r.name)
  1348  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1349  			default:
  1350  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1351  			}
  1352  			goto more
  1353  		case limiter <- struct{}{}:
  1354  			rq++
  1355  			if *oTrc {
  1356  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1357  			}
  1358  			failed[pth] = struct{}{}
  1359  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1360  		}
  1361  		return nil
  1362  	})
  1363  	if err != nil {
  1364  		t.Fatal(err)
  1365  	}
  1366  	for res != rq {
  1367  		r := <-results
  1368  		res++
  1369  		<-limiter
  1370  		switch r.err.(type) {
  1371  		case nil:
  1372  			ok++
  1373  			delete(failed, r.name)
  1374  		case skipErr:
  1375  			delete(failed, r.name)
  1376  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1377  		default:
  1378  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1379  		}
  1380  	}
  1381  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1382  	if len(failed) == 0 {
  1383  		return
  1384  	}
  1385  
  1386  	var a []string
  1387  	for k := range failed {
  1388  		a = append(a, k)
  1389  	}
  1390  	sort.Strings(a)
  1391  	for _, v := range a {
  1392  		t.Logf("FAIL %s", v)
  1393  	}
  1394  }
  1395  
  1396  func TestMirLacc(t *testing.T) {
  1397  	const root = "/github.com/vnmakarov/mir/c-tests/lacc"
  1398  	mustEmptyDir(t, tempDir)
  1399  	wd, err := os.Getwd()
  1400  	if err != nil {
  1401  		t.Fatal(err)
  1402  	}
  1403  
  1404  	if err := os.Chdir(tempDir); err != nil {
  1405  		t.Fatal(err)
  1406  	}
  1407  
  1408  	defer func() {
  1409  		if err := os.Chdir(wd); err != nil {
  1410  			t.Fatal(err)
  1411  		}
  1412  	}()
  1413  
  1414  	needFiles(t, root, []string{
  1415  		"hello.c",
  1416  		"header.h",
  1417  	})
  1418  	blacklist := map[string]struct{}{
  1419  		"function-incomplete.c": {}, // Calls int foo(char*) without argument, no intent to support.
  1420  
  1421  		"macro-repeat-expand.c": {}, //TODO
  1422  		"pointer-immediate.c":   {}, //TODO
  1423  		"string-addr.c":         {}, //TODO
  1424  		"string-conversion.c":   {}, //TODO
  1425  		"strings.c":             {}, //TODO
  1426  	}
  1427  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
  1428  		blacklist["assignment-type.c"] = struct{}{}         //TODO
  1429  		blacklist["bitfield-basic.c"] = struct{}{}          //TODO
  1430  		blacklist["bitfield-load.c"] = struct{}{}           //TODO
  1431  		blacklist["bitfield-pack-next.c"] = struct{}{}      //TODO
  1432  		blacklist["bitfield-packing.c"] = struct{}{}        //TODO
  1433  		blacklist["bitfield-types-init.c"] = struct{}{}     //TODO
  1434  		blacklist["bitfield-types.c"] = struct{}{}          //TODO
  1435  		blacklist["cast-immediate-truncate.c"] = struct{}{} //TODO
  1436  		blacklist["comment.c"] = struct{}{}                 //TODO
  1437  		blacklist["convert-unsigned-float.c"] = struct{}{}  //TODO
  1438  		blacklist["function-char-args.c"] = struct{}{}      //TODO
  1439  		blacklist["return-bitfield.c"] = struct{}{}         //TODO
  1440  		blacklist["stringify.c"] = struct{}{}               //TODO
  1441  		blacklist["struct-comma-call.c"] = struct{}{}       //TODO
  1442  		blacklist["token.c"] = struct{}{}                   //TODO
  1443  		blacklist["union-bitfield.c"] = struct{}{}          //TODO
  1444  	}
  1445  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  1446  		blacklist["bitfield-basic.c"] = struct{}{}         //TODO
  1447  		blacklist["bitfield-pack-next.c"] = struct{}{}     //TODO
  1448  		blacklist["bitfield-trailing-zero.c"] = struct{}{} //TODO
  1449  		blacklist["bitfield-types-init.c"] = struct{}{}    //TODO
  1450  		blacklist["constant-expression.c"] = struct{}{}    //TODO
  1451  		blacklist["ptrdiff.c"] = struct{}{}                //TODO
  1452  		blacklist["signed-division.c"] = struct{}{}        //TODO
  1453  	}
  1454  	if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
  1455  		blacklist["bitfield-pack-next.c"] = struct{}{}  //TODO
  1456  		blacklist["bitfield-types-init.c"] = struct{}{} //TODO
  1457  	}
  1458  	if runtime.GOOS == "linux" && runtime.GOARCH == "arm" {
  1459  		blacklist["assignment-type.c"] = struct{}{}         //TODO
  1460  		blacklist["bitfield-basic.c"] = struct{}{}          //TODO
  1461  		blacklist["bitfield-trailing-zero.c"] = struct{}{}  //TODO
  1462  		blacklist["bitfield-types-init.c"] = struct{}{}     //TODO
  1463  		blacklist["cast-immediate-truncate.c"] = struct{}{} //TODO
  1464  		blacklist["function-char-args.c"] = struct{}{}      //TODO
  1465  		blacklist["stringify.c"] = struct{}{}               //TODO
  1466  	}
  1467  	if runtime.GOOS == "linux" && runtime.GOARCH == "arm64" {
  1468  		blacklist["assignment-type.c"] = struct{}{}         //TODO
  1469  		blacklist["bitfield-basic.c"] = struct{}{}          //TODO
  1470  		blacklist["bitfield-trailing-zero.c"] = struct{}{}  //TODO
  1471  		blacklist["bitfield-types-init.c"] = struct{}{}     //TODO
  1472  		blacklist["cast-immediate-truncate.c"] = struct{}{} //TODO
  1473  		blacklist["function-char-args.c"] = struct{}{}      //TODO
  1474  		blacklist["stringify.c"] = struct{}{}               //TODO
  1475  	}
  1476  	binary := map[string]bool{}
  1477  	var rq, res, ok int
  1478  	limit := runtime.GOMAXPROCS(0)
  1479  	limiter := make(chan struct{}, limit)
  1480  	results := make(chan *runResult, limit)
  1481  	failed := map[string]struct{}{}
  1482  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1483  		if !strings.HasSuffix(pth, ".c") {
  1484  			return nil
  1485  		}
  1486  
  1487  		switch {
  1488  		case re != nil:
  1489  			if !re.MatchString(pth) {
  1490  				return nil
  1491  			}
  1492  		default:
  1493  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1494  				return nil
  1495  			}
  1496  		}
  1497  
  1498  	more:
  1499  		select {
  1500  		case r := <-results:
  1501  			res++
  1502  			<-limiter
  1503  			switch r.err.(type) {
  1504  			case nil:
  1505  				ok++
  1506  				delete(failed, r.name)
  1507  			case skipErr:
  1508  				delete(failed, r.name)
  1509  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1510  			default:
  1511  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1512  			}
  1513  			goto more
  1514  		case limiter <- struct{}{}:
  1515  			rq++
  1516  			if *oTrc {
  1517  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1518  			}
  1519  			failed[pth] = struct{}{}
  1520  			go run(pth, binary[filepath.Base(pth)], false, false, results, "-trigraphs") // comment.c needs trigraphs
  1521  		}
  1522  		return nil
  1523  	})
  1524  	if err != nil {
  1525  		t.Fatal(err)
  1526  	}
  1527  	for res != rq {
  1528  		r := <-results
  1529  		res++
  1530  		<-limiter
  1531  		switch r.err.(type) {
  1532  		case nil:
  1533  			ok++
  1534  			delete(failed, r.name)
  1535  		case skipErr:
  1536  			delete(failed, r.name)
  1537  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1538  		default:
  1539  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1540  		}
  1541  	}
  1542  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1543  	if len(failed) == 0 {
  1544  		return
  1545  	}
  1546  
  1547  	var a []string
  1548  	for k := range failed {
  1549  		a = append(a, k)
  1550  	}
  1551  	sort.Strings(a)
  1552  	for _, v := range a {
  1553  		t.Logf("FAIL %s", v)
  1554  	}
  1555  }
  1556  
  1557  func TestMirNew(t *testing.T) {
  1558  	const root = "/github.com/vnmakarov/mir/c-tests/new"
  1559  	mustEmptyDir(t, tempDir)
  1560  	wd, err := os.Getwd()
  1561  	if err != nil {
  1562  		t.Fatal(err)
  1563  	}
  1564  
  1565  	if err := os.Chdir(tempDir); err != nil {
  1566  		t.Fatal(err)
  1567  	}
  1568  
  1569  	defer func() {
  1570  		if err := os.Chdir(wd); err != nil {
  1571  			t.Fatal(err)
  1572  		}
  1573  	}()
  1574  
  1575  	blacklist := map[string]struct{}{
  1576  		// 1: /github.com/vnmakarov/mir/c-tests/new/endif.c
  1577  		//     all_test.go:1045: /github.com/vnmakarov/mir/c-tests/new/endif.c: /usr/bin/gcc: system C compiler: exit status 1
  1578  		//         endif.c:1:2: error: #endif without #if
  1579  		//          #endif
  1580  		//           ^~~~~
  1581  		"endif.c": {}, // No intent to support.
  1582  
  1583  		// 1: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c
  1584  		//     all_test.go:1051: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c: /usr/bin/gcc: system C compiler: exit status 1
  1585  		//         fermian-2.c:1:3: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
  1586  		//          a {
  1587  		//            ^
  1588  		"fermian-2.c": {}, // No intent to support.
  1589  		"fermian.c":   {}, // No main.
  1590  
  1591  		"array-elem-addr-in-initializer.c": {}, //TODO
  1592  		"issue117.c":                       {}, //TODO
  1593  		"issue23.c":                        {}, //TODO
  1594  	}
  1595  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  1596  		blacklist["setjmp2.c"] = struct{}{} //TODO
  1597  	}
  1598  	binary := map[string]bool{}
  1599  	var rq, res, ok int
  1600  	limit := runtime.GOMAXPROCS(0)
  1601  	limiter := make(chan struct{}, limit)
  1602  	results := make(chan *runResult, limit)
  1603  	failed := map[string]struct{}{}
  1604  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1605  		if !strings.HasSuffix(pth, ".c") {
  1606  			return nil
  1607  		}
  1608  
  1609  		switch {
  1610  		case re != nil:
  1611  			if !re.MatchString(pth) {
  1612  				return nil
  1613  			}
  1614  		default:
  1615  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1616  				return nil
  1617  			}
  1618  		}
  1619  
  1620  	more:
  1621  		select {
  1622  		case r := <-results:
  1623  			res++
  1624  			<-limiter
  1625  			switch r.err.(type) {
  1626  			case nil:
  1627  				ok++
  1628  				delete(failed, r.name)
  1629  			case skipErr:
  1630  				delete(failed, r.name)
  1631  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1632  			default:
  1633  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1634  			}
  1635  			goto more
  1636  		case limiter <- struct{}{}:
  1637  			rq++
  1638  			if *oTrc {
  1639  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1640  			}
  1641  			failed[pth] = struct{}{}
  1642  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1643  		}
  1644  		return nil
  1645  	})
  1646  	if err != nil {
  1647  		t.Fatal(err)
  1648  	}
  1649  	for res != rq {
  1650  		r := <-results
  1651  		res++
  1652  		<-limiter
  1653  		switch r.err.(type) {
  1654  		case nil:
  1655  			ok++
  1656  			delete(failed, r.name)
  1657  		case skipErr:
  1658  			delete(failed, r.name)
  1659  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1660  		default:
  1661  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1662  		}
  1663  	}
  1664  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1665  	if len(failed) == 0 {
  1666  		return
  1667  	}
  1668  
  1669  	var a []string
  1670  	for k := range failed {
  1671  		a = append(a, k)
  1672  	}
  1673  	sort.Strings(a)
  1674  	for _, v := range a {
  1675  		t.Logf("FAIL %s", v)
  1676  	}
  1677  }
  1678  
  1679  func TestCompCert(t *testing.T) {
  1680  	const root = "/github.com/AbsInt/CompCert/test/c/"
  1681  	mustEmptyDir(t, tempDir)
  1682  	wd, err := os.Getwd()
  1683  	if err != nil {
  1684  		t.Fatal(err)
  1685  	}
  1686  
  1687  	if err := os.Chdir(tempDir); err != nil {
  1688  		t.Fatal(err)
  1689  	}
  1690  
  1691  	defer func() {
  1692  		if err := os.Chdir(wd); err != nil {
  1693  			t.Fatal(err)
  1694  		}
  1695  	}()
  1696  
  1697  	needFiles(t, root, []string{
  1698  		"Results/knucleotide-input.txt",
  1699  		"endian.h",
  1700  	})
  1701  	blacklist := map[string]struct{}{}
  1702  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
  1703  		blacklist["aes.c"] = struct{}{} //TODO
  1704  	}
  1705  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  1706  		blacklist["qsort.c"] = struct{}{} //TODO
  1707  	}
  1708  	binary := map[string]bool{
  1709  		"mandelbrot.c": true,
  1710  	}
  1711  	var rq, res, ok int
  1712  	limit := runtime.GOMAXPROCS(0)
  1713  	limiter := make(chan struct{}, limit)
  1714  	results := make(chan *runResult, limit)
  1715  	failed := map[string]struct{}{}
  1716  	err = walk(root, func(pth string, fi os.FileInfo) error {
  1717  		if !strings.HasSuffix(pth, ".c") {
  1718  			return nil
  1719  		}
  1720  
  1721  		switch {
  1722  		case re != nil:
  1723  			if !re.MatchString(pth) {
  1724  				return nil
  1725  			}
  1726  		default:
  1727  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  1728  				return nil
  1729  			}
  1730  		}
  1731  
  1732  	more:
  1733  		select {
  1734  		case r := <-results:
  1735  			res++
  1736  			<-limiter
  1737  			switch r.err.(type) {
  1738  			case nil:
  1739  				ok++
  1740  				delete(failed, r.name)
  1741  			case skipErr:
  1742  				delete(failed, r.name)
  1743  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1744  			default:
  1745  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1746  			}
  1747  			goto more
  1748  		case limiter <- struct{}{}:
  1749  			rq++
  1750  			if *oTrc {
  1751  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  1752  			}
  1753  			failed[pth] = struct{}{}
  1754  			go run(pth, binary[filepath.Base(pth)], false, false, results)
  1755  		}
  1756  		return nil
  1757  	})
  1758  	if err != nil {
  1759  		t.Fatal(err)
  1760  	}
  1761  	for res != rq {
  1762  		r := <-results
  1763  		res++
  1764  		<-limiter
  1765  		switch r.err.(type) {
  1766  		case nil:
  1767  			ok++
  1768  			delete(failed, r.name)
  1769  		case skipErr:
  1770  			delete(failed, r.name)
  1771  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  1772  		default:
  1773  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  1774  		}
  1775  	}
  1776  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  1777  	if len(failed) == 0 {
  1778  		return
  1779  	}
  1780  
  1781  	var a []string
  1782  	for k := range failed {
  1783  		a = append(a, k)
  1784  	}
  1785  	sort.Strings(a)
  1786  	for _, v := range a {
  1787  		t.Logf("FAIL %s", v)
  1788  	}
  1789  }
  1790  
  1791  func TestGCCExecute(t *testing.T) {
  1792  	const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute"
  1793  	mustEmptyDir(t, tempDir)
  1794  	wd, err := os.Getwd()
  1795  	if err != nil {
  1796  		t.Fatal(err)
  1797  	}
  1798  
  1799  	if err := os.Chdir(tempDir); err != nil {
  1800  		t.Fatal(err)
  1801  	}
  1802  
  1803  	defer func() {
  1804  		if err := os.Chdir(wd); err != nil {
  1805  			t.Fatal(err)
  1806  		}
  1807  	}()
  1808  
  1809  	// Prepare testdata
  1810  	needFiles(t, root, []string{
  1811  		"20040709-2.c",
  1812  	})
  1813  	blacklist := map[string]struct{}{
  1814  		"eeprof-1.c": {}, // Requires -finstrument-functions
  1815  		"pr64242.c":  {}, // Depends on specific stack corruption.
  1816  
  1817  		// assembler
  1818  		"20001009-2.c": {}, //TODO
  1819  		"20020107-1.c": {}, //TODO
  1820  		"20050203-1.c": {}, //TODO
  1821  		"20061031-1.c": {}, //TODO
  1822  		"20071211-1.c": {}, //TODO
  1823  		"20071220-1.c": {}, //TODO
  1824  		"20071220-2.c": {}, //TODO
  1825  		"20080122-1.c": {}, //TODO
  1826  		"960312-1.c":   {}, //TODO
  1827  		"990130-1.c":   {}, //TODO
  1828  		"990413-2.c":   {}, //TODO
  1829  		"bitfld-5.c":   {}, //TODO
  1830  		"pr38533.c":    {}, //TODO
  1831  		"pr40022.c":    {}, //TODO
  1832  		"pr40657.c":    {}, //TODO
  1833  		"pr41239.c":    {}, //TODO
  1834  		"pr43385.c":    {}, //TODO
  1835  		"pr43560.c":    {}, //TODO
  1836  		"pr44852.c":    {}, //TODO
  1837  		"pr45695.c":    {}, //TODO
  1838  		"pr46309.c":    {}, //TODO
  1839  		"pr47925.c":    {}, //TODO
  1840  		"pr49218.c":    {}, //TODO
  1841  		"pr49279.c":    {}, //TODO
  1842  		"pr49390.c":    {}, //TODO
  1843  		"pr51581-1.c":  {}, //TODO
  1844  		"pr51581-2.c":  {}, //TODO
  1845  		"pr51877.c":    {}, //TODO
  1846  		"pr51933.c":    {}, //TODO
  1847  		"pr52286.c":    {}, //TODO
  1848  		"pr56205.c":    {}, //TODO
  1849  		"pr56866.c":    {}, //TODO
  1850  		"pr56982.c":    {}, //TODO
  1851  		"pr57344-1.c":  {}, //TODO
  1852  		"pr57344-2.c":  {}, //TODO
  1853  		"pr57344-3.c":  {}, //TODO
  1854  		"pr57344-4.c":  {}, //TODO
  1855  		"pr58277-1.c":  {}, //TODO
  1856  		"pr58419.c":    {}, //TODO
  1857  		"pr63641.c":    {}, //TODO
  1858  		"pr65053-1.c":  {}, //TODO
  1859  		"pr65053-2.c":  {}, //TODO
  1860  		"pr65648.c":    {}, //TODO
  1861  		"pr65956.c":    {}, //TODO
  1862  		"pr68328.c":    {}, //TODO
  1863  		"pr69320-2.c":  {}, //TODO
  1864  		"pr69691.c":    {}, //TODO
  1865  		"pr78438.c":    {}, //TODO
  1866  		"pr78726.c":    {}, //TODO
  1867  		"pr79354.c":    {}, //TODO
  1868  		"pr79737-2.c":  {}, //TODO
  1869  		"pr80421.c":    {}, //TODO
  1870  		"pr81588.c":    {}, //TODO
  1871  		"pr82954.c":    {}, //TODO
  1872  		"pr84478.c":    {}, //TODO
  1873  		"pr84524.c":    {}, //TODO
  1874  		"pr85156.c":    {}, //TODO
  1875  		"pr85756.c":    {}, //TODO
  1876  		"pr88904.c":    {}, //TODO
  1877  		"pr93945.c":    {}, //TODO
  1878  		"pr94130.c":    {}, //TODO
  1879  		"stkalign.c":   {}, //TODO
  1880  
  1881  		// variable type size
  1882  		"20010209-1.c":    {}, //TODO
  1883  		"20020412-1.c":    {}, //TODO
  1884  		"20040308-1.c":    {}, //TODO
  1885  		"20040411-1.c":    {}, //TODO
  1886  		"20040423-1.c":    {}, //TODO
  1887  		"20040811-1.c":    {}, //TODO
  1888  		"20041218-2.c":    {}, //TODO
  1889  		"20070919-1.c":    {}, //TODO
  1890  		"920721-2.c":      {}, //TODO
  1891  		"920929-1.c":      {}, //TODO
  1892  		"970217-1.c":      {}, //TODO
  1893  		"align-nest.c":    {}, //TODO
  1894  		"pr22061-1.c":     {}, //TODO
  1895  		"pr41935.c":       {}, //TODO
  1896  		"pr43220.c":       {}, //TODO
  1897  		"pr77767.c":       {}, //TODO
  1898  		"pr82210.c":       {}, //TODO
  1899  		"vla-dealloc-1.c": {}, //TODO
  1900  
  1901  		// vector
  1902  		"20050316-1.c":   {}, //TODO
  1903  		"20050316-2.c":   {}, //TODO
  1904  		"20050316-3.c":   {}, //TODO
  1905  		"20050604-1.c":   {}, //TODO
  1906  		"20050607-1.c":   {}, //TODO
  1907  		"20060420-1.c":   {}, //TODO
  1908  		"pr23135.c":      {}, //TODO
  1909  		"pr53645-2.c":    {}, //TODO
  1910  		"pr53645.c":      {}, //TODO
  1911  		"pr60960.c":      {}, //TODO
  1912  		"pr65427.c":      {}, //TODO
  1913  		"pr70903.c":      {}, //TODO
  1914  		"pr71626-1.c":    {}, //TODO
  1915  		"pr71626-2.c":    {}, //TODO
  1916  		"pr85169.c":      {}, //TODO
  1917  		"pr85331.c":      {}, //TODO
  1918  		"pr92618.c":      {}, //TODO
  1919  		"pr94412.c":      {}, //TODO
  1920  		"pr94524-1.c":    {}, //TODO
  1921  		"pr94524-2.c":    {}, //TODO
  1922  		"pr94591.c":      {}, //TODO
  1923  		"scal-to-vec1.c": {}, //TODO
  1924  		"scal-to-vec2.c": {}, //TODO
  1925  		"scal-to-vec3.c": {}, //TODO
  1926  		"simd-1.c":       {}, //TODO
  1927  		"simd-2.c":       {}, //TODO
  1928  		"simd-4.c":       {}, //TODO
  1929  		"simd-5.c":       {}, //TODO
  1930  		"simd-6.c":       {}, //TODO
  1931  
  1932  		// #pragma push_macro("_")
  1933  		"pushpop_macro.c": {}, //TODO
  1934  
  1935  		// __attribute__ ((alias("a")))
  1936  		"alias-2.c": {}, //TODO
  1937  		"alias-3.c": {}, //TODO
  1938  		"alias-4.c": {}, //TODO
  1939  
  1940  		// assignment to expression with array type
  1941  		"pr64979.c": {}, //TODO
  1942  
  1943  		// argument 3 in call to function ‘__builtin_mul_overflow’ does not have pointer to integral type
  1944  		"pr64006.c":   {}, //TODO
  1945  		"pr68381.c":   {}, //TODO
  1946  		"pr71554.c":   {}, //TODO
  1947  		"pr85095.c":   {}, //TODO
  1948  		"pr89434.c":   {}, //TODO
  1949  		"pr90311.c":   {}, //TODO
  1950  		"pr91450-1.c": {}, //TODO
  1951  		"pr91450-2.c": {}, //TODO
  1952  		"pr91635.c":   {}, //TODO
  1953  		"pr93494.c":   {}, //TODO
  1954  
  1955  		// __builtin_va_arg_pack
  1956  		"va-arg-pack-1.c": {}, //TODO
  1957  
  1958  		// __complex__ types
  1959  		"20010605-2.c": {}, //TODO
  1960  		"20020227-1.c": {}, //TODO
  1961  		"20020411-1.c": {}, //TODO
  1962  		"20030910-1.c": {}, //TODO
  1963  		"20041124-1.c": {}, //TODO
  1964  		"20041201-1.c": {}, //TODO
  1965  		"20050121-1.c": {}, //TODO
  1966  		"20070614-1.c": {}, //TODO
  1967  		"960512-1.c":   {}, //TODO
  1968  		"complex-1.c":  {}, //TODO
  1969  		"complex-2.c":  {}, //TODO
  1970  		"complex-4.c":  {}, //TODO
  1971  		"complex-5.c":  {}, //TODO
  1972  		"complex-6.c":  {}, //TODO
  1973  		"complex-7.c":  {}, //TODO
  1974  		"pr38151.c":    {}, //TODO
  1975  		"pr38969.c":    {}, //TODO
  1976  		"pr42248.c":    {}, //TODO
  1977  		"pr49644.c":    {}, //TODO
  1978  		"pr56837.c":    {}, //TODO
  1979  
  1980  		// &&label or __label__
  1981  		"20040302-1.c":  {},
  1982  		"20041214-1.c":  {},
  1983  		"20071210-1.c":  {},
  1984  		"920302-1.c":    {},
  1985  		"920415-1.c":    {},
  1986  		"920428-2.c":    {},
  1987  		"920501-4.c":    {},
  1988  		"920501-5.c":    {},
  1989  		"920501-7.c":    {},
  1990  		"920721-4.c":    {},
  1991  		"930406-1.c":    {},
  1992  		"980526-1.c":    {},
  1993  		"990208-1.c":    {},
  1994  		"comp-goto-1.c": {},
  1995  		"comp-goto-2.c": {},
  1996  		"pr24135.c":     {},
  1997  		"pr51447.c":     {},
  1998  		"pr70460.c":     {},
  1999  		"pr71494.c":     {},
  2000  
  2001  		// local func def
  2002  		"20000822-1.c":   {},
  2003  		"20010605-1.c":   {},
  2004  		"20030501-1.c":   {},
  2005  		"20040520-1.c":   {},
  2006  		"20061220-1.c":   {},
  2007  		"20090219-1.c":   {},
  2008  		"920612-2.c":     {},
  2009  		"921017-1.c":     {},
  2010  		"921215-1.c":     {},
  2011  		"931002-1.c":     {},
  2012  		"nest-align-1.c": {},
  2013  		"nest-stdar-1.c": {},
  2014  		"nestfunc-1.c":   {},
  2015  		"nestfunc-2.c":   {},
  2016  		"nestfunc-3.c":   {},
  2017  		"nestfunc-5.c":   {},
  2018  		"nestfunc-6.c":   {},
  2019  		"nestfunc-7.c":   {},
  2020  		"pr22061-3.c":    {},
  2021  		"pr22061-4.c":    {},
  2022  
  2023  		// goto * expr;
  2024  		"920501-3.c": {},
  2025  
  2026  		// Flexible array member
  2027  		"20010924-1.c": {},
  2028  		"20030109-1.c": {},
  2029  		"20050613-1.c": {},
  2030  		"pr28865.c":    {},
  2031  		"pr33382.c":    {},
  2032  
  2033  		// __builtin_classify_type
  2034  		"20040709-1.c": {},
  2035  		"20040709-2.c": {},
  2036  		"20040709-3.c": {},
  2037  
  2038  		// LabeledStatementRange
  2039  		"pr34154.c": {},
  2040  
  2041  		// __builtin_apply
  2042  		"pr47237.c": {},
  2043  
  2044  		// 128 bit int/uint
  2045  		"pr54471.c":   {},
  2046  		"pr61375.c":   {},
  2047  		"pr63302.c":   {},
  2048  		"pr65170.c":   {},
  2049  		"pr84169.c":   {},
  2050  		"pr84748.c":   {},
  2051  		"pr85582-2.c": {},
  2052  		"pr85582-3.c": {},
  2053  		"pr92904.c":   {},
  2054  		"pr93213.c":   {},
  2055  		"pr98474.c":   {},
  2056  
  2057  		// _Decimal64
  2058  		"pr80692.c": {},
  2059  
  2060  		"builtin-types-compatible-p.c": {}, //TODO
  2061  		"call-trap-1.c":                {}, //TODO
  2062  		"pr70602.c":                    {}, //TODO
  2063  		"pr71700.c":                    {}, //TODO
  2064  
  2065  		"vfprintf-chk-1.c": {}, //TODO va_list (nuc_64 only)
  2066  	}
  2067  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
  2068  		blacklist["20020201-1.c"] = struct{}{} //TODO
  2069  		blacklist["20020226-1.c"] = struct{}{} //TODO
  2070  		blacklist["20020508-1.c"] = struct{}{} //TODO
  2071  		blacklist["20020508-2.c"] = struct{}{} //TODO
  2072  		blacklist["20020508-3.c"] = struct{}{} //TODO
  2073  		blacklist["20020911-1.c"] = struct{}{} //TODO
  2074  		blacklist["20030128-1.c"] = struct{}{} //TODO
  2075  		blacklist["20050215-1.c"] = struct{}{} //TODO
  2076  		blacklist["20070724-1.c"] = struct{}{} //TODO
  2077  		blacklist["20180921-1.c"] = struct{}{} //TODO
  2078  		blacklist["bf-pack-1.c"] = struct{}{}  //TODO
  2079  		blacklist["bitfld-6.c"] = struct{}{}   //TODO
  2080  		blacklist["bitfld-7.c"] = struct{}{}   //TODO
  2081  		blacklist["memchr-1.c"] = struct{}{}   //TODO
  2082  		blacklist["memset-1.c"] = struct{}{}   //TODO
  2083  		blacklist["memset-2.c"] = struct{}{}   //TODO
  2084  		blacklist["memset-3.c"] = struct{}{}   //TODO
  2085  		blacklist["packed-1.c"] = struct{}{}   //TODO
  2086  		blacklist["pr19606.c"] = struct{}{}    //TODO
  2087  		blacklist["pr23467.c"] = struct{}{}    //TODO
  2088  		blacklist["pr29695-2.c"] = struct{}{}  //TODO
  2089  		blacklist["pr40386.c"] = struct{}{}    //TODO
  2090  		blacklist["pr42269-2.c"] = struct{}{}  //TODO
  2091  		blacklist["pr43438.c"] = struct{}{}    //TODO
  2092  		blacklist["pr44164.c"] = struct{}{}    //TODO
  2093  		blacklist["pr58574.c"] = struct{}{}    //TODO
  2094  		blacklist["pr77766.c"] = struct{}{}    //TODO
  2095  		blacklist["pr81503.c"] = struct{}{}    //TODO
  2096  		blacklist["pr81555.c"] = struct{}{}    //TODO
  2097  		blacklist["pr83383.c"] = struct{}{}    //TODO
  2098  		blacklist["pr94567.c"] = struct{}{}    //TODO
  2099  		blacklist["pr98366.c"] = struct{}{}    //TODO
  2100  	}
  2101  	if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" {
  2102  		blacklist["pr44164.c"] = struct{}{} //TODO
  2103  		blacklist["pr98366.c"] = struct{}{} //TODO
  2104  	}
  2105  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  2106  		blacklist["20000519-1.c"] = struct{}{}     //TODO va_list
  2107  		blacklist["20001108-1.c"] = struct{}{}     //TODO
  2108  		blacklist["20071213-1.c"] = struct{}{}     //TODO va_list
  2109  		blacklist["20101011-1.c"] = struct{}{}     //TODO
  2110  		blacklist["930513-1.c"] = struct{}{}       //TODO
  2111  		blacklist["950607-2.c"] = struct{}{}       //TODO
  2112  		blacklist["960416-1.c"] = struct{}{}       //TODO
  2113  		blacklist["fprintf-2.c"] = struct{}{}      //TODO
  2114  		blacklist["fprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2115  		blacklist["loop-2f.c"] = struct{}{}        //TODO
  2116  		blacklist["loop-2g.c"] = struct{}{}        //TODO
  2117  		blacklist["multdi-1.c"] = struct{}{}       //TODO
  2118  		blacklist["pr34456.c"] = struct{}{}        //TODO
  2119  		blacklist["pr78622.c"] = struct{}{}        //TODO
  2120  		blacklist["pr98366.c"] = struct{}{}        //TODO
  2121  		blacklist["printf-2.c"] = struct{}{}       //TODO
  2122  		blacklist["printf-chk-1.c"] = struct{}{}   //TODO va_list
  2123  		blacklist["stdarg-1.c"] = struct{}{}       //TODO va_list
  2124  		blacklist["stdarg-2.c"] = struct{}{}       //TODO va_list
  2125  		blacklist["stdarg-4.c"] = struct{}{}       //TODO va_list
  2126  		blacklist["user-printf.c"] = struct{}{}    //TODO
  2127  		blacklist["va-arg-10.c"] = struct{}{}      //TODO va_list
  2128  		blacklist["va-arg-13.c"] = struct{}{}      //TODO
  2129  		blacklist["va-arg-14.c"] = struct{}{}      //TODO va_list
  2130  		blacklist["va-arg-20.c"] = struct{}{}      //TODO va_list
  2131  		blacklist["va-arg-21.c"] = struct{}{}      //TODO
  2132  		blacklist["va-arg-9.c"] = struct{}{}       //TODO va_list
  2133  		blacklist["vfprintf-1.c"] = struct{}{}     //TODO va_list
  2134  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO va_list
  2135  		blacklist["vprintf-1.c"] = struct{}{}      //TODO va_list
  2136  		blacklist["vprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2137  	}
  2138  	if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
  2139  		blacklist["20000519-1.c"] = struct{}{}     //TODO va_list
  2140  		blacklist["20071213-1.c"] = struct{}{}     //TODO va_list
  2141  		blacklist["960416-1.c"] = struct{}{}       //TODO
  2142  		blacklist["960830-1.c"] = struct{}{}       //TODO
  2143  		blacklist["floatunsisf-1.c"] = struct{}{}  //TODO
  2144  		blacklist["fprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2145  		blacklist["pr23467.c"] = struct{}{}        //TODO
  2146  		blacklist["pr97073.c"] = struct{}{}        //TODO
  2147  		blacklist["pr98366.c"] = struct{}{}        //TODO
  2148  		blacklist["printf-chk-1.c"] = struct{}{}   //TODO va_list
  2149  		blacklist["stdarg-1.c"] = struct{}{}       //TODO va_list
  2150  		blacklist["stdarg-2.c"] = struct{}{}       //TODO va_list
  2151  		blacklist["stdarg-4.c"] = struct{}{}       //TODO va_list
  2152  		blacklist["user-printf.c"] = struct{}{}    //TODO va_list
  2153  		blacklist["va-arg-10.c"] = struct{}{}      //TODO va_list
  2154  		blacklist["va-arg-13.c"] = struct{}{}      //TODO
  2155  		blacklist["va-arg-14.c"] = struct{}{}      //TODO va_list
  2156  		blacklist["va-arg-20.c"] = struct{}{}      //TODO va_list
  2157  		blacklist["va-arg-21.c"] = struct{}{}      //TODO
  2158  		blacklist["va-arg-9.c"] = struct{}{}       //TODO va_list
  2159  		blacklist["vfprintf-1.c"] = struct{}{}     //TODO va_list
  2160  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO va_list
  2161  		blacklist["vprintf-1.c"] = struct{}{}      //TODO va_list
  2162  		blacklist["vprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2163  	}
  2164  	if runtime.GOOS == "linux" && runtime.GOARCH == "arm" {
  2165  		blacklist["20000519-1.c"] = struct{}{}     //TODO va_list
  2166  		blacklist["20071213-1.c"] = struct{}{}     //TODO va_list
  2167  		blacklist["960416-1.c"] = struct{}{}       //TODO
  2168  		blacklist["fprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2169  		blacklist["pr23467.c"] = struct{}{}        //TODO
  2170  		blacklist["pr44164.c"] = struct{}{}        //TODO
  2171  		blacklist["pr98366.c"] = struct{}{}        //TODO
  2172  		blacklist["printf-chk-1.c"] = struct{}{}   //TODO va_list
  2173  		blacklist["stdarg-1.c"] = struct{}{}       //TODO va_list
  2174  		blacklist["stdarg-2.c"] = struct{}{}       //TODO va_list
  2175  		blacklist["stdarg-4.c"] = struct{}{}       //TODO va_list
  2176  		blacklist["strct-pack-1.c"] = struct{}{}   //TODO
  2177  		blacklist["user-printf.c"] = struct{}{}    //TODO va_list
  2178  		blacklist["va-arg-10.c"] = struct{}{}      //TODO va_list
  2179  		blacklist["va-arg-13.c"] = struct{}{}      //TODO
  2180  		blacklist["va-arg-14.c"] = struct{}{}      //TODO va_list
  2181  		blacklist["va-arg-20.c"] = struct{}{}      //TODO va_list
  2182  		blacklist["va-arg-21.c"] = struct{}{}      //TODO
  2183  		blacklist["va-arg-9.c"] = struct{}{}       //TODO va_list
  2184  		blacklist["vfprintf-1.c"] = struct{}{}     //TODO va_list
  2185  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO va_list
  2186  		blacklist["vprintf-1.c"] = struct{}{}      //TODO va_list
  2187  		blacklist["vprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2188  	}
  2189  	if runtime.GOOS == "linux" && runtime.GOARCH == "arm64" {
  2190  		blacklist["20000519-1.c"] = struct{}{}     //TODO va_list
  2191  		blacklist["20071213-1.c"] = struct{}{}     //TODO va_list
  2192  		blacklist["fprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2193  		blacklist["pr44164.c"] = struct{}{}        //TODO
  2194  		blacklist["pr98366.c"] = struct{}{}        //TODO
  2195  		blacklist["pr98681.c"] = struct{}{}        //TODO
  2196  		blacklist["pr98853-2.c"] = struct{}{}      //TODO
  2197  		blacklist["printf-chk-1.c"] = struct{}{}   //TODO va_list
  2198  		blacklist["stdarg-1.c"] = struct{}{}       //TODO va_list
  2199  		blacklist["stdarg-2.c"] = struct{}{}       //TODO va_list
  2200  		blacklist["stdarg-4.c"] = struct{}{}       //TODO va_list
  2201  		blacklist["user-printf.c"] = struct{}{}    //TODO va_list
  2202  		blacklist["va-arg-10.c"] = struct{}{}      //TODO va_list
  2203  		blacklist["va-arg-13.c"] = struct{}{}      //TODO
  2204  		blacklist["va-arg-14.c"] = struct{}{}      //TODO va_list
  2205  		blacklist["va-arg-20.c"] = struct{}{}      //TODO va_list
  2206  		blacklist["va-arg-21.c"] = struct{}{}      //TODO
  2207  		blacklist["va-arg-9.c"] = struct{}{}       //TODO va_list
  2208  		blacklist["vfprintf-1.c"] = struct{}{}     //TODO va_list
  2209  		blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO
  2210  		blacklist["vprintf-1.c"] = struct{}{}      //TODO va_list
  2211  		blacklist["vprintf-chk-1.c"] = struct{}{}  //TODO va_list
  2212  	}
  2213  	binary := map[string]bool{}
  2214  	var rq, res, ok int
  2215  	limit := runtime.GOMAXPROCS(0)
  2216  	limiter := make(chan struct{}, limit)
  2217  	results := make(chan *runResult, limit)
  2218  	failed := map[string]struct{}{}
  2219  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2220  		if strings.Contains(pth, "/ieee/") || !strings.HasSuffix(pth, ".c") {
  2221  			return nil
  2222  		}
  2223  
  2224  		switch {
  2225  		case re != nil:
  2226  			if !re.MatchString(pth) {
  2227  				return nil
  2228  			}
  2229  		default:
  2230  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2231  				return nil
  2232  			}
  2233  		}
  2234  
  2235  	more:
  2236  		select {
  2237  		case r := <-results:
  2238  			res++
  2239  			<-limiter
  2240  			switch r.err.(type) {
  2241  			case nil:
  2242  				ok++
  2243  				delete(failed, r.name)
  2244  			case skipErr:
  2245  				delete(failed, r.name)
  2246  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2247  			default:
  2248  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2249  			}
  2250  			goto more
  2251  		case limiter <- struct{}{}:
  2252  			rq++
  2253  			if *oTrc {
  2254  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2255  			}
  2256  			base := filepath.Base(pth)
  2257  			var opts []string
  2258  			switch base {
  2259  			case
  2260  				"20010122-1.c", //TODO
  2261  				"20101011-1.c", //TODO
  2262  				"pr44164.c",    //TODO
  2263  				"pr97386-1.c",  //TODO
  2264  				"pr97386-2.c",  //TODO
  2265  				"pr98366.c":    //TODO
  2266  
  2267  				opts = []string{"-O0"}
  2268  			}
  2269  			failed[pth] = struct{}{}
  2270  			go run(pth, binary[base], true, false, results, opts...)
  2271  		}
  2272  		return nil
  2273  	})
  2274  	if err != nil {
  2275  		t.Fatal(err)
  2276  	}
  2277  	for res != rq {
  2278  		r := <-results
  2279  		res++
  2280  		<-limiter
  2281  		switch r.err.(type) {
  2282  		case nil:
  2283  			ok++
  2284  			delete(failed, r.name)
  2285  		case skipErr:
  2286  			delete(failed, r.name)
  2287  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2288  		default:
  2289  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2290  		}
  2291  	}
  2292  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2293  	if len(failed) == 0 {
  2294  		return
  2295  	}
  2296  
  2297  	var a []string
  2298  	for k := range failed {
  2299  		a = append(a, k)
  2300  	}
  2301  	sort.Strings(a)
  2302  	for _, v := range a {
  2303  		t.Logf("FAIL %s", v)
  2304  	}
  2305  }
  2306  
  2307  func TestGCCExecuteIEEE(t *testing.T) {
  2308  	const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute/ieee"
  2309  	mustEmptyDir(t, tempDir)
  2310  	wd, err := os.Getwd()
  2311  	if err != nil {
  2312  		t.Fatal(err)
  2313  	}
  2314  
  2315  	if err := os.Chdir(tempDir); err != nil {
  2316  		t.Fatal(err)
  2317  	}
  2318  
  2319  	defer func() {
  2320  		if err := os.Chdir(wd); err != nil {
  2321  			t.Fatal(err)
  2322  		}
  2323  	}()
  2324  
  2325  	blacklist := map[string]struct{}{
  2326  		"builtin-nan-1.c": {}, //TODO
  2327  		"copysign1.c":     {}, //TODO
  2328  		"copysign2.c":     {}, //TODO
  2329  		"fp-cmp-3.c":      {}, //TODO
  2330  		"fp-cmp-4l.c":     {}, //TODO
  2331  		"fp-cmp-8l.c":     {}, //TODO
  2332  		"pr50310.c":       {}, //TODO
  2333  		"pr72824-2.c":     {}, //TODO
  2334  	}
  2335  	if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
  2336  		blacklist["20030331-1.c"] = struct{}{} //TODO
  2337  		blacklist["pr67218.c"] = struct{}{}    //TODO
  2338  	}
  2339  	binary := map[string]bool{}
  2340  	var rq, res, ok int
  2341  	limit := runtime.GOMAXPROCS(0)
  2342  	limiter := make(chan struct{}, limit)
  2343  	results := make(chan *runResult, limit)
  2344  	failed := map[string]struct{}{}
  2345  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2346  		if !strings.HasSuffix(pth, ".c") {
  2347  			return nil
  2348  		}
  2349  
  2350  		switch {
  2351  		case re != nil:
  2352  			if !re.MatchString(pth) {
  2353  				return nil
  2354  			}
  2355  		default:
  2356  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2357  				return nil
  2358  			}
  2359  		}
  2360  
  2361  	more:
  2362  		select {
  2363  		case r := <-results:
  2364  			res++
  2365  			<-limiter
  2366  			switch r.err.(type) {
  2367  			case nil:
  2368  				ok++
  2369  				delete(failed, r.name)
  2370  			case skipErr:
  2371  				delete(failed, r.name)
  2372  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2373  			default:
  2374  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2375  			}
  2376  			goto more
  2377  		case limiter <- struct{}{}:
  2378  			rq++
  2379  			if *oTrc {
  2380  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2381  			}
  2382  			failed[pth] = struct{}{}
  2383  			go run(pth, binary[filepath.Base(pth)], true, false, results)
  2384  		}
  2385  		return nil
  2386  	})
  2387  	if err != nil {
  2388  		t.Fatal(err)
  2389  	}
  2390  	for res != rq {
  2391  		r := <-results
  2392  		res++
  2393  		<-limiter
  2394  		switch r.err.(type) {
  2395  		case nil:
  2396  			ok++
  2397  			delete(failed, r.name)
  2398  		case skipErr:
  2399  			delete(failed, r.name)
  2400  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2401  		default:
  2402  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2403  		}
  2404  	}
  2405  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  2406  	if len(failed) == 0 {
  2407  		return
  2408  	}
  2409  
  2410  	var a []string
  2411  	for k := range failed {
  2412  		a = append(a, k)
  2413  	}
  2414  	sort.Strings(a)
  2415  	for _, v := range a {
  2416  		t.Logf("FAIL %s", v)
  2417  	}
  2418  }
  2419  
  2420  var installOnce sync.Once
  2421  
  2422  func installEcc(t *testing.T) bool {
  2423  	if !*oInstall && os.Getenv("INSTALL_ECC") != "1" {
  2424  		return false
  2425  	}
  2426  
  2427  	var out []byte
  2428  	var err error
  2429  	installOnce.Do(func() {
  2430  		t.Log("installing binaries")
  2431  		out, err = ccgo.Shell("go", "install", "-v", "../...")
  2432  		s := os.Getenv("GOPATH")
  2433  		if s == "" {
  2434  			s = build.Default.GOPATH
  2435  		}
  2436  		s = filepath.Join(s, "bin")
  2437  		p := os.Getenv("PATH")
  2438  		if !strings.Contains(p, s) {
  2439  			p = s + string(os.PathListSeparator) + p
  2440  			t.Logf("setting PATH=%s", p)
  2441  			os.Setenv("PATH", p)
  2442  		}
  2443  		if os.Getenv("QBEC_CC") == "" {
  2444  			if s := os.Getenv("CC"); s == "" || s == "ecc" {
  2445  				t.Logf("setting QBEC_CC=gcc")
  2446  				os.Setenv("QBEC_CC", "gcc")
  2447  			}
  2448  		}
  2449  	})
  2450  	if err != nil {
  2451  		t.Fatalf("%s\n%s", err, out)
  2452  	}
  2453  
  2454  	t.Logf("ecc %v installed", Version())
  2455  	return true
  2456  }
  2457  
  2458  func TestZlib(t *testing.T) {
  2459  	if !installEcc(t) {
  2460  		t.Skip("set INSTALL_ECC=1 or add -install to execute this test")
  2461  	}
  2462  
  2463  	const root = "/github.com/madler/zlib.tar.gz"
  2464  	archive, err := fs.Open(root)
  2465  	if err != nil {
  2466  		t.Fatal(err)
  2467  	}
  2468  
  2469  	mustEmptyDir(t, tempDir)
  2470  	if err := ccgo.Untar(tempDir, archive, nil); err != nil {
  2471  		t.Fatal(err)
  2472  	}
  2473  
  2474  	if err := ccgo.InDir(filepath.Join(tempDir, "zlib"), func() error {
  2475  		switch {
  2476  		case
  2477  			runtime.GOOS == "darwin" && runtime.GOARCH == "amd64",
  2478  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "386",
  2479  			runtime.GOOS == "linux" && runtime.GOARCH == "amd64",
  2480  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "arm",
  2481  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "arm64",
  2482  			runtime.GOOS == "linux" && runtime.GOARCH == "s390x":
  2483  
  2484  			out, err := ccgo.Shell("sh", "-c", "CC=ecc ./configure && make check")
  2485  			if err != nil || strings.Contains(string(out), "FAILED") {
  2486  				return errorf("err: %v\n%s", err, out)
  2487  			}
  2488  		default:
  2489  			// windows/amd64
  2490  			//TODO
  2491  			t.Skip("TODO") //TODO
  2492  		}
  2493  
  2494  		return nil
  2495  	}); err != nil {
  2496  		t.Fatal(err)
  2497  	}
  2498  }
  2499  
  2500  func TestBenchmarksGame(t *testing.T) {
  2501  	const root = "/benchmarksgame-team.pages.debian.net/"
  2502  
  2503  	if testing.Short() {
  2504  		t.Skip("skipped: -short")
  2505  	}
  2506  
  2507  	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
  2508  		t.Skip("skipped: supported currently only on linux/amd64") //TODO
  2509  	}
  2510  
  2511  	mustEmptyDir(t, tempDir)
  2512  	wd, err := os.Getwd()
  2513  	if err != nil {
  2514  		t.Fatal(err)
  2515  	}
  2516  
  2517  	if err := os.Chdir(tempDir); err != nil {
  2518  		t.Fatal(err)
  2519  	}
  2520  
  2521  	defer func() {
  2522  		if err := os.Chdir(wd); err != nil {
  2523  			t.Fatal(err)
  2524  		}
  2525  	}()
  2526  
  2527  	// Prepare testdata
  2528  	needFiles(t, root, []string{
  2529  		"Include/khash.h",
  2530  		"fasta.c",
  2531  	})
  2532  	bin, err := makeCCBinary("fasta.c", false)
  2533  	if err != nil {
  2534  		t.Fatal(err)
  2535  	}
  2536  
  2537  	defer os.Remove(bin)
  2538  
  2539  	for _, size := range []int{5e6, 1e8, 25e6} {
  2540  		cmd := exec.Command(bin, fmt.Sprint(size))
  2541  		fn := fmt.Sprintf("%d.txt", size)
  2542  		f, err := os.Create(fn)
  2543  		if err != nil {
  2544  			t.Fatal(err)
  2545  		}
  2546  
  2547  		w := bufio.NewWriter(f)
  2548  		cmd.Stdout = w
  2549  		if err := cmd.Run(); err != nil {
  2550  			t.Fatal(err)
  2551  		}
  2552  
  2553  		if err := w.Flush(); err != nil {
  2554  			t.Fatal(err)
  2555  		}
  2556  
  2557  		if err := f.Close(); err != nil {
  2558  			t.Fatal(err)
  2559  		}
  2560  	}
  2561  
  2562  	blacklist := map[string]struct{}{
  2563  		"binary-trees-2.c":  {}, //TODO
  2564  		"binary-trees-3.c":  {}, //TODO
  2565  		"fannkuchredux-4.c": {}, //TODO
  2566  		"fannkuchredux-5.c": {}, //TODO
  2567  		"fannkuchredux.c":   {}, //TODO
  2568  		"fasta-2.c":         {}, //TODO
  2569  		"fasta-5.c":         {}, //TODO
  2570  		"fasta-6.c":         {}, //TODO
  2571  		"fasta-7.c":         {}, //TODO
  2572  		"k-nucleotide.c":    {}, //TODO
  2573  		"mandelbrot-3.c":    {}, //TODO
  2574  		"mandelbrot-4.c":    {}, //TODO
  2575  		"mandelbrot-6.c":    {}, //TODO
  2576  		"mandelbrot-7.c":    {}, //TODO
  2577  		"mandelbrot-8.c":    {}, //TODO
  2578  		"mandelbrot-9.c":    {}, //TODO
  2579  		"mandelbrot.c":      {}, //TODO
  2580  		"nbody-4.c":         {}, //TODO
  2581  		"nbody-5.c":         {}, //TODO
  2582  		"nbody-8.c":         {}, //TODO
  2583  		"nbody-9.c":         {}, //TODO
  2584  		"pidigits-6.c":      {}, //TODO
  2585  		"regex-redux-4.c":   {}, //TODO
  2586  		"regex-redux-5.c":   {}, //TODO
  2587  		"spectral-norm-4.c": {}, //TODO
  2588  		"spectral-norm-5.c": {}, //TODO
  2589  		"spectral-norm-6.c": {}, //TODO
  2590  		"spectral-norm.c":   {}, //TODO
  2591  	}
  2592  
  2593  	m := map[string]*runResult{}
  2594  	var names []string
  2595  	collect := func(r *runResult) {
  2596  		nm := filepath.Base(r.name)
  2597  		ex := m[nm]
  2598  		if ex == nil {
  2599  			m[nm] = r
  2600  			names = append(names, nm)
  2601  			return
  2602  		}
  2603  
  2604  		if ex.ccTime > r.ccTime {
  2605  			ex.ccTime = r.ccTime
  2606  		}
  2607  		if ex.eccTime > r.eccTime {
  2608  			ex.eccTime = r.eccTime
  2609  		}
  2610  	}
  2611  	binary := map[string]bool{
  2612  		"fasta-3.c":              true,
  2613  		"fasta-4.c":              true,
  2614  		"fasta-8.c":              true,
  2615  		"fasta-9.c":              true,
  2616  		"fasta.c":                true,
  2617  		"mandelbrot-2.c":         true,
  2618  		"mandelbrot-3.c":         true,
  2619  		"mandelbrot-4.c":         true,
  2620  		"mandelbrot-6.c":         true,
  2621  		"mandelbrot-7.c":         true,
  2622  		"mandelbrot-8.c":         true,
  2623  		"mandelbrot-9.c":         true,
  2624  		"mandelbrot.c":           true,
  2625  		"reverse-complement-2.c": true,
  2626  		"reverse-complement-4.c": true,
  2627  		"reverse-complement-5.c": true,
  2628  		"reverse-complement-6.c": true,
  2629  	}
  2630  	var rq, res, ok int
  2631  	limit := 1
  2632  	limiter := make(chan struct{}, limit)
  2633  	results := make(chan *runResult, limit)
  2634  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2635  		if !strings.HasSuffix(pth, ".c") {
  2636  			return nil
  2637  		}
  2638  
  2639  		switch {
  2640  		case re != nil:
  2641  			if !re.MatchString(pth) {
  2642  				return nil
  2643  			}
  2644  
  2645  			fallthrough
  2646  		default:
  2647  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2648  				return nil
  2649  			}
  2650  		}
  2651  
  2652  		for i := 0; i < *oBestOf; i++ {
  2653  		more:
  2654  			select {
  2655  			case r := <-results:
  2656  				res++
  2657  				<-limiter
  2658  				switch r.err.(type) {
  2659  				case nil:
  2660  					ok++
  2661  					collect(r)
  2662  				case skipErr:
  2663  					t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2664  				default:
  2665  					t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2666  				}
  2667  				goto more
  2668  			case limiter <- struct{}{}:
  2669  				rq++
  2670  				if *oTrc {
  2671  					fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2672  				}
  2673  				opts := []string{
  2674  					"-D_GNU_SOURCE",
  2675  					"-I/usr/include/apr-1.0",
  2676  					"-IInclude",
  2677  					"-lapr-1",
  2678  					"-lgmp",
  2679  					"-lm",
  2680  					"-lpcre",
  2681  					"-lpcre2-8",
  2682  					"-pthread",
  2683  					fmt.Sprintf("-O%d", *oBenchO),
  2684  				}
  2685  				if s := *oMarch; s != "" {
  2686  					opts = append(opts, fmt.Sprintf("-march=%s", s))
  2687  				}
  2688  				if s := *oMtune; s != "" {
  2689  					opts = append(opts, fmt.Sprintf("-mtune=%s", s))
  2690  				}
  2691  				if *oOpenmp {
  2692  					opts = append(opts, "-fopenmp")
  2693  				}
  2694  				base := filepath.Base(pth)
  2695  				task := &runTask{
  2696  					c:               results,
  2697  					hasBinaryOutput: binary[base],
  2698  					opts:            opts,
  2699  					src:             pth,
  2700  				}
  2701  				switch {
  2702  				case strings.HasPrefix(base, "regex-redux"):
  2703  					switch runtime.GOOS {
  2704  					case "windows":
  2705  						panic(todo(""))
  2706  					default:
  2707  						task.cmd = "sh"
  2708  						task.args = []string{"-c", fmt.Sprintf("./%s < 5000000.txt", base[:len(base)-2])}
  2709  					}
  2710  				case strings.HasPrefix(base, "k-nucleotide"):
  2711  					switch runtime.GOOS {
  2712  					case "windows":
  2713  						panic(todo(""))
  2714  					default:
  2715  						task.cmd = "sh"
  2716  						task.args = []string{"-c", fmt.Sprintf("./%s < 25000000.txt", base[:len(base)-2])}
  2717  					}
  2718  				case strings.HasPrefix(base, "reverse-complement"):
  2719  					switch runtime.GOOS {
  2720  					case "windows":
  2721  						panic(todo(""))
  2722  					default:
  2723  						task.cmd = "sh"
  2724  						task.args = []string{"-c", fmt.Sprintf("./%s < 100000000.txt", base[:len(base)-2])}
  2725  					}
  2726  				}
  2727  				go task.run()
  2728  			}
  2729  		}
  2730  		return nil
  2731  	})
  2732  	if err != nil {
  2733  		t.Fatal(err)
  2734  	}
  2735  	for res != rq {
  2736  		r := <-results
  2737  		res++
  2738  		<-limiter
  2739  		switch r.err.(type) {
  2740  		case nil:
  2741  			ok++
  2742  			collect(r)
  2743  		case skipErr:
  2744  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2745  		default:
  2746  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2747  		}
  2748  	}
  2749  	benchmarkResults(t, rq, ok, names, m)
  2750  }
  2751  
  2752  func benchmarkResults(t *testing.T, rq, ok int, names []string, m map[string]*runResult) {
  2753  	t.Logf("files %v, ok %v", rq, ok)
  2754  	if ok == 0 {
  2755  		return
  2756  	}
  2757  
  2758  	sort.Strings(names)
  2759  	var ccDurations, eccDurations time.Duration
  2760  	t.Logf("  os/arch: %s/%s", runtime.GOOS, runtime.GOARCH)
  2761  	t.Logf("       cc: %s", systemCC)
  2762  	t.Logf("--version: %s", systemCCVersion)
  2763  	t.Logf("       -O: %d", *oBenchO)
  2764  	t.Logf("   -march: %s", *oMarch)
  2765  	t.Logf("   -mtune: %s", *oMtune)
  2766  	t.Logf(" -fopenmp: %v", *oOpenmp)
  2767  	t.Logf("  best of: %d", *oBestOf)
  2768  	t.Logf("                       src   ecc      cc      ecc/cc")
  2769  	var min, max float64
  2770  	geomean := 1.0
  2771  	for i, nm := range names {
  2772  		r := m[nm]
  2773  		coeff := float64(r.eccTime) / float64(r.ccTime)
  2774  		ccDurations += r.ccTime
  2775  		eccDurations += r.eccTime
  2776  		t.Logf("%25s: %7.3fs %7.3fs  %.3f%s", nm, r.eccTime.Seconds(), r.ccTime.Seconds(), coeff, star(coeff))
  2777  		switch {
  2778  		case i == 0:
  2779  			min, max = coeff, coeff
  2780  		default:
  2781  			if coeff < min {
  2782  				min = coeff
  2783  			}
  2784  			if coeff > max {
  2785  				max = coeff
  2786  			}
  2787  		}
  2788  		geomean *= coeff
  2789  	}
  2790  	geomean = math.Pow(geomean, 1/float64(len(names)))
  2791  	coeff := float64(eccDurations) / float64(ccDurations)
  2792  	t.Logf(
  2793  		"                   overall %7.3fs %7.3fs  %.3f%s (min %.3f%s max %.3f%s)",
  2794  		eccDurations.Seconds(),
  2795  		ccDurations.Seconds(),
  2796  		float64(eccDurations)/float64(ccDurations), star(coeff),
  2797  		min, star(min),
  2798  		max, star(max),
  2799  	)
  2800  	t.Logf("                   geomean                  %7.3f%s", geomean, star(geomean))
  2801  }
  2802  
  2803  func star(n float64) string {
  2804  	if n < 1 {
  2805  		return "*"
  2806  	}
  2807  
  2808  	return ""
  2809  }
  2810  
  2811  func TestBenchmarksMir(t *testing.T) {
  2812  	const root = "/github.com/vnmakarov/mir/c-benchmarks"
  2813  
  2814  	if testing.Short() {
  2815  		t.Skip("skipped: -short")
  2816  	}
  2817  
  2818  	mustEmptyDir(t, tempDir)
  2819  	wd, err := os.Getwd()
  2820  	if err != nil {
  2821  		t.Fatal(err)
  2822  	}
  2823  
  2824  	if err := os.Chdir(tempDir); err != nil {
  2825  		t.Fatal(err)
  2826  	}
  2827  
  2828  	defer func() {
  2829  		if err := os.Chdir(wd); err != nil {
  2830  			t.Fatal(err)
  2831  		}
  2832  	}()
  2833  
  2834  	needFiles(t, root, []string{
  2835  		"simple_hash.h",
  2836  	})
  2837  	blacklist := map[string]struct{}{}
  2838  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  2839  		blacklist["except.c"] = struct{}{} //TODO
  2840  	}
  2841  	m := map[string]*runResult{}
  2842  	var names []string
  2843  	collect := func(r *runResult) {
  2844  		nm := filepath.Base(r.name)
  2845  		ex := m[nm]
  2846  		if ex == nil {
  2847  			m[nm] = r
  2848  			names = append(names, nm)
  2849  			return
  2850  		}
  2851  
  2852  		if ex.ccTime > r.ccTime {
  2853  			ex.ccTime = r.ccTime
  2854  		}
  2855  		if ex.eccTime > r.eccTime {
  2856  			ex.eccTime = r.eccTime
  2857  		}
  2858  	}
  2859  	binary := map[string]bool{
  2860  		"mandelbrot.c": true,
  2861  	}
  2862  	var rq, res, ok int
  2863  	limit := 1
  2864  	limiter := make(chan struct{}, limit)
  2865  	results := make(chan *runResult, limit)
  2866  	err = walk(root, func(pth string, fi os.FileInfo) error {
  2867  		if !strings.HasSuffix(pth, ".c") {
  2868  			return nil
  2869  		}
  2870  
  2871  		switch {
  2872  		case re != nil:
  2873  			if !re.MatchString(pth) {
  2874  				return nil
  2875  			}
  2876  
  2877  			fallthrough
  2878  		default:
  2879  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  2880  				return nil
  2881  			}
  2882  		}
  2883  
  2884  		for i := 0; i < *oBestOf; i++ {
  2885  		more:
  2886  			select {
  2887  			case r := <-results:
  2888  				res++
  2889  				<-limiter
  2890  				switch r.err.(type) {
  2891  				case nil:
  2892  					ok++
  2893  					collect(r)
  2894  				case skipErr:
  2895  					t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2896  				default:
  2897  					t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2898  				}
  2899  				goto more
  2900  			case limiter <- struct{}{}:
  2901  				rq++
  2902  				if *oTrc {
  2903  					fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  2904  				}
  2905  				opts := []string{
  2906  					fmt.Sprintf("-O%d", *oBenchO),
  2907  				}
  2908  				if s := *oMarch; s != "" {
  2909  					opts = append(opts, fmt.Sprintf("-march=%s", s))
  2910  				}
  2911  				if s := *oMtune; s != "" {
  2912  					opts = append(opts, fmt.Sprintf("-mtune=%s", s))
  2913  				}
  2914  				go run(pth, binary[filepath.Base(pth)], true, false, results, opts...)
  2915  			}
  2916  		}
  2917  		return nil
  2918  	})
  2919  	if err != nil {
  2920  		t.Fatal(err)
  2921  	}
  2922  	for res != rq {
  2923  		r := <-results
  2924  		res++
  2925  		<-limiter
  2926  		switch r.err.(type) {
  2927  		case nil:
  2928  			ok++
  2929  			collect(r)
  2930  		case skipErr:
  2931  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  2932  		default:
  2933  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  2934  		}
  2935  	}
  2936  	benchmarkResults(t, rq, ok, names, m)
  2937  }
  2938  
  2939  func TestBenchmarksCompCert(t *testing.T) {
  2940  	const root = "/github.com/AbsInt/CompCert/test/c/"
  2941  
  2942  	if testing.Short() {
  2943  		t.Skip("skipped: -short")
  2944  	}
  2945  
  2946  	mustEmptyDir(t, tempDir)
  2947  	wd, err := os.Getwd()
  2948  	if err != nil {
  2949  		t.Fatal(err)
  2950  	}
  2951  
  2952  	if err := os.Chdir(tempDir); err != nil {
  2953  		t.Fatal(err)
  2954  	}
  2955  
  2956  	defer func() {
  2957  		if err := os.Chdir(wd); err != nil {
  2958  			t.Fatal(err)
  2959  		}
  2960  	}()
  2961  
  2962  	needFiles(t, root, []string{
  2963  		"Results/knucleotide-input.txt",
  2964  		"endian.h",
  2965  	})
  2966  	blacklist := map[string]struct{}{}
  2967  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
  2968  		blacklist["aes.c"] = struct{}{} //TODO
  2969  	}
  2970  	if runtime.GOOS == "windows" && runtime.GOARCH == "amd64" {
  2971  		blacklist["bisect.c"] = struct{}{} //TODO va_list
  2972  		blacklist["fftw.c"] = struct{}{}   //TODO va_list
  2973  		blacklist["perlin.c"] = struct{}{} //TODO va_list
  2974  		blacklist["qsort.c"] = struct{}{}  //TODO
  2975  
  2976  	}
  2977  	binary := map[string]bool{
  2978  		"mandelbrot.c": true, //TODO
  2979  	}
  2980  
  2981  	m := map[string]*runResult{}
  2982  	var names []string
  2983  	collect := func(r *runResult) {
  2984  		nm := filepath.Base(r.name)
  2985  		ex := m[nm]
  2986  		if ex == nil {
  2987  			m[nm] = r
  2988  			names = append(names, nm)
  2989  			return
  2990  		}
  2991  
  2992  		if ex.ccTime > r.ccTime {
  2993  			ex.ccTime = r.ccTime
  2994  		}
  2995  		if ex.eccTime > r.eccTime {
  2996  			ex.eccTime = r.eccTime
  2997  		}
  2998  	}
  2999  	var rq, res, ok int
  3000  	limit := 1
  3001  	limiter := make(chan struct{}, limit)
  3002  	results := make(chan *runResult, limit)
  3003  	err = walk(root, func(pth string, fi os.FileInfo) error {
  3004  		if !strings.HasSuffix(pth, ".c") {
  3005  			return nil
  3006  		}
  3007  
  3008  		switch {
  3009  		case re != nil:
  3010  			if !re.MatchString(pth) {
  3011  				return nil
  3012  			}
  3013  
  3014  			fallthrough
  3015  		default:
  3016  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  3017  				return nil
  3018  			}
  3019  		}
  3020  
  3021  		for i := 0; i < *oBestOf; i++ {
  3022  		more:
  3023  			select {
  3024  			case r := <-results:
  3025  				res++
  3026  				<-limiter
  3027  				switch r.err.(type) {
  3028  				case nil:
  3029  					ok++
  3030  					collect(r)
  3031  				case skipErr:
  3032  					t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  3033  				default:
  3034  					t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  3035  				}
  3036  				goto more
  3037  			case limiter <- struct{}{}:
  3038  				rq++
  3039  				if *oTrc {
  3040  					fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  3041  				}
  3042  				opts := []string{
  3043  					fmt.Sprintf("-O%d", *oBenchO),
  3044  				}
  3045  				if s := *oMarch; s != "" {
  3046  					opts = append(opts, fmt.Sprintf("-march=%s", s))
  3047  				}
  3048  				if s := *oMtune; s != "" {
  3049  					opts = append(opts, fmt.Sprintf("-mtune=%s", s))
  3050  				}
  3051  				if *oOpenmp {
  3052  					opts = append(opts, "-fopenmp")
  3053  				}
  3054  				go run(pth, binary[filepath.Base(pth)], true, false, results, opts...)
  3055  			}
  3056  		}
  3057  		return nil
  3058  	})
  3059  	if err != nil {
  3060  		t.Fatal(err)
  3061  	}
  3062  	for res != rq {
  3063  		r := <-results
  3064  		res++
  3065  		<-limiter
  3066  		switch r.err.(type) {
  3067  		case nil:
  3068  			ok++
  3069  			collect(r)
  3070  		case skipErr:
  3071  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  3072  		default:
  3073  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  3074  		}
  3075  	}
  3076  	benchmarkResults(t, rq, ok, names, m)
  3077  }
  3078  
  3079  func TestPCRE(t *testing.T) {
  3080  	if !installEcc(t) {
  3081  		t.Skip("set INSTALL_ECC=1 or add -install to execute this test")
  3082  	}
  3083  
  3084  	const root = "/ftp.pcre.org/pub/pcre.tar.gz"
  3085  	archive, err := fs.Open(root)
  3086  	if err != nil {
  3087  		t.Fatal(err)
  3088  	}
  3089  
  3090  	mustEmptyDir(t, tempDir)
  3091  	if err := ccgo.Untar(tempDir, archive, nil); err != nil {
  3092  		t.Fatal(err)
  3093  	}
  3094  
  3095  	if err := ccgo.InDir(filepath.Join(tempDir, "pcre"), func() error {
  3096  		switch {
  3097  		case
  3098  			//TODO runtime.GOOS == "darwin" && runtime.GOARCH == "amd64",
  3099  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "386",
  3100  			runtime.GOOS == "linux" && runtime.GOARCH == "amd64":
  3101  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "arm",
  3102  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "arm64",
  3103  			//TODO runtime.GOOS == "linux" && runtime.GOARCH == "s390x":
  3104  
  3105  			//TODO --enable-pcre16 fails
  3106  			//TODO --enable-jit need assembler support
  3107  			out, err := ccgo.Shell("sh", "-c", "CC=ecc ./configure --disable-cpp --enable-shared=no --enable-pcre16 --enable-pcre32 --enable-utf --enable-unicode-properties && make check")
  3108  			if err != nil {
  3109  				return errorf("err: %v\n%s", err, out)
  3110  			}
  3111  		default:
  3112  			// windows/amd64
  3113  			//TODO
  3114  			t.Skip("TODO") //TODO
  3115  		}
  3116  
  3117  		return nil
  3118  	}); err != nil {
  3119  		t.Fatal(err)
  3120  	}
  3121  }
  3122  
  3123  func TestCxgo(t *testing.T) {
  3124  	const root = "/github.com/cxgo"
  3125  	mustEmptyDir(t, tempDir)
  3126  	wd, err := os.Getwd()
  3127  	if err != nil {
  3128  		t.Fatal(err)
  3129  	}
  3130  
  3131  	if err := os.Chdir(tempDir); err != nil {
  3132  		t.Fatal(err)
  3133  	}
  3134  
  3135  	defer func() {
  3136  		if err := os.Chdir(wd); err != nil {
  3137  			t.Fatal(err)
  3138  		}
  3139  	}()
  3140  
  3141  	needFiles(t, root, []string{})
  3142  	blacklist := map[string]struct{}{
  3143  		"function forward decl 2.c": {}, //TODO
  3144  		"inet.c":                    {}, //TODO
  3145  	}
  3146  	if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" {
  3147  		blacklist["function forward decl 2.c"] = struct{}{} //TODO
  3148  	}
  3149  	if runtime.GOOS == "linux" && runtime.GOARCH == "s390x" {
  3150  		blacklist["function forward decl 2.c"] = struct{}{} //TODO
  3151  	}
  3152  	if runtime.GOOS == "linux" && runtime.GOARCH == "arm64" {
  3153  		blacklist["function forward decl 2.c"] = struct{}{} //TODO
  3154  	}
  3155  	if runtime.GOOS == "linux" && runtime.GOARCH == "386" {
  3156  		blacklist["enum fixed.c"] = struct{}{}              //TODO
  3157  		blacklist["enum no zero 2.c"] = struct{}{}          //TODO
  3158  		blacklist["enum no zero.c"] = struct{}{}            //TODO
  3159  		blacklist["enum start.c"] = struct{}{}              //TODO
  3160  		blacklist["enum zero.c"] = struct{}{}               //TODO
  3161  		blacklist["extern var.c"] = struct{}{}              //TODO
  3162  		blacklist["forward enum.c"] = struct{}{}            //TODO
  3163  		blacklist["function forward decl 2.c"] = struct{}{} //TODO
  3164  		blacklist["go ints.c"] = struct{}{}                 //TODO
  3165  		blacklist["named enum.c"] = struct{}{}              //TODO
  3166  		blacklist["return enum.c"] = struct{}{}             //TODO
  3167  		blacklist["struct and func.c"] = struct{}{}         //TODO
  3168  		blacklist["typedef enum.c"] = struct{}{}            //TODO
  3169  		blacklist["typedef primitive.c"] = struct{}{}       //TODO
  3170  		blacklist["unnamed enum.c"] = struct{}{}            //TODO
  3171  	}
  3172  	var rq, res, ok int
  3173  	limit := runtime.GOMAXPROCS(0)
  3174  	limiter := make(chan struct{}, limit)
  3175  	results := make(chan *runResult, limit)
  3176  	failed := map[string]struct{}{}
  3177  	err = walk(root, func(pth string, fi os.FileInfo) error {
  3178  		if !strings.HasSuffix(pth, ".c") {
  3179  			return nil
  3180  		}
  3181  
  3182  		switch {
  3183  		case re != nil:
  3184  			if !re.MatchString(pth) {
  3185  				return nil
  3186  			}
  3187  		default:
  3188  			if _, ok := blacklist[filepath.Base(pth)]; ok {
  3189  				return nil
  3190  			}
  3191  		}
  3192  
  3193  	more:
  3194  		select {
  3195  		case r := <-results:
  3196  			res++
  3197  			<-limiter
  3198  			switch r.err.(type) {
  3199  			case nil:
  3200  				ok++
  3201  				delete(failed, r.name)
  3202  			case skipErr:
  3203  				delete(failed, r.name)
  3204  				t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  3205  			default:
  3206  				t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  3207  			}
  3208  			goto more
  3209  		case limiter <- struct{}{}:
  3210  			rq++
  3211  			if *oTrc {
  3212  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  3213  			}
  3214  			failed[pth] = struct{}{}
  3215  			go run(pth, false, false, true, results)
  3216  		}
  3217  		return nil
  3218  	})
  3219  	if err != nil {
  3220  		t.Fatal(err)
  3221  	}
  3222  	for res != rq {
  3223  		r := <-results
  3224  		res++
  3225  		<-limiter
  3226  		switch r.err.(type) {
  3227  		case nil:
  3228  			ok++
  3229  			delete(failed, r.name)
  3230  		case skipErr:
  3231  			delete(failed, r.name)
  3232  			t.Logf("%v: %v\n%s", r.name, r.err, r.out)
  3233  		default:
  3234  			t.Errorf("%v: %v\n%s", r.name, r.err, r.out)
  3235  		}
  3236  	}
  3237  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  3238  	if len(failed) == 0 {
  3239  		return
  3240  	}
  3241  
  3242  	var a []string
  3243  	for k := range failed {
  3244  		a = append(a, k)
  3245  	}
  3246  	sort.Strings(a)
  3247  	for _, v := range a {
  3248  		t.Logf("FAIL %s", v)
  3249  	}
  3250  }
  3251  
  3252  func TestCSmith(t *testing.T) {
  3253  	return //TODO-
  3254  
  3255  	if *oCSmith == 0 {
  3256  		return
  3257  	}
  3258  
  3259  	fixedBugs := []string{
  3260  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 169375684",
  3261  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1833258637",
  3262  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1885311141",
  3263  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324",
  3264  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2273393378",
  3265  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 241244373",
  3266  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2517344771",
  3267  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2648215054",
  3268  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2876930815",
  3269  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3043990076",
  3270  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3100949894",
  3271  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3126091077",
  3272  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3130410542",
  3273  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3329111231",
  3274  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3363122597",
  3275  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3365074920",
  3276  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3578720023",
  3277  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3645367888",
  3278  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3919255949",
  3279  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4058772172",
  3280  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4101947480",
  3281  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4130344133",
  3282  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4146870674",
  3283  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 517639208",
  3284  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 56498550",
  3285  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 890611563",
  3286  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 963985971",
  3287  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1341005347",
  3288  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1346606946",
  3289  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1410729753",
  3290  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1473217979",
  3291  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1485689586",
  3292  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1872452393",
  3293  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 1947158672",
  3294  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 2232359541",
  3295  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 2295327168",
  3296  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 231122029",
  3297  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 2452101147",
  3298  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 251697819",
  3299  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 2545154538",
  3300  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 2551936195",
  3301  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 3394478498",
  3302  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 3688696230",
  3303  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 4151780743",
  3304  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 4275869822",
  3305  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 541090131",
  3306  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 828263634",
  3307  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 885721321",
  3308  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 964049230",
  3309  		"--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-volatile-pointers --no-volatiles --paranoid -s 980538434",
  3310  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1906742816",
  3311  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 3629008936",
  3312  		"--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 612971101",
  3313  		"--no-bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3720922579",
  3314  	}
  3315  
  3316  	csmithDefaultArgs := strings.Join([]string{
  3317  		"--bitfields",                     // --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default).
  3318  		"--max-nested-struct-level", "10", // --max-nested-struct-level <num>: limit maximum nested level of structs to <num>(default 0). Only works in the exhaustive mode.
  3319  		"--no-const-pointers",    // --const-pointers | --no-const-pointers: enable | disable const pointers (enabled by default).
  3320  		"--no-consts",            // --consts | --no-consts: enable | disable const qualifier (enabled by default).
  3321  		"--no-volatile-pointers", // --volatile-pointers | --no-volatile-pointers: enable | disable volatile pointers (enabled by default).
  3322  		"--no-volatiles",         // --volatiles | --no-volatiles: enable | disable volatiles (enabled by default).
  3323  		"--paranoid",             // --paranoid | --no-paranoid: enable | disable pointer-related assertions (disabled by default).
  3324  	}, " ")
  3325  
  3326  	csmith, err := exec.LookPath("csmith")
  3327  	if err != nil {
  3328  		t.Skip("csmith executable not found")
  3329  		return
  3330  	}
  3331  
  3332  	var csp string
  3333  	switch runtime.GOOS {
  3334  	case "linux", "darwin":
  3335  		csp = "/usr/include/csmith"
  3336  	}
  3337  	if s := os.Getenv("CSMITH_PATH"); s != "" {
  3338  		csp = s
  3339  	}
  3340  	if csp != "" {
  3341  		csp = fmt.Sprintf("-I%s", csp)
  3342  	}
  3343  
  3344  	argCh := make(chan string, 100)
  3345  	doneCh := make(chan struct{})
  3346  
  3347  	go func() {
  3348  		for _, v := range fixedBugs {
  3349  			select {
  3350  			case <-doneCh:
  3351  				return
  3352  			default:
  3353  				argCh <- v
  3354  			}
  3355  		}
  3356  		for {
  3357  			select {
  3358  			case <-doneCh:
  3359  				return
  3360  			default:
  3361  				argCh <- csmithDefaultArgs
  3362  			}
  3363  		}
  3364  	}()
  3365  
  3366  	go func() {
  3367  		<-time.After(*oCSmith)
  3368  		close(doneCh)
  3369  	}()
  3370  
  3371  	mustEmptyDir(t, tempDir)
  3372  	wd, err := os.Getwd()
  3373  	if err != nil {
  3374  		t.Fatal(err)
  3375  	}
  3376  
  3377  	if err := os.Chdir(tempDir); err != nil {
  3378  		t.Fatal(err)
  3379  	}
  3380  
  3381  	defer func() {
  3382  		if err := os.Chdir(wd); err != nil {
  3383  			t.Fatal(err)
  3384  		}
  3385  	}()
  3386  
  3387  	blacklist := map[string]struct{}{}
  3388  
  3389  	var rq, res, ok int
  3390  	limit := runtime.GOMAXPROCS(0)
  3391  	limiter := make(chan struct{}, limit)
  3392  	results := make(chan *runResult, limit)
  3393  	failed := map[string]string{}
  3394  	iFile := 0
  3395  loop:
  3396  	for {
  3397  		var args string
  3398  		select {
  3399  		case args = <-argCh:
  3400  			// ok
  3401  		case <-doneCh:
  3402  			break loop
  3403  		}
  3404  
  3405  		switch {
  3406  		case re != nil:
  3407  			if !re.MatchString(args) {
  3408  				continue
  3409  			}
  3410  
  3411  			close(doneCh)
  3412  		default:
  3413  			if _, ok := blacklist[filepath.Base(args)]; ok {
  3414  				continue
  3415  			}
  3416  		}
  3417  
  3418  		pth := fmt.Sprintf("%06d.c", iFile)
  3419  		iFile++
  3420  	more:
  3421  		select {
  3422  		case r := <-results:
  3423  			res++
  3424  			<-limiter
  3425  			switch r.err.(type) {
  3426  			case nil:
  3427  				os.Remove(r.name)
  3428  				ok++
  3429  				delete(failed, r.name)
  3430  			case skipErr:
  3431  				os.Remove(r.name)
  3432  				delete(failed, r.name)
  3433  				t.Errorf("%v: ERROR %v\n%s", r.name, r.err, r.out)
  3434  				if *oFF {
  3435  					break loop
  3436  				}
  3437  			default:
  3438  				t.Errorf("%v: ERROR %v\n%s", r.name, r.err, r.out)
  3439  				if *oFF {
  3440  					break loop
  3441  				}
  3442  			}
  3443  			goto more
  3444  		case limiter <- struct{}{}:
  3445  			rq++
  3446  			if *oTrc {
  3447  				fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth)
  3448  			}
  3449  			csOut, err := exec.Command(csmith, strings.Split(args, " ")...).Output()
  3450  			if err != nil {
  3451  				t.Fatalf("%v\n%s", err, csOut)
  3452  			}
  3453  
  3454  			if err := os.WriteFile(pth, csOut, 0660); err != nil {
  3455  				t.Fatalf("%s, %s: %v", pth, args, err)
  3456  			}
  3457  
  3458  			failed[pth] = string(csOut)
  3459  			go (&runTask{
  3460  				c:         results,
  3461  				csmithSrc: csOut,
  3462  				opts:      []string{csp},
  3463  				src:       pth,
  3464  			}).runCSmith()
  3465  		}
  3466  	}
  3467  	for res != rq {
  3468  		r := <-results
  3469  		res++
  3470  		<-limiter
  3471  		switch r.err.(type) {
  3472  		case nil:
  3473  			os.Remove(r.name)
  3474  			ok++
  3475  			delete(failed, r.name)
  3476  		case skipErr:
  3477  			os.Remove(r.name)
  3478  			delete(failed, r.name)
  3479  			t.Errorf("%v: ERROR %v\n%s", r.name, r.err, r.out)
  3480  		default:
  3481  			t.Errorf("%v: ERROR %v\n%s", r.name, r.err, r.out)
  3482  		}
  3483  	}
  3484  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  3485  	if len(failed) == 0 {
  3486  		return
  3487  	}
  3488  
  3489  	var a []string
  3490  	for k := range failed {
  3491  		a = append(a, k)
  3492  	}
  3493  	sort.Strings(a)
  3494  	for _, v := range a {
  3495  		t.Logf("FAIL %s\n%s", v, failed[v])
  3496  		if *oFF {
  3497  			break
  3498  		}
  3499  	}
  3500  	t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed))
  3501  	for _, v := range a {
  3502  		t.Logf("FAIL %s: %s", v, extractCSmithOptions(failed[v]))
  3503  		if *oFF {
  3504  			break
  3505  		}
  3506  	}
  3507  }
  3508  
  3509  func extractCSmithOptions(s string) string {
  3510  	const (
  3511  		tag  = "* Options:"
  3512  		tag2 = "* Seed:"
  3513  	)
  3514  	x := strings.Index(s, tag)
  3515  	s = s[x+len(tag):]
  3516  	x = strings.Index(s, "\n")
  3517  	s2 := s[x:]
  3518  	s = s[:x]
  3519  	s = strings.TrimSpace(s)
  3520  	if strings.Contains(s, " -s ") {
  3521  		return s
  3522  	}
  3523  
  3524  	x = strings.Index(s2, tag2)
  3525  	s2 = s2[x+len(tag):]
  3526  	x = strings.Index(s2, "\n")
  3527  	s2 = s2[:x]
  3528  	return fmt.Sprintf("%s -s %s", s, strings.TrimSpace(s2))
  3529  }