modernc.org/gocc@v0.0.1/all_test.go (about) 1 // Copyright 2019 The GOCC 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 gcc 4.7 6 7 package main // import "modernc.org/gocc" 8 9 import ( 10 "archive/tar" 11 "archive/zip" 12 "bufio" 13 "bytes" 14 "compress/bzip2" 15 "compress/gzip" 16 "context" 17 "encoding/hex" 18 "flag" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "net/http" 23 "os" 24 "os/exec" 25 "path" 26 "path/filepath" 27 "regexp" 28 "runtime" 29 "runtime/debug" 30 "sort" 31 "strings" 32 "testing" 33 "time" 34 35 "github.com/dustin/go-humanize" 36 "github.com/google/go-cmp/cmp" 37 "modernc.org/cc/v3" 38 ) 39 40 func caller(s string, va ...interface{}) { 41 if s == "" { 42 s = strings.Repeat("%v ", len(va)) 43 } 44 _, fn, fl, _ := runtime.Caller(2) 45 fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 46 fmt.Fprintf(os.Stderr, s, va...) 47 fmt.Fprintln(os.Stderr) 48 _, fn, fl, _ = runtime.Caller(1) 49 fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 50 fmt.Fprintln(os.Stderr) 51 os.Stderr.Sync() 52 } 53 54 func dbg(s string, va ...interface{}) { 55 if s == "" { 56 s = strings.Repeat("%v ", len(va)) 57 } 58 _, fn, fl, _ := runtime.Caller(1) 59 fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 60 fmt.Fprintf(os.Stderr, s, va...) 61 fmt.Fprintln(os.Stderr) 62 os.Stderr.Sync() 63 } 64 65 func TODO(...interface{}) string { //TODOOK 66 _, fn, fl, _ := runtime.Caller(1) 67 return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 68 } 69 70 func stack() string { return string(debug.Stack()) } 71 72 func use(...interface{}) {} 73 74 func init() { 75 use(caller, dbg, TODO, stack, dumpLayout) //TODOOK 76 } 77 78 // ---------------------------------------------------------------------------- 79 80 var ( 81 oBlackBox = flag.String("blackbox", "", "Record CSmith file to this file") 82 oCSmith = flag.Duration("csmith", time.Minute, "") 83 oCertN = flag.Int("certN", 5, "") 84 oDev = flag.Bool("dev", false, "Enable developer tests/downloads.") 85 oDownload = flag.Bool("download", false, "Download missing testdata. Add -dev to download also 100+ MB of developer resources.") 86 oEdit = flag.Bool("edit", false, "") 87 oFF = flag.Bool("ff", false, "Fail fast") 88 oM32 = flag.Bool("m32", false, "") 89 oRE = flag.String("re", "", "") 90 oStackTrace = flag.Bool("trcstack", false, "") 91 oTrace = flag.Bool("trc", false, "Print tested paths.") 92 oTraceO = flag.Bool("trco", false, "Print test output") 93 94 csmithDefaultArgs = strings.Join([]string{ 95 "--bitfields", // --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default). 96 "--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. 97 "--no-const-pointers", // --const-pointers | --no-const-pointers: enable | disable const pointers (enabled by default). 98 "--no-consts", // --consts | --no-consts: enable | disable const qualifier (enabled by default). 99 "--no-packed-struct", // --packed-struct | --no-packed-struct: enable | disable packed structs by adding #pragma pack(1) before struct definition (disabled by default). 100 // "--no-safe-math", // --safe-math | --no-safe-math: Emit safe math wrapper functions (enabled by default). 101 "--no-volatile-pointers", // --volatile-pointers | --no-volatile-pointers: enable | disable volatile pointers (enabled by default). 102 "--no-volatiles", // --volatiles | --no-volatiles: enable | disable volatiles (enabled by default). 103 "--paranoid", // --paranoid | --no-paranoid: enable | disable pointer-related assertions (disabled by default). 104 }, " ") 105 106 downloads = []struct { 107 dir, url string 108 sz int 109 dev bool 110 }{ 111 {gccDir, "http://mirror.koddos.net/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.gz", 118000, true}, 112 {sqliteDir, "https://www.sqlite.org/2019/sqlite-amalgamation-3300100.zip", 2400, false}, 113 {tccDir, "http://download.savannah.gnu.org/releases/tinycc/tcc-0.9.27.tar.bz2", 620, false}, 114 } 115 116 gccDir = filepath.FromSlash("testdata/gcc-9.1.0") 117 sqliteDir = filepath.FromSlash("testdata/sqlite-amalgamation-3300100") 118 tccDir = filepath.FromSlash("testdata/tcc-0.9.27") 119 testWD string 120 121 gccTestDecls = cc.Source{Name: "<gcc-test-builtin>", Value: ` 122 char *strchr(const char *s, int c); 123 char *strcpy(char *dest, const char *src); 124 double copysign(double x, double y); 125 double fabs(double x); 126 float copysignf(float x, float y); 127 int abs(int j); 128 int ffs(int i); 129 int isprint(int c); 130 int memcmp(const void *s1, const void *s2, size_t n); 131 int printf(const char *format, ...); 132 int snprintf(char *str, size_t size, const char *format, ...); 133 int sprintf(char *str, const char *format, ...); 134 int strcmp(const char *s1, const char *s2); 135 size_t strlen(const char *s); 136 void *malloc(size_t size); 137 void *memcpy(void *dest, const void *src, size_t n); 138 void *memset(void *s, int c, size_t n); 139 void abort(void); 140 void exit(int status); 141 void free(void *ptr); 142 `} 143 ) 144 145 func TestMain(m *testing.M) { 146 isTesting = true 147 148 defer func() { 149 os.Exit(m.Run()) 150 }() 151 152 flag.BoolVar(&oQuiet, "q", false, "") 153 flag.BoolVar(&oTODO, "todo", false, "") 154 flag.BoolVar(&traceIL, "il", false, "print generated IL") 155 156 flag.Parse() 157 var err error 158 if testWD, err = os.Getwd(); err != nil { 159 panic("Cannot determine working dir: " + err.Error()) 160 } 161 162 if *oDownload { 163 download() 164 } 165 } 166 167 func download() { 168 tmp, err := ioutil.TempDir("", "") 169 if err != nil { 170 fmt.Fprintf(os.Stderr, "%s\n", err) 171 return 172 } 173 174 defer os.RemoveAll(tmp) 175 176 for _, v := range downloads { 177 dir := filepath.FromSlash(v.dir) 178 root := filepath.Dir(v.dir) 179 fi, err := os.Stat(dir) 180 switch { 181 case err == nil: 182 if !fi.IsDir() { 183 fmt.Fprintf(os.Stderr, "expected %s to be a directory\n", dir) 184 } 185 continue 186 default: 187 if !os.IsNotExist(err) { 188 fmt.Fprintf(os.Stderr, "%s", err) 189 continue 190 } 191 192 if v.dev && !*oDev { 193 fmt.Printf("Not downloading (no -dev) %v MB from %s\n", float64(v.sz)/1000, v.url) 194 continue 195 } 196 197 } 198 199 if err := func() error { 200 fmt.Printf("Downloading %v MB from %s\n", float64(v.sz)/1000, v.url) 201 resp, err := http.Get(v.url) 202 if err != nil { 203 return err 204 } 205 206 defer resp.Body.Close() 207 208 base := filepath.Base(v.url) 209 name := filepath.Join(tmp, base) 210 f, err := os.Create(name) 211 if err != nil { 212 return err 213 } 214 215 defer os.Remove(name) 216 217 n, err := io.Copy(f, resp.Body) 218 if err != nil { 219 return err 220 } 221 222 if _, err := f.Seek(0, io.SeekStart); err != nil { 223 return err 224 } 225 226 switch { 227 case strings.HasSuffix(base, ".tar.bz2"): 228 b2r := bzip2.NewReader(bufio.NewReader(f)) 229 tr := tar.NewReader(b2r) 230 for { 231 hdr, err := tr.Next() 232 if err != nil { 233 if err != io.EOF { 234 return err 235 } 236 237 return nil 238 } 239 240 switch hdr.Typeflag { 241 case tar.TypeDir: 242 if err = os.MkdirAll(filepath.Join(root, hdr.Name), 0770); err != nil { 243 return err 244 } 245 case tar.TypeReg, tar.TypeRegA: 246 f, err := os.OpenFile(filepath.Join(root, hdr.Name), os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode)) 247 if err != nil { 248 return err 249 } 250 251 w := bufio.NewWriter(f) 252 if _, err = io.Copy(w, tr); err != nil { 253 return err 254 } 255 256 if err := w.Flush(); err != nil { 257 return err 258 } 259 260 if err := f.Close(); err != nil { 261 return err 262 } 263 default: 264 return fmt.Errorf("unexpected tar header typeflag %#02x", hdr.Typeflag) 265 } 266 } 267 case strings.HasSuffix(base, ".tar.gz"): 268 return untar(root, bufio.NewReader(f)) 269 case strings.HasSuffix(base, ".zip"): 270 r, err := zip.NewReader(f, n) 271 if err != nil { 272 return err 273 } 274 275 for _, f := range r.File { 276 fi := f.FileInfo() 277 if fi.IsDir() { 278 if err := os.MkdirAll(filepath.Join(root, f.Name), 0770); err != nil { 279 return err 280 } 281 282 continue 283 } 284 285 if err := func() error { 286 rc, err := f.Open() 287 if err != nil { 288 return err 289 } 290 291 defer rc.Close() 292 293 dname := filepath.Join(root, f.Name) 294 g, err := os.Create(dname) 295 if err != nil { 296 return err 297 } 298 299 defer g.Close() 300 301 n, err = io.Copy(g, rc) 302 return err 303 }(); err != nil { 304 return err 305 } 306 } 307 return nil 308 } 309 panic("internal error") //TODOOK 310 }(); err != nil { 311 fmt.Fprintln(os.Stderr, err) 312 } 313 } 314 } 315 316 func TestTCC(t *testing.T) { 317 root := filepath.Join(testWD, filepath.FromSlash(tccDir)) 318 if _, err := os.Stat(root); err != nil { 319 t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root) 320 } 321 322 g := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 323 324 defer g.close() 325 326 todos = map[todoPos]int{} 327 var files, ok int 328 if *oEdit { 329 defer func() { 330 fmt.Printf("TCC files %s, ok %s\n", h(files), h(ok)) 331 }() 332 } 333 const dir = "tests/tests2" 334 t.Run("noOpt", func(t *testing.T) { 335 f, o := testTCCExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false) 336 files += f 337 ok += o 338 }) 339 t.Logf("files %s, ok %s", h(files), h(ok)) 340 if !oQuiet { 341 dumpTODOs(t) 342 } 343 344 g2 := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH)) 345 346 defer g2.close() 347 todos = map[todoPos]int{} 348 files = 0 349 ok = 0 350 t.Run("opt", func(t *testing.T) { 351 f, o := testTCCExec(g2.w, t, filepath.Join(root, filepath.FromSlash(dir)), true) 352 files += f 353 ok += o 354 }) 355 t.Logf("files %s, ok %s", h(files), h(ok)) 356 if !oQuiet { 357 dumpTODOs(t) 358 } 359 } 360 361 type golden struct { 362 t *testing.T 363 f *os.File 364 w *bufio.Writer 365 } 366 367 func newGolden(t *testing.T, fn string) *golden { 368 f, err := os.Create(filepath.FromSlash(fn)) 369 if err != nil { 370 t.Fatal(err) 371 } 372 373 w := bufio.NewWriter(f) 374 return &golden{t, f, w} 375 } 376 377 func (g *golden) close() { 378 if err := g.w.Flush(); err != nil { 379 g.t.Fatal(err) 380 } 381 382 if err := g.f.Close(); err != nil { 383 g.t.Fatal(err) 384 } 385 } 386 387 func fail(t *testing.T, s string, args ...interface{}) { 388 if *oFF { 389 t.Fatalf(s, args...) 390 } 391 392 if !oQuiet { 393 t.Errorf(s, args...) 394 } 395 } 396 397 func testTCCExec(w io.Writer, t *testing.T, dir string, optimize bool) (files, ok int) { 398 const binaryName = "a.out" 399 blacklist := map[string]struct{}{ 400 "34_array_assignment.c": {}, // gcc: 16:6: error: assignment to expression with array type 401 "60_errors_and_warnings.c": {}, // Not a standalone test. gcc fails. 402 "93_integer_promotion.c": {}, // The expected output does not agree with gcc. 403 "95_bitfields.c": {}, // Included from 95_bitfields_ms.c 404 "95_bitfields_ms.c": {}, // The expected output does not agree with gcc. 405 "96_nodata_wanted.c": {}, // Not a standalone test. gcc fails. 406 "99_fastcall.c": {}, // 386 only 407 408 "73_arm64.c": {}, //TODO struct varargs, not supported by QBE 409 "75_array_in_struct_init.c": {}, //TODO flat struct initializer 410 "80_flexarray.c": {}, //TODO Flexible array member 411 "85_asm-outside-function.c": {}, //TODO 412 "90_struct-init.c": {}, //TODO cc ... in designator 413 "94_generic.c": {}, //TODO cc _Generic 414 "98_al_ax_extend.c": {}, //TODO 415 } 416 wd, err := os.Getwd() 417 if err != nil { 418 t.Fatal(err) 419 } 420 421 defer os.Chdir(wd) 422 423 temp, err := ioutil.TempDir("", "gocc-test-") 424 if err != nil { 425 t.Fatal(err) 426 } 427 428 defer os.RemoveAll(temp) 429 430 if err := os.Chdir(temp); err != nil { 431 t.Fatal(err) 432 } 433 434 var re *regexp.Regexp 435 if s := *oRE; s != "" { 436 re = regexp.MustCompile(s) 437 } 438 439 if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 440 if err != nil { 441 if os.IsNotExist(err) { 442 err = nil 443 } 444 return err 445 } 446 447 if info.IsDir() { 448 return skipDir(path) 449 } 450 451 if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 { 452 return nil 453 } 454 455 if _, ok := blacklist[filepath.Base(path)]; ok { 456 return nil 457 } 458 459 files++ 460 461 if re != nil && !re.MatchString(path) { 462 return nil 463 } 464 465 if *oTrace { 466 fmt.Fprintln(os.Stderr, files, ok, path) 467 } 468 469 if err := os.Remove(binaryName); err != nil && !os.IsNotExist(err) { 470 return err 471 } 472 473 goccArgs := []string{"gocc", "-o", binaryName, "-Dasm=__asm__", "-w"} 474 var args []string 475 switch base := filepath.Base(path); base { 476 case 477 "22_floating_point.c", 478 "24_math_library.c": 479 480 goccArgs = append(goccArgs, "-lm") 481 case "31_args.c": 482 args = []string{"arg1", "arg2", "arg3", "arg4", "arg5"} 483 case "46_grep.c": 484 if err := copyFile(path, filepath.Join(temp, base)); err != nil { 485 return err 486 } 487 488 args = []string{`[^* ]*[:a:d: ]+\:\*-/: $`, base} 489 } 490 491 if !func() (r bool) { 492 defer func() { 493 if err := recover(); err != nil { 494 if *oStackTrace { 495 fmt.Printf("%s\n", stack()) 496 } 497 if *oTrace { 498 fmt.Println(err) 499 } 500 if !oQuiet { 501 fail(t, "%s: %v", path, err) 502 } 503 r = false 504 } 505 }() 506 507 goccArgs = append(goccArgs, path) 508 switch base := filepath.Base(path); base { 509 case 510 "22_floating_point.c", 511 "24_math_library.c": 512 513 goccArgs = append(goccArgs, "-lm") 514 } 515 if _, err := execute(goccArgs, optimize); err != nil { 516 if *oTrace { 517 fmt.Println(err) 518 } 519 if !oQuiet { 520 fail(t, "%s: %v", path, err) 521 } 522 return false 523 } 524 525 return true 526 }() { 527 return nil 528 } 529 530 out, err := exec.Command("./"+binaryName, args...).CombinedOutput() 531 if err != nil { 532 if *oTrace { 533 fmt.Println(err) 534 } 535 t.Errorf("%v: %v", path, err) 536 return nil 537 } 538 539 if *oTraceO { 540 fmt.Printf("%s\n", out) 541 } 542 exp, err := ioutil.ReadFile(noExt(path) + ".expect") 543 if err != nil { 544 if os.IsNotExist(err) { 545 fmt.Fprintln(w, filepath.Base(path)) 546 ok++ 547 return nil 548 } 549 550 return err 551 } 552 553 out = trim(out) 554 exp = trim(exp) 555 556 switch base := filepath.Base(path); base { 557 case "70_floating_point_literals.c": //TODO TCC binary extension 558 a := strings.Split(string(exp), "\n") 559 exp = []byte(strings.Join(a[:35], "\n")) 560 } 561 562 if !bytes.Equal(out, exp) { 563 if *oTrace { 564 fmt.Println(err) 565 } 566 t.Errorf("%v: %s\nout\n%s\nexp\n%s", path, cmp.Diff(string(exp), string(out)), out, exp) 567 return nil 568 } 569 570 fmt.Fprintln(w, filepath.Base(path)) 571 ok++ 572 return nil 573 }); err != nil { 574 fail(t, "%v", err) 575 } 576 return files, ok 577 } 578 579 func TestTCCGo(t *testing.T) { 580 root := filepath.Join(testWD, filepath.FromSlash(tccDir)) 581 if _, err := os.Stat(root); err != nil { 582 t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root) 583 } 584 585 g := newGolden(t, fmt.Sprintf("testdata/tcc_go_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 586 587 defer g.close() 588 589 todos = map[todoPos]int{} 590 var files, ok int 591 if *oEdit { 592 defer func() { 593 fmt.Printf("TCC files %s, ok %s\n", h(files), h(ok)) 594 }() 595 } 596 const dir = "tests/tests2" 597 f, o := testTCCGoExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false) 598 files += f 599 ok += o 600 t.Logf("files %s, ok %s", h(files), h(ok)) 601 if !oQuiet { 602 dumpTODOs(t) 603 } 604 } 605 606 func testTCCGoExec(w io.Writer, t *testing.T, dir string, optimize bool) (files, ok int) { 607 const main = "main.go" 608 blacklist := map[string]struct{}{ 609 "34_array_assignment.c": {}, // gcc: 16:6: error: assignment to expression with array type 610 "60_errors_and_warnings.c": {}, // Not a standalone test. gcc fails. 611 "93_integer_promotion.c": {}, // The expected output does not agree with gcc. 612 "95_bitfields.c": {}, // Included from 95_bitfields_ms.c 613 "95_bitfields_ms.c": {}, // The expected output does not agree with gcc. 614 "96_nodata_wanted.c": {}, // Not a standalone test. gcc fails. 615 "99_fastcall.c": {}, // 386 only 616 617 "40_stdio.c": {}, //TODO 618 "42_function_pointer.c": {}, //TODO 619 "46_grep.c": {}, //TODO 620 "73_arm64.c": {}, //TODO struct varargs, not supported by QBE 621 "75_array_in_struct_init.c": {}, //TODO flat struct initializer 622 "80_flexarray.c": {}, //TODO Flexible array member 623 "85_asm-outside-function.c": {}, //TODO 624 "90_struct-init.c": {}, //TODO cc ... in designator 625 "94_generic.c": {}, //TODO cc _Generic 626 "98_al_ax_extend.c": {}, //TODO 627 } 628 wd, err := os.Getwd() 629 if err != nil { 630 t.Fatal(err) 631 } 632 633 defer os.Chdir(wd) 634 635 temp, err := ioutil.TempDir("", "gocc-test-") 636 if err != nil { 637 t.Fatal(err) 638 } 639 640 defer os.RemoveAll(temp) 641 642 if err := os.Chdir(temp); err != nil { 643 t.Fatal(err) 644 } 645 646 var re *regexp.Regexp 647 if s := *oRE; s != "" { 648 re = regexp.MustCompile(s) 649 } 650 651 if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 652 if err != nil { 653 if os.IsNotExist(err) { 654 err = nil 655 } 656 return err 657 } 658 659 if info.IsDir() { 660 return skipDir(path) 661 } 662 663 if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 { 664 return nil 665 } 666 667 if _, ok := blacklist[filepath.Base(path)]; ok { 668 return nil 669 } 670 671 files++ 672 673 if re != nil && !re.MatchString(path) { 674 return nil 675 } 676 677 if *oTrace { 678 fmt.Fprintln(os.Stderr, files, ok, path) 679 } 680 681 if err := os.Remove(main); err != nil && !os.IsNotExist(err) { 682 return err 683 } 684 685 goccArgs := []string{"gocc", "-o", main, "-Dasm=__asm__"} 686 var args []string 687 switch base := filepath.Base(path); base { 688 case 689 "22_floating_point.c", 690 "24_math_library.c": 691 goccArgs = append(goccArgs, "-lm") 692 case "31_args.c": 693 args = []string{"arg1", "arg2", "arg3", "arg4", "arg5"} 694 case "46_grep.c": 695 if err := copyFile(path, filepath.Join(temp, base)); err != nil { 696 return err 697 } 698 args = []string{`[^* ]*[:a:d: ]+\:\*-/: $`, base} 699 } 700 if !func() (r bool) { 701 defer func() { 702 if err := recover(); err != nil { 703 if *oStackTrace { 704 fmt.Printf("%s\n", stack()) 705 } 706 if *oTrace { 707 fmt.Println(err) 708 } 709 if !oQuiet { 710 fail(t, "%s: %v", path, err) 711 } 712 r = false 713 } 714 }() 715 716 goccArgs = append(goccArgs, path) 717 if _, err := execute(goccArgs, optimize); err != nil { 718 if *oTrace { 719 fmt.Println(err) 720 } 721 if !oQuiet { 722 fail(t, "%s: %v", path, err) 723 } 724 return false 725 } 726 727 return true 728 }() { 729 return nil 730 } 731 732 out, err := exec.Command("go", append([]string{"run", main}, args...)...).CombinedOutput() 733 if err != nil { 734 if *oTrace { 735 fmt.Println(err) 736 } 737 t.Errorf("%v: %s\n%v", path, out, err) 738 return nil 739 } 740 741 if *oTraceO { 742 fmt.Printf("%s\n", out) 743 } 744 exp, err := ioutil.ReadFile(noExt(path) + ".expect") 745 if err != nil { 746 if os.IsNotExist(err) { 747 fmt.Fprintln(w, filepath.Base(path)) 748 ok++ 749 return nil 750 } 751 752 return err 753 } 754 755 out = trim(out) 756 exp = trim(exp) 757 758 switch base := filepath.Base(path); base { 759 case "70_floating_point_literals.c": //TODO TCC binary extension 760 a := strings.Split(string(exp), "\n") 761 exp = []byte(strings.Join(a[:35], "\n")) 762 } 763 764 if !bytes.Equal(out, exp) { 765 if *oTrace { 766 fmt.Println(err) 767 } 768 t.Errorf("%v: %s\nout\n%s\nexp\n%s", path, cmp.Diff(string(exp), string(out)), out, exp) 769 return nil 770 } 771 772 fmt.Fprintln(w, filepath.Base(path)) 773 ok++ 774 return nil 775 }); err != nil { 776 fail(t, "%v", err) 777 } 778 return files, ok 779 } 780 781 func noExt(s string) string { 782 ext := filepath.Ext(s) 783 if ext == "" { 784 panic("internal error") //TODOOK 785 } 786 return s[:len(s)-len(ext)] 787 } 788 789 func copyFile(src, dst string) error { 790 b, err := ioutil.ReadFile(src) 791 if err != nil { 792 return err 793 } 794 795 return ioutil.WriteFile(dst, b, 0660) 796 } 797 798 func trim(b []byte) (r []byte) { 799 b = bytes.TrimLeft(b, "\n") 800 b = bytes.TrimRight(b, "\n") 801 a := bytes.Split(b, []byte("\n")) 802 for i, v := range a { 803 a[i] = bytes.TrimSpace(v) 804 } 805 return bytes.Join(a, []byte("\n")) 806 } 807 808 func execute(args []string, optimize bool, more ...cc.Source) ([]byte, error) { 809 args = append(args, "-w") 810 if *oM32 { 811 args = append(args, "-m32") 812 } 813 if optimize { 814 args = append(args, "-O") 815 } 816 t, err := newTask(args) 817 if err != nil { 818 return nil, err 819 } 820 821 t.testSources = more 822 t.doNotCache = true 823 var stdout, stderr bytes.Buffer 824 rc := t.main(&stdout, &stderr) 825 if stdout.Len() != 0 { 826 fmt.Printf("%s", stdout.Bytes()) 827 } 828 if stderr.Len() != 0 { 829 return nil, fmt.Errorf("%s", stderr.Bytes()) 830 } 831 832 if rc != 0 { 833 return nil, fmt.Errorf("internal error") 834 } 835 836 return stdout.Bytes(), nil 837 } 838 839 func skipDir(path string) error { 840 if strings.HasPrefix(filepath.Base(path), ".") { 841 return filepath.SkipDir 842 } 843 844 return nil 845 } 846 847 func h(v interface{}) string { 848 switch x := v.(type) { 849 case int: 850 return humanize.Comma(int64(x)) 851 case int64: 852 return humanize.Comma(x) 853 case uint64: 854 return humanize.Comma(int64(x)) 855 case float64: 856 return humanize.CommafWithDigits(x, 0) 857 default: 858 panic(fmt.Errorf("%T", x)) //TODOOK 859 } 860 } 861 862 func TestMiniGMP(t *testing.T) { 863 g := newGolden(t, fmt.Sprintf("testdata/mini-gmp_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 864 865 defer g.close() 866 867 var files, ok int 868 t.Run("noOpt", func(t *testing.T) { 869 files, ok = testMiniGMP(g.w, t, false, nil) 870 }) 871 t.Logf("files %s, ok %s", h(files), h(ok)) 872 873 g2 := newGolden(t, fmt.Sprintf("testdata/mini-gmp_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH)) 874 875 defer g2.close() 876 877 var blacklist map[string]struct{} 878 if arch == 32 || *oM32 { 879 blacklist = map[string]struct{}{ 880 "t-double": {}, // gcc 7.4 -O bug 881 "t-cmp_d": {}, // gcc 7.4 -O bug 882 } 883 } 884 t.Run("opt", func(t *testing.T) { 885 files, ok = testMiniGMP(g2.w, t, true, blacklist) 886 }) 887 t.Logf("files %s, ok %s", h(files), h(ok)) 888 } 889 890 func testMiniGMP(w io.Writer, t *testing.T, opt bool, blacklist map[string]struct{}) (files, ok int) { 891 var re *regexp.Regexp 892 if s := *oRE; s != "" { 893 re = regexp.MustCompile(s) 894 } 895 896 b, err := ioutil.ReadFile(filepath.FromSlash("testdata/mini-gmp.tar.gz")) 897 if err != nil { 898 t.Fatal(err) 899 } 900 901 dir, err := ioutil.TempDir("", "gocc-test-") 902 if err != nil { 903 t.Fatal(err) 904 } 905 906 defer os.RemoveAll(dir) 907 908 if err := untar(dir, bytes.NewReader(b)); err != nil { 909 t.Fatal(err) 910 } 911 912 wd, err := os.Getwd() 913 if err != nil { 914 t.Fatal(err) 915 } 916 917 if err := os.Chdir(filepath.Join(dir, filepath.FromSlash("mini-gmp/tests"))); err != nil { 918 t.Fatal(err) 919 } 920 921 defer os.Chdir(wd) 922 923 for _, v := range strings.Split(strings.TrimSpace(` 924 gocc -w -c testutils.c -o testutils.o 925 gocc -w -c t-add.c -o t-add.o 926 gocc -w -c hex-random.c -o hex-random.o 927 gocc -w -c mini-random.c -o mini-random.o 928 gocc -w t-add.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-add 929 gocc -w -c t-sub.c -o t-sub.o 930 gocc -w t-sub.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-sub 931 gocc -w -c t-mul.c -o t-mul.o 932 gocc -w t-mul.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-mul 933 gocc -w -c t-invert.c -o t-invert.o 934 gocc -w t-invert.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-invert 935 gocc -w -c t-div.c -o t-div.o 936 gocc -w t-div.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-div 937 gocc -w -c t-div_2exp.c -o t-div_2exp.o 938 gocc -w t-div_2exp.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-div_2exp 939 gocc -w -c t-double.c -o t-double.o 940 gocc -w t-double.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-double 941 gocc -w -c t-cmp_d.c -o t-cmp_d.o 942 gocc -w t-cmp_d.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-cmp_d 943 gocc -w -c t-gcd.c -o t-gcd.o 944 gocc -w t-gcd.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-gcd 945 gocc -w -c t-lcm.c -o t-lcm.o 946 gocc -w t-lcm.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-lcm 947 gocc -w -c t-import.c -o t-import.o 948 gocc -w t-import.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-import 949 gocc -w -c t-comb.c -o t-comb.o 950 gocc -w t-comb.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-comb 951 gocc -w -c t-signed.c -o t-signed.o 952 gocc -w t-signed.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-signed 953 gocc -w -c t-sqrt.c -o t-sqrt.o 954 gocc -w t-sqrt.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-sqrt 955 gocc -w -c t-root.c -o t-root.o 956 gocc -w t-root.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-root 957 gocc -w -c t-powm.c -o t-powm.o 958 gocc -w t-powm.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-powm 959 gocc -w -c t-logops.c -o t-logops.o 960 gocc -w t-logops.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-logops 961 gocc -w -c t-bitops.c -o t-bitops.o 962 gocc -w t-bitops.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-bitops 963 gocc -w -c t-scan.c -o t-scan.o 964 gocc -w t-scan.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-scan 965 gocc -w -c t-str.c -o t-str.o 966 gocc -w t-str.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-str 967 gocc -w -c t-reuse.c -o t-reuse.o 968 gocc -w t-reuse.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-reuse 969 gocc -w -c t-aorsmul.c -o t-aorsmul.o 970 gocc -w t-aorsmul.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-aorsmul 971 gocc -w -c t-limbs.c -o t-limbs.o 972 gocc -w t-limbs.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-limbs 973 gocc -w -c t-cong.c -o t-cong.o 974 gocc -w t-cong.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-cong 975 gocc -w -c t-pprime_p.c -o t-pprime_p.o 976 gocc -w t-pprime_p.o hex-random.o mini-random.o testutils.o -lgmp -lm -lmcheck -o t-pprime_p 977 `), "\n") { 978 979 if *oTrace { 980 fmt.Fprintln(os.Stderr, v) 981 } 982 out, err := execute(strings.Split(v, " "), opt) 983 if err != nil { 984 t.Fatalf("%s\n%v", out, err) 985 } 986 } 987 for _, v := range strings.Split("t-add t-sub t-mul t-invert t-div t-div_2exp t-double t-cmp_d t-gcd t-lcm t-import t-comb t-signed t-sqrt t-root t-powm t-logops t-bitops t-scan t-str t-reuse t-aorsmul t-limbs t-cong t-pprime_p", " ") { 988 if _, ok := blacklist[v]; ok { 989 continue 990 } 991 992 if *oTrace { 993 fmt.Fprintln(os.Stderr, v) 994 } 995 files++ 996 if re != nil && !re.MatchString(v) { 997 continue 998 } 999 1000 out, err := exec.Command("./" + v).CombinedOutput() 1001 if err != nil { 1002 t.Errorf("%v\n%s\n%v", v, out, err) 1003 continue 1004 } 1005 1006 fmt.Fprintln(w, v) 1007 ok++ 1008 } 1009 return files, ok 1010 } 1011 1012 func untar(root string, r io.Reader) error { 1013 gr, err := gzip.NewReader(r) 1014 if err != nil { 1015 return err 1016 } 1017 1018 tr := tar.NewReader(gr) 1019 for { 1020 hdr, err := tr.Next() 1021 if err != nil { 1022 if err != io.EOF { 1023 return err 1024 } 1025 1026 return nil 1027 } 1028 1029 switch hdr.Typeflag { 1030 case tar.TypeDir: 1031 if err = os.MkdirAll(filepath.Join(root, hdr.Name), 0770); err != nil { 1032 return err 1033 } 1034 case tar.TypeReg, tar.TypeRegA: 1035 f, err := os.OpenFile(filepath.Join(root, hdr.Name), os.O_CREATE|os.O_WRONLY, os.FileMode(hdr.Mode)) 1036 if err != nil { 1037 return err 1038 } 1039 1040 w := bufio.NewWriter(f) 1041 if _, err = io.Copy(w, tr); err != nil { 1042 return err 1043 } 1044 1045 if err := w.Flush(); err != nil { 1046 return err 1047 } 1048 1049 if err := f.Close(); err != nil { 1050 return err 1051 } 1052 default: 1053 return fmt.Errorf("unexpected tar header typeflag %#02x", hdr.Typeflag) 1054 } 1055 } 1056 } 1057 1058 func dumpTODOs(t *testing.T) { 1059 var a []string 1060 sum := 0 1061 for k, v := range todos { 1062 sum += v 1063 a = append(a, fmt.Sprintf("%6d %s:%d", v, k.file, k.line)) 1064 } 1065 sort.Sort(sort.Reverse(sort.StringSlice(a))) 1066 t.Logf("\n%s\nsum: %d", strings.Join(a, "\n"), sum) 1067 } 1068 1069 func TestGCCExec(t *testing.T) { 1070 root := filepath.Join(testWD, filepath.FromSlash(gccDir)) 1071 if _, err := os.Stat(root); err != nil { 1072 t.Fatalf("Missing resources in %s. Please run 'go test -download -dev' to fix.", root) 1073 } 1074 1075 g := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1076 1077 defer g.close() 1078 1079 todos = map[todoPos]int{} 1080 var files, ok int 1081 if *oEdit { 1082 defer func() { 1083 fmt.Printf("GCC files %s, ok %s\n", h(files), h(ok)) 1084 }() 1085 } 1086 const dir = "gcc/testsuite/gcc.c-torture/execute" 1087 t.Run("noOpt", func(t *testing.T) { 1088 f, o := testGCCExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false) 1089 files += f 1090 ok += o 1091 }) 1092 t.Logf("files %s, ok %s", h(files), h(ok)) 1093 if !oQuiet { 1094 dumpTODOs(t) 1095 } 1096 1097 g2 := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.opt.golden", runtime.GOOS, runtime.GOARCH)) 1098 1099 defer g2.close() 1100 todos = map[todoPos]int{} 1101 files = 0 1102 ok = 0 1103 t.Run("opt", func(t *testing.T) { 1104 f, o := testGCCExec(g2.w, t, filepath.Join(root, filepath.FromSlash(dir)), true) 1105 files += f 1106 ok += o 1107 }) 1108 t.Logf("files %s, ok %s", h(files), h(ok)) 1109 if !oQuiet { 1110 dumpTODOs(t) 1111 } 1112 } 1113 1114 func testGCCExec(w io.Writer, t *testing.T, dir string, opt bool) (files, ok int) { 1115 const binaryName = "a.out" 1116 blacklist := map[string]struct{}{ //TODO- 1117 "20021127-1.c": {}, // non standard GCC behavior 1118 "strlen-3.c": {}, // not a standalone test 1119 "eeprof-1.c": {}, // requires instrumentation 1120 1121 "20010904-1.c": {}, //TODO __attribute__((aligned(alignment))) 1122 "20010904-2.c": {}, //TODO __attribute__((aligned(alignment))) 1123 "20040411-1.c": {}, //TODO typedef VLA 1124 "20040423-1.c": {}, //TODO typedef VLA 1125 "20041218-2.c": {}, //TODO struct VLA 1126 "20050215-1.c": {}, //TODO __attribute__ aligned 1127 "991014-1.c": {}, //TODO struct size overflow 1128 "align-3.c": {}, //TODO attr 1129 "const-addr-expr-1.c": {}, //TODO complex const addresss initialzer 1130 "pr23135.c": {}, //TODO QBE OOM 1131 "pr41935.c": {}, //TODO * VLA 1132 "pr64006.c": {}, //TODO __builtin_mul_overflow 1133 "pr82210.c": {}, //TODO VLA struct array, hangs 1134 "pr85095.c": {}, //TODO __builtin_add_overflow 1135 "rbug.c": {}, //TODO floating point rounding? 1136 "simd-1.c": {}, //TODO __attribute__((vector_size (16))) 1137 "simd-2.c": {}, //TODO __attribute__((vector_size (16))) 1138 } 1139 if opt { 1140 blacklist["20101011-1.c"] = struct{}{} // gcc 7.4 does not respect __attribute__ ((used)). 1141 } 1142 if opt && (arch == 32 || *oM32) { 1143 blacklist["20030331-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug 1144 blacklist["960830-1.c"] = struct{}{} // asm 1145 blacklist["floatunsisf-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug 1146 } 1147 wd, err := os.Getwd() 1148 if err != nil { 1149 t.Fatal(err) 1150 } 1151 1152 defer os.Chdir(wd) 1153 1154 temp, err := ioutil.TempDir("", "gocc-test-") 1155 if err != nil { 1156 t.Fatal(err) 1157 } 1158 1159 defer os.RemoveAll(temp) 1160 1161 if err := os.Chdir(temp); err != nil { 1162 t.Fatal(err) 1163 } 1164 1165 var re *regexp.Regexp 1166 if s := *oRE; s != "" { 1167 re = regexp.MustCompile(s) 1168 } 1169 1170 if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 1171 if err != nil { 1172 if os.IsNotExist(err) { 1173 err = nil 1174 } 1175 return err 1176 } 1177 1178 if info.IsDir() { 1179 return skipDir(path) 1180 } 1181 1182 if strings.Contains(filepath.ToSlash(path), "/builtins/") { 1183 return nil 1184 } 1185 1186 if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 { 1187 return nil 1188 } 1189 1190 if _, ok := blacklist[filepath.Base(path)]; ok { 1191 return nil 1192 } 1193 1194 files++ 1195 1196 if re != nil && !re.MatchString(path) { 1197 return nil 1198 } 1199 1200 if *oTrace { 1201 fmt.Fprintln(os.Stderr, files, ok, path) 1202 } 1203 1204 if err := os.Remove(binaryName); err != nil && !os.IsNotExist(err) { 1205 return err 1206 } 1207 1208 goccArgs := []string{"gocc", "-o", binaryName, "-Dasm=__asm__", "-w"} 1209 if !func() (r bool) { 1210 defer func() { 1211 if err := recover(); err != nil { 1212 if *oStackTrace { 1213 fmt.Printf("%s\n", stack()) 1214 } 1215 if *oTrace { 1216 fmt.Println(err) 1217 } 1218 if !oQuiet { 1219 fail(t, "%s: %v", path, err) 1220 } 1221 r = false 1222 } 1223 }() 1224 1225 if _, err := execute(append(goccArgs, path, "-lm"), opt, gccTestDecls); err != nil { 1226 if *oTrace { 1227 fmt.Println(err) 1228 } 1229 if !oQuiet { 1230 fail(t, "%s: %v", path, err) 1231 } 1232 return false 1233 } 1234 1235 return true 1236 }() { 1237 return nil 1238 } 1239 1240 out, err := exec.Command("./" + binaryName).CombinedOutput() 1241 if err != nil { 1242 if *oTrace { 1243 fmt.Println(err) 1244 } 1245 t.Errorf("%v: %v: exec fail", path, err) 1246 return nil 1247 } 1248 1249 if *oTraceO { 1250 fmt.Printf("%s\n", out) 1251 } 1252 1253 fmt.Fprintln(w, filepath.Base(path)) 1254 ok++ 1255 return nil 1256 }); err != nil { 1257 fail(t, "%v", err) 1258 } 1259 return files, ok 1260 } 1261 1262 func TestGCCGoExec(t *testing.T) { 1263 root := filepath.Join(testWD, filepath.FromSlash(gccDir)) 1264 if _, err := os.Stat(root); err != nil { 1265 t.Fatalf("Missing resources in %s. Please run 'go test -download -dev' to fix.", root) 1266 } 1267 1268 g := newGolden(t, fmt.Sprintf("testdata/gcc_go_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1269 1270 defer g.close() 1271 1272 todos = map[todoPos]int{} 1273 var files, ok int 1274 if *oEdit { 1275 defer func() { 1276 fmt.Printf("GCC files %s, ok %s\n", h(files), h(ok)) 1277 }() 1278 } 1279 const dir = "gcc/testsuite/gcc.c-torture/execute" 1280 f, o := testGCCGoExec(g.w, t, filepath.Join(root, filepath.FromSlash(dir)), false) 1281 files += f 1282 ok += o 1283 t.Logf("files %s, ok %s", h(files), h(ok)) 1284 if !oQuiet { 1285 dumpTODOs(t) 1286 } 1287 } 1288 1289 func testGCCGoExec(w io.Writer, t *testing.T, dir string, opt bool) (files, ok int) { 1290 const ( 1291 bin = "a.out" 1292 main = "main.go" 1293 crt = "crt.go" 1294 ) 1295 blacklist := map[string]struct{}{ //TODO- 1296 "20021127-1.c": {}, // non standard GCC behavior 1297 "strlen-3.c": {}, // not a standalone test 1298 "eeprof-1.c": {}, // requires instrumentation 1299 1300 "20010904-1.c": {}, //TODO __attribute__((aligned(alignment))) 1301 "20010904-2.c": {}, //TODO __attribute__((aligned(alignment))) 1302 "20040411-1.c": {}, //TODO typedef VLA 1303 "20040423-1.c": {}, //TODO typedef VLA 1304 "20041218-2.c": {}, //TODO struct VLA 1305 "20050215-1.c": {}, //TODO __attribute__ aligned 1306 "991014-1.c": {}, //TODO struct size overflow 1307 "align-3.c": {}, //TODO attr 1308 "const-addr-expr-1.c": {}, //TODO complex const addresss initialzer 1309 "pr23135.c": {}, //TODO QBE OOM 1310 "pr41935.c": {}, //TODO * VLA 1311 "pr64006.c": {}, //TODO __builtin_mul_overflow 1312 "pr82210.c": {}, //TODO VLA struct array, hangs 1313 "pr85095.c": {}, //TODO __builtin_add_overflow 1314 "rbug.c": {}, //TODO floating point rounding? 1315 "simd-1.c": {}, //TODO __attribute__((vector_size (16))) 1316 "simd-2.c": {}, //TODO __attribute__((vector_size (16))) 1317 } 1318 if opt { 1319 blacklist["20101011-1.c"] = struct{}{} // gcc 7.4 does not respect __attribute__ ((used)). 1320 } 1321 if opt && (arch == 32 || *oM32) { 1322 blacklist["20030331-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug 1323 blacklist["960830-1.c"] = struct{}{} // asm 1324 blacklist["floatunsisf-1.c"] = struct{}{} // gcc 7.4 -O -m32 bug 1325 } 1326 wd, err := os.Getwd() 1327 if err != nil { 1328 t.Fatal(err) 1329 } 1330 1331 defer os.Chdir(wd) 1332 1333 temp, err := ioutil.TempDir("", "gocc-test-") 1334 if err != nil { 1335 t.Fatal(err) 1336 } 1337 1338 defer os.RemoveAll(temp) 1339 1340 if err := os.Chdir(temp); err != nil { 1341 t.Fatal(err) 1342 } 1343 1344 var re *regexp.Regexp 1345 if s := *oRE; s != "" { 1346 re = regexp.MustCompile(s) 1347 } 1348 1349 if err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 1350 if err != nil { 1351 if os.IsNotExist(err) { 1352 err = nil 1353 } 1354 return err 1355 } 1356 1357 if info.IsDir() { 1358 return skipDir(path) 1359 } 1360 1361 if strings.Contains(filepath.ToSlash(path), "/builtins/") { 1362 return nil 1363 } 1364 1365 if filepath.Ext(path) != ".c" || info.Mode()&os.ModeType != 0 { 1366 return nil 1367 } 1368 1369 if _, ok := blacklist[filepath.Base(path)]; ok { 1370 return nil 1371 } 1372 1373 files++ 1374 1375 if re != nil && !re.MatchString(path) { 1376 return nil 1377 } 1378 1379 if *oTrace { 1380 fmt.Fprintln(os.Stderr, files, ok, path) 1381 } 1382 1383 if err := os.Remove(main); err != nil && !os.IsNotExist(err) { 1384 return err 1385 } 1386 1387 goccArgs := []string{ 1388 "gocc", 1389 "-o", main, 1390 "-Dasm=__asm__", 1391 "-DSIGNAL_SUPPRESS", 1392 "-gocc-long-double-is-double", 1393 "-gocc-emit-definitions", 1394 } 1395 if !func() (r bool) { 1396 defer func() { 1397 if err := recover(); err != nil { 1398 if *oStackTrace { 1399 fmt.Printf("%s\n", stack()) 1400 } 1401 if *oTrace { 1402 fmt.Println(err) 1403 } 1404 if !oQuiet { 1405 fail(t, "%s: %v", path, err) 1406 } 1407 r = false 1408 } 1409 }() 1410 1411 if out, err := execute(append(goccArgs, path), opt, gccTestDecls); err != nil { 1412 if *oTrace { 1413 fmt.Printf("%s\n%s\n", out, err) 1414 } 1415 if !oQuiet { 1416 fail(t, "%s: %s\n%s", path, out, err) 1417 } 1418 return false 1419 } 1420 1421 return true 1422 }() { 1423 return nil 1424 } 1425 1426 os.Remove(bin) 1427 out, err := exec.Command("go", "build", "-o", bin, main).CombinedOutput() 1428 if err != nil { 1429 if *oTrace { 1430 fmt.Printf("%s\n%s\n", out, err) 1431 } 1432 t.Errorf("%v: %s\n%s", path, out, err) 1433 return nil 1434 } 1435 1436 if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil { 1437 if *oTrace { 1438 fmt.Printf("%s\n%s\n", out, err) 1439 } 1440 t.Errorf("%v: %v: exec fail", path, err) 1441 return nil 1442 } 1443 1444 if *oTraceO { 1445 fmt.Printf("%s\n", out) 1446 } 1447 1448 fmt.Fprintln(w, filepath.Base(path)) 1449 ok++ 1450 return nil 1451 }); err != nil { 1452 fail(t, "%v", err) 1453 } 1454 return files, ok 1455 } 1456 1457 func TestSQLite(t *testing.T) { 1458 root := filepath.Join(testWD, filepath.FromSlash(sqliteDir)) 1459 if _, err := os.Stat(root); err != nil { 1460 t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root) 1461 } 1462 1463 t.Run("noOpt", func(t *testing.T) { testSQLite(t, root, false) }) 1464 t.Run("opt", func(t *testing.T) { testSQLite(t, root, true) }) 1465 } 1466 1467 func testSQLite(t *testing.T, dir string, opt bool) { 1468 const binaryName = "a.out" 1469 wd, err := os.Getwd() 1470 if err != nil { 1471 t.Fatal(err) 1472 } 1473 1474 defer os.Chdir(wd) 1475 1476 temp, err := ioutil.TempDir("", "gocc-test-") 1477 if err != nil { 1478 t.Fatal(err) 1479 } 1480 1481 defer os.RemoveAll(temp) 1482 1483 if err := os.Chdir(temp); err != nil { 1484 t.Fatal(err) 1485 } 1486 1487 if !func() (r bool) { 1488 defer func() { 1489 if err := recover(); err != nil { 1490 if *oStackTrace { 1491 fmt.Printf("%s\n", stack()) 1492 } 1493 if *oTrace { 1494 fmt.Println(err) 1495 } 1496 if !oQuiet { 1497 fail(t, "%s: %v", dir, err) 1498 } 1499 r = false 1500 } 1501 }() 1502 1503 if _, err := execute(append([]string{"gocc"}, filepath.Join(dir, "shell.c"), filepath.Join(dir, "sqlite3.c"), "-lpthread", "-ldl"), opt); err != nil { 1504 if *oTrace { 1505 fmt.Println(err) 1506 } 1507 if !oQuiet { 1508 fail(t, "%s: %v", dir, err) 1509 } 1510 return false 1511 } 1512 1513 return true 1514 }() { 1515 return 1516 } 1517 1518 out, err := exec.Command("./"+binaryName, "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput() 1519 if err != nil { 1520 if *oTrace { 1521 fmt.Println(err) 1522 } 1523 fail(t, "%v", err) 1524 return 1525 } 1526 1527 if g, e := strings.TrimSpace(string(out)), "462"; g != e { 1528 t.Errorf("%q %q", g, e) 1529 } 1530 if *oTraceO { 1531 fmt.Printf("%s\n", out) 1532 } 1533 1534 if out, err = exec.Command("./"+binaryName, "tmp", "select 13*i from t;").CombinedOutput(); err != nil { 1535 if *oTrace { 1536 fmt.Println(err) 1537 } 1538 fail(t, "%v", err) 1539 return 1540 } 1541 1542 if g, e := strings.TrimSpace(string(out)), "546"; g != e { 1543 t.Errorf("%q %q", g, e) 1544 } 1545 if *oTraceO { 1546 fmt.Printf("%s\n", out) 1547 } 1548 } 1549 1550 func TestSQLiteGo(t *testing.T) { 1551 root := filepath.Join(testWD, filepath.FromSlash(sqliteDir)) 1552 if _, err := os.Stat(root); err != nil { 1553 t.Fatalf("Missing resources in %s. Please run 'go test -download' to fix.", root) 1554 } 1555 1556 testSQLiteGo(t, root) 1557 } 1558 1559 func testSQLiteGo(t *testing.T, dir string) { 1560 const main = "main.go" 1561 wd, err := os.Getwd() 1562 if err != nil { 1563 t.Fatal(err) 1564 } 1565 1566 defer os.Chdir(wd) 1567 1568 temp, err := ioutil.TempDir("", "gocc-test-") 1569 if err != nil { 1570 t.Fatal(err) 1571 } 1572 1573 defer os.RemoveAll(temp) 1574 1575 if err := os.Chdir(temp); err != nil { 1576 t.Fatal(err) 1577 } 1578 1579 if !func() (r bool) { 1580 defer func() { 1581 if err := recover(); err != nil { 1582 if *oStackTrace { 1583 fmt.Printf("%s\n", stack()) 1584 } 1585 if *oTrace { 1586 fmt.Println(err) 1587 } 1588 if !oQuiet { 1589 fail(t, "%s: %v", dir, err) 1590 } 1591 r = false 1592 } 1593 }() 1594 1595 if out, err := execute(append([]string{"gocc"}, 1596 filepath.Join(dir, "shell.c"), 1597 "-o", "shell.go", 1598 "-DLONGDOUBLE_TYPE=double", 1599 "-DSQLITE_DEBUG", 1600 "-DSQLITE_DEFAULT_MEMSTATUS=0", 1601 "-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1", 1602 "-DSQLITE_DQS=0", 1603 "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", 1604 "-DSQLITE_MAX_EXPR_DEPTH=0", 1605 "-DSQLITE_MEMDEBUG", 1606 "-DSQLITE_OMIT_DECLTYPE", 1607 "-DSQLITE_OMIT_DEPRECATED", 1608 "-DSQLITE_OMIT_PROGRESS_CALLBACK", 1609 "-DSQLITE_OMIT_SHARED_CACHE", 1610 "-DSQLITE_THREADSAFE=0", 1611 "-DSQLITE_USE_ALLOCA", 1612 ), false); err != nil { 1613 if *oTrace { 1614 fmt.Printf("%s\n%s\n", out, err) 1615 } 1616 if !oQuiet { 1617 fail(t, "%s: %s\n%s", dir, out, err) 1618 } 1619 return false 1620 } 1621 1622 if out, err := execute(append([]string{"gocc"}, 1623 filepath.Join(dir, "sqlite3.c"), 1624 "-o", "sqlite3.go", 1625 "-qbec-pkgname", "main", 1626 "-DLONGDOUBLE_TYPE=double", 1627 "-DSQLITE_DEBUG", 1628 "-DSQLITE_DEFAULT_MEMSTATUS=0", 1629 "-DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1", 1630 "-DSQLITE_DQS=0", 1631 "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", 1632 "-DSQLITE_MAX_EXPR_DEPTH=0", 1633 "-DSQLITE_MEMDEBUG", 1634 "-DSQLITE_OMIT_DECLTYPE", 1635 "-DSQLITE_OMIT_DEPRECATED", 1636 "-DSQLITE_OMIT_PROGRESS_CALLBACK", 1637 "-DSQLITE_OMIT_SHARED_CACHE", 1638 "-DSQLITE_THREADSAFE=0", 1639 "-DSQLITE_USE_ALLOCA", 1640 ), 1641 false, 1642 ); err != nil { 1643 if *oTrace { 1644 fmt.Printf("%s\n%s\n", out, err) 1645 } 1646 if !oQuiet { 1647 fail(t, "%s: %s\n%s", dir, out, err) 1648 } 1649 return false 1650 } 1651 1652 return true 1653 }() { 1654 return 1655 } 1656 1657 // out, err := exec.Command("go", "build", "-tags", "crt.dmesg", "-gcflags", "-e", "-o", "test", "shell.go", "sqlite3.go").CombinedOutput() 1658 out, err := exec.Command("go", "build", "-gcflags", "-e", "-o", "test", "shell.go", "sqlite3.go").CombinedOutput() 1659 if err != nil { 1660 if *oTrace { 1661 fmt.Printf("%s\n%s\n", out, err) 1662 } 1663 fail(t, "%v", err) 1664 return 1665 } 1666 1667 if out, err = exec.Command("./test", "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput(); err != nil { 1668 if *oTrace { 1669 fmt.Printf("%s\n%s\n", out, err) 1670 } 1671 fail(t, "%v", err) 1672 return 1673 } 1674 1675 if g, e := strings.TrimSpace(string(out)), "462"; g != e { 1676 t.Errorf("%q %q", g, e) 1677 } 1678 if *oTraceO { 1679 fmt.Printf("%s\n", out) 1680 } 1681 1682 if out, err = exec.Command("./test", "tmp", "select 13*i from t;").CombinedOutput(); err != nil { 1683 if *oTrace { 1684 fmt.Printf("%s\n%s\n", out, err) 1685 } 1686 fail(t, "%v", err) 1687 return 1688 } 1689 1690 if g, e := strings.TrimSpace(string(out)), "546"; g != e { 1691 t.Errorf("%q %q", g, e) 1692 } 1693 if *oTraceO { 1694 fmt.Printf("%s\n", out) 1695 } 1696 } 1697 1698 func fields(t cc.Type) string { 1699 var b strings.Builder 1700 fields2(t, &b, "") 1701 return b.String() 1702 } 1703 1704 func fields2(t cc.Type, b *strings.Builder, pref string) { 1705 fmt.Fprintf(b, "%s==== typ %v, kind %v, sz %v align %v\n", pref, t, t.Kind(), t.Size(), t.Align()) 1706 for i := 0; i < t.NumField(); i++ { 1707 f := t.FieldByIndex([]int{i}) 1708 fmt.Fprintf(b, 1709 "%snm %q, type %v, sz %v, align %v, off %v, pad %v, bitfield %v, boff %v bits %v\n", 1710 pref, f.Name(), f.Type(), f.Type().Size(), f.Type().Align(), f.Offset(), f.Padding(), 1711 f.IsBitField(), f.BitFieldOffset(), f.BitFieldWidth(), 1712 ) 1713 switch f.Type().Kind() { 1714 case cc.Struct, cc.Union: 1715 fields2(f.Type(), b, pref+"ยท ") 1716 } 1717 } 1718 } 1719 1720 func TestCSmith(t *testing.T) { 1721 gcc, err := exec.LookPath("gcc") 1722 if err != nil { 1723 t.Fatalf("%v", err) 1724 return 1725 } 1726 1727 csmith, err := exec.LookPath("csmith") 1728 if err != nil { 1729 t.Fatalf("%v", err) 1730 return 1731 } 1732 1733 if _, err := exec.LookPath("gocc"); err != nil { 1734 t.Fatalf("%v: please run go install", err) 1735 return 1736 } 1737 1738 binaryName := filepath.FromSlash("./a.out") 1739 wd, err := os.Getwd() 1740 if err != nil { 1741 t.Fatal(err) 1742 } 1743 1744 defer os.Chdir(wd) 1745 1746 temp, err := ioutil.TempDir("", "gocc-test-") 1747 if err != nil { 1748 t.Fatal(err) 1749 } 1750 1751 defer os.RemoveAll(temp) 1752 1753 if err := os.Chdir(temp); err != nil { 1754 t.Fatal(err) 1755 } 1756 1757 fixedBugs := []string{ 1758 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1906742816", 1759 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 612971101", 1760 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 3629008936", 1761 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4130344133", 1762 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3130410542", 1763 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1833258637", 1764 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3126091077", 1765 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324", 1766 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3043990076", 1767 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2517344771", 1768 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 56498550", 1769 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3645367888", 1770 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 169375684", 1771 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3578720023", 1772 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1885311141", 1773 } 1774 ch := time.After(*oCSmith) 1775 t0 := time.Now() 1776 var files, ok int 1777 var size int64 1778 out: 1779 for i := 0; ; i++ { 1780 extra := "" 1781 var args string 1782 switch { 1783 case i < len(fixedBugs): 1784 args += fixedBugs[i] 1785 a := strings.Split(fixedBugs[i], " ") 1786 extra = strings.Join(a[len(a)-2:], " ") 1787 t.Log(args) 1788 default: 1789 select { 1790 case <-ch: 1791 break out 1792 default: 1793 } 1794 1795 args += csmithDefaultArgs 1796 } 1797 csOut, err := exec.Command(csmith, strings.Split(args, " ")...).Output() 1798 if err != nil { 1799 t.Fatalf("%v\n%s", err, csOut) 1800 } 1801 1802 if fn := *oBlackBox; fn != "" { 1803 if err := ioutil.WriteFile(fn, csOut, 0660); err != nil { 1804 t.Fatal(err) 1805 } 1806 } 1807 1808 if err := ioutil.WriteFile("main.c", csOut, 0660); err != nil { 1809 t.Fatal(err) 1810 } 1811 1812 csp := fmt.Sprintf("-I%s", filepath.FromSlash("/usr/include/csmith")) 1813 ccOut, err := exec.Command(gcc, "-o", binaryName, "main.c", csp).CombinedOutput() 1814 if err != nil { 1815 t.Fatalf("%s\n%s\ncc: %v", extra, ccOut, err) 1816 } 1817 1818 binOutA, err := func() ([]byte, error) { 1819 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 1820 defer cancel() 1821 1822 return exec.CommandContext(ctx, binaryName).CombinedOutput() 1823 }() 1824 if err != nil { 1825 continue 1826 } 1827 1828 size += int64(len(csOut)) 1829 1830 if err := os.Remove(binaryName); err != nil { 1831 t.Fatal(err) 1832 } 1833 1834 // noOpt 1835 files++ 1836 j, err := newTask([]string{"gocc", "-o", binaryName, "-O0", "-lm", csp, "main.c"}) 1837 j.doNotCacheMain = true 1838 j.Config3.MaxSourceLine = 1 << 19 1839 if err != nil { 1840 t.Error(err) 1841 break 1842 } 1843 1844 func() { 1845 var stdout, stderr bytes.Buffer 1846 1847 defer func() { 1848 if err := recover(); err != nil { 1849 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack()) 1850 } 1851 }() 1852 1853 if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 { 1854 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err) 1855 } 1856 }() 1857 1858 binOutB, err := func() ([]byte, error) { 1859 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) 1860 defer cancel() 1861 1862 return exec.CommandContext(ctx, binaryName).CombinedOutput() 1863 }() 1864 if err != nil { 1865 t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err) 1866 break 1867 } 1868 1869 if g, e := binOutB, binOutA; !bytes.Equal(g, e) { 1870 t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e) 1871 break 1872 } 1873 1874 ok++ 1875 if *oTrace { 1876 fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " no opt") 1877 } 1878 1879 if err := os.Remove(binaryName); err != nil { 1880 t.Fatal(err) 1881 } 1882 1883 // opt 1884 files++ 1885 j, err = newTask([]string{"gocc", "-o", binaryName, "-lm", csp, "main.c"}) 1886 j.doNotCacheMain = true 1887 j.Config3.MaxSourceLine = 1 << 19 1888 if err != nil { 1889 t.Fatal(err) 1890 } 1891 1892 func() { 1893 var stdout, stderr bytes.Buffer 1894 1895 defer func() { 1896 if err := recover(); err != nil { 1897 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack()) 1898 } 1899 }() 1900 1901 if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 { 1902 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err) 1903 } 1904 }() 1905 1906 binOutB, err = func() ([]byte, error) { 1907 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) 1908 defer cancel() 1909 1910 return exec.CommandContext(ctx, binaryName).CombinedOutput() 1911 }() 1912 if err != nil { 1913 t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err) 1914 break 1915 } 1916 1917 if g, e := binOutB, binOutA; !bytes.Equal(g, e) { 1918 t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e) 1919 break 1920 } 1921 1922 ok++ 1923 if *oTrace { 1924 fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " opt") 1925 } 1926 1927 // Go 1928 os.Remove("main.go") 1929 os.Remove(binaryName) 1930 files++ 1931 j, err = newTask([]string{"gocc", "-o", "main.go", csp, "main.c", "-gocc-long-double-is-double"}) 1932 j.doNotCacheMain = true 1933 j.Config3.MaxSourceLine = 1 << 19 1934 if err != nil { 1935 t.Fatal(err) 1936 } 1937 1938 func() { 1939 var stdout, stderr bytes.Buffer 1940 1941 defer func() { 1942 if err := recover(); err != nil { 1943 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), err, debug.Stack()) 1944 } 1945 }() 1946 1947 if rc := j.main(&stdout, &stderr); rc != 0 || stdout.Len() != 0 { 1948 t.Fatalf("%s\n%s\ngocc: %s\n%s\n%v", extra, csOut, stdout.Bytes(), stderr.Bytes(), err) 1949 } 1950 }() 1951 1952 out, err := exec.Command("go", "build", "-o", binaryName, "main.go").CombinedOutput() 1953 if err != nil { 1954 t.Errorf("%s\n%s\ngocc: %v", extra, out, err) 1955 break 1956 } 1957 1958 binOutB, err = func() ([]byte, error) { 1959 ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second) 1960 defer cancel() 1961 1962 return exec.CommandContext(ctx, binaryName).CombinedOutput() 1963 }() 1964 if err != nil { 1965 t.Errorf("%s\n%s\ngocc: %v", extra, csOut, err) 1966 break 1967 } 1968 1969 if g, e := binOutB, binOutA; !bytes.Equal(g, e) { 1970 t.Errorf("%s\n%s\ngocc: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e) 1971 break 1972 } 1973 1974 ok++ 1975 if *oTrace { 1976 fmt.Fprintln(os.Stderr, time.Since(t0), files, ok, " Go") 1977 } 1978 } 1979 d := time.Since(t0) 1980 t.Logf("files %v, bytes %v, ok %v in %v", h(files), h(size), h(ok), d) 1981 } 1982 1983 type compCertResult struct { 1984 compiler string 1985 test string 1986 run time.Duration 1987 k float64 1988 1989 compileOK bool 1990 execOK bool 1991 resultOK bool 1992 } 1993 1994 func (r *compCertResult) String() string { 1995 var s string 1996 if r.k != 0 { 1997 s = fmt.Sprintf("%8.3f", r.k) 1998 if r.k == 1 { 1999 s += " *" 2000 } 2001 } 2002 return fmt.Sprintf("%10v%15v%10.3fms%6v%6v%6v%s", r.compiler, r.test, float64(r.run)/float64(time.Millisecond), r.compileOK, r.execOK, r.resultOK, s) 2003 } 2004 2005 func TestCompCert(t *testing.T) { 2006 const root = "testdata/CompCert-3.6/test/c" 2007 2008 b, err := ioutil.ReadFile(filepath.FromSlash(root + "/Results/knucleotide-input.txt")) 2009 if err != nil { 2010 t.Fatal(err) 2011 } 2012 2013 dir := filepath.FromSlash(root) 2014 m, err := filepath.Glob(filepath.Join(dir, "*.c")) 2015 if err != nil { 2016 t.Fatal(err) 2017 } 2018 2019 for i, v := range m { 2020 v, err := filepath.Abs(v) 2021 if err != nil { 2022 t.Fatal(err) 2023 } 2024 2025 m[i] = v 2026 } 2027 2028 rdir, err := filepath.Abs(filepath.FromSlash(root + "/Results")) 2029 if err != nil { 2030 t.Fatal(err) 2031 } 2032 2033 wd, err := os.Getwd() 2034 if err != nil { 2035 t.Fatal(err) 2036 } 2037 2038 defer os.Chdir(wd) 2039 2040 temp, err := ioutil.TempDir("", "gocc-test-") 2041 if err != nil { 2042 t.Fatal(err) 2043 } 2044 2045 defer os.RemoveAll(temp) 2046 2047 if err := os.Chdir(temp); err != nil { 2048 t.Fatal(err) 2049 } 2050 2051 if err := os.Mkdir("Results", 0770); err != nil { 2052 t.Fatal(err) 2053 } 2054 2055 if err := ioutil.WriteFile(filepath.FromSlash("Results/knucleotide-input.txt"), b, 0660); err != nil { 2056 t.Fatal(err) 2057 } 2058 2059 var r []*compCertResult 2060 t.Run("gcc", func(t *testing.T) { r = append(r, testCompCertGcc(t, m, *oCertN, rdir)...) }) 2061 t.Run("gocc", func(t *testing.T) { r = append(r, testCompCertGocc(t, m, *oCertN, rdir)...) }) 2062 t.Run("goccgo", func(t *testing.T) { r = append(r, testCompCertGoccgo(t, m, *oCertN, rdir)...) }) 2063 consider := map[string]struct{}{} 2064 for _, v := range r { 2065 consider[v.test] = struct{}{} 2066 } 2067 for _, v := range r { 2068 if ok := v.compileOK && v.execOK && v.resultOK; !ok { 2069 delete(consider, v.test) 2070 } 2071 } 2072 times := map[string]time.Duration{} 2073 tests := map[string][]*compCertResult{} 2074 for _, v := range r { 2075 if _, ok := consider[v.test]; !ok { 2076 continue 2077 } 2078 2079 times[v.compiler] += v.run 2080 tests[v.test] = append(tests[v.test], v) 2081 } 2082 for _, a := range tests { 2083 if len(a) < 2 { 2084 continue 2085 } 2086 min := time.Duration(-1) 2087 for _, v := range a { 2088 if min < 0 || v.run < min { 2089 min = v.run 2090 } 2091 } 2092 for _, v := range a { 2093 v.k = float64(v.run) / float64(min) 2094 } 2095 } 2096 t.Log(" compiler test T comp exec match coef") 2097 for _, v := range r { 2098 t.Log(v) 2099 } 2100 var a []string 2101 for k := range times { 2102 a = append(a, k) 2103 } 2104 sort.Strings(a) 2105 t.Logf("Considered tests: %d/%d", len(consider), len(m)) 2106 min := time.Duration(-1) 2107 for _, v := range times { 2108 if min < 0 || v < min { 2109 min = v 2110 } 2111 } 2112 for _, k := range a { 2113 t.Logf("%10s%15v %6.3f", k, times[k], float64(times[k])/float64(min)) 2114 } 2115 } 2116 2117 func testCompCertGcc(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) { 2118 const nm = "gcc" 2119 next: 2120 for _, fn := range files { 2121 base := filepath.Base(fn) 2122 if *oTrace { 2123 fmt.Println(base) 2124 } 2125 bin := nm + "-" + base + ".out" 2126 out, err := exec.Command("gcc", "-O", "-o", bin, fn, "-lm").CombinedOutput() 2127 if err != nil { 2128 t.Errorf("%s: %s:\n%s", base, err, out) 2129 r = append(r, &compCertResult{nm, base, 0, 0, false, false, false}) 2130 continue 2131 } 2132 2133 t0 := time.Now() 2134 for i := 0; i < N; i++ { 2135 if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil { 2136 t.Errorf("%s: %s:\n%s", base, err, out) 2137 r = append(r, &compCertResult{nm, base, 0, 0, true, false, false}) 2138 continue next 2139 } 2140 } 2141 d := time.Since(t0) / time.Duration(N) 2142 r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)}) 2143 } 2144 return r 2145 } 2146 2147 func checkResult(t *testing.T, out []byte, base, rdir string) bool { 2148 base = base[:len(base)-len(filepath.Ext(base))] 2149 b, err := ioutil.ReadFile(filepath.Join(rdir, base)) 2150 if err != nil { 2151 t.Errorf("%v: %v", base, err) 2152 return false 2153 } 2154 2155 if !bytes.Equal(out, b) { 2156 t.Logf("got\n%s", hex.Dump(out)) 2157 t.Logf("exp\n%s", hex.Dump(b)) 2158 t.Errorf("%v: result differs", base) 2159 return false 2160 } 2161 2162 return true 2163 } 2164 2165 func testCompCertGocc(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) { 2166 const nm = "gocc" 2167 next: 2168 for _, fn := range files { 2169 base := filepath.Base(fn) 2170 if *oTrace { 2171 fmt.Println(base) 2172 } 2173 bin := nm + "-" + base + ".out" 2174 out, err := execute([]string{"gocc", "-O", "-o", bin, fn, "-lm"}, false) 2175 if err != nil { 2176 t.Errorf("%s: %s:\n%s", base, err, out) 2177 r = append(r, &compCertResult{nm, base, 0, 0, false, false, false}) 2178 continue 2179 } 2180 2181 t0 := time.Now() 2182 for i := 0; i < N; i++ { 2183 if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil { 2184 t.Errorf("%s: %s:\n%s", base, err, out) 2185 r = append(r, &compCertResult{nm, base, 0, 0, true, false, false}) 2186 continue next 2187 } 2188 } 2189 d := time.Since(t0) / time.Duration(N) 2190 r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)}) 2191 } 2192 return r 2193 } 2194 2195 func testCompCertGoccgo(t *testing.T, files []string, N int, rdir string) (r []*compCertResult) { 2196 const nm = "goccgo" 2197 next: 2198 for _, fn := range files { 2199 base := filepath.Base(fn) 2200 if *oTrace { 2201 fmt.Println(base) 2202 } 2203 src := nm + "-" + base + ".go" 2204 bin := nm + "-" + base + ".out" 2205 out, err := execute([]string{"gocc", "-o", src, fn}, false) 2206 if err != nil { 2207 t.Errorf("%s: %s:\n%s", base, err, out) 2208 r = append(r, &compCertResult{nm, base, 0, 0, false, false, false}) 2209 continue 2210 } 2211 2212 //if out, err = exec.Command("go", "build", "-o", bin, "-tags", "crt.dmesg", src).CombinedOutput(); err != nil { 2213 if out, err = exec.Command("go", "build", "-o", bin, src).CombinedOutput(); err != nil { 2214 t.Errorf("%s: %s:\n%s", base, err, out) 2215 r = append(r, &compCertResult{nm, base, 0, 0, false, false, false}) 2216 continue next 2217 } 2218 2219 t0 := time.Now() 2220 for i := 0; i < N; i++ { 2221 if out, err = exec.Command("./" + bin).CombinedOutput(); err != nil { 2222 t.Errorf("%s: %s:\n%s", base, err, out) 2223 r = append(r, &compCertResult{nm, base, 0, 0, true, false, false}) 2224 continue next 2225 } 2226 } 2227 d := time.Since(t0) / time.Duration(N) 2228 r = append(r, &compCertResult{nm, base, d, 0, true, true, checkResult(t, out, base, rdir)}) 2229 } 2230 return r 2231 } 2232 2233 func dumpLayout(t cc.Type) string { 2234 switch t.Kind() { 2235 case cc.Struct, cc.Union: 2236 // ok 2237 default: 2238 return t.String() 2239 } 2240 2241 nf := t.NumField() 2242 var a []string 2243 for i := 0; i < nf; i++ { 2244 f := t.FieldByIndex([]int{i}) 2245 a = append(a, fmt.Sprintf("%2d: %q: BitFieldOffset %v, BitFieldWidth %v, IsBitField %v, Mask: %#0x, off: %v, pad %v", 2246 i, f.Name(), f.BitFieldOffset(), f.BitFieldWidth(), 2247 f.IsBitField(), f.Mask(), f.Offset(), f.Padding(), 2248 )) 2249 } 2250 return strings.Join(a, "\n") 2251 }