From 3af0d791bed25e6cb4689fed9cc8379554971cb8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 23 Feb 2015 14:20:01 -0500 Subject: [dev.cc] cmd/6a, cmd/6g etc: replace C implementations with Go implementations Change-Id: I58e00a39cf63df07813d21453f91e68eef6a413c Reviewed-on: https://go-review.googlesource.com/5635 Reviewed-by: Rob Pike --- src/cmd/5a/Makefile | 10 - src/cmd/5a/a.h | 173 -- src/cmd/5a/a.y | 385 ++-- src/cmd/5a/doc.go | 20 - src/cmd/5a/lex.c | 538 ----- src/cmd/5a/lex.go | 371 ++++ src/cmd/5a/y.go | 1362 ++++++++++++ src/cmd/5a/y.tab.c | 2855 ------------------------- src/cmd/5a/y.tab.h | 166 -- src/cmd/5g/Makefile | 5 - src/cmd/5g/cgen.c | 1840 ---------------- src/cmd/5g/cgen.go | 2003 ++++++++++++++++++ src/cmd/5g/cgen64.c | 760 ------- src/cmd/5g/cgen64.go | 833 ++++++++ src/cmd/5g/doc.go | 15 - src/cmd/5g/galign.c | 87 - src/cmd/5g/galign.go | 85 + src/cmd/5g/gg.go | 32 + src/cmd/5g/gg.h | 177 -- src/cmd/5g/ggen.c | 751 ------- src/cmd/5g/ggen.go | 822 ++++++++ src/cmd/5g/gsubr.c | 1527 -------------- src/cmd/5g/gsubr.go | 1599 ++++++++++++++ src/cmd/5g/peep.c | 1619 -------------- src/cmd/5g/peep.go | 1868 +++++++++++++++++ src/cmd/5g/prog.c | 160 -- src/cmd/5g/prog.go | 163 ++ src/cmd/5g/reg.c | 146 -- src/cmd/5g/reg.go | 136 ++ src/cmd/5g/util.go | 12 + src/cmd/6a/Makefile | 10 - src/cmd/6a/a.h | 188 -- src/cmd/6a/a.y | 383 ++-- src/cmd/6a/doc.go | 20 - src/cmd/6a/lex.c | 1137 ---------- src/cmd/6a/lex.go | 978 +++++++++ src/cmd/6a/y.go | 1330 ++++++++++++ src/cmd/6a/y.tab.c | 2800 ------------------------ src/cmd/6a/y.tab.h | 139 -- src/cmd/6g/Makefile | 5 - src/cmd/6g/cgen.c | 1745 --------------- src/cmd/6g/cgen.go | 1889 +++++++++++++++++ src/cmd/6g/doc.go | 15 - src/cmd/6g/galign.c | 110 - src/cmd/6g/galign.go | 110 + src/cmd/6g/gg.go | 24 + src/cmd/6g/gg.h | 176 -- src/cmd/6g/ggen.c | 1046 --------- src/cmd/6g/ggen.go | 1169 +++++++++++ src/cmd/6g/gsubr.c | 1737 --------------- src/cmd/6g/gsubr.go | 1752 ++++++++++++++++ src/cmd/6g/peep.c | 988 --------- src/cmd/6g/peep.go | 1077 ++++++++++ src/cmd/6g/prog.c | 318 --- src/cmd/6g/prog.go | 272 +++ src/cmd/6g/reg.c | 153 -- src/cmd/6g/reg.go | 144 ++ src/cmd/6g/util.go | 12 + src/cmd/8a/Makefile | 10 - src/cmd/8a/a.h | 186 -- src/cmd/8a/a.y | 381 ++-- src/cmd/8a/doc.go | 21 - src/cmd/8a/lex.c | 914 -------- src/cmd/8a/lex.go | 771 +++++++ src/cmd/8a/y.go | 1308 ++++++++++++ src/cmd/8a/y.tab.c | 2778 ------------------------ src/cmd/8a/y.tab.h | 135 -- src/cmd/8g/Makefile | 5 - src/cmd/8g/cgen.c | 1590 -------------- src/cmd/8g/cgen.go | 1730 +++++++++++++++ src/cmd/8g/cgen64.c | 549 ----- src/cmd/8g/cgen64.go | 607 ++++++ src/cmd/8g/doc.go | 15 - src/cmd/8g/galign.c | 87 - src/cmd/8g/galign.go | 85 + src/cmd/8g/gg.go | 34 + src/cmd/8g/gg.h | 189 -- src/cmd/8g/ggen.c | 1165 ---------- src/cmd/8g/ggen.go | 1297 ++++++++++++ src/cmd/8g/gsubr.c | 1874 ----------------- src/cmd/8g/gsubr.go | 1931 +++++++++++++++++ src/cmd/8g/peep.c | 773 ------- src/cmd/8g/peep.go | 847 ++++++++ src/cmd/8g/prog.c | 349 --- src/cmd/8g/prog.go | 291 +++ src/cmd/8g/reg.c | 112 - src/cmd/8g/reg.go | 112 + src/cmd/8g/util.go | 12 + src/cmd/9a/Makefile | 10 - src/cmd/9a/a.h | 172 -- src/cmd/9a/a.y | 544 ++--- src/cmd/9a/doc.go | 21 - src/cmd/9a/lex.c | 726 ------- src/cmd/9a/lex.go | 555 +++++ src/cmd/9a/y.go | 1953 +++++++++++++++++ src/cmd/9a/y.tab.c | 3466 ------------------------------ src/cmd/9a/y.tab.h | 190 -- src/cmd/9g/cgen.c | 1758 ---------------- src/cmd/9g/cgen.go | 1888 +++++++++++++++++ src/cmd/9g/doc.go | 16 - src/cmd/9g/galign.c | 94 - src/cmd/9g/galign.go | 93 + src/cmd/9g/gg.go | 28 + src/cmd/9g/gg.h | 169 -- src/cmd/9g/ggen.c | 965 --------- src/cmd/9g/ggen.go | 1060 ++++++++++ src/cmd/9g/gsubr.c | 1158 ---------- src/cmd/9g/gsubr.go | 1165 ++++++++++ src/cmd/9g/opt.go | 42 + src/cmd/9g/opt.h | 13 - src/cmd/9g/peep.c | 959 --------- src/cmd/9g/peep.go | 1071 ++++++++++ src/cmd/9g/prog.c | 308 --- src/cmd/9g/prog.go | 318 +++ src/cmd/9g/reg.c | 172 -- src/cmd/9g/reg.go | 164 ++ src/cmd/9g/util.go | 12 + src/cmd/gc/Makefile | 17 - src/cmd/gc/align.c | 689 ------ src/cmd/gc/array.c | 107 - src/cmd/gc/bisonerrors | 156 -- src/cmd/gc/bits.c | 173 -- src/cmd/gc/builtin.c | 165 -- src/cmd/gc/bv.c | 213 -- src/cmd/gc/closure.c | 659 ------ src/cmd/gc/const.c | 1678 --------------- src/cmd/gc/cplx.c | 494 ----- src/cmd/gc/dcl.c | 1479 ------------- src/cmd/gc/doc.go | 95 - src/cmd/gc/esc.c | 1342 ------------ src/cmd/gc/export.c | 563 ----- src/cmd/gc/fmt.c | 1697 --------------- src/cmd/gc/gen.c | 987 --------- src/cmd/gc/go.errors | 79 - src/cmd/gc/go.h | 1757 ---------------- src/cmd/gc/go.y | 2225 -------------------- src/cmd/gc/gsubr.c | 654 ------ src/cmd/gc/init.c | 194 -- src/cmd/gc/inl.c | 986 --------- src/cmd/gc/lex.c | 2590 ----------------------- src/cmd/gc/md5.c | 302 --- src/cmd/gc/md5.h | 16 - src/cmd/gc/mkbuiltin | 36 - src/cmd/gc/mkbuiltin1.c | 102 - src/cmd/gc/mkopnames | 24 - src/cmd/gc/mparith1.c | 655 ------ src/cmd/gc/mparith2.c | 689 ------ src/cmd/gc/mparith3.c | 346 --- src/cmd/gc/obj.c | 498 ----- src/cmd/gc/order.c | 1164 ---------- src/cmd/gc/pgen.c | 547 ----- src/cmd/gc/plive.c | 2005 ------------------ src/cmd/gc/popt.c | 1022 --------- src/cmd/gc/popt.h | 152 -- src/cmd/gc/racewalk.c | 653 ------ src/cmd/gc/range.c | 378 ---- src/cmd/gc/reflect.c | 1609 -------------- src/cmd/gc/reg.c | 1233 ----------- src/cmd/gc/runtime.go | 191 -- src/cmd/gc/select.c | 375 ---- src/cmd/gc/sinit.c | 1502 ------------- src/cmd/gc/subr.c | 3856 ---------------------------------- src/cmd/gc/swt.c | 944 --------- src/cmd/gc/typecheck.c | 3649 -------------------------------- src/cmd/gc/unsafe.c | 150 -- src/cmd/gc/unsafe.go | 18 - src/cmd/gc/walk.c | 4189 ------------------------------------ src/cmd/gc/y.tab.c | 5134 --------------------------------------------- src/cmd/gc/y.tab.h | 167 -- src/cmd/gc/yerr.h | 79 - src/cmd/new5a/a.y | 795 ------- src/cmd/new5a/lex.go | 371 ---- src/cmd/new5a/y.go | 1362 ------------ src/cmd/new5g/cgen.go | 2003 ------------------ src/cmd/new5g/cgen64.go | 833 -------- src/cmd/new5g/galign.go | 85 - src/cmd/new5g/gg.go | 32 - src/cmd/new5g/ggen.go | 822 -------- src/cmd/new5g/gsubr.go | 1599 -------------- src/cmd/new5g/peep.go | 1868 ----------------- src/cmd/new5g/prog.go | 163 -- src/cmd/new5g/reg.go | 136 -- src/cmd/new5g/util.go | 12 - src/cmd/new6a/a.y | 723 ------- src/cmd/new6a/lex.go | 978 --------- src/cmd/new6a/y.go | 1330 ------------ src/cmd/new6g/cgen.go | 1889 ----------------- src/cmd/new6g/galign.go | 110 - src/cmd/new6g/gg.go | 24 - src/cmd/new6g/ggen.go | 1169 ----------- src/cmd/new6g/gsubr.go | 1752 ---------------- src/cmd/new6g/peep.go | 1077 ---------- src/cmd/new6g/prog.go | 272 --- src/cmd/new6g/reg.go | 144 -- src/cmd/new6g/util.go | 12 - src/cmd/new8a/a.y | 713 ------- src/cmd/new8a/lex.go | 771 ------- src/cmd/new8a/y.go | 1308 ------------ src/cmd/new8g/cgen.go | 1730 --------------- src/cmd/new8g/cgen64.go | 607 ------ src/cmd/new8g/galign.go | 85 - src/cmd/new8g/gg.go | 34 - src/cmd/new8g/ggen.go | 1297 ------------ src/cmd/new8g/gsubr.go | 1931 ----------------- src/cmd/new8g/peep.go | 847 -------- src/cmd/new8g/prog.go | 291 --- src/cmd/new8g/reg.go | 112 - src/cmd/new8g/util.go | 12 - src/cmd/new9a/a.y | 1055 ---------- src/cmd/new9a/lex.go | 555 ----- src/cmd/new9a/y.go | 1953 ----------------- src/cmd/new9g/cgen.go | 1888 ----------------- src/cmd/new9g/galign.go | 93 - src/cmd/new9g/gg.go | 28 - src/cmd/new9g/ggen.go | 1060 ---------- src/cmd/new9g/gsubr.go | 1165 ---------- src/cmd/new9g/opt.go | 42 - src/cmd/new9g/peep.go | 1071 ---------- src/cmd/new9g/prog.go | 318 --- src/cmd/new9g/reg.go | 164 -- src/cmd/new9g/util.go | 12 - src/cmd/objwriter/main.go | 411 ---- 222 files changed, 36273 insertions(+), 133020 deletions(-) delete mode 100644 src/cmd/5a/Makefile delete mode 100644 src/cmd/5a/a.h delete mode 100644 src/cmd/5a/doc.go delete mode 100644 src/cmd/5a/lex.c create mode 100644 src/cmd/5a/lex.go create mode 100644 src/cmd/5a/y.go delete mode 100644 src/cmd/5a/y.tab.c delete mode 100644 src/cmd/5a/y.tab.h delete mode 100644 src/cmd/5g/Makefile delete mode 100644 src/cmd/5g/cgen.c create mode 100644 src/cmd/5g/cgen.go delete mode 100644 src/cmd/5g/cgen64.c create mode 100644 src/cmd/5g/cgen64.go delete mode 100644 src/cmd/5g/doc.go delete mode 100644 src/cmd/5g/galign.c create mode 100644 src/cmd/5g/galign.go create mode 100644 src/cmd/5g/gg.go delete mode 100644 src/cmd/5g/gg.h delete mode 100644 src/cmd/5g/ggen.c create mode 100644 src/cmd/5g/ggen.go delete mode 100644 src/cmd/5g/gsubr.c create mode 100644 src/cmd/5g/gsubr.go delete mode 100644 src/cmd/5g/peep.c create mode 100644 src/cmd/5g/peep.go delete mode 100644 src/cmd/5g/prog.c create mode 100644 src/cmd/5g/prog.go delete mode 100644 src/cmd/5g/reg.c create mode 100644 src/cmd/5g/reg.go create mode 100644 src/cmd/5g/util.go delete mode 100644 src/cmd/6a/Makefile delete mode 100644 src/cmd/6a/a.h delete mode 100644 src/cmd/6a/doc.go delete mode 100644 src/cmd/6a/lex.c create mode 100644 src/cmd/6a/lex.go create mode 100644 src/cmd/6a/y.go delete mode 100644 src/cmd/6a/y.tab.c delete mode 100644 src/cmd/6a/y.tab.h delete mode 100644 src/cmd/6g/Makefile delete mode 100644 src/cmd/6g/cgen.c create mode 100644 src/cmd/6g/cgen.go delete mode 100644 src/cmd/6g/doc.go delete mode 100644 src/cmd/6g/galign.c create mode 100644 src/cmd/6g/galign.go create mode 100644 src/cmd/6g/gg.go delete mode 100644 src/cmd/6g/gg.h delete mode 100644 src/cmd/6g/ggen.c create mode 100644 src/cmd/6g/ggen.go delete mode 100644 src/cmd/6g/gsubr.c create mode 100644 src/cmd/6g/gsubr.go delete mode 100644 src/cmd/6g/peep.c create mode 100644 src/cmd/6g/peep.go delete mode 100644 src/cmd/6g/prog.c create mode 100644 src/cmd/6g/prog.go delete mode 100644 src/cmd/6g/reg.c create mode 100644 src/cmd/6g/reg.go create mode 100644 src/cmd/6g/util.go delete mode 100644 src/cmd/8a/Makefile delete mode 100644 src/cmd/8a/a.h delete mode 100644 src/cmd/8a/doc.go delete mode 100644 src/cmd/8a/lex.c create mode 100644 src/cmd/8a/lex.go create mode 100644 src/cmd/8a/y.go delete mode 100644 src/cmd/8a/y.tab.c delete mode 100644 src/cmd/8a/y.tab.h delete mode 100644 src/cmd/8g/Makefile delete mode 100644 src/cmd/8g/cgen.c create mode 100644 src/cmd/8g/cgen.go delete mode 100644 src/cmd/8g/cgen64.c create mode 100644 src/cmd/8g/cgen64.go delete mode 100644 src/cmd/8g/doc.go delete mode 100644 src/cmd/8g/galign.c create mode 100644 src/cmd/8g/galign.go create mode 100644 src/cmd/8g/gg.go delete mode 100644 src/cmd/8g/gg.h delete mode 100644 src/cmd/8g/ggen.c create mode 100644 src/cmd/8g/ggen.go delete mode 100644 src/cmd/8g/gsubr.c create mode 100644 src/cmd/8g/gsubr.go delete mode 100644 src/cmd/8g/peep.c create mode 100644 src/cmd/8g/peep.go delete mode 100644 src/cmd/8g/prog.c create mode 100644 src/cmd/8g/prog.go delete mode 100644 src/cmd/8g/reg.c create mode 100644 src/cmd/8g/reg.go create mode 100644 src/cmd/8g/util.go delete mode 100644 src/cmd/9a/Makefile delete mode 100644 src/cmd/9a/a.h delete mode 100644 src/cmd/9a/doc.go delete mode 100644 src/cmd/9a/lex.c create mode 100644 src/cmd/9a/lex.go create mode 100644 src/cmd/9a/y.go delete mode 100644 src/cmd/9a/y.tab.c delete mode 100644 src/cmd/9a/y.tab.h delete mode 100644 src/cmd/9g/cgen.c create mode 100644 src/cmd/9g/cgen.go delete mode 100644 src/cmd/9g/doc.go delete mode 100644 src/cmd/9g/galign.c create mode 100644 src/cmd/9g/galign.go create mode 100644 src/cmd/9g/gg.go delete mode 100644 src/cmd/9g/gg.h delete mode 100644 src/cmd/9g/ggen.c create mode 100644 src/cmd/9g/ggen.go delete mode 100644 src/cmd/9g/gsubr.c create mode 100644 src/cmd/9g/gsubr.go create mode 100644 src/cmd/9g/opt.go delete mode 100644 src/cmd/9g/opt.h delete mode 100644 src/cmd/9g/peep.c create mode 100644 src/cmd/9g/peep.go delete mode 100644 src/cmd/9g/prog.c create mode 100644 src/cmd/9g/prog.go delete mode 100644 src/cmd/9g/reg.c create mode 100644 src/cmd/9g/reg.go create mode 100644 src/cmd/9g/util.go delete mode 100644 src/cmd/gc/Makefile delete mode 100644 src/cmd/gc/align.c delete mode 100644 src/cmd/gc/array.c delete mode 100755 src/cmd/gc/bisonerrors delete mode 100644 src/cmd/gc/bits.c delete mode 100644 src/cmd/gc/builtin.c delete mode 100644 src/cmd/gc/bv.c delete mode 100644 src/cmd/gc/closure.c delete mode 100644 src/cmd/gc/const.c delete mode 100644 src/cmd/gc/cplx.c delete mode 100644 src/cmd/gc/dcl.c delete mode 100644 src/cmd/gc/doc.go delete mode 100644 src/cmd/gc/esc.c delete mode 100644 src/cmd/gc/export.c delete mode 100644 src/cmd/gc/fmt.c delete mode 100644 src/cmd/gc/gen.c delete mode 100644 src/cmd/gc/go.errors delete mode 100644 src/cmd/gc/go.h delete mode 100644 src/cmd/gc/go.y delete mode 100644 src/cmd/gc/gsubr.c delete mode 100644 src/cmd/gc/init.c delete mode 100644 src/cmd/gc/inl.c delete mode 100644 src/cmd/gc/lex.c delete mode 100644 src/cmd/gc/md5.c delete mode 100644 src/cmd/gc/md5.h delete mode 100755 src/cmd/gc/mkbuiltin delete mode 100644 src/cmd/gc/mkbuiltin1.c delete mode 100755 src/cmd/gc/mkopnames delete mode 100644 src/cmd/gc/mparith1.c delete mode 100644 src/cmd/gc/mparith2.c delete mode 100644 src/cmd/gc/mparith3.c delete mode 100644 src/cmd/gc/obj.c delete mode 100644 src/cmd/gc/order.c delete mode 100644 src/cmd/gc/pgen.c delete mode 100644 src/cmd/gc/plive.c delete mode 100644 src/cmd/gc/popt.c delete mode 100644 src/cmd/gc/popt.h delete mode 100644 src/cmd/gc/racewalk.c delete mode 100644 src/cmd/gc/range.c delete mode 100644 src/cmd/gc/reflect.c delete mode 100644 src/cmd/gc/reg.c delete mode 100644 src/cmd/gc/runtime.go delete mode 100644 src/cmd/gc/select.c delete mode 100644 src/cmd/gc/sinit.c delete mode 100644 src/cmd/gc/subr.c delete mode 100644 src/cmd/gc/swt.c delete mode 100644 src/cmd/gc/typecheck.c delete mode 100644 src/cmd/gc/unsafe.c delete mode 100644 src/cmd/gc/unsafe.go delete mode 100644 src/cmd/gc/walk.c delete mode 100644 src/cmd/gc/y.tab.c delete mode 100644 src/cmd/gc/y.tab.h delete mode 100644 src/cmd/gc/yerr.h delete mode 100644 src/cmd/new5a/a.y delete mode 100644 src/cmd/new5a/lex.go delete mode 100644 src/cmd/new5a/y.go delete mode 100644 src/cmd/new5g/cgen.go delete mode 100644 src/cmd/new5g/cgen64.go delete mode 100644 src/cmd/new5g/galign.go delete mode 100644 src/cmd/new5g/gg.go delete mode 100644 src/cmd/new5g/ggen.go delete mode 100644 src/cmd/new5g/gsubr.go delete mode 100644 src/cmd/new5g/peep.go delete mode 100644 src/cmd/new5g/prog.go delete mode 100644 src/cmd/new5g/reg.go delete mode 100644 src/cmd/new5g/util.go delete mode 100644 src/cmd/new6a/a.y delete mode 100644 src/cmd/new6a/lex.go delete mode 100644 src/cmd/new6a/y.go delete mode 100644 src/cmd/new6g/cgen.go delete mode 100644 src/cmd/new6g/galign.go delete mode 100644 src/cmd/new6g/gg.go delete mode 100644 src/cmd/new6g/ggen.go delete mode 100644 src/cmd/new6g/gsubr.go delete mode 100644 src/cmd/new6g/peep.go delete mode 100644 src/cmd/new6g/prog.go delete mode 100644 src/cmd/new6g/reg.go delete mode 100644 src/cmd/new6g/util.go delete mode 100644 src/cmd/new8a/a.y delete mode 100644 src/cmd/new8a/lex.go delete mode 100644 src/cmd/new8a/y.go delete mode 100644 src/cmd/new8g/cgen.go delete mode 100644 src/cmd/new8g/cgen64.go delete mode 100644 src/cmd/new8g/galign.go delete mode 100644 src/cmd/new8g/gg.go delete mode 100644 src/cmd/new8g/ggen.go delete mode 100644 src/cmd/new8g/gsubr.go delete mode 100644 src/cmd/new8g/peep.go delete mode 100644 src/cmd/new8g/prog.go delete mode 100644 src/cmd/new8g/reg.go delete mode 100644 src/cmd/new8g/util.go delete mode 100644 src/cmd/new9a/a.y delete mode 100644 src/cmd/new9a/lex.go delete mode 100644 src/cmd/new9a/y.go delete mode 100644 src/cmd/new9g/cgen.go delete mode 100644 src/cmd/new9g/galign.go delete mode 100644 src/cmd/new9g/gg.go delete mode 100644 src/cmd/new9g/ggen.go delete mode 100644 src/cmd/new9g/gsubr.go delete mode 100644 src/cmd/new9g/opt.go delete mode 100644 src/cmd/new9g/peep.go delete mode 100644 src/cmd/new9g/prog.go delete mode 100644 src/cmd/new9g/reg.go delete mode 100644 src/cmd/new9g/util.go delete mode 100644 src/cmd/objwriter/main.go diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile deleted file mode 100644 index 27290ddd71..0000000000 --- a/src/cmd/5a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist - -install: y.tab.h - -y.tab.h: a.y - LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h deleted file mode 100644 index 8a6764b166..0000000000 --- a/src/cmd/5a/a.h +++ /dev/null @@ -1,173 +0,0 @@ -// Inferno utils/5a/a.h -// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "../5l/5.out.h" - -#ifndef EXTERN -#define EXTERN extern -#endif - -#undef getc -#undef ungetc -#undef BUFSIZ - -#define getc ccgetc -#define ungetc ccungetc - -typedef struct Sym Sym; -typedef struct Io Io; - -#define MAXALIGN 7 -#define FPCHIP 1 -#define NSYMB 8192 -#define BUFSIZ 8192 -#define HISTSZ 20 -#ifndef EOF -#define EOF (-1) -#endif -#define IGN (-2) -#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) -#define NHASH 503 -#define STRINGSZ 200 -#define NMACRO 10 - -struct Sym -{ - Sym* link; - char* macro; - int32 value; - ushort type; - char *name; - char* labelname; - char sym; -}; -#define S ((Sym*)0) - -EXTERN struct -{ - char* p; - int c; -} fi; - -struct Io -{ - Io* link; - char b[BUFSIZ]; - char* p; - short c; - short f; -}; -#define I ((Io*)0) - -enum -{ - CLAST, - CMACARG, - CMACRO, - CPREPROC, - - Always = C_SCOND_NONE, -}; - -EXTERN int debug[256]; -EXTERN Sym* hash[NHASH]; -EXTERN char** Dlist; -EXTERN int nDlist; -EXTERN int newflag; -EXTERN char* hunk; -EXTERN char** include; -EXTERN Io* iofree; -EXTERN Io* ionext; -EXTERN Io* iostack; -EXTERN int32 lineno; -EXTERN int nerrors; -EXTERN int32 nhunk; -EXTERN int ninclude; -EXTERN int32 nsymb; -EXTERN Addr nullgen; -EXTERN char* outfile; -EXTERN int pass; -EXTERN int32 pc; -EXTERN int peekc; -EXTERN int32 stmtline; -EXTERN int sym; -EXTERN char* symb; -EXTERN int thechar; -EXTERN char* thestring; -EXTERN int32 thunk; -EXTERN Biobuf obuf; -EXTERN Link* ctxt; -EXTERN Biobuf bstdout; -EXTERN Prog* lastpc; - -void* alloc(int32); -void* allocn(void*, int32, int32); -void ensuresymb(int32); -void errorexit(void); -void pushio(void); -void newio(void); -void newfile(char*, int); -Sym* slookup(char*); -Sym* lookup(void); -Sym* labellookup(Sym*); -void settext(LSym*); -void syminit(Sym*); -int32 yylex(void); -int getc(void); -int getnsc(void); -void unget(int); -int escchar(int); -void cinit(void); -void pinit(char*); -void cclean(void); -int isreg(Addr*); -void outcode(int, int, Addr*, int, Addr*); -int filbuf(void); -Sym* getsym(void); -void domacro(void); -void macund(void); -void macdef(void); -void macexpand(Sym*, char*); -void macinc(void); -void maclin(void); -void macprag(void); -void macif(int); -void macend(void); -void dodefine(char*); -void prfile(int32); -void linehist(char*, int); -void gethunk(void); -void yyerror(char*, ...); -int yyparse(void); -void setinclude(char*); -int assemble(char*); -void listinit(void); diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y index 10e9f6feea..39fab8fa26 100644 --- a/src/cmd/5a/a.y +++ b/src/cmd/5a/a.y @@ -29,20 +29,23 @@ // THE SOFTWARE. %{ -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/arm" +) %} -%union -{ - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; + +%union { + sym *asm.Sym + lval int32 + dval float64 + sval string + addr obj.Addr } + %left '|' %left '^' %left '&' @@ -51,12 +54,12 @@ %left '*' '/' '%' %token LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 %token LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA -%token LTYPEB LGLOBL LTYPEC LTYPED LTYPEE +%token LTYPEB LTYPEC LTYPED LTYPEE %token LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK %token LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD %token LCONST LSP LSB LFP LPC %token LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR -%token LCOND LS LAT +%token LCOND LS LAT LGLOBL %token LFCONST %token LSCONST %token LNAME LLAB LVAR @@ -68,30 +71,32 @@ prog: | prog { - stmtline = lineno; + stmtline = asm.Lineno; } line line: LNAME ':' { - $1 = labellookup($1); - if($1->type == LLAB && $1->value != pc) - yyerror("redeclaration of %s", $1->labelname); - $1->type = LLAB; - $1->value = pc; + $1 = asm.LabelLookup($1); + if $1.Type == LLAB && $1.Value != int64(asm.PC) { + yyerror("redeclaration of %s", $1.Labelname) + } + $1.Type = LLAB; + $1.Value = int64(asm.PC) } line | LNAME '=' expr ';' { - $1->type = LVAR; - $1->value = $3; + $1.Type = LVAR; + $1.Value = int64($3); } | LVAR '=' expr ';' { - if($1->value != $3) - yyerror("redeclaration of %s", $1->name); - $1->value = $3; + if $1.Value != int64($3) { + yyerror("redeclaration of %s", $1.Name) + } + $1.Value = int64($3); } | ';' | inst ';' @@ -171,20 +176,20 @@ inst: */ | LTYPE8 cond ioreg ',' '[' reglist ']' { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = $6; + g.Type = obj.TYPE_CONST; + g.Offset = int64($6); outcode($1, $2, &$3, 0, &g); } | LTYPE8 cond '[' reglist ']' ',' ioreg { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = $4; + g.Type = obj.TYPE_CONST; + g.Offset = int64($4); outcode($1, $2, &g, 0, &$7); } /* @@ -192,15 +197,15 @@ inst: */ | LTYPE9 cond reg ',' ireg ',' reg { - outcode($1, $2, &$5, $3.reg, &$7); + outcode($1, $2, &$5, int32($3.Reg), &$7); } | LTYPE9 cond reg ',' ireg comma { - outcode($1, $2, &$5, $3.reg, &$3); + outcode($1, $2, &$5, int32($3.Reg), &$3); } | LTYPE9 cond comma ireg ',' reg { - outcode($1, $2, &$4, $6.reg, &$6); + outcode($1, $2, &$4, int32($6.Reg), &$6); } /* * RET @@ -214,16 +219,16 @@ inst: */ | LTYPEB name ',' '$' textsize { - settext($2.sym); + asm.Settext($2.Sym); outcode($1, Always, &$2, 0, &$5); } | LTYPEB name ',' con ',' '$' textsize { - settext($2.sym); + asm.Settext($2.Sym); outcode($1, Always, &$2, 0, &$7); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST; + lastpc.From3.Offset = int64($4) } } /* @@ -231,27 +236,28 @@ inst: */ | LGLOBL name ',' imm { - settext($2.sym); - outcode($1, Always, &$2, 0, &$4); + asm.Settext($2.Sym) + outcode($1, Always, &$2, 0, &$4) } | LGLOBL name ',' con ',' imm { - settext($2.sym); - outcode($1, Always, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym) + outcode($1, Always, &$2, 0, &$6) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = int64($4) } } + /* * DATA */ | LTYPEC name '/' con ',' ximm { - outcode($1, Always, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + outcode($1, Always, &$2, 0, &$6) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = int64($4) } } /* @@ -285,18 +291,18 @@ inst: } | LTYPEL cond freg ',' freg comma { - outcode($1, $2, &$3, $5.reg, &nullgen); + outcode($1, $2, &$3, int32($5.Reg), &nullgen); } /* * MCR MRC */ | LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = + g.Type = obj.TYPE_CONST; + g.Offset = int64( (0xe << 24) | /* opcode */ ($1 << 20) | /* MCR/MRC */ (($2^C_SCOND_XOR) << 28) | /* scond */ @@ -306,7 +312,7 @@ inst: (($9 & 15) << 16) | /* Crn */ (($11 & 15) << 0) | /* Crm */ (($12 & 7) << 5) | /* coprocessor information */ - (1<<4); /* must be set */ + (1<<4)); /* must be set */ outcode(AMRC, Always, &nullgen, 0, &g); } /* @@ -314,17 +320,17 @@ inst: */ | LTYPEM cond reg ',' reg ',' regreg { - outcode($1, $2, &$3, $5.reg, &$7); + outcode($1, $2, &$3, int32($5.Reg), &$7); } /* - * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff -> r4 + * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4 * MULAW{T,B} r1,r2,r3,r4 */ | LTYPEN cond reg ',' reg ',' reg ',' spreg { - $7.type = TYPE_REGREG2; - $7.offset = $9; - outcode($1, $2, &$3, $5.reg, &$7); + $7.Type = obj.TYPE_REGREG2; + $7.Offset = int64($9); + outcode($1, $2, &$3, int32($5.Reg), &$7); } /* * PLD @@ -338,8 +344,9 @@ inst: */ | LTYPEPC gen ',' gen { - if($2.type != TYPE_CONST || $4.type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); + if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST { + yyerror("arguments to PCDATA must be integer constants") + } outcode($1, Always, &$2, 0, &$4); } /* @@ -347,10 +354,12 @@ inst: */ | LTYPEF gen ',' gen { - if($2.type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM) - yyerror("value for FUNCDATA must be symbol reference"); + if $2.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if $4.Type != obj.NAME_EXTERN && $4.Type != obj.NAME_STATIC && $4.Type != obj.TYPE_MEM { + yyerror("value for FUNCDATA must be symbol reference") + } outcode($1, Always, &$2, 0, &$4); } /* @@ -361,13 +370,43 @@ inst: outcode($1, Always, &nullgen, 0, &nullgen); } +textsize: + LCONST + { + $$ = nullgen; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = int64($1) + $$.U.Argsize = obj.ArgsSizeUnknown; + } +| '-' LCONST + { + $$ = nullgen; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -int64($2) + $$.U.Argsize = obj.ArgsSizeUnknown; + } +| LCONST '-' LCONST + { + $$ = nullgen; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = int64($1) + $$.U.Argsize = int32($3); + } +| '-' LCONST '-' LCONST + { + $$ = nullgen; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -int64($2) + $$.U.Argsize = int32($4); + } + cond: { $$ = Always; } | cond LCOND { - $$ = ($1 & ~C_SCOND) | $2; + $$ = ($1 & ^ C_SCOND) | $2; } | cond LS { @@ -381,65 +420,36 @@ rel: con '(' LPC ')' { $$ = nullgen; - $$.type = TYPE_BRANCH; - $$.offset = $1 + pc; + $$.Type = obj.TYPE_BRANCH; + $$.Offset = int64($1) + int64(asm.PC); } | LNAME offset { - $1 = labellookup($1); + $1 = asm.LabelLookup($1); $$ = nullgen; - if(pass == 2 && $1->type != LLAB) - yyerror("undefined label: %s", $1->labelname); - $$.type = TYPE_BRANCH; - $$.offset = $1->value + $2; - } - -textsize: - LCONST - { - $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = ArgsSizeUnknown; - } -| '-' LCONST - { - $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = ArgsSizeUnknown; - } -| LCONST '-' LCONST - { - $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = $3; - } -| '-' LCONST '-' LCONST - { - $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = $4; + if asm.Pass == 2 && $1.Type != LLAB { + yyerror("undefined label: %s", $1.Labelname) + } + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1.Value + int64($2); } ximm: '$' con { $$ = nullgen; - $$.type = TYPE_CONST; - $$.offset = $2; + $$.Type = obj.TYPE_CONST; + $$.Offset = int64($2); } | '$' oreg { $$ = $2; - $$.type = TYPE_ADDR; + $$.Type = obj.TYPE_ADDR; } | '$' LSCONST { $$ = nullgen; - $$.type = TYPE_SCONST; - memcpy($$.u.sval, $2, sizeof($$.u.sval)); + $$.Type = obj.TYPE_SCONST; + $$.U.Sval = $2 } | fcon @@ -447,45 +457,34 @@ fcon: '$' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $2; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $2; } | '$' '-' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$3; } reglist: spreg { - if($1 < REG_R0 || $1 > REG_R15) - yyerror("invalid register in reglist"); - - $$ = 1 << ($1&15); + $$ = 1 << uint($1&15); } | spreg '-' spreg { - int i; - - if($1 < REG_R0 || $1 > REG_R15) - yyerror("invalid register in reglist"); - if($3 < REG_R0 || $3 > REG_R15) - yyerror("invalid register in reglist"); - $$=0; - for(i=$1; i<=$3; i++) - $$ |= 1<<(i&15); - for(i=$3; i<=$1; i++) - $$ |= 1<<(i&15); + for i:=$1; i<=$3; i++ { + $$ |= 1< REG_R15) - yyerror("invalid register in reglist"); - - $$ = (1<<($1&15)) | $3; + $$ = (1<' '>' rcon { $$ = nullgen; - $$.type = TYPE_SHIFT; - $$.offset = $1&15 | $4 | (1 << 5); + $$.Type = obj.TYPE_SHIFT; + $$.Offset = int64($1&15) | int64($4) | (1 << 5); } | spreg '-' '>' rcon { $$ = nullgen; - $$.type = TYPE_SHIFT; - $$.offset = $1&15 | $4 | (2 << 5); + $$.Type = obj.TYPE_SHIFT; + $$.Offset = int64($1&15) | int64($4) | (2 << 5); } | spreg LAT '>' rcon { $$ = nullgen; - $$.type = TYPE_SHIFT; - $$.offset = $1&15 | $4 | (3 << 5); + $$.Type = obj.TYPE_SHIFT; + $$.Offset = int64($1&15) | int64($4) | (3 << 5); } rcon: spreg { - if($$ < REG_R0 || $$ > REG_R15) - print("register value out of range in shift\n"); + if $$ < REG_R0 || $$ > REG_R15 { + print("register value out of range\n") + } $$ = (($1&15) << 8) | (1 << 4); } | con { - if($$ < 0 || $$ >= 32) - print("shift value out of range\n"); + if $$ < 0 || $$ >= 32 { + print("shift value out of range\n") + } $$ = ($1&31) << 7; } @@ -633,8 +634,9 @@ sreg: } | LR '(' expr ')' { - if($3 < 0 || $3 >= NREG) - print("register value out of range in R(...)\n"); + if $3 < 0 || $3 >= NREG { + print("register value out of range\n") + } $$ = REG_R0 + $3; } @@ -649,8 +651,9 @@ creg: LCREG | LC '(' expr ')' { - if($3 < 0 || $3 >= NREG) - print("register value out of range in C(...)\n"); + if $3 < 0 || $3 >= NREG { + print("register value out of range\n") + } $$ = $3; // TODO(rsc): REG_C0+$3 } @@ -662,40 +665,40 @@ freg: LFREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } | LF '(' con ')' { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = REG_F0 + $3; + $$.Type = obj.TYPE_REG; + $$.Reg = int16(REG_F0 + $3); } name: con '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $3; - $$.sym = nil; - $$.offset = $1; + $$.Type = obj.TYPE_MEM; + $$.Name = int8($3); + $$.Sym = nil; + $$.Offset = int64($1); } | LNAME offset '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $4; - $$.sym = linklookup(ctxt, $1->name, 0); - $$.offset = $2; + $$.Type = obj.TYPE_MEM; + $$.Name = int8($4); + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); + $$.Offset = int64($2); } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = NAME_STATIC; - $$.sym = linklookup(ctxt, $1->name, 1); - $$.offset = $4; + $$.Type = obj.TYPE_MEM; + $$.Name = obj.NAME_STATIC; + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); + $$.Offset = int64($4); } offset: @@ -720,7 +723,7 @@ con: LCONST | LVAR { - $$ = $1->value; + $$ = int32($1.Value); } | '-' con { @@ -732,7 +735,7 @@ con: } | '~' con { - $$ = ~$2; + $$ = ^$2; } | '(' expr ')' { @@ -772,11 +775,11 @@ expr: } | expr '<' '<' expr { - $$ = $1 << $4; + $$ = $1 << uint($4); } | expr '>' '>' expr { - $$ = $1 >> $4; + $$ = $1 >> uint($4); } | expr '&' expr { diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go deleted file mode 100644 index 3e9e78fe6d..0000000000 --- a/src/cmd/5a/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -5a is a version of the Plan 9 assembler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8a - -Go-specific considerations are documented at - - http://golang.org/doc/asm - -Its target architecture is the ARM, referred to by these tools as arm. - -*/ -package main diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c deleted file mode 100644 index 6f56922a4e..0000000000 --- a/src/cmd/5a/lex.c +++ /dev/null @@ -1,538 +0,0 @@ -// Inferno utils/5a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include -#include -#include "a.h" -#include "y.tab.h" - -enum -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; - -int -systemtype(int sys) -{ -#ifdef _WIN32 - return sys&Windows; -#else - return sys&Plan9; -#endif -} - -int -Lconv(Fmt *fp) -{ - return linklinefmt(ctxt, fp); -} - -void -dodef(char *p) -{ - if(nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; -} - -void -usage(void) -{ - print("usage: %ca [options] file.c...\n", thechar); - flagprint(1); - errorexit(); -} - -void -main(int argc, char *argv[]) -{ - char *p; - - thechar = '5'; - thestring = "arm"; - - ctxt = linknew(&linkarm); - ctxt->diag = yyerror; - ctxt->bso = &bstdout; - ctxt->enforce_data_order = 1; - Binit(&bstdout, 1, OWRITE); - listinit5(); - fmtinstall('L', Lconv); - - // Allow GOARCH=thestring or GOARCH=thestringsuffix, - // but not other values. - p = getgoarch(); - if(strncmp(p, thestring, strlen(thestring)) != 0) - sysfatal("cannot use %cc with GOARCH=%s", thechar, p); - - ensuresymb(NSYMB); - memset(debug, 0, sizeof(debug)); - cinit(); - outfile = 0; - setinclude("."); - - flagfn1("D", "name[=value]: add #define", dodef); - flagfn1("I", "dir: add dir to include path", setinclude); - flagcount("S", "print assembly and machine code", &debug['S']); - flagcount("m", "debug preprocessor macros", &debug['m']); - flagstr("o", "file: set output file", &outfile); - flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - - flagparse(&argc, &argv, usage); - ctxt->debugasm = debug['S']; - - if(argc < 1) - usage(); - if(argc > 1){ - print("can't assemble multiple files\n"); - errorexit(); - } - - if(assemble(argv[0])) - errorexit(); - Bflush(&bstdout); - if(nerrors > 0) - errorexit(); - exits(0); -} - -int -assemble(char *file) -{ - char *ofile, *p; - int i, of; - - ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) - strcpy(ofile, file); - p = utfrrune(ofile, '/'); - if(p) { - include[0] = ofile; - *p++ = 0; - } else - p = ofile; - if(outfile == 0) { - outfile = p; - if(outfile){ - p = utfrrune(outfile, '.'); - if(p) - if(p[1] == 's' && p[2] == 0) - p[0] = 0; - p = utfrune(outfile, 0); - p[0] = '.'; - p[1] = thechar; - p[2] = 0; - } else - outfile = "/dev/null"; - } - - of = create(outfile, OWRITE, 0664); - if(of < 0) { - yyerror("%ca: cannot create %s", thechar, outfile); - errorexit(); - } - Binit(&obuf, of, OWRITE); - Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - Bprint(&obuf, "!\n"); - - for(pass = 1; pass <= 2; pass++) { - pinit(file); - for(i=0; itype = itab[i].type; - s->value = itab[i].value; - } -} - -void -syminit(Sym *s) -{ - - s->type = LNAME; - s->value = 0; -} - -int -isreg(Addr *g) -{ - - USED(g); - return 1; -} - -void -cclean(void) -{ - outcode(AEND, Always, &nullgen, 0, &nullgen); -} - -static int bcode[] = -{ - ABEQ, - ABNE, - ABCS, - ABCC, - ABMI, - ABPL, - ABVS, - ABVC, - ABHI, - ABLS, - ABGE, - ABLT, - ABGT, - ABLE, - AB, - ANOP, -}; - -void -outcode(int a, int scond, Addr *g1, int reg, Addr *g2) -{ - Prog *p; - Plist *pl; - - /* hack to make B.NE etc. work: turn it into the corresponding conditional */ - if(a == AB){ - a = bcode[(scond^C_SCOND_XOR)&0xf]; - scond = (scond & ~0xf) | C_SCOND_NONE; - } - - if(pass == 1) - goto out; - - p = malloc(sizeof *p); - memset(p, 0, sizeof *p); - p->as = a; - p->lineno = stmtline; - p->scond = scond; - p->from = *g1; - p->reg = reg; - p->to = *g2; - p->pc = pc; - - if(lastpc == nil) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastpc->link = p; - lastpc = p; - -out: - if(a != AGLOBL && a != ADATA) - pc++; -} - -#include "../cc/lexbody" -#include "../cc/macbody" diff --git a/src/cmd/5a/lex.go b/src/cmd/5a/lex.go new file mode 100644 index 0000000000..1afd827793 --- /dev/null +++ b/src/cmd/5a/lex.go @@ -0,0 +1,371 @@ +// Inferno utils/5a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//go:generate go tool yacc a.y + +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/arm" +) + +var ( + yyerror = asm.Yyerror + nullgen obj.Addr + stmtline int32 +) + +const Always = arm.C_SCOND_NONE + +func main() { + cinit() + + asm.LSCONST = LSCONST + asm.LCONST = LCONST + asm.LFCONST = LFCONST + asm.LNAME = LNAME + asm.LVAR = LVAR + asm.LLAB = LLAB + + asm.Lexinit = lexinit + asm.Cclean = cclean + asm.Yyparse = yyparse + + asm.Thechar = '5' + asm.Thestring = "arm" + asm.Thelinkarch = &arm.Linkarm + + asm.Main() +} + +type yy struct{} + +func (yy) Lex(v *yySymType) int { + var av asm.Yylval + tok := asm.Yylex(&av) + v.sym = av.Sym + v.lval = int32(av.Lval) + v.sval = av.Sval + v.dval = av.Dval + return tok +} + +func (yy) Error(msg string) { + asm.Yyerror("%s", msg) +} + +func yyparse() { + yyParse(yy{}) +} + +var lexinit = []asm.Lextab{ + {"SP", LSP, obj.NAME_AUTO}, + {"SB", LSB, obj.NAME_EXTERN}, + {"FP", LFP, obj.NAME_PARAM}, + {"PC", LPC, obj.TYPE_BRANCH}, + + {"R", LR, 0}, + + {"R0", LREG, arm.REG_R0}, + {"R1", LREG, arm.REG_R1}, + {"R2", LREG, arm.REG_R2}, + {"R3", LREG, arm.REG_R3}, + {"R4", LREG, arm.REG_R4}, + {"R5", LREG, arm.REG_R5}, + {"R6", LREG, arm.REG_R6}, + {"R7", LREG, arm.REG_R7}, + {"R8", LREG, arm.REG_R8}, + {"R9", LREG, arm.REG_R9}, + {"g", LREG, arm.REG_R10}, // avoid unintentionally clobber g using R10 + {"R11", LREG, arm.REG_R11}, + {"R12", LREG, arm.REG_R12}, + {"R13", LREG, arm.REG_R13}, + {"R14", LREG, arm.REG_R14}, + {"R15", LREG, arm.REG_R15}, + {"F", LF, 0}, + {"F0", LFREG, arm.REG_F0}, + {"F1", LFREG, arm.REG_F1}, + {"F2", LFREG, arm.REG_F2}, + {"F3", LFREG, arm.REG_F3}, + {"F4", LFREG, arm.REG_F4}, + {"F5", LFREG, arm.REG_F5}, + {"F6", LFREG, arm.REG_F6}, + {"F7", LFREG, arm.REG_F7}, + {"F8", LFREG, arm.REG_F8}, + {"F9", LFREG, arm.REG_F9}, + {"F10", LFREG, arm.REG_F10}, + {"F11", LFREG, arm.REG_F11}, + {"F12", LFREG, arm.REG_F12}, + {"F13", LFREG, arm.REG_F13}, + {"F14", LFREG, arm.REG_F14}, + {"F15", LFREG, arm.REG_F15}, + {"C", LC, 0}, + {"C0", LCREG, 0}, + {"C1", LCREG, 1}, + {"C2", LCREG, 2}, + {"C3", LCREG, 3}, + {"C4", LCREG, 4}, + {"C5", LCREG, 5}, + {"C6", LCREG, 6}, + {"C7", LCREG, 7}, + {"C8", LCREG, 8}, + {"C9", LCREG, 9}, + {"C10", LCREG, 10}, + {"C11", LCREG, 11}, + {"C12", LCREG, 12}, + {"C13", LCREG, 13}, + {"C14", LCREG, 14}, + {"C15", LCREG, 15}, + {"CPSR", LPSR, arm.REG_CPSR}, + {"SPSR", LPSR, arm.REG_SPSR}, + {"FPSR", LFCR, arm.REG_FPSR}, + {"FPCR", LFCR, arm.REG_FPCR}, + {".EQ", LCOND, arm.C_SCOND_EQ}, + {".NE", LCOND, arm.C_SCOND_NE}, + {".CS", LCOND, arm.C_SCOND_HS}, + {".HS", LCOND, arm.C_SCOND_HS}, + {".CC", LCOND, arm.C_SCOND_LO}, + {".LO", LCOND, arm.C_SCOND_LO}, + {".MI", LCOND, arm.C_SCOND_MI}, + {".PL", LCOND, arm.C_SCOND_PL}, + {".VS", LCOND, arm.C_SCOND_VS}, + {".VC", LCOND, arm.C_SCOND_VC}, + {".HI", LCOND, arm.C_SCOND_HI}, + {".LS", LCOND, arm.C_SCOND_LS}, + {".GE", LCOND, arm.C_SCOND_GE}, + {".LT", LCOND, arm.C_SCOND_LT}, + {".GT", LCOND, arm.C_SCOND_GT}, + {".LE", LCOND, arm.C_SCOND_LE}, + {".AL", LCOND, arm.C_SCOND_NONE}, + {".U", LS, arm.C_UBIT}, + {".S", LS, arm.C_SBIT}, + {".W", LS, arm.C_WBIT}, + {".P", LS, arm.C_PBIT}, + {".PW", LS, arm.C_WBIT | arm.C_PBIT}, + {".WP", LS, arm.C_WBIT | arm.C_PBIT}, + {".F", LS, arm.C_FBIT}, + {".IBW", LS, arm.C_WBIT | arm.C_PBIT | arm.C_UBIT}, + {".IAW", LS, arm.C_WBIT | arm.C_UBIT}, + {".DBW", LS, arm.C_WBIT | arm.C_PBIT}, + {".DAW", LS, arm.C_WBIT}, + {".IB", LS, arm.C_PBIT | arm.C_UBIT}, + {".IA", LS, arm.C_UBIT}, + {".DB", LS, arm.C_PBIT}, + {".DA", LS, 0}, + {"@", LAT, 0}, + {"AND", LTYPE1, arm.AAND}, + {"EOR", LTYPE1, arm.AEOR}, + {"SUB", LTYPE1, arm.ASUB}, + {"RSB", LTYPE1, arm.ARSB}, + {"ADD", LTYPE1, arm.AADD}, + {"ADC", LTYPE1, arm.AADC}, + {"SBC", LTYPE1, arm.ASBC}, + {"RSC", LTYPE1, arm.ARSC}, + {"ORR", LTYPE1, arm.AORR}, + {"BIC", LTYPE1, arm.ABIC}, + {"SLL", LTYPE1, arm.ASLL}, + {"SRL", LTYPE1, arm.ASRL}, + {"SRA", LTYPE1, arm.ASRA}, + {"MUL", LTYPE1, arm.AMUL}, + {"MULA", LTYPEN, arm.AMULA}, + {"DIV", LTYPE1, arm.ADIV}, + {"MOD", LTYPE1, arm.AMOD}, + {"MULL", LTYPEM, arm.AMULL}, + {"MULAL", LTYPEM, arm.AMULAL}, + {"MULLU", LTYPEM, arm.AMULLU}, + {"MULALU", LTYPEM, arm.AMULALU}, + {"MVN", LTYPE2, arm.AMVN}, /* op2 ignored */ + {"MOVB", LTYPE3, arm.AMOVB}, + {"MOVBU", LTYPE3, arm.AMOVBU}, + {"MOVH", LTYPE3, arm.AMOVH}, + {"MOVHU", LTYPE3, arm.AMOVHU}, + {"MOVW", LTYPE3, arm.AMOVW}, + {"MOVD", LTYPE3, arm.AMOVD}, + {"MOVDF", LTYPE3, arm.AMOVDF}, + {"MOVDW", LTYPE3, arm.AMOVDW}, + {"MOVF", LTYPE3, arm.AMOVF}, + {"MOVFD", LTYPE3, arm.AMOVFD}, + {"MOVFW", LTYPE3, arm.AMOVFW}, + {"MOVWD", LTYPE3, arm.AMOVWD}, + {"MOVWF", LTYPE3, arm.AMOVWF}, + {"LDREX", LTYPE3, arm.ALDREX}, + {"LDREXD", LTYPE3, arm.ALDREXD}, + {"STREX", LTYPE9, arm.ASTREX}, + {"STREXD", LTYPE9, arm.ASTREXD}, + + /* + {"NEGF", LTYPEI, ANEGF}, + {"NEGD", LTYPEI, ANEGD}, + {"SQTF", LTYPEI, ASQTF}, + {"SQTD", LTYPEI, ASQTD}, + {"RNDF", LTYPEI, ARNDF}, + {"RNDD", LTYPEI, ARNDD}, + {"URDF", LTYPEI, AURDF}, + {"URDD", LTYPEI, AURDD}, + {"NRMF", LTYPEI, ANRMF}, + {"NRMD", LTYPEI, ANRMD}, + */ + {"ABSF", LTYPEI, arm.AABSF}, + {"ABSD", LTYPEI, arm.AABSD}, + {"SQRTF", LTYPEI, arm.ASQRTF}, + {"SQRTD", LTYPEI, arm.ASQRTD}, + {"CMPF", LTYPEL, arm.ACMPF}, + {"CMPD", LTYPEL, arm.ACMPD}, + {"ADDF", LTYPEK, arm.AADDF}, + {"ADDD", LTYPEK, arm.AADDD}, + {"SUBF", LTYPEK, arm.ASUBF}, + {"SUBD", LTYPEK, arm.ASUBD}, + {"MULF", LTYPEK, arm.AMULF}, + {"MULD", LTYPEK, arm.AMULD}, + {"DIVF", LTYPEK, arm.ADIVF}, + {"DIVD", LTYPEK, arm.ADIVD}, + {"B", LTYPE4, arm.AB}, + {"BL", LTYPE4, arm.ABL}, + {"BX", LTYPEBX, arm.ABX}, + {"BEQ", LTYPE5, arm.ABEQ}, + {"BNE", LTYPE5, arm.ABNE}, + {"BCS", LTYPE5, arm.ABCS}, + {"BHS", LTYPE5, arm.ABHS}, + {"BCC", LTYPE5, arm.ABCC}, + {"BLO", LTYPE5, arm.ABLO}, + {"BMI", LTYPE5, arm.ABMI}, + {"BPL", LTYPE5, arm.ABPL}, + {"BVS", LTYPE5, arm.ABVS}, + {"BVC", LTYPE5, arm.ABVC}, + {"BHI", LTYPE5, arm.ABHI}, + {"BLS", LTYPE5, arm.ABLS}, + {"BGE", LTYPE5, arm.ABGE}, + {"BLT", LTYPE5, arm.ABLT}, + {"BGT", LTYPE5, arm.ABGT}, + {"BLE", LTYPE5, arm.ABLE}, + {"BCASE", LTYPE5, arm.ABCASE}, + {"SWI", LTYPE6, arm.ASWI}, + {"CMP", LTYPE7, arm.ACMP}, + {"TST", LTYPE7, arm.ATST}, + {"TEQ", LTYPE7, arm.ATEQ}, + {"CMN", LTYPE7, arm.ACMN}, + {"MOVM", LTYPE8, arm.AMOVM}, + {"SWPBU", LTYPE9, arm.ASWPBU}, + {"SWPW", LTYPE9, arm.ASWPW}, + {"RET", LTYPEA, obj.ARET}, + {"RFE", LTYPEA, arm.ARFE}, + {"TEXT", LTYPEB, obj.ATEXT}, + {"GLOBL", LGLOBL, obj.AGLOBL}, + {"DATA", LTYPEC, obj.ADATA}, + {"CASE", LTYPED, arm.ACASE}, + {"END", LTYPEE, obj.AEND}, + {"WORD", LTYPEH, arm.AWORD}, + {"NOP", LTYPEI, obj.ANOP}, + {"MCR", LTYPEJ, 0}, + {"MRC", LTYPEJ, 1}, + {"PLD", LTYPEPLD, arm.APLD}, + {"UNDEF", LTYPEE, obj.AUNDEF}, + {"CLZ", LTYPE2, arm.ACLZ}, + {"MULWT", LTYPE1, arm.AMULWT}, + {"MULWB", LTYPE1, arm.AMULWB}, + {"MULAWT", LTYPEN, arm.AMULAWT}, + {"MULAWB", LTYPEN, arm.AMULAWB}, + {"USEFIELD", LTYPEN, obj.AUSEFIELD}, + {"PCDATA", LTYPEPC, obj.APCDATA}, + {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, +} + +func cinit() { +} + +func isreg(g *obj.Addr) bool { + return true +} + +func cclean() { + outcode(obj.AEND, Always, &nullgen, 0, &nullgen) +} + +var bcode = []int{ + arm.ABEQ, + arm.ABNE, + arm.ABCS, + arm.ABCC, + arm.ABMI, + arm.ABPL, + arm.ABVS, + arm.ABVC, + arm.ABHI, + arm.ABLS, + arm.ABGE, + arm.ABLT, + arm.ABGT, + arm.ABLE, + arm.AB, + obj.ANOP, +} + +var lastpc *obj.Prog + +func outcode(a, scond int32, g1 *obj.Addr, reg int32, g2 *obj.Addr) { + var p *obj.Prog + var pl *obj.Plist + + /* hack to make B.NE etc. work: turn it into the corresponding conditional */ + if a == arm.AB { + a = int32(bcode[(scond^arm.C_SCOND_XOR)&0xf]) + scond = (scond &^ 0xf) | Always + } + + if asm.Pass == 1 { + goto out + } + + p = new(obj.Prog) + *p = obj.Prog{} + p.Ctxt = asm.Ctxt + p.As = int16(a) + p.Lineno = stmtline + p.Scond = uint8(scond) + p.From = *g1 + p.Reg = int16(reg) + p.To = *g2 + p.Pc = int64(asm.PC) + + if lastpc == nil { + pl = obj.Linknewplist(asm.Ctxt) + pl.Firstpc = p + } else { + lastpc.Link = p + } + lastpc = p + +out: + if a != obj.AGLOBL && a != obj.ADATA { + asm.PC++ + } +} diff --git a/src/cmd/5a/y.go b/src/cmd/5a/y.go new file mode 100644 index 0000000000..17ee80ee51 --- /dev/null +++ b/src/cmd/5a/y.go @@ -0,0 +1,1362 @@ +//line a.y:32 +package main + +import __yyfmt__ "fmt" + +//line a.y:32 +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/arm" +) + +//line a.y:41 +type yySymType struct { + yys int + sym *asm.Sym + lval int32 + dval float64 + sval string + addr obj.Addr +} + +const LTYPE1 = 57346 +const LTYPE2 = 57347 +const LTYPE3 = 57348 +const LTYPE4 = 57349 +const LTYPE5 = 57350 +const LTYPE6 = 57351 +const LTYPE7 = 57352 +const LTYPE8 = 57353 +const LTYPE9 = 57354 +const LTYPEA = 57355 +const LTYPEB = 57356 +const LTYPEC = 57357 +const LTYPED = 57358 +const LTYPEE = 57359 +const LTYPEG = 57360 +const LTYPEH = 57361 +const LTYPEI = 57362 +const LTYPEJ = 57363 +const LTYPEK = 57364 +const LTYPEL = 57365 +const LTYPEM = 57366 +const LTYPEN = 57367 +const LTYPEBX = 57368 +const LTYPEPLD = 57369 +const LCONST = 57370 +const LSP = 57371 +const LSB = 57372 +const LFP = 57373 +const LPC = 57374 +const LTYPEX = 57375 +const LTYPEPC = 57376 +const LTYPEF = 57377 +const LR = 57378 +const LREG = 57379 +const LF = 57380 +const LFREG = 57381 +const LC = 57382 +const LCREG = 57383 +const LPSR = 57384 +const LFCR = 57385 +const LCOND = 57386 +const LS = 57387 +const LAT = 57388 +const LGLOBL = 57389 +const LFCONST = 57390 +const LSCONST = 57391 +const LNAME = 57392 +const LLAB = 57393 +const LVAR = 57394 + +var yyToknames = []string{ + "'|'", + "'^'", + "'&'", + "'<'", + "'>'", + "'+'", + "'-'", + "'*'", + "'/'", + "'%'", + "LTYPE1", + "LTYPE2", + "LTYPE3", + "LTYPE4", + "LTYPE5", + "LTYPE6", + "LTYPE7", + "LTYPE8", + "LTYPE9", + "LTYPEA", + "LTYPEB", + "LTYPEC", + "LTYPED", + "LTYPEE", + "LTYPEG", + "LTYPEH", + "LTYPEI", + "LTYPEJ", + "LTYPEK", + "LTYPEL", + "LTYPEM", + "LTYPEN", + "LTYPEBX", + "LTYPEPLD", + "LCONST", + "LSP", + "LSB", + "LFP", + "LPC", + "LTYPEX", + "LTYPEPC", + "LTYPEF", + "LR", + "LREG", + "LF", + "LFREG", + "LC", + "LCREG", + "LPSR", + "LFCR", + "LCOND", + "LS", + "LAT", + "LGLOBL", + "LFCONST", + "LSCONST", + "LNAME", + "LLAB", + "LVAR", +} +var yyStatenames = []string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyMaxDepth = 200 + +//line yacctab:1 +var yyExca = []int{ + -1, 1, + 1, -1, + -2, 2, + -1, 196, + 68, 63, + -2, 53, +} + +const yyNprod = 134 +const yyPrivate = 57344 + +var yyTokenNames []string +var yyStates []string + +const yyLast = 708 + +var yyAct = []int{ + + 125, 328, 259, 73, 202, 79, 85, 106, 91, 195, + 3, 129, 84, 115, 75, 72, 338, 324, 278, 136, + 78, 77, 178, 177, 176, 174, 175, 169, 170, 171, + 172, 173, 301, 86, 86, 289, 52, 61, 62, 90, + 89, 86, 86, 86, 71, 103, 104, 284, 277, 86, + 58, 57, 276, 120, 275, 96, 99, 101, 263, 112, + 145, 105, 105, 224, 110, 334, 321, 302, 206, 105, + 140, 123, 141, 143, 146, 113, 249, 152, 151, 55, + 114, 58, 57, 197, 139, 92, 190, 165, 94, 341, + 148, 149, 95, 93, 44, 46, 164, 154, 150, 231, + 160, 128, 87, 56, 108, 64, 300, 311, 254, 167, + 55, 60, 45, 59, 152, 97, 253, 58, 57, 86, + 88, 255, 196, 340, 111, 184, 188, 189, 118, 191, + 333, 124, 126, 331, 56, 327, 325, 309, 39, 199, + 192, 108, 60, 308, 59, 211, 55, 58, 57, 92, + 45, 305, 94, 295, 86, 226, 95, 93, 292, 222, + 223, 288, 103, 104, 103, 104, 267, 86, 266, 262, + 56, 103, 104, 258, 38, 225, 55, 45, 60, 108, + 59, 245, 221, 45, 86, 233, 220, 144, 234, 235, + 236, 237, 238, 239, 252, 219, 242, 243, 244, 250, + 56, 246, 218, 247, 37, 248, 223, 200, 60, 216, + 59, 264, 100, 257, 215, 198, 194, 193, 183, 265, + 214, 182, 268, 269, 180, 271, 166, 153, 279, 279, + 279, 279, 137, 53, 53, 53, 127, 35, 36, 272, + 231, 273, 274, 317, 74, 83, 83, 281, 282, 283, + 217, 330, 329, 251, 196, 83, 293, 196, 323, 116, + 286, 287, 122, 291, 58, 57, 294, 90, 89, 314, + 133, 134, 135, 304, 303, 90, 270, 256, 261, 297, + 299, 147, 178, 177, 176, 174, 175, 169, 170, 171, + 172, 173, 138, 55, 92, 315, 312, 94, 162, 298, + 159, 95, 93, 316, 155, 156, 260, 157, 319, 310, + 58, 57, 318, 90, 89, 240, 313, 56, 241, 103, + 104, 181, 326, 80, 186, 60, 230, 59, 332, 229, + 322, 83, 335, 290, 92, 336, 228, 94, 296, 55, + 201, 95, 93, 207, 208, 209, 204, 203, 205, 285, + 212, 213, 306, 158, 337, 103, 104, 94, 131, 132, + 342, 95, 93, 56, 107, 107, 83, 227, 121, 102, + 8, 76, 107, 59, 7, 98, 133, 232, 130, 83, + 131, 132, 9, 10, 11, 12, 14, 15, 16, 17, + 18, 19, 20, 22, 23, 34, 83, 24, 25, 28, + 26, 27, 29, 30, 13, 31, 171, 172, 173, 58, + 57, 109, 32, 33, 2, 58, 57, 1, 119, 92, + 185, 142, 94, 320, 339, 21, 95, 93, 4, 0, + 5, 0, 0, 6, 103, 104, 0, 0, 55, 0, + 280, 280, 280, 280, 55, 92, 45, 0, 94, 0, + 58, 57, 95, 93, 90, 89, 0, 0, 81, 82, + 103, 104, 56, 0, 0, 0, 54, 0, 56, 0, + 60, 0, 59, 0, 0, 87, 76, 0, 59, 55, + 92, 0, 0, 94, 0, 0, 0, 95, 93, 90, + 89, 0, 0, 81, 82, 58, 163, 0, 58, 57, + 0, 54, 0, 56, 0, 122, 204, 203, 205, 251, + 87, 76, 0, 59, 178, 177, 176, 174, 175, 169, + 170, 171, 172, 173, 55, 58, 57, 55, 0, 0, + 0, 58, 57, 0, 58, 57, 0, 58, 57, 169, + 170, 171, 172, 173, 162, 161, 54, 0, 56, 187, + 0, 56, 0, 0, 55, 0, 76, 0, 59, 76, + 55, 59, 0, 55, 0, 0, 55, 0, 0, 0, + 0, 0, 204, 203, 205, 94, 117, 0, 56, 95, + 93, 210, 54, 0, 56, 54, 60, 56, 59, 0, + 56, 0, 76, 0, 59, 60, 0, 59, 76, 0, + 59, 178, 177, 176, 174, 175, 169, 170, 171, 172, + 173, 178, 177, 176, 174, 175, 169, 170, 171, 172, + 173, 178, 177, 176, 174, 175, 169, 170, 171, 172, + 173, 92, 0, 0, 94, 0, 0, 0, 95, 93, + 40, 0, 0, 0, 0, 0, 103, 104, 0, 0, + 0, 41, 42, 43, 0, 0, 47, 48, 49, 50, + 51, 0, 0, 307, 63, 0, 65, 66, 67, 68, + 69, 70, 179, 177, 176, 174, 175, 169, 170, 171, + 172, 173, 168, 178, 177, 176, 174, 175, 169, 170, + 171, 172, 173, 176, 174, 175, 169, 170, 171, 172, + 173, 174, 175, 169, 170, 171, 172, 173, +} +var yyPact = []int{ + + -1000, -1000, 368, -1000, 174, 140, -1000, 109, 73, -1000, + -1000, -1000, -1000, 84, 84, -1000, -1000, -1000, -1000, -1000, + 525, 525, 525, -1000, 84, -1000, -1000, -1000, -1000, -1000, + -1000, 522, 441, 441, 84, -1000, 400, 400, -1000, -1000, + 110, 110, 406, 117, 5, 84, 516, 117, 110, 301, + 380, 117, 170, 31, 371, -1000, -1000, 400, 400, 400, + 400, 166, 280, 592, 33, 265, -9, 265, 108, 592, + 592, -1000, 28, -1000, 8, -1000, 255, 161, -1000, -1000, + 27, -1000, -1000, 8, -1000, -1000, 297, 486, -1000, -1000, + 26, -1000, -1000, -1000, -1000, 17, 160, -1000, 368, 617, + -1000, 607, 158, -1000, -1000, -1000, -1000, -1000, 400, 155, + 152, 489, -1000, 295, -1000, -1000, 16, 349, 441, 151, + 150, 295, 13, 149, 5, -1000, -1000, 138, 307, -2, + 335, 400, 400, -1000, -1000, -1000, 510, 72, 400, 84, + -1000, 148, 143, -1000, -1000, 240, 136, 129, 120, 116, + 315, 533, -8, 441, 295, 360, 328, 321, 318, 8, + -1000, -1000, -1000, 41, 400, 400, 441, -1000, -1000, 400, + 400, 400, 400, 400, 308, 310, 400, 400, 400, -1000, + 295, -1000, 295, 441, -1000, -1000, 6, 371, -1000, -1000, + 211, -1000, -1000, 295, 49, 40, 111, 315, 5, 107, + 268, 103, -13, -1000, -1000, -1000, 307, 349, -1000, -1000, + -1000, -1000, 102, 100, -1000, 219, 227, 182, 219, 400, + 295, 295, -17, -19, -1000, -1000, -23, 255, 255, 255, + 255, -1000, -24, 278, -1000, 395, 395, -1000, -1000, -1000, + 400, 400, 694, 687, 668, 95, -1000, -1000, -1000, 467, + -2, -36, 84, 295, 92, 295, 295, 87, 295, -1000, + 289, 242, 37, -1000, -39, -3, 35, 33, -1000, -1000, + 85, 84, 597, 77, 71, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 530, 530, 295, -1000, + -1000, 39, 528, -1000, -1000, 46, -1000, -1000, 231, 285, + 268, -1000, 203, -1000, -1000, 219, -1000, 295, -4, 295, + -1000, -1000, -1000, -1000, -1000, 220, -1000, -54, -1000, 70, + -1000, 295, 69, -1000, -1000, 201, 67, 295, 64, -1000, + -5, 295, -1000, 201, 400, -55, 57, 18, -1000, -1000, + 400, -1000, 679, +} +var yyPgo = []int{ + + 0, 212, 19, 424, 4, 11, 8, 0, 1, 18, + 640, 9, 21, 13, 20, 423, 6, 323, 120, 421, + 2, 7, 5, 15, 12, 14, 420, 3, 369, 417, + 414, 10, 375, 374, 80, +} +var yyR1 = []int{ + + 0, 29, 30, 29, 32, 31, 31, 31, 31, 31, + 31, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 20, 20, 20, 20, + 10, 10, 10, 34, 34, 13, 13, 22, 22, 22, + 22, 18, 18, 11, 11, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 26, 26, 25, 27, 27, + 24, 24, 24, 28, 28, 28, 21, 14, 15, 17, + 17, 17, 17, 9, 9, 6, 6, 6, 7, 7, + 8, 8, 19, 19, 16, 16, 23, 23, 23, 5, + 5, 5, 4, 4, 4, 1, 1, 1, 1, 1, + 1, 3, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, +} +var yyR2 = []int{ + + 0, 0, 0, 3, 0, 4, 4, 4, 1, 2, + 2, 7, 6, 5, 5, 5, 4, 4, 3, 3, + 4, 6, 7, 7, 7, 6, 6, 3, 5, 7, + 4, 6, 6, 4, 3, 5, 5, 7, 6, 12, + 7, 9, 2, 4, 4, 2, 1, 2, 3, 4, + 0, 2, 2, 0, 2, 4, 2, 2, 2, 2, + 1, 2, 3, 1, 3, 3, 1, 1, 1, 4, + 1, 1, 1, 1, 1, 1, 1, 3, 1, 4, + 1, 4, 1, 1, 1, 1, 2, 1, 5, 4, + 4, 4, 4, 1, 1, 1, 1, 4, 1, 1, + 1, 4, 1, 1, 1, 4, 4, 5, 7, 0, + 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, + 3, 0, 2, 1, 3, 3, 3, 3, 3, 4, + 4, 3, 3, 3, +} +var yyChk = []int{ + + -1000, -29, -30, -31, 60, 62, 65, -33, 2, 14, + 15, 16, 17, 36, 18, 19, 20, 21, 22, 23, + 24, 57, 25, 26, 29, 30, 32, 33, 31, 34, + 35, 37, 44, 45, 27, 63, 64, 64, 65, 65, + -10, -10, -10, -10, -34, 66, -34, -10, -10, -10, + -10, -10, -23, -1, 60, 38, 62, 10, 9, 72, + 70, -23, -23, -10, -34, -10, -10, -10, -10, -10, + -10, -24, -23, -27, -1, -25, 70, -12, -14, -22, + -17, 52, 53, -1, -24, -16, -7, 69, -18, 49, + 48, -6, 39, 47, 42, 46, -12, -34, -32, -2, + -1, -2, -28, 54, 55, -14, -21, -17, 69, -28, + -12, -34, -25, 70, -34, -13, -1, 60, -34, -28, + -27, 67, -1, -14, -34, -7, -34, 66, 70, -5, + 7, 9, 10, -1, -1, -1, -2, 66, 12, -14, + -22, -16, -19, -16, -18, 69, -16, -1, -14, -14, + 70, 70, -7, 66, 70, 7, 8, 10, 56, -1, + -24, 59, 58, 10, 70, 70, 66, -31, 65, 9, + 10, 11, 12, 13, 7, 8, 6, 5, 4, 65, + 66, -1, 66, 66, -13, -26, -1, 60, -25, -23, + 70, -5, -12, 66, 66, -11, -7, 70, 66, -25, + 69, -1, -4, 40, 39, 41, 70, 8, -1, -1, + 71, -21, -1, -1, -34, 66, 66, 10, 66, 66, + 66, 66, -6, -6, 71, -12, -7, 7, 8, 8, + 8, 58, -1, -2, -12, -2, -2, -2, -2, -2, + 7, 8, -2, -2, -2, -7, -14, -14, -12, 70, + -5, 42, -7, 67, 68, 10, -34, -25, 66, -20, + 38, 10, 66, 71, -4, -5, 66, 66, -16, -16, + 49, -16, -2, -14, -14, 71, 71, 71, -9, -7, + -1, -9, -9, -9, 71, 71, -2, -2, 66, 71, + -34, -11, 66, -7, -11, 66, -34, -14, 10, 38, + 69, 71, 70, -21, -22, 66, -34, 66, 66, 66, + -14, 68, -27, -14, 38, 10, -20, 40, -16, -7, + -15, 70, -14, 38, 71, 66, -7, 66, -8, 51, + 50, 66, -7, 66, 70, -7, -8, -2, 71, -3, + 66, 71, -2, +} +var yyDef = []int{ + + 1, -2, 0, 3, 0, 0, 8, 0, 0, 50, + 50, 50, 50, 53, 53, 50, 50, 50, 50, 50, + 0, 0, 0, 50, 53, 50, 50, 50, 50, 50, + 50, 0, 0, 0, 53, 4, 0, 0, 9, 10, + 0, 0, 0, 53, 0, 53, 0, 53, 0, 0, + 53, 53, 0, 0, 109, 115, 116, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 80, 82, 0, 78, 0, 0, 66, 67, + 68, 70, 71, 72, 73, 74, 87, 0, 60, 104, + 0, 98, 99, 95, 96, 0, 0, 45, 0, 0, + 123, 0, 0, 51, 52, 83, 84, 85, 0, 0, + 0, 0, 18, 0, 54, 19, 0, 109, 0, 0, + 0, 0, 0, 0, 0, 87, 27, 0, 0, 0, + 0, 0, 0, 117, 118, 119, 0, 0, 0, 53, + 34, 0, 0, 102, 103, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, + 58, 59, 61, 0, 0, 0, 0, 5, 6, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 86, 0, 0, 16, 17, 0, 109, 75, 76, + 0, 56, 20, 0, 0, 0, -2, 0, 0, 0, + 0, 0, 0, 112, 113, 114, 0, 109, 110, 111, + 120, 30, 0, 0, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 77, 43, 0, 0, 0, 0, + 0, 62, 0, 0, 44, 124, 125, 126, 127, 128, + 0, 0, 131, 132, 133, 87, 13, 14, 15, 0, + 56, 0, 53, 0, 0, 0, 0, 53, 0, 28, + 46, 0, 0, 106, 0, 0, 0, 0, 35, 36, + 104, 53, 0, 0, 0, 81, 79, 69, 89, 93, + 94, 90, 91, 92, 105, 97, 129, 130, 12, 55, + 21, 0, 0, 64, 65, 53, 25, 26, 0, 47, + 0, 107, 0, 31, 32, 0, 38, 0, 0, 0, + 11, 22, 23, 24, 48, 0, 29, 0, 37, 0, + 40, 0, 0, 49, 108, 0, 0, 0, 0, 100, + 0, 0, 41, 0, 0, 0, 121, 0, 88, 39, + 0, 101, 122, +} +var yyTok1 = []int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 69, 13, 6, 3, + 70, 71, 11, 9, 66, 10, 3, 12, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 63, 65, + 7, 64, 8, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 67, 3, 68, 5, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 3, 72, +} +var yyTok2 = []int{ + + 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, +} +var yyTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yylex1(lex yyLexer, lval *yySymType) int { + c := 0 + char := lex.Lex(lval) + if char <= 0 { + c = yyTok1[0] + goto out + } + if char < len(yyTok1) { + c = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + c = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + c = yyTok3[i+0] + if c == char { + c = yyTok3[i+1] + goto out + } + } + +out: + if c == 0 { + c = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) + } + return c +} + +func yyParse(yylex yyLexer) int { + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, yyMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yychar := -1 + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + yyn += yychar + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yychar { /* valid shift */ + yychar = -1 + yyVAL = yylval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yychar { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error("syntax error") + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) + } + if yychar == yyEofCode { + goto ret1 + } + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 2: + //line a.y:73 + { + stmtline = asm.Lineno + } + case 4: + //line a.y:80 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { + yyerror("redeclaration of %s", yyS[yypt-1].sym.Labelname) + } + yyS[yypt-1].sym.Type = LLAB + yyS[yypt-1].sym.Value = int64(asm.PC) + } + case 6: + //line a.y:90 + { + yyS[yypt-3].sym.Type = LVAR + yyS[yypt-3].sym.Value = int64(yyS[yypt-1].lval) + } + case 7: + //line a.y:95 + { + if yyS[yypt-3].sym.Value != int64(yyS[yypt-1].lval) { + yyerror("redeclaration of %s", yyS[yypt-3].sym.Name) + } + yyS[yypt-3].sym.Value = int64(yyS[yypt-1].lval) + } + case 11: + //line a.y:110 + { + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, yyS[yypt-2].lval, &yyS[yypt-0].addr) + } + case 12: + //line a.y:114 + { + outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, yyS[yypt-1].lval, &nullgen) + } + case 13: + //line a.y:118 + { + outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 14: + //line a.y:125 + { + outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 15: + //line a.y:132 + { + outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 16: + //line a.y:139 + { + outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) + } + case 17: + //line a.y:143 + { + outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) + } + case 18: + //line a.y:150 + { + outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) + } + case 19: + //line a.y:157 + { + outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) + } + case 20: + //line a.y:164 + { + outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) + } + case 21: + //line a.y:171 + { + outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, yyS[yypt-1].lval, &nullgen) + } + case 22: + //line a.y:178 + { + var g obj.Addr + + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = int64(yyS[yypt-1].lval) + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, 0, &g) + } + case 23: + //line a.y:187 + { + var g obj.Addr + + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = int64(yyS[yypt-3].lval) + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &g, 0, &yyS[yypt-0].addr) + } + case 24: + //line a.y:199 + { + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-2].addr, int32(yyS[yypt-4].addr.Reg), &yyS[yypt-0].addr) + } + case 25: + //line a.y:203 + { + outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-1].addr, int32(yyS[yypt-3].addr.Reg), &yyS[yypt-3].addr) + } + case 26: + //line a.y:207 + { + outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-2].addr, int32(yyS[yypt-0].addr.Reg), &yyS[yypt-0].addr) + } + case 27: + //line a.y:214 + { + outcode(yyS[yypt-2].lval, yyS[yypt-1].lval, &nullgen, 0, &nullgen) + } + case 28: + //line a.y:221 + { + asm.Settext(yyS[yypt-3].addr.Sym) + outcode(yyS[yypt-4].lval, Always, &yyS[yypt-3].addr, 0, &yyS[yypt-0].addr) + } + case 29: + //line a.y:226 + { + asm.Settext(yyS[yypt-5].addr.Sym) + outcode(yyS[yypt-6].lval, Always, &yyS[yypt-5].addr, 0, &yyS[yypt-0].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = int64(yyS[yypt-3].lval) + } + } + case 30: + //line a.y:238 + { + asm.Settext(yyS[yypt-2].addr.Sym) + outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 31: + //line a.y:243 + { + asm.Settext(yyS[yypt-4].addr.Sym) + outcode(yyS[yypt-5].lval, Always, &yyS[yypt-4].addr, 0, &yyS[yypt-0].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = int64(yyS[yypt-2].lval) + } + } + case 32: + //line a.y:256 + { + outcode(yyS[yypt-5].lval, Always, &yyS[yypt-4].addr, 0, &yyS[yypt-0].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = int64(yyS[yypt-2].lval) + } + } + case 33: + //line a.y:267 + { + outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &yyS[yypt-1].addr, 0, &nullgen) + } + case 34: + //line a.y:274 + { + outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) + } + case 35: + //line a.y:281 + { + outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 36: + //line a.y:285 + { + outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 37: + //line a.y:289 + { + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, yyS[yypt-2].lval, &yyS[yypt-0].addr) + } + case 38: + //line a.y:293 + { + outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, int32(yyS[yypt-1].addr.Reg), &nullgen) + } + case 39: + //line a.y:300 + { + var g obj.Addr + + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = int64( + (0xe << 24) | /* opcode */ + (yyS[yypt-11].lval << 20) | /* MCR/MRC */ + ((yyS[yypt-10].lval ^ C_SCOND_XOR) << 28) | /* scond */ + ((yyS[yypt-9].lval & 15) << 8) | /* coprocessor number */ + ((yyS[yypt-7].lval & 7) << 21) | /* coprocessor operation */ + ((yyS[yypt-5].lval & 15) << 12) | /* arm register */ + ((yyS[yypt-3].lval & 15) << 16) | /* Crn */ + ((yyS[yypt-1].lval & 15) << 0) | /* Crm */ + ((yyS[yypt-0].lval & 7) << 5) | /* coprocessor information */ + (1 << 4)) /* must be set */ + outcode(AMRC, Always, &nullgen, 0, &g) + } + case 40: + //line a.y:312 + { + outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, int32(yyS[yypt-2].addr.Reg), &yyS[yypt-0].addr) + } + case 41: + //line a.y:320 + { + yyS[yypt-2].addr.Type = obj.TYPE_REGREG2 + yyS[yypt-2].addr.Offset = int64(yyS[yypt-0].lval) + outcode(yyS[yypt-8].lval, yyS[yypt-7].lval, &yyS[yypt-6].addr, int32(yyS[yypt-4].addr.Reg), &yyS[yypt-2].addr) + } + case 42: + //line a.y:329 + { + outcode(yyS[yypt-1].lval, Always, &yyS[yypt-0].addr, 0, &nullgen) + } + case 43: + //line a.y:336 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { + yyerror("arguments to PCDATA must be integer constants") + } + outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 44: + //line a.y:346 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if yyS[yypt-0].addr.Type != obj.NAME_EXTERN && yyS[yypt-0].addr.Type != obj.NAME_STATIC && yyS[yypt-0].addr.Type != obj.TYPE_MEM { + yyerror("value for FUNCDATA must be symbol reference") + } + outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) + } + case 45: + //line a.y:359 + { + outcode(yyS[yypt-1].lval, Always, &nullgen, 0, &nullgen) + } + case 46: + //line a.y:365 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = int64(yyS[yypt-0].lval) + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 47: + //line a.y:372 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -int64(yyS[yypt-0].lval) + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 48: + //line a.y:379 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = int64(yyS[yypt-2].lval) + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 49: + //line a.y:386 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -int64(yyS[yypt-2].lval) + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 50: + //line a.y:394 + { + yyVAL.lval = Always + } + case 51: + //line a.y:398 + { + yyVAL.lval = (yyS[yypt-1].lval & ^C_SCOND) | yyS[yypt-0].lval + } + case 52: + //line a.y:402 + { + yyVAL.lval = yyS[yypt-1].lval | yyS[yypt-0].lval + } + case 55: + //line a.y:411 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + int64(asm.PC) + } + case 56: + //line a.y:417 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + yyVAL.addr = nullgen + if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { + yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) + } + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyS[yypt-1].sym.Value + int64(yyS[yypt-0].lval) + } + case 57: + //line a.y:428 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + yyVAL.addr.Offset = int64(yyS[yypt-0].lval) + } + case 58: + //line a.y:434 + { + yyVAL.addr = yyS[yypt-0].addr + yyVAL.addr.Type = obj.TYPE_ADDR + } + case 59: + //line a.y:439 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SCONST + yyVAL.addr.U.Sval = yyS[yypt-0].sval + } + case 60: + yyVAL.addr = yyS[yypt-0].addr + case 61: + //line a.y:448 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyS[yypt-0].dval + } + case 62: + //line a.y:454 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyS[yypt-0].dval + } + case 63: + //line a.y:462 + { + yyVAL.lval = 1 << uint(yyS[yypt-0].lval&15) + } + case 64: + //line a.y:466 + { + yyVAL.lval = 0 + for i := yyS[yypt-2].lval; i <= yyS[yypt-0].lval; i++ { + yyVAL.lval |= 1 << uint(i&15) + } + for i := yyS[yypt-0].lval; i <= yyS[yypt-2].lval; i++ { + yyVAL.lval |= 1 << uint(i&15) + } + } + case 65: + //line a.y:476 + { + yyVAL.lval = (1 << uint(yyS[yypt-2].lval&15)) | yyS[yypt-0].lval + } + case 66: + yyVAL.addr = yyS[yypt-0].addr + case 67: + yyVAL.addr = yyS[yypt-0].addr + case 68: + yyVAL.addr = yyS[yypt-0].addr + case 69: + //line a.y:485 + { + yyVAL.addr = yyS[yypt-3].addr + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + } + case 70: + //line a.y:490 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 71: + //line a.y:496 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 72: + //line a.y:502 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Offset = int64(yyS[yypt-0].lval) + } + case 73: + yyVAL.addr = yyS[yypt-0].addr + case 74: + yyVAL.addr = yyS[yypt-0].addr + case 75: + yyVAL.addr = yyS[yypt-0].addr + case 76: + //line a.y:513 + { + yyVAL.addr = yyS[yypt-0].addr + if yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC { + } + } + case 77: + //line a.y:521 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = 0 + } + case 78: + yyVAL.addr = yyS[yypt-0].addr + case 79: + //line a.y:531 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + } + case 80: + yyVAL.addr = yyS[yypt-0].addr + case 81: + //line a.y:541 + { + yyVAL.addr = yyS[yypt-3].addr + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + } + case 82: + yyVAL.addr = yyS[yypt-0].addr + case 83: + yyVAL.addr = yyS[yypt-0].addr + case 84: + yyVAL.addr = yyS[yypt-0].addr + case 85: + yyVAL.addr = yyS[yypt-0].addr + case 86: + //line a.y:554 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + yyVAL.addr.Offset = int64(yyS[yypt-0].lval) + } + case 87: + //line a.y:562 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 88: + //line a.y:570 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REGREG + yyVAL.addr.Reg = int16(yyS[yypt-3].lval) + yyVAL.addr.Offset = int64(yyS[yypt-1].lval) + } + case 89: + //line a.y:579 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SHIFT + yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (0 << 5) + } + case 90: + //line a.y:585 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SHIFT + yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (1 << 5) + } + case 91: + //line a.y:591 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SHIFT + yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (2 << 5) + } + case 92: + //line a.y:597 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SHIFT + yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (3 << 5) + } + case 93: + //line a.y:605 + { + if yyVAL.lval < REG_R0 || yyVAL.lval > REG_R15 { + print("register value out of range\n") + } + yyVAL.lval = ((yyS[yypt-0].lval & 15) << 8) | (1 << 4) + } + case 94: + //line a.y:612 + { + if yyVAL.lval < 0 || yyVAL.lval >= 32 { + print("shift value out of range\n") + } + yyVAL.lval = (yyS[yypt-0].lval & 31) << 7 + } + case 95: + yyVAL.lval = yyS[yypt-0].lval + case 96: + //line a.y:622 + { + yyVAL.lval = REGPC + } + case 97: + //line a.y:626 + { + if yyS[yypt-1].lval < 0 || yyS[yypt-1].lval >= NREG { + print("register value out of range\n") + } + yyVAL.lval = REG_R0 + yyS[yypt-1].lval + } + case 98: + yyVAL.lval = yyS[yypt-0].lval + case 99: + //line a.y:636 + { + yyVAL.lval = REGSP + } + case 100: + yyVAL.lval = yyS[yypt-0].lval + case 101: + //line a.y:643 + { + if yyS[yypt-1].lval < 0 || yyS[yypt-1].lval >= NREG { + print("register value out of range\n") + } + yyVAL.lval = yyS[yypt-1].lval // TODO(rsc): REG_C0+$3 + } + case 102: + yyVAL.addr = yyS[yypt-0].addr + case 103: + yyVAL.addr = yyS[yypt-0].addr + case 104: + //line a.y:656 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 105: + //line a.y:662 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(REG_F0 + yyS[yypt-1].lval) + } + case 106: + //line a.y:670 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyS[yypt-1].lval) + yyVAL.addr.Sym = nil + yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + } + case 107: + //line a.y:678 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyS[yypt-1].lval) + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) + yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + } + case 108: + //line a.y:686 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = obj.NAME_STATIC + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) + yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + } + case 109: + //line a.y:695 + { + yyVAL.lval = 0 + } + case 110: + //line a.y:699 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 111: + //line a.y:703 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 112: + yyVAL.lval = yyS[yypt-0].lval + case 113: + yyVAL.lval = yyS[yypt-0].lval + case 114: + yyVAL.lval = yyS[yypt-0].lval + case 115: + yyVAL.lval = yyS[yypt-0].lval + case 116: + //line a.y:715 + { + yyVAL.lval = int32(yyS[yypt-0].sym.Value) + } + case 117: + //line a.y:719 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 118: + //line a.y:723 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 119: + //line a.y:727 + { + yyVAL.lval = ^yyS[yypt-0].lval + } + case 120: + //line a.y:731 + { + yyVAL.lval = yyS[yypt-1].lval + } + case 121: + //line a.y:736 + { + yyVAL.lval = 0 + } + case 122: + //line a.y:740 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 123: + yyVAL.lval = yyS[yypt-0].lval + case 124: + //line a.y:747 + { + yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval + } + case 125: + //line a.y:751 + { + yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval + } + case 126: + //line a.y:755 + { + yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval + } + case 127: + //line a.y:759 + { + yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval + } + case 128: + //line a.y:763 + { + yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval + } + case 129: + //line a.y:767 + { + yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) + } + case 130: + //line a.y:771 + { + yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) + } + case 131: + //line a.y:775 + { + yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval + } + case 132: + //line a.y:779 + { + yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval + } + case 133: + //line a.y:783 + { + yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval + } + } + goto yystack /* stack new state and value */ +} diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c deleted file mode 100644 index 416af9a321..0000000000 --- a/src/cmd/5a/y.tab.c +++ /dev/null @@ -1,2855 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.3" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE1 = 258, - LTYPE2 = 259, - LTYPE3 = 260, - LTYPE4 = 261, - LTYPE5 = 262, - LTYPE6 = 263, - LTYPE7 = 264, - LTYPE8 = 265, - LTYPE9 = 266, - LTYPEA = 267, - LTYPEB = 268, - LGLOBL = 269, - LTYPEC = 270, - LTYPED = 271, - LTYPEE = 272, - LTYPEG = 273, - LTYPEH = 274, - LTYPEI = 275, - LTYPEJ = 276, - LTYPEK = 277, - LTYPEL = 278, - LTYPEM = 279, - LTYPEN = 280, - LTYPEBX = 281, - LTYPEPLD = 282, - LCONST = 283, - LSP = 284, - LSB = 285, - LFP = 286, - LPC = 287, - LTYPEX = 288, - LTYPEPC = 289, - LTYPEF = 290, - LR = 291, - LREG = 292, - LF = 293, - LFREG = 294, - LC = 295, - LCREG = 296, - LPSR = 297, - LFCR = 298, - LCOND = 299, - LS = 300, - LAT = 301, - LFCONST = 302, - LSCONST = 303, - LNAME = 304, - LLAB = 305, - LVAR = 306 - }; -#endif -/* Tokens. */ -#define LTYPE1 258 -#define LTYPE2 259 -#define LTYPE3 260 -#define LTYPE4 261 -#define LTYPE5 262 -#define LTYPE6 263 -#define LTYPE7 264 -#define LTYPE8 265 -#define LTYPE9 266 -#define LTYPEA 267 -#define LTYPEB 268 -#define LGLOBL 269 -#define LTYPEC 270 -#define LTYPED 271 -#define LTYPEE 272 -#define LTYPEG 273 -#define LTYPEH 274 -#define LTYPEI 275 -#define LTYPEJ 276 -#define LTYPEK 277 -#define LTYPEL 278 -#define LTYPEM 279 -#define LTYPEN 280 -#define LTYPEBX 281 -#define LTYPEPLD 282 -#define LCONST 283 -#define LSP 284 -#define LSB 285 -#define LFP 286 -#define LPC 287 -#define LTYPEX 288 -#define LTYPEPC 289 -#define LTYPEF 290 -#define LR 291 -#define LREG 292 -#define LF 293 -#define LFREG 294 -#define LC 295 -#define LCREG 296 -#define LPSR 297 -#define LFCR 298 -#define LCOND 299 -#define LS 300 -#define LAT 301 -#define LFCONST 302 -#define LSCONST 303 -#define LNAME 304 -#define LLAB 305 -#define LVAR 306 - - - - -/* Copy the first part of user declarations. */ -#line 31 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 39 "a.y" -{ - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; -} -/* Line 193 of yacc.c. */ -#line 214 "y.tab.c" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 216 of yacc.c. */ -#line 227 "y.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int i) -#else -static int -YYID (i) - int i; -#endif -{ - return i; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 2 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 655 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 72 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 35 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 134 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 344 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 306 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 68, 12, 5, 2, - 69, 70, 10, 8, 65, 9, 2, 11, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 62, 64, - 6, 63, 7, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 66, 2, 67, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 71, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 4, 5, 9, 10, 15, 20, 25, - 27, 30, 33, 41, 48, 54, 60, 66, 71, 76, - 80, 84, 89, 96, 104, 112, 120, 127, 134, 138, - 144, 152, 157, 164, 171, 176, 180, 186, 192, 200, - 207, 220, 228, 238, 241, 246, 251, 254, 255, 258, - 261, 262, 265, 270, 273, 275, 278, 282, 287, 290, - 293, 296, 298, 301, 305, 307, 311, 315, 317, 319, - 321, 326, 328, 330, 332, 334, 336, 338, 340, 344, - 346, 351, 353, 358, 360, 362, 364, 366, 369, 371, - 377, 382, 387, 392, 397, 399, 401, 403, 405, 410, - 412, 414, 416, 421, 423, 425, 427, 432, 437, 443, - 451, 452, 455, 458, 460, 462, 464, 466, 468, 471, - 474, 477, 481, 482, 485, 487, 491, 495, 499, 503, - 507, 512, 517, 521, 525 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 73, 0, -1, -1, -1, 73, 74, 75, -1, -1, - 59, 62, 76, 75, -1, 59, 63, 106, 64, -1, - 61, 63, 106, 64, -1, 64, -1, 77, 64, -1, - 1, 64, -1, 13, 78, 90, 65, 97, 65, 92, - -1, 13, 78, 90, 65, 97, 65, -1, 13, 78, - 90, 65, 92, -1, 14, 78, 90, 65, 92, -1, - 15, 78, 85, 65, 85, -1, 16, 78, 79, 80, - -1, 16, 78, 79, 86, -1, 36, 79, 87, -1, - 17, 79, 80, -1, 18, 78, 79, 85, -1, 19, - 78, 90, 65, 97, 79, -1, 20, 78, 88, 65, - 66, 84, 67, -1, 20, 78, 66, 84, 67, 65, - 88, -1, 21, 78, 92, 65, 87, 65, 92, -1, - 21, 78, 92, 65, 87, 79, -1, 21, 78, 79, - 87, 65, 92, -1, 22, 78, 79, -1, 23, 101, - 65, 68, 81, -1, 23, 101, 65, 104, 65, 68, - 81, -1, 24, 101, 65, 91, -1, 24, 101, 65, - 104, 65, 91, -1, 25, 101, 11, 104, 65, 82, - -1, 26, 78, 92, 79, -1, 29, 79, 82, -1, - 30, 78, 100, 65, 100, -1, 32, 78, 99, 65, - 100, -1, 32, 78, 99, 65, 49, 65, 100, -1, - 33, 78, 100, 65, 100, 79, -1, 31, 78, 104, - 65, 106, 65, 97, 65, 98, 65, 98, 105, -1, - 34, 78, 92, 65, 92, 65, 93, -1, 35, 78, - 92, 65, 92, 65, 92, 65, 97, -1, 37, 89, - -1, 44, 85, 65, 85, -1, 45, 85, 65, 85, - -1, 27, 79, -1, -1, 78, 54, -1, 78, 55, - -1, -1, 65, 79, -1, 104, 69, 42, 70, -1, - 59, 102, -1, 38, -1, 9, 38, -1, 38, 9, - 38, -1, 9, 38, 9, 38, -1, 68, 104, -1, - 68, 89, -1, 68, 58, -1, 83, -1, 68, 57, - -1, 68, 9, 57, -1, 97, -1, 97, 9, 97, - -1, 97, 79, 84, -1, 92, -1, 82, -1, 94, - -1, 94, 69, 97, 70, -1, 52, -1, 53, -1, - 104, -1, 89, -1, 100, -1, 87, -1, 101, -1, - 69, 97, 70, -1, 87, -1, 104, 69, 96, 70, - -1, 101, -1, 101, 69, 96, 70, -1, 88, -1, - 92, -1, 91, -1, 94, -1, 68, 104, -1, 97, - -1, 69, 97, 65, 97, 70, -1, 97, 6, 6, - 95, -1, 97, 7, 7, 95, -1, 97, 9, 7, - 95, -1, 97, 56, 7, 95, -1, 97, -1, 104, - -1, 47, -1, 42, -1, 46, 69, 106, 70, -1, - 96, -1, 39, -1, 51, -1, 50, 69, 106, 70, - -1, 100, -1, 83, -1, 49, -1, 48, 69, 104, - 70, -1, 104, 69, 103, 70, -1, 59, 102, 69, - 103, 70, -1, 59, 6, 7, 102, 69, 40, 70, - -1, -1, 8, 104, -1, 9, 104, -1, 40, -1, - 39, -1, 41, -1, 38, -1, 61, -1, 9, 104, - -1, 8, 104, -1, 71, 104, -1, 69, 106, 70, - -1, -1, 65, 106, -1, 104, -1, 106, 8, 106, - -1, 106, 9, 106, -1, 106, 10, 106, -1, 106, - 11, 106, -1, 106, 12, 106, -1, 106, 6, 6, - 106, -1, 106, 7, 7, 106, -1, 106, 5, 106, - -1, 106, 4, 106, -1, 106, 3, 106, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 68, 68, 70, 69, 77, 76, 85, 90, 96, - 97, 98, 104, 108, 112, 119, 126, 133, 137, 144, - 151, 158, 165, 172, 181, 193, 197, 201, 208, 215, - 220, 232, 237, 249, 260, 267, 274, 278, 282, 286, - 293, 315, 323, 332, 339, 348, 359, 365, 368, 372, - 377, 378, 381, 387, 398, 405, 412, 419, 427, 433, - 438, 444, 447, 453, 461, 468, 483, 492, 493, 494, - 495, 500, 506, 512, 518, 519, 522, 523, 531, 540, - 541, 550, 551, 557, 560, 561, 562, 564, 572, 580, - 589, 595, 601, 607, 615, 621, 629, 630, 634, 642, - 643, 649, 650, 658, 659, 662, 668, 676, 684, 692, - 702, 705, 709, 715, 716, 717, 720, 721, 725, 729, - 733, 737, 743, 746, 752, 753, 757, 761, 765, 769, - 773, 777, 781, 785, 789 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'", - "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4", - "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB", - "LGLOBL", "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI", - "LTYPEJ", "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD", - "LCONST", "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF", - "LR", "LREG", "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND", - "LS", "LAT", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='", - "';'", "','", "'['", "']'", "'$'", "'('", "')'", "'~'", "$accept", - "prog", "@1", "line", "@2", "inst", "cond", "comma", "rel", "textsize", - "ximm", "fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg", - "imsr", "imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg", - "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 124, 94, 38, 60, 62, 43, 45, - 42, 47, 37, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 58, 61, 59, 44, 91, 93, 36, 40, - 41, 126 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 72, 73, 74, 73, 76, 75, 75, 75, 75, - 75, 75, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 78, 78, 78, - 79, 79, 80, 80, 81, 81, 81, 81, 82, 82, - 82, 82, 83, 83, 84, 84, 84, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 86, 86, 87, 88, - 88, 89, 89, 89, 90, 90, 90, 91, 92, 93, - 94, 94, 94, 94, 95, 95, 96, 96, 96, 97, - 97, 98, 98, 99, 99, 100, 100, 101, 101, 101, - 102, 102, 102, 103, 103, 103, 104, 104, 104, 104, - 104, 104, 105, 105, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 0, 0, 3, 0, 4, 4, 4, 1, - 2, 2, 7, 6, 5, 5, 5, 4, 4, 3, - 3, 4, 6, 7, 7, 7, 6, 6, 3, 5, - 7, 4, 6, 6, 4, 3, 5, 5, 7, 6, - 12, 7, 9, 2, 4, 4, 2, 0, 2, 2, - 0, 2, 4, 2, 1, 2, 3, 4, 2, 2, - 2, 1, 2, 3, 1, 3, 3, 1, 1, 1, - 4, 1, 1, 1, 1, 1, 1, 1, 3, 1, - 4, 1, 4, 1, 1, 1, 1, 2, 1, 5, - 4, 4, 4, 4, 1, 1, 1, 1, 4, 1, - 1, 1, 4, 1, 1, 1, 4, 4, 5, 7, - 0, 2, 2, 1, 1, 1, 1, 1, 2, 2, - 2, 3, 0, 2, 1, 3, 3, 3, 3, 3, - 4, 4, 3, 3, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 2, 3, 1, 0, 0, 47, 47, 47, 47, 50, - 47, 47, 47, 47, 47, 0, 0, 0, 47, 50, - 50, 47, 47, 47, 47, 47, 47, 50, 0, 0, - 0, 0, 0, 9, 4, 0, 11, 0, 0, 0, - 50, 50, 0, 50, 0, 0, 50, 50, 0, 0, - 116, 110, 117, 0, 0, 0, 0, 0, 0, 0, - 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 79, 83, 43, 81, 0, 100, 97, 0, 96, 0, - 105, 71, 72, 0, 68, 61, 0, 74, 67, 69, - 99, 88, 75, 73, 0, 5, 0, 0, 10, 48, - 49, 0, 0, 85, 84, 86, 0, 0, 0, 51, - 110, 20, 0, 0, 0, 0, 0, 0, 0, 0, - 88, 28, 119, 118, 0, 0, 0, 0, 124, 0, - 120, 0, 0, 0, 0, 50, 35, 0, 0, 0, - 104, 0, 103, 0, 0, 0, 0, 19, 0, 0, - 0, 0, 0, 0, 62, 60, 59, 58, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, - 0, 0, 110, 17, 18, 76, 77, 0, 53, 0, - 21, 0, 0, 50, 0, 0, 0, 0, 110, 111, - 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 121, 0, 0, 114, 113, 115, 0, 31, - 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, - 78, 0, 0, 0, 0, 63, 44, 0, 0, 0, - 0, 0, 45, 6, 7, 8, 14, 88, 15, 16, - 53, 0, 0, 50, 0, 0, 0, 0, 0, 50, - 0, 0, 134, 133, 132, 0, 0, 125, 126, 127, - 128, 129, 0, 54, 29, 0, 107, 0, 0, 36, - 0, 105, 37, 50, 0, 0, 82, 80, 98, 106, - 70, 90, 94, 95, 91, 92, 93, 13, 52, 22, - 0, 65, 66, 0, 27, 50, 26, 0, 108, 130, - 131, 55, 0, 0, 32, 33, 0, 0, 39, 0, - 0, 12, 24, 23, 25, 0, 0, 56, 30, 0, - 38, 0, 41, 0, 109, 57, 0, 0, 0, 0, - 101, 0, 0, 42, 0, 0, 0, 0, 122, 89, - 102, 0, 40, 123 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 3, 34, 165, 35, 37, 109, 111, 264, - 84, 85, 182, 86, 174, 70, 71, 87, 102, 103, - 88, 322, 89, 281, 90, 120, 331, 141, 92, 73, - 127, 208, 128, 342, 129 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -130 -static const yytype_int16 yypact[] = -{ - -130, 12, -130, 305, -35, -130, -130, -130, -130, -33, - -130, -130, -130, -130, -130, 427, 427, 427, -130, -33, - -33, -130, -130, -130, -130, -130, -130, -33, 445, 370, - 370, 10, -24, -130, -130, -30, -130, 140, 140, 335, - -13, -33, 449, -13, 140, 70, 484, -13, 359, 359, - -130, 114, -130, 359, 359, 27, -11, 62, 76, 167, - -130, 7, 171, 424, 64, 171, 167, 167, 65, 405, - -130, -130, -130, 68, 74, -130, -130, 78, -130, 86, - -130, -130, -130, 402, -130, -130, 96, -130, -130, 107, - -130, 21, -130, 74, 118, -130, 359, 359, -130, -130, - -130, 359, 131, -130, -130, -130, 150, 158, 473, -130, - 98, -130, 155, 370, 187, 43, 192, 199, 65, 205, - -130, -130, -130, -130, 262, 359, 359, 203, -130, 90, - -130, 106, 164, 233, 359, -33, -130, 211, 223, -3, - -130, 226, -130, 231, 235, 240, 43, -130, 220, 122, - 608, 359, 359, 491, -130, -130, -130, 74, 370, 43, - 287, 291, 300, 301, 370, 305, 560, 582, -130, 43, - 43, 370, 114, -130, -130, -130, -130, 264, -130, 267, - -130, 43, 279, -4, 281, 122, 283, 65, 98, -130, - -130, 164, 359, 359, 359, 345, 356, 359, 359, 359, - 359, 359, -130, 15, 306, -130, -130, -130, 282, -130, - 307, 310, -130, 32, 359, 308, 132, 32, 43, 43, - -130, 315, 316, 225, 321, -130, -130, 322, 405, 405, - 405, 405, -130, -130, -130, -130, -130, 311, -130, -130, - 203, 204, 323, -33, 333, 43, 43, 43, 43, 334, - 331, 337, 631, 611, 547, 359, 359, 228, 228, -130, - -130, -130, 332, 371, -130, 353, -130, 357, 7, -130, - 350, 336, -130, -33, 340, 361, -130, -130, -130, -130, - -130, -130, -130, -130, -130, -130, -130, 43, -130, -130, - 513, -130, -130, 360, -130, 146, -130, 384, -130, 303, - 303, 425, 399, 15, -130, -130, 43, 32, -130, 373, - 43, -130, -130, -130, -130, 375, 408, -130, -130, 383, - -130, 43, -130, 385, -130, -130, 120, 390, 43, 380, - -130, 391, 43, -130, 359, 120, 394, 275, 403, -130, - -130, 359, -130, 622 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -130, -130, -130, 302, -130, -130, 589, 24, 362, 166, - -58, 411, -57, -8, -130, -61, -43, -7, 22, -129, - -21, -130, 72, 34, -94, -29, 137, -130, -51, 3, - -84, 286, 20, -130, 61 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -65 -static const yytype_int16 yytable[] = -{ - 91, 91, 116, 136, 209, 245, 215, 147, 91, 91, - 91, 137, 2, 142, 143, 91, 104, 104, 55, 57, - 58, 72, 94, 104, 262, 119, 178, 160, 161, 36, - 162, 107, 41, 42, 98, 56, 56, 56, 135, 97, - 148, 99, 100, 60, 61, 144, 145, 175, 74, 93, - 93, 68, 41, 263, 154, 221, 222, 186, 132, 93, - 106, 41, 112, -64, 108, 117, 114, 113, 122, 123, - 118, 121, 95, 96, 130, 83, 156, 163, 48, 49, - 79, 80, 75, 138, 91, 76, 183, 134, 240, 77, - 78, 222, 131, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 157, 250, 180, 125, 126, 50, 105, - 105, 176, 79, 80, 48, 49, 105, 148, 99, 100, - 124, 168, 125, 126, 99, 100, 249, 133, 177, 91, - 227, 52, 139, 93, 146, 91, 115, 149, 304, 69, - 237, 54, 91, 150, 50, 189, 190, 151, 236, 238, - 226, 204, 243, 210, 211, 152, 232, 166, 167, 212, - 202, 158, 269, 239, 76, 272, 273, 52, 77, 78, - 329, 330, 224, 123, 203, 53, 159, 54, 93, 75, - 79, 271, 76, 164, 93, 75, 77, 78, 76, 292, - 293, 93, 77, 78, 99, 100, 169, 274, 275, 282, - 282, 282, 282, 205, 206, 207, 75, 246, 101, 76, - 305, 41, 223, 77, 78, 170, 291, 183, 183, 79, - 80, 99, 100, 171, 179, 99, 100, 294, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 199, 200, - 201, 48, 49, 205, 206, 207, 242, 312, 283, 283, - 283, 283, 181, 252, 253, 254, 320, 184, 257, 258, - 259, 260, 261, 284, 285, 286, 311, 289, 185, 188, - 187, 50, 191, 296, 314, 270, 213, 319, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 214, 323, - 220, 216, 327, 228, 52, 278, 217, 308, 229, 333, - 218, 101, 53, 336, 54, 219, 4, 230, 231, 242, - 117, 197, 198, 199, 200, 201, 299, 300, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 241, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 48, 49, 340, 244, 247, 248, 29, - 30, 255, 266, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 256, 31, 225, 32, 48, 49, 33, - 301, 265, 267, 50, 75, 268, 287, 76, 48, 49, - 302, 77, 78, 79, 80, 276, 277, 81, 82, 99, - 100, 279, 280, 288, 51, 337, 52, 50, 290, 295, - 297, 307, 343, 83, 69, 309, 54, 298, 50, 75, - 48, 153, 76, 48, 49, 306, 77, 78, 79, 80, - 52, 303, 81, 82, 315, 101, 310, 313, 53, 51, - 54, 52, 48, 49, 316, 48, 49, 317, 83, 69, - 50, 54, 321, 50, 75, 324, 325, 76, 326, 334, - 328, 77, 78, 48, 49, 332, 335, 48, 49, 154, - 155, 51, 50, 52, 339, 50, 52, 233, 341, 318, - 173, 69, 338, 54, 53, 140, 54, 251, 99, 100, - 0, 48, 49, 50, 0, 52, 51, 50, 52, 0, - 0, 0, 0, 53, 0, 54, 53, 0, 54, 48, - 49, 0, 0, 0, 51, 0, 52, 0, 110, 0, - 52, 50, 0, 0, 69, 0, 54, 0, 53, 0, - 54, 48, 49, 75, 0, 0, 76, 0, 0, 50, - 77, 78, 172, 0, 52, 0, 0, 0, 99, 100, - 0, 0, 69, 0, 54, 0, 0, 0, 225, 41, - 0, 50, 52, 195, 196, 197, 198, 199, 200, 201, - 53, 0, 54, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 0, 52, 0, 0, 0, 0, 0, - 0, 0, 69, 0, 54, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 38, 39, 40, 0, 43, - 44, 45, 46, 47, 0, 0, 0, 59, 0, 0, - 62, 63, 64, 65, 66, 67, 194, 195, 196, 197, - 198, 199, 200, 201, 234, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 0, 0, 235, 205, 206, 207, - 76, 0, 0, 0, 77, 78 -}; - -static const yytype_int16 yycheck[] = -{ - 29, 30, 45, 61, 133, 9, 9, 68, 37, 38, - 39, 62, 0, 64, 65, 44, 37, 38, 15, 16, - 17, 28, 30, 44, 9, 46, 110, 6, 7, 64, - 9, 39, 65, 9, 64, 15, 16, 17, 59, 63, - 69, 54, 55, 19, 20, 66, 67, 108, 28, 29, - 30, 27, 65, 38, 57, 149, 150, 118, 69, 39, - 38, 65, 42, 67, 40, 45, 44, 43, 48, 49, - 46, 47, 62, 63, 54, 68, 83, 56, 8, 9, - 48, 49, 39, 63, 113, 42, 115, 11, 172, 46, - 47, 185, 65, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 83, 188, 113, 8, 9, 38, 37, - 38, 108, 48, 49, 8, 9, 44, 146, 54, 55, - 6, 101, 8, 9, 54, 55, 187, 65, 108, 158, - 159, 61, 68, 113, 69, 164, 66, 69, 267, 69, - 169, 71, 171, 69, 38, 125, 126, 69, 169, 170, - 158, 131, 181, 133, 134, 69, 164, 96, 97, 135, - 70, 65, 213, 171, 42, 216, 217, 61, 46, 47, - 50, 51, 152, 153, 68, 69, 69, 71, 158, 39, - 48, 49, 42, 65, 164, 39, 46, 47, 42, 246, - 247, 171, 46, 47, 54, 55, 65, 218, 219, 228, - 229, 230, 231, 39, 40, 41, 39, 183, 68, 42, - 268, 65, 151, 46, 47, 65, 245, 246, 247, 48, - 49, 54, 55, 65, 69, 54, 55, 248, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 10, 11, - 12, 8, 9, 39, 40, 41, 42, 290, 228, 229, - 230, 231, 65, 192, 193, 194, 307, 65, 197, 198, - 199, 200, 201, 229, 230, 231, 287, 243, 69, 7, - 65, 38, 69, 249, 295, 214, 65, 306, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 65, 310, - 70, 65, 321, 6, 61, 70, 65, 273, 7, 328, - 65, 68, 69, 332, 71, 65, 1, 7, 7, 42, - 290, 8, 9, 10, 11, 12, 255, 256, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 69, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 8, 9, 70, 67, 66, 65, 44, - 45, 6, 70, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 7, 59, 57, 61, 8, 9, 64, - 38, 65, 65, 38, 39, 65, 65, 42, 8, 9, - 9, 46, 47, 48, 49, 70, 70, 52, 53, 54, - 55, 70, 70, 70, 59, 334, 61, 38, 65, 65, - 69, 65, 341, 68, 69, 65, 71, 70, 38, 39, - 8, 9, 42, 8, 9, 65, 46, 47, 48, 49, - 61, 68, 52, 53, 40, 68, 65, 67, 69, 59, - 71, 61, 8, 9, 9, 8, 9, 38, 68, 69, - 38, 71, 69, 38, 39, 70, 38, 42, 65, 69, - 65, 46, 47, 8, 9, 65, 65, 8, 9, 57, - 58, 59, 38, 61, 70, 38, 61, 165, 65, 303, - 108, 69, 335, 71, 69, 64, 71, 191, 54, 55, - -1, 8, 9, 38, -1, 61, 59, 38, 61, -1, - -1, -1, -1, 69, -1, 71, 69, -1, 71, 8, - 9, -1, -1, -1, 59, -1, 61, -1, 59, -1, - 61, 38, -1, -1, 69, -1, 71, -1, 69, -1, - 71, 8, 9, 39, -1, -1, 42, -1, -1, 38, - 46, 47, 59, -1, 61, -1, -1, -1, 54, 55, - -1, -1, 69, -1, 71, -1, -1, -1, 57, 65, - -1, 38, 61, 6, 7, 8, 9, 10, 11, 12, - 69, -1, 71, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, -1, 61, -1, -1, -1, -1, -1, - -1, -1, 69, -1, 71, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 6, 7, 8, -1, 10, - 11, 12, 13, 14, -1, -1, -1, 18, -1, -1, - 21, 22, 23, 24, 25, 26, 5, 6, 7, 8, - 9, 10, 11, 12, 64, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 4, 5, 6, 7, 8, - 9, 10, 11, 12, -1, -1, 64, 39, 40, 41, - 42, -1, -1, -1, 46, 47 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 73, 0, 74, 1, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 44, - 45, 59, 61, 64, 75, 77, 64, 78, 78, 78, - 78, 65, 79, 78, 78, 78, 78, 78, 8, 9, - 38, 59, 61, 69, 71, 101, 104, 101, 101, 78, - 79, 79, 78, 78, 78, 78, 78, 78, 79, 69, - 87, 88, 89, 101, 104, 39, 42, 46, 47, 48, - 49, 52, 53, 68, 82, 83, 85, 89, 92, 94, - 96, 97, 100, 104, 85, 62, 63, 63, 64, 54, - 55, 68, 90, 91, 92, 94, 90, 85, 79, 79, - 59, 80, 104, 79, 90, 66, 88, 104, 79, 92, - 97, 79, 104, 104, 6, 8, 9, 102, 104, 106, - 104, 65, 69, 65, 11, 92, 82, 100, 104, 68, - 83, 99, 100, 100, 92, 92, 69, 87, 97, 69, - 69, 69, 69, 9, 57, 58, 89, 104, 65, 69, - 6, 7, 9, 56, 65, 76, 106, 106, 104, 65, - 65, 65, 59, 80, 86, 87, 101, 104, 102, 69, - 85, 65, 84, 97, 65, 69, 87, 65, 7, 104, - 104, 69, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 70, 68, 104, 39, 40, 41, 103, 91, - 104, 104, 79, 65, 65, 9, 65, 65, 65, 65, - 70, 96, 96, 106, 104, 57, 85, 97, 6, 7, - 7, 7, 85, 75, 64, 64, 92, 97, 92, 85, - 102, 69, 42, 97, 67, 9, 79, 66, 65, 87, - 102, 103, 106, 106, 106, 6, 7, 106, 106, 106, - 106, 106, 9, 38, 81, 65, 70, 65, 65, 100, - 106, 49, 100, 100, 92, 92, 70, 70, 70, 70, - 70, 95, 97, 104, 95, 95, 95, 65, 70, 79, - 65, 97, 84, 84, 92, 65, 79, 69, 70, 106, - 106, 38, 9, 68, 91, 82, 65, 65, 79, 65, - 65, 92, 88, 67, 92, 40, 9, 38, 81, 97, - 100, 69, 93, 92, 70, 38, 65, 97, 65, 50, - 51, 98, 65, 97, 69, 65, 97, 106, 98, 70, - 70, 65, 105, 106 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) -#else -static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - fprintf (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - fprintf (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The look-ahead symbol. */ -int yychar; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to look-ahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a look-ahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the look-ahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: -#line 70 "a.y" - { - stmtline = lineno; - } - break; - - case 5: -#line 77 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc) - yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyvsp[(1) - (2)].sym)->type = LLAB; - (yyvsp[(1) - (2)].sym)->value = pc; - } - break; - - case 7: -#line 86 "a.y" - { - (yyvsp[(1) - (4)].sym)->type = LVAR; - (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval); - } - break; - - case 8: -#line 91 "a.y" - { - if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval)) - yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name); - (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval); - } - break; - - case 12: -#line 105 "a.y" - { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr)); - } - break; - - case 13: -#line 109 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen); - } - break; - - case 14: -#line 113 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 15: -#line 120 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 16: -#line 127 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 17: -#line 134 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 18: -#line 138 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 19: -#line 145 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 20: -#line 152 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 21: -#line 159 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 22: -#line 166 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen); - } - break; - - case 23: -#line 173 "a.y" - { - Addr g; - - g = nullgen; - g.type = TYPE_CONST; - g.offset = (yyvsp[(6) - (7)].lval); - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), 0, &g); - } - break; - - case 24: -#line 182 "a.y" - { - Addr g; - - g = nullgen; - g.type = TYPE_CONST; - g.offset = (yyvsp[(4) - (7)].lval); - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, 0, &(yyvsp[(7) - (7)].addr)); - } - break; - - case 25: -#line 194 "a.y" - { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr)); - } - break; - - case 26: -#line 198 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr)); - } - break; - - case 27: -#line 202 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr)); - } - break; - - case 28: -#line 209 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, 0, &nullgen); - } - break; - - case 29: -#line 216 "a.y" - { - settext((yyvsp[(2) - (5)].addr).sym); - outcode((yyvsp[(1) - (5)].lval), Always, &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 30: -#line 221 "a.y" - { - settext((yyvsp[(2) - (7)].addr).sym); - outcode((yyvsp[(1) - (7)].lval), Always, &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (7)].lval); - } - } - break; - - case 31: -#line 233 "a.y" - { - settext((yyvsp[(2) - (4)].addr).sym); - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 32: -#line 238 "a.y" - { - settext((yyvsp[(2) - (6)].addr).sym); - outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 33: -#line 250 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 34: -#line 261 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), 0, &nullgen); - } - break; - - case 35: -#line 268 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 36: -#line 275 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 37: -#line 279 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 38: -#line 283 "a.y" - { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr)); - } - break; - - case 39: -#line 287 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen); - } - break; - - case 40: -#line 294 "a.y" - { - Addr g; - - g = nullgen; - g.type = TYPE_CONST; - g.offset = - (0xe << 24) | /* opcode */ - ((yyvsp[(1) - (12)].lval) << 20) | /* MCR/MRC */ - (((yyvsp[(2) - (12)].lval)^C_SCOND_XOR) << 28) | /* scond */ - (((yyvsp[(3) - (12)].lval) & 15) << 8) | /* coprocessor number */ - (((yyvsp[(5) - (12)].lval) & 7) << 21) | /* coprocessor operation */ - (((yyvsp[(7) - (12)].lval) & 15) << 12) | /* arm register */ - (((yyvsp[(9) - (12)].lval) & 15) << 16) | /* Crn */ - (((yyvsp[(11) - (12)].lval) & 15) << 0) | /* Crm */ - (((yyvsp[(12) - (12)].lval) & 7) << 5) | /* coprocessor information */ - (1<<4); /* must be set */ - outcode(AMRC, Always, &nullgen, 0, &g); - } - break; - - case 41: -#line 316 "a.y" - { - outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr)); - } - break; - - case 42: -#line 324 "a.y" - { - (yyvsp[(7) - (9)].addr).type = TYPE_REGREG2; - (yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval); - outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr)); - } - break; - - case 43: -#line 333 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), 0, &nullgen); - } - break; - - case 44: -#line 340 "a.y" - { - if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 45: -#line 349 "a.y" - { - if((yyvsp[(2) - (4)].addr).type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM) - yyerror("value for FUNCDATA must be symbol reference"); - outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 46: -#line 360 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, 0, &nullgen); - } - break; - - case 47: -#line 365 "a.y" - { - (yyval.lval) = Always; - } - break; - - case 48: -#line 369 "a.y" - { - (yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval); - } - break; - - case 49: -#line 373 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval); - } - break; - - case 52: -#line 382 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; - } - break; - - case 53: -#line 388 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - (yyval.addr) = nullgen; - if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB) - yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); - } - break; - - case 54: -#line 399 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 55: -#line 406 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (2)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 56: -#line 413 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (3)].lval); - (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval); - } - break; - - case 57: -#line 420 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (4)].lval); - (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval); - } - break; - - case 58: -#line 428 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - (yyval.addr).offset = (yyvsp[(2) - (2)].lval); - } - break; - - case 59: -#line 434 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - (yyval.addr).type = TYPE_ADDR; - } - break; - - case 60: -#line 439 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SCONST; - memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); - } - break; - - case 62: -#line 448 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); - } - break; - - case 63: -#line 454 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); - } - break; - - case 64: -#line 462 "a.y" - { - if((yyvsp[(1) - (1)].lval) < REG_R0 || (yyvsp[(1) - (1)].lval) > REG_R15) - yyerror("invalid register in reglist"); - - (yyval.lval) = 1 << ((yyvsp[(1) - (1)].lval)&15); - } - break; - - case 65: -#line 469 "a.y" - { - int i; - - if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15) - yyerror("invalid register in reglist"); - if((yyvsp[(3) - (3)].lval) < REG_R0 || (yyvsp[(3) - (3)].lval) > REG_R15) - yyerror("invalid register in reglist"); - - (yyval.lval)=0; - for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++) - (yyval.lval) |= 1<<(i&15); - for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++) - (yyval.lval) |= 1<<(i&15); - } - break; - - case 66: -#line 484 "a.y" - { - if((yyvsp[(1) - (3)].lval) < REG_R0 || (yyvsp[(1) - (3)].lval) > REG_R15) - yyerror("invalid register in reglist"); - - (yyval.lval) = (1<<((yyvsp[(1) - (3)].lval)&15)) | (yyvsp[(3) - (3)].lval); - } - break; - - case 70: -#line 496 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (4)].addr); - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - } - break; - - case 71: -#line 501 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 72: -#line 507 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 73: -#line 513 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - } - break; - - case 77: -#line 524 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (1)].addr); - if((yyvsp[(1) - (1)].addr).name != NAME_EXTERN && (yyvsp[(1) - (1)].addr).name != NAME_STATIC) { - } - } - break; - - case 78: -#line 532 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (3)].lval); - (yyval.addr).offset = 0; - } - break; - - case 80: -#line 542 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 82: -#line 552 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (4)].addr); - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - } - break; - - case 87: -#line 565 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - (yyval.addr).offset = (yyvsp[(2) - (2)].lval); - } - break; - - case 88: -#line 573 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 89: -#line 581 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REGREG; - (yyval.addr).reg = (yyvsp[(2) - (5)].lval); - (yyval.addr).offset = (yyvsp[(4) - (5)].lval); - } - break; - - case 90: -#line 590 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SHIFT; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (0 << 5); - } - break; - - case 91: -#line 596 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SHIFT; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (1 << 5); - } - break; - - case 92: -#line 602 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SHIFT; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (2 << 5); - } - break; - - case 93: -#line 608 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SHIFT; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval)&15 | (yyvsp[(4) - (4)].lval) | (3 << 5); - } - break; - - case 94: -#line 616 "a.y" - { - if((yyval.lval) < REG_R0 || (yyval.lval) > REG_R15) - print("register value out of range in shift\n"); - (yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4); - } - break; - - case 95: -#line 622 "a.y" - { - if((yyval.lval) < 0 || (yyval.lval) >= 32) - print("shift value out of range\n"); - (yyval.lval) = ((yyvsp[(1) - (1)].lval)&31) << 7; - } - break; - - case 97: -#line 631 "a.y" - { - (yyval.lval) = REGPC; - } - break; - - case 98: -#line 635 "a.y" - { - if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG) - print("register value out of range in R(...)\n"); - (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval); - } - break; - - case 100: -#line 644 "a.y" - { - (yyval.lval) = REGSP; - } - break; - - case 102: -#line 651 "a.y" - { - if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG) - print("register value out of range in C(...)\n"); - (yyval.lval) = (yyvsp[(3) - (4)].lval); // TODO(rsc): REG_C0+$3 - } - break; - - case 105: -#line 663 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 106: -#line 669 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval); - } - break; - - case 107: -#line 677 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(3) - (4)].lval); - (yyval.addr).sym = nil; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 108: -#line 685 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(4) - (5)].lval); - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); - (yyval.addr).offset = (yyvsp[(2) - (5)].lval); - } - break; - - case 109: -#line 693 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = NAME_STATIC; - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); - (yyval.addr).offset = (yyvsp[(4) - (7)].lval); - } - break; - - case 110: -#line 702 "a.y" - { - (yyval.lval) = 0; - } - break; - - case 111: -#line 706 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 112: -#line 710 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 117: -#line 722 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; - } - break; - - case 118: -#line 726 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 119: -#line 730 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 120: -#line 734 "a.y" - { - (yyval.lval) = ~(yyvsp[(2) - (2)].lval); - } - break; - - case 121: -#line 738 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (3)].lval); - } - break; - - case 122: -#line 743 "a.y" - { - (yyval.lval) = 0; - } - break; - - case 123: -#line 747 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 125: -#line 754 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); - } - break; - - case 126: -#line 758 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); - } - break; - - case 127: -#line 762 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); - } - break; - - case 128: -#line 766 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); - } - break; - - case 129: -#line 770 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); - } - break; - - case 130: -#line 774 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); - } - break; - - case 131: -#line 778 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); - } - break; - - case 132: -#line 782 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); - } - break; - - case 133: -#line 786 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); - } - break; - - case 134: -#line 790 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); - } - break; - - -/* Line 1267 of yacc.c. */ -#line 2642 "y.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse look-ahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse look-ahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h deleted file mode 100644 index fbbdbef99b..0000000000 --- a/src/cmd/5a/y.tab.h +++ /dev/null @@ -1,166 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE1 = 258, - LTYPE2 = 259, - LTYPE3 = 260, - LTYPE4 = 261, - LTYPE5 = 262, - LTYPE6 = 263, - LTYPE7 = 264, - LTYPE8 = 265, - LTYPE9 = 266, - LTYPEA = 267, - LTYPEB = 268, - LGLOBL = 269, - LTYPEC = 270, - LTYPED = 271, - LTYPEE = 272, - LTYPEG = 273, - LTYPEH = 274, - LTYPEI = 275, - LTYPEJ = 276, - LTYPEK = 277, - LTYPEL = 278, - LTYPEM = 279, - LTYPEN = 280, - LTYPEBX = 281, - LTYPEPLD = 282, - LCONST = 283, - LSP = 284, - LSB = 285, - LFP = 286, - LPC = 287, - LTYPEX = 288, - LTYPEPC = 289, - LTYPEF = 290, - LR = 291, - LREG = 292, - LF = 293, - LFREG = 294, - LC = 295, - LCREG = 296, - LPSR = 297, - LFCR = 298, - LCOND = 299, - LS = 300, - LAT = 301, - LFCONST = 302, - LSCONST = 303, - LNAME = 304, - LLAB = 305, - LVAR = 306 - }; -#endif -/* Tokens. */ -#define LTYPE1 258 -#define LTYPE2 259 -#define LTYPE3 260 -#define LTYPE4 261 -#define LTYPE5 262 -#define LTYPE6 263 -#define LTYPE7 264 -#define LTYPE8 265 -#define LTYPE9 266 -#define LTYPEA 267 -#define LTYPEB 268 -#define LGLOBL 269 -#define LTYPEC 270 -#define LTYPED 271 -#define LTYPEE 272 -#define LTYPEG 273 -#define LTYPEH 274 -#define LTYPEI 275 -#define LTYPEJ 276 -#define LTYPEK 277 -#define LTYPEL 278 -#define LTYPEM 279 -#define LTYPEN 280 -#define LTYPEBX 281 -#define LTYPEPLD 282 -#define LCONST 283 -#define LSP 284 -#define LSB 285 -#define LFP 286 -#define LPC 287 -#define LTYPEX 288 -#define LTYPEPC 289 -#define LTYPEF 290 -#define LR 291 -#define LREG 292 -#define LF 293 -#define LFREG 294 -#define LC 295 -#define LCREG 296 -#define LPSR 297 -#define LFCR 298 -#define LCOND 299 -#define LS 300 -#define LAT 301 -#define LFCONST 302 -#define LSCONST 303 -#define LNAME 304 -#define LLAB 305 -#define LVAR 306 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 39 "a.y" -{ - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; -} -/* Line 1529 of yacc.c. */ -#line 159 "y.tab.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/5g/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c deleted file mode 100644 index 354e0cbfd6..0000000000 --- a/src/cmd/5g/cgen.c +++ /dev/null @@ -1,1840 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -void -cgen(Node *n, Node *res) -{ - Node *nl, *nr, *r; - Node n1, n2, f0, f1; - int a, w, rg; - Prog *p1, *p2, *p3; - Addr addr; - - if(debug['g']) { - dump("\ncgen-n", n); - dump("cgen-res", res); - } - if(n == N || n->type == T) - goto ret; - - if(res == N || res->type == T) - fatal("cgen: res nil"); - - switch(n->op) { - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_slice(n, &n1); - cgen(&n1, res); - } else - cgen_slice(n, res); - return; - case OEFACE: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_eface(n, &n1); - cgen(&n1, res); - } else - cgen_eface(n, res); - return; - } - - while(n->op == OCONVNOP) - n = n->left; - - if(n->ullman >= UINF) { - if(n->op == OINDREG) - fatal("cgen: this is going to misscompile"); - if(res->ullman >= UINF) { - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - goto ret; - } - } - - if(isfat(n->type)) { - if(n->type->width < 0) - fatal("forgot to compute width for %T", n->type); - sgen(n, res, n->type->width); - goto ret; - } - - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch(n->op) { - case OSPTR: - case OLEN: - if(isslice(n->left->type) || istype(n->left->type, TSTRING)) - n->addable = n->left->addable; - break; - case OCAP: - if(isslice(n->left->type)) - n->addable = n->left->addable; - break; - case OITAB: - n->addable = n->left->addable; - break; - } - - // if both are addressable, move - if(n->addable && res->addable) { - if(is64(n->type) || is64(res->type) || - n->op == OREGISTER || res->op == OREGISTER || - iscomplex[n->type->etype] || iscomplex[res->type->etype]) { - gmove(n, res); - } else { - regalloc(&n1, n->type, N); - gmove(n, &n1); - cgen(&n1, res); - regfree(&n1); - } - goto ret; - } - - // if both are not addressable, use a temporary. - if(!n->addable && !res->addable) { - // could use regalloc here sometimes, - // but have to check for ullman >= UINF. - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - return; - } - - // if result is not addressable directly but n is, - // compute its address and then store via the address. - if(!res->addable) { - igen(res, &n1, N); - cgen(n, &n1); - regfree(&n1); - return; - } - - if(complexop(n, res)) { - complexgen(n, res); - return; - } - - // if n is sudoaddable generate addr and move - if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) { - a = optoas(OAS, n->type); - if(sudoaddable(a, n, &addr, &w)) { - if (res->op != OREGISTER) { - regalloc(&n2, res->type, N); - p1 = gins(a, N, &n2); - p1->from = addr; - if(debug['g']) - print("%P [ignore previous line]\n", p1); - gmove(&n2, res); - regfree(&n2); - } else { - p1 = gins(a, N, res); - p1->from = addr; - if(debug['g']) - print("%P [ignore previous line]\n", p1); - } - sudoclean(); - goto ret; - } - } - - // otherwise, the result is addressable but n is not. - // let's do some computation. - - nl = n->left; - nr = n->right; - - if(nl != N && nl->ullman >= UINF) - if(nr != N && nr->ullman >= UINF) { - tempname(&n1, nl->type); - cgen(nl, &n1); - n2 = *n; - n2.left = &n1; - cgen(&n2, res); - goto ret; - } - - // 64-bit ops are hard on 32-bit machine. - if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) { - switch(n->op) { - // math goes to cgen64. - case OMINUS: - case OCOM: - case OADD: - case OSUB: - case OMUL: - case OLROT: - case OLSH: - case ORSH: - case OAND: - case OOR: - case OXOR: - cgen64(n, res); - return; - } - } - - if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) - goto flt; - switch(n->op) { - default: - dump("cgen", n); - fatal("cgen: unknown op %+hN", n); - break; - - case OREAL: - case OIMAG: - case OCOMPLEX: - fatal("unexpected complex"); - break; - - // these call bgen to get a bool value - case OOROR: - case OANDAND: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case ONOT: - p1 = gbranch(AB, T, 0); - p2 = pc; - gmove(nodbool(1), res); - p3 = gbranch(AB, T, 0); - patch(p1, pc); - bgen(n, 1, 0, p2); - gmove(nodbool(0), res); - patch(p3, pc); - goto ret; - - case OPLUS: - cgen(nl, res); - goto ret; - - // unary - case OCOM: - a = optoas(OXOR, nl->type); - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - nodconst(&n2, nl->type, -1); - gins(a, &n2, &n1); - goto norm; - - case OMINUS: - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - nodconst(&n2, nl->type, 0); - gins(optoas(OMINUS, nl->type), &n2, &n1); - goto norm; - - // symmetric binary - case OAND: - case OOR: - case OXOR: - case OADD: - case OMUL: - a = optoas(n->op, nl->type); - goto sbop; - - // asymmetric binary - case OSUB: - a = optoas(n->op, nl->type); - goto abop; - - case OHMUL: - cgen_hmul(nl, nr, res); - break; - - case OLROT: - case OLSH: - case ORSH: - cgen_shift(n->op, n->bounded, nl, nr, res); - break; - - case OCONV: - if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) { - cgen(nl, res); - break; - } - if(nl->addable && !is64(nl->type)) { - regalloc(&n1, nl->type, res); - gmove(nl, &n1); - } else { - if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype]) - tempname(&n1, nl->type); - else - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - } - if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype]) - tempname(&n2, n->type); - else - regalloc(&n2, n->type, N); - gmove(&n1, &n2); - gmove(&n2, res); - if(n1.op == OREGISTER) - regfree(&n1); - if(n2.op == OREGISTER) - regfree(&n2); - break; - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case OITAB: - // interface table is first word of interface value - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OSPTR: - // pointer is the first word of string or slice. - if(isconst(nl, CTSTR)) { - regalloc(&n1, types[tptr], res); - p1 = gins(AMOVW, N, &n1); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - gmove(&n1, res); - regfree(&n1); - break; - } - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OLEN: - if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { - // map has len in the first 32-bit word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gcmp(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); - - n2 = n1; - n2.op = OINDREG; - n2.type = types[TINT32]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(istype(nl->type, TSTRING) || isslice(nl->type)) { - // both slice and string have len one pointer into the struct. - igen(nl, &n1, res); - n1.type = types[TUINT32]; - n1.xoffset += Array_nel; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OLEN: unknown type %lT", nl->type); - break; - - case OCAP: - if(istype(nl->type, TCHAN)) { - // chan has cap in the second 32-bit word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gcmp(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); - - n2 = n1; - n2.op = OINDREG; - n2.xoffset = 4; - n2.type = types[TINT32]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(isslice(nl->type)) { - igen(nl, &n1, res); - n1.type = types[TUINT32]; - n1.xoffset += Array_cap; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OCAP: unknown type %lT", nl->type); - break; - - case OADDR: - agen(nl, res); - break; - - case OCALLMETH: - case OCALLFUNC: - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - rg = -1; - if(n->ullman >= UINF) { - if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { - rg = res->val.u.reg; - reg[rg]--; - } - } - if(n->op == OCALLMETH) - cgen_callmeth(n, 0); - else - cgen_call(n, 0); - if(rg >= 0) - reg[rg]++; - cgen_callret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_callret(n, res); - break; - - case OMOD: - case ODIV: - a = optoas(n->op, nl->type); - goto abop; - } - goto ret; - -sbop: // symmetric binary - if(nl->ullman < nr->ullman) { - r = nl; - nl = nr; - nr = r; - } - -abop: // asymmetric binary - // TODO(kaib): use fewer registers here. - if(nl->ullman >= nr->ullman) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - switch(n->op) { - case OADD: - case OSUB: - case OAND: - case OOR: - case OXOR: - if(smallintconst(nr)) { - n2 = *nr; - break; - } - default: - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - } - } else { - switch(n->op) { - case OADD: - case OSUB: - case OAND: - case OOR: - case OXOR: - if(smallintconst(nr)) { - n2 = *nr; - break; - } - default: - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - } - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - } - gins(a, &n2, &n1); -norm: - // Normalize result for types smaller than word. - if(n->type->width < widthptr) { - switch(n->op) { - case OADD: - case OSUB: - case OMUL: - case OCOM: - case OMINUS: - gins(optoas(OAS, n->type), &n1, &n1); - break; - } - } - gmove(&n1, res); - regfree(&n1); - if(n2.op != OLITERAL) - regfree(&n2); - goto ret; - -flt: // floating-point. - regalloc(&f0, nl->type, res); - if(nr != N) - goto flt2; - - if(n->op == OMINUS) { - nr = nodintconst(-1); - convlit(&nr, n->type); - n->op = OMUL; - goto flt2; - } - - // unary - cgen(nl, &f0); - if(n->op != OCONV && n->op != OPLUS) - gins(optoas(n->op, n->type), &f0, &f0); - gmove(&f0, res); - regfree(&f0); - goto ret; - -flt2: // binary - if(nl->ullman >= nr->ullman) { - cgen(nl, &f0); - regalloc(&f1, n->type, N); - gmove(&f0, &f1); - cgen(nr, &f0); - gins(optoas(n->op, n->type), &f0, &f1); - } else { - cgen(nr, &f0); - regalloc(&f1, n->type, N); - cgen(nl, &f1); - gins(optoas(n->op, n->type), &f0, &f1); - } - gmove(&f1, res); - regfree(&f0); - regfree(&f1); - goto ret; - -ret: - ; -} - -/* - * generate array index into res. - * n might be any size; res is 32-bit. - * returns Prog* to patch to panic call. - */ -Prog* -cgenindex(Node *n, Node *res, int bounded) -{ - Node tmp, lo, hi, zero, n1, n2; - - if(!is64(n->type)) { - cgen(n, res); - return nil; - } - - tempname(&tmp, types[TINT64]); - cgen(n, &tmp); - split64(&tmp, &lo, &hi); - gmove(&lo, res); - if(bounded) { - splitclean(); - return nil; - } - regalloc(&n1, types[TINT32], N); - regalloc(&n2, types[TINT32], N); - nodconst(&zero, types[TINT32], 0); - gmove(&hi, &n1); - gmove(&zero, &n2); - gcmp(ACMP, &n1, &n2); - regfree(&n2); - regfree(&n1); - splitclean(); - return gbranch(ABNE, T, -1); -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -void -agen(Node *n, Node *res) -{ - Node *nl; - Node n1, n2, n3; - int r; - - if(debug['g']) { - dump("\nagen-res", res); - dump("agen-r", n); - } - if(n == N || n->type == T || res == N || res->type == T) - fatal("agen"); - - while(n->op == OCONVNOP) - n = n->left; - - if(isconst(n, CTNIL) && n->type->width > widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - tempname(&n1, n->type); - gvardef(&n1); - clearfat(&n1); - regalloc(&n2, types[tptr], res); - gins(AMOVW, &n1, &n2); - gmove(&n2, res); - regfree(&n2); - goto ret; - } - - - if(n->addable) { - memset(&n1, 0, sizeof n1); - n1.op = OADDR; - n1.left = n; - regalloc(&n2, types[tptr], res); - gins(AMOVW, &n1, &n2); - gmove(&n2, res); - regfree(&n2); - goto ret; - } - - nl = n->left; - - switch(n->op) { - default: - fatal("agen: unknown op %+hN", n); - break; - - case OCALLMETH: - case OCALLFUNC: - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - r = -1; - if(n->ullman >= UINF) { - if(res->op == OREGISTER || res->op == OINDREG) { - r = res->val.u.reg; - reg[r]--; - } - } - if(n->op == OCALLMETH) - cgen_callmeth(n, 0); - else - cgen_call(n, 0); - if(r >= 0) - reg[r]++; - cgen_aret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_aret(n, res); - break; - - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - tempname(&n1, n->type); - cgen_slice(n, &n1); - agen(&n1, res); - break; - - case OEFACE: - tempname(&n1, n->type); - cgen_eface(n, &n1); - agen(&n1, res); - break; - - case OINDEX: - agenr(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case ONAME: - // should only get here with names in this func. - if(n->funcdepth > 0 && n->funcdepth != funcdepth) { - dump("bad agen", n); - fatal("agen: bad ONAME funcdepth %d != %d", - n->funcdepth, funcdepth); - } - - // should only get here for heap vars or paramref - if(!(n->class & PHEAP) && n->class != PPARAMREF) { - dump("bad agen", n); - fatal("agen: bad ONAME class %#x", n->class); - } - cgen(n->heapaddr, res); - if(n->xoffset != 0) { - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[TINT32], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } - break; - - case OIND: - cgen(nl, res); - cgen_checknil(res); - break; - - case ODOT: - agen(nl, res); - if(n->xoffset != 0) { - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[TINT32], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } - break; - - case ODOTPTR: - cgen(nl, res); - cgen_checknil(res); - if(n->xoffset != 0) { - nodconst(&n1, types[TINT32], n->xoffset); - regalloc(&n2, n1.type, N); - regalloc(&n3, types[tptr], N); - gmove(&n1, &n2); - gmove(res, &n3); - gins(optoas(OADD, types[tptr]), &n2, &n3); - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - } - break; - } - -ret: - ; -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -void -igen(Node *n, Node *a, Node *res) -{ - Node n1; - int r; - - if(debug['g']) { - dump("\nigen-n", n); - } - switch(n->op) { - case ONAME: - if((n->class&PHEAP) || n->class == PPARAMREF) - break; - *a = *n; - return; - - case OINDREG: - // Increase the refcount of the register so that igen's caller - // has to call regfree. - if(n->val.u.reg != REGSP) - reg[n->val.u.reg]++; - *a = *n; - return; - - case ODOT: - igen(n->left, a, res); - a->xoffset += n->xoffset; - a->type = n->type; - return; - - case ODOTPTR: - if(n->left->addable - || n->left->op == OCALLFUNC - || n->left->op == OCALLMETH - || n->left->op == OCALLINTER) { - // igen-able nodes. - igen(n->left, &n1, res); - regalloc(a, types[tptr], &n1); - gmove(&n1, a); - regfree(&n1); - } else { - regalloc(a, types[tptr], res); - cgen(n->left, a); - } - cgen_checknil(a); - a->op = OINDREG; - a->xoffset = n->xoffset; - a->type = n->type; - return; - - case OCALLMETH: - case OCALLFUNC: - case OCALLINTER: - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - r = -1; - if(n->ullman >= UINF) { - if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { - r = res->val.u.reg; - reg[r]--; - } - } - switch(n->op) { - case OCALLMETH: - cgen_callmeth(n, 0); - break; - case OCALLFUNC: - cgen_call(n, 0); - break; - case OCALLINTER: - cgen_callinter(n, N, 0); - break; - } - if(r >= 0) - reg[r]++; - regalloc(a, types[tptr], res); - cgen_aret(n, a); - a->op = OINDREG; - a->type = n->type; - return; - } - - agenr(n, a, res); - a->op = OINDREG; - a->type = n->type; -} - -/* - * allocate a register in res and generate - * newreg = &n - * The caller must call regfree(a). - */ -void -cgenr(Node *n, Node *a, Node *res) -{ - Node n1; - - if(debug['g']) - dump("cgenr-n", n); - - if(isfat(n->type)) - fatal("cgenr on fat node"); - - if(n->addable) { - regalloc(a, types[tptr], res); - gmove(n, a); - return; - } - - switch(n->op) { - case ONAME: - case ODOT: - case ODOTPTR: - case OINDEX: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - gmove(&n1, a); - regfree(&n1); - break; - default: - regalloc(a, n->type, res); - cgen(n, a); - break; - } -} - -/* - * generate: - * newreg = &n; - * - * caller must regfree(a). - * The generated code checks that the result is not nil. - */ -void -agenr(Node *n, Node *a, Node *res) -{ - Node *nl, *nr; - Node n1, n2, n3, n4, tmp; - Prog *p1, *p2; - uint32 w; - uint64 v; - int bounded; - - if(debug['g']) - dump("agenr-n", n); - - nl = n->left; - nr = n->right; - - switch(n->op) { - case ODOT: - case ODOTPTR: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - agen(&n1, a); - regfree(&n1); - break; - - case OIND: - cgenr(n->left, a, res); - cgen_checknil(a); - break; - - case OINDEX: - p2 = nil; // to be patched to panicindex. - w = n->type->width; - bounded = debug['B'] || n->bounded; - if(nr->addable) { - if(!isconst(nr, CTINT)) - tempname(&tmp, types[TINT32]); - if(!isconst(nl, CTSTR)) - agenr(nl, &n3, res); - if(!isconst(nr, CTINT)) { - p2 = cgenindex(nr, &tmp, bounded); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - } else - if(nl->addable) { - if(!isconst(nr, CTINT)) { - tempname(&tmp, types[TINT32]); - p2 = cgenindex(nr, &tmp, bounded); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - if(!isconst(nl, CTSTR)) { - agenr(nl, &n3, res); - } - } else { - tempname(&tmp, types[TINT32]); - p2 = cgenindex(nr, &tmp, bounded); - nr = &tmp; - if(!isconst(nl, CTSTR)) - agenr(nl, &n3, res); - regalloc(&n1, tmp.type, N); - gins(optoas(OAS, tmp.type), &tmp, &n1); - } - - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // w is width - - // constant index - if(isconst(nr, CTINT)) { - if(isconst(nl, CTSTR)) - fatal("constant string constant index"); - v = mpgetfix(nr->val.u.xval); - if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(!debug['B'] && !n->bounded) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - regalloc(&n4, n1.type, N); - gmove(&n1, &n4); - nodconst(&n2, types[TUINT32], v); - gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2); - regfree(&n4); - p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); - ginscall(panicindex, 0); - patch(p1, pc); - } - - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, &n3); - } - - nodconst(&n2, types[tptr], v*w); - gins(optoas(OADD, types[tptr]), &n2, &n3); - *a = n3; - break; - } - - regalloc(&n2, types[TINT32], &n1); // i - gmove(&n1, &n2); - regfree(&n1); - - if(!debug['B'] && !n->bounded) { - // check bounds - if(isconst(nl, CTSTR)) { - nodconst(&n4, types[TUINT32], nl->val.u.sval->len); - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - regalloc(&n4, types[TUINT32], N); - gmove(&n1, &n4); - } else { - nodconst(&n4, types[TUINT32], nl->type->bound); - } - gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4); - if(n4.op == OREGISTER) - regfree(&n4); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - if(p2) - patch(p2, pc); - ginscall(panicindex, 0); - patch(p1, pc); - } - - if(isconst(nl, CTSTR)) { - regalloc(&n3, types[tptr], res); - p1 = gins(AMOVW, N, &n3); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - p1->from.type = TYPE_ADDR; - } else - if(isslice(nl->type) || nl->type->etype == TSTRING) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, &n3); - } - - if(w == 0) { - // nothing to do - } else if(w == 1 || w == 2 || w == 4 || w == 8) { - memset(&n4, 0, sizeof n4); - n4.op = OADDR; - n4.left = &n2; - cgen(&n4, &n3); - if (w == 1) - gins(AADD, &n2, &n3); - else if(w == 2) - gshift(AADD, &n2, SHIFT_LL, 1, &n3); - else if(w == 4) - gshift(AADD, &n2, SHIFT_LL, 2, &n3); - else if(w == 8) - gshift(AADD, &n2, SHIFT_LL, 3, &n3); - } else { - regalloc(&n4, types[TUINT32], N); - nodconst(&n1, types[TUINT32], w); - gmove(&n1, &n4); - gins(optoas(OMUL, types[TUINT32]), &n4, &n2); - gins(optoas(OADD, types[tptr]), &n2, &n3); - regfree(&n4); - } - - *a = n3; - regfree(&n2); - break; - - default: - regalloc(a, types[tptr], res); - agen(n, a); - break; - } -} - -void -gencmp0(Node *n, Type *t, int o, int likely, Prog *to) -{ - Node n1, n2, n3; - int a; - - regalloc(&n1, t, N); - cgen(n, &n1); - a = optoas(OCMP, t); - if(a != ACMP) { - nodconst(&n2, t, 0); - regalloc(&n3, t, N); - gmove(&n2, &n3); - gcmp(a, &n1, &n3); - regfree(&n3); - } else - gins(ATST, &n1, N); - a = optoas(o, t); - patch(gbranch(a, t, likely), to); - regfree(&n1); -} - -/* - * generate: - * if(n == true) goto to; - */ -void -bgen(Node *n, int true, int likely, Prog *to) -{ - int et, a; - Node *nl, *nr, *r; - Node n1, n2, n3, tmp; - NodeList *ll; - Prog *p1, *p2; - - if(debug['g']) { - dump("\nbgen", n); - } - - if(n == N) - n = nodbool(1); - - if(n->ninit != nil) - genlist(n->ninit); - - if(n->type == T) { - convlit(&n, types[TBOOL]); - if(n->type == T) - goto ret; - } - - et = n->type->etype; - if(et != TBOOL) { - yyerror("cgen: bad type %T for %O", n->type, n->op); - patch(gins(AEND, N, N), to); - goto ret; - } - nr = N; - - switch(n->op) { - default: - a = ONE; - if(!true) - a = OEQ; - gencmp0(n, n->type, a, likely, to); - goto ret; - - case OLITERAL: - // need to ask if it is bool? - if(!true == !n->val.u.bval) - patch(gbranch(AB, T, 0), to); - goto ret; - - case OANDAND: - case OOROR: - if((n->op == OANDAND) == true) { - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n->left, !true, -likely, p2); - bgen(n->right, !true, -likely, p2); - p1 = gbranch(AJMP, T, 0); - patch(p1, to); - patch(p2, pc); - } else { - bgen(n->left, true, likely, to); - bgen(n->right, true, likely, to); - } - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - nr = n->right; - if(nr == N || nr->type == T) - goto ret; - - case ONOT: // unary - nl = n->left; - if(nl == N || nl->type == T) - goto ret; - } - - switch(n->op) { - - case ONOT: - bgen(nl, !true, likely, to); - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - a = n->op; - if(!true) { - if(isfloat[nl->type->etype]) { - // brcom is not valid on floats when NaN is involved. - p1 = gbranch(AB, T, 0); - p2 = gbranch(AB, T, 0); - patch(p1, pc); - ll = n->ninit; - n->ninit = nil; - bgen(n, 1, -likely, p2); - n->ninit = ll; - patch(gbranch(AB, T, 0), to); - patch(p2, pc); - goto ret; - } - a = brcom(a); - true = !true; - } - - // make simplest on right - if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) { - a = brrev(a); - r = nl; - nl = nr; - nr = r; - } - - if(isslice(nl->type)) { - // only valid to cmp darray to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal array comparison"); - break; - } - - igen(nl, &n1, N); - n1.xoffset += Array_array; - n1.type = types[tptr]; - gencmp0(&n1, types[tptr], a, likely, to); - regfree(&n1); - break; - } - - if(isinter(nl->type)) { - // front end shold only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal interface comparison"); - break; - } - - igen(nl, &n1, N); - n1.type = types[tptr]; - n1.xoffset += 0; - gencmp0(&n1, types[tptr], a, likely, to); - regfree(&n1); - break; - } - - if(iscomplex[nl->type->etype]) { - complexbool(a, nl, nr, true, likely, to); - break; - } - - if(is64(nr->type)) { - if(!nl->addable) { - tempname(&n1, nl->type); - cgen(nl, &n1); - nl = &n1; - } - if(!nr->addable) { - tempname(&n2, nr->type); - cgen(nr, &n2); - nr = &n2; - } - cmp64(nl, nr, a, likely, to); - break; - } - - if(nr->op == OLITERAL) { - if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) { - gencmp0(nl, nl->type, a, likely, to); - break; - } - if(nr->val.ctype == CTNIL) { - gencmp0(nl, nl->type, a, likely, to); - break; - } - } - - a = optoas(a, nr->type); - - if(nr->ullman >= UINF) { - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - - tempname(&tmp, nl->type); - gmove(&n1, &tmp); - regfree(&n1); - - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - - regalloc(&n1, nl->type, N); - cgen(&tmp, &n1); - - gcmp(optoas(OCMP, nr->type), &n1, &n2); - patch(gbranch(a, nr->type, likely), to); - - regfree(&n1); - regfree(&n2); - break; - } - - tempname(&n3, nl->type); - cgen(nl, &n3); - - tempname(&tmp, nr->type); - cgen(nr, &tmp); - - regalloc(&n1, nl->type, N); - gmove(&n3, &n1); - - regalloc(&n2, nr->type, N); - gmove(&tmp, &n2); - - gcmp(optoas(OCMP, nr->type), &n1, &n2); - if(isfloat[nl->type->etype]) { - if(n->op == ONE) { - p1 = gbranch(ABVS, nr->type, likely); - patch(gbranch(a, nr->type, likely), to); - patch(p1, to); - } else { - p1 = gbranch(ABVS, nr->type, -likely); - patch(gbranch(a, nr->type, likely), to); - patch(p1, pc); - } - } else { - patch(gbranch(a, nr->type, likely), to); - } - regfree(&n1); - regfree(&n2); - break; - } - goto ret; - -ret: - ; -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -int32 -stkof(Node *n) -{ - Type *t; - Iter flist; - int32 off; - - switch(n->op) { - case OINDREG: - return n->xoffset; - - case ODOT: - t = n->left->type; - if(isptr[t->etype]) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - return off + n->xoffset; - - case OINDEX: - t = n->left->type; - if(!isfixedarray(t)) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - if(isconst(n->right, CTINT)) - return off + t->type->width * mpgetfix(n->right->val.u.xval); - return 1000; - - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - t = structfirst(&flist, getoutarg(t)); - if(t != T) - return t->width + 4; // correct for LR - break; - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000; -} - -/* - * block copy: - * memmove(&res, &n, w); - * NB: character copy assumed little endian architecture - */ -void -sgen(Node *n, Node *res, int64 w) -{ - Node dst, src, tmp, nend, r0, r1, r2, *f; - int32 c, odst, osrc; - int dir, align, op; - Prog *p, *ploop; - NodeList *l; - - if(debug['g']) { - print("\nsgen w=%lld\n", w); - dump("r", n); - dump("res", res); - } - - if(n->ullman >= UINF && res->ullman >= UINF) - fatal("sgen UINF"); - - if(w < 0 || (int32)w != w) - fatal("sgen copy %lld", w); - - if(n->type == T) - fatal("sgen: missing type"); - - if(w == 0) { - // evaluate side effects only. - regalloc(&dst, types[tptr], N); - agen(res, &dst); - agen(n, &dst); - regfree(&dst); - return; - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0) - for(l = curfn->dcl; l != nil; l = l->next) - if(l->n->class == PPARAMOUT) - gvardef(l->n); - - // Avoid taking the address for simple enough types. - if(componentgen(n, res)) - return; - - // determine alignment. - // want to avoid unaligned access, so have to use - // smaller operations for less aligned types. - // for example moving [4]byte must use 4 MOVB not 1 MOVW. - align = n->type->align; - switch(align) { - default: - fatal("sgen: invalid alignment %d for %T", align, n->type); - case 1: - op = AMOVB; - break; - case 2: - op = AMOVH; - break; - case 4: - op = AMOVW; - break; - } - if(w%align) - fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type); - c = w / align; - - // offset on the stack - osrc = stkof(n); - odst = stkof(res); - if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - tempname(&tmp, n->type); - sgen(n, &tmp, w); - sgen(&tmp, res, w); - return; - } - if(osrc%align != 0 || odst%align != 0) - fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - dir = align; - if(osrc < odst && odst < osrc+w) - dir = -dir; - - if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) { - r0.op = OREGISTER; - r0.val.u.reg = REGALLOC_R0; - r1.op = OREGISTER; - r1.val.u.reg = REGALLOC_R0 + 1; - r2.op = OREGISTER; - r2.val.u.reg = REGALLOC_R0 + 2; - - regalloc(&src, types[tptr], &r1); - regalloc(&dst, types[tptr], &r2); - if(n->ullman >= res->ullman) { - // eval n first - agen(n, &src); - if(res->op == ONAME) - gvardef(res); - agen(res, &dst); - } else { - // eval res first - if(res->op == ONAME) - gvardef(res); - agen(res, &dst); - agen(n, &src); - } - regalloc(&tmp, types[tptr], &r0); - f = sysfunc("duffcopy"); - p = gins(ADUFFCOPY, N, f); - afunclit(&p->to, f); - // 8 and 128 = magic constants: see ../../runtime/asm_arm.s - p->to.offset = 8*(128-c); - - regfree(&tmp); - regfree(&src); - regfree(&dst); - return; - } - - if(n->ullman >= res->ullman) { - agenr(n, &dst, res); // temporarily use dst - regalloc(&src, types[tptr], N); - gins(AMOVW, &dst, &src); - if(res->op == ONAME) - gvardef(res); - agen(res, &dst); - } else { - if(res->op == ONAME) - gvardef(res); - agenr(res, &dst, res); - agenr(n, &src, N); - } - - regalloc(&tmp, types[TUINT32], N); - - // set up end marker - memset(&nend, 0, sizeof nend); - if(c >= 4) { - regalloc(&nend, types[TUINT32], N); - - p = gins(AMOVW, &src, &nend); - p->from.type = TYPE_ADDR; - if(dir < 0) - p->from.offset = dir; - else - p->from.offset = w; - } - - // move src and dest to the end of block if necessary - if(dir < 0) { - p = gins(AMOVW, &src, &src); - p->from.type = TYPE_ADDR; - p->from.offset = w + dir; - - p = gins(AMOVW, &dst, &dst); - p->from.type = TYPE_ADDR; - p->from.offset = w + dir; - } - - // move - if(c >= 4) { - p = gins(op, &src, &tmp); - p->from.type = TYPE_MEM; - p->from.offset = dir; - p->scond |= C_PBIT; - ploop = p; - - p = gins(op, &tmp, &dst); - p->to.type = TYPE_MEM; - p->to.offset = dir; - p->scond |= C_PBIT; - - p = gins(ACMP, &src, N); - raddr(&nend, p); - - patch(gbranch(ABNE, T, 0), ploop); - regfree(&nend); - } else { - while(c-- > 0) { - p = gins(op, &src, &tmp); - p->from.type = TYPE_MEM; - p->from.offset = dir; - p->scond |= C_PBIT; - - p = gins(op, &tmp, &dst); - p->to.type = TYPE_MEM; - p->to.offset = dir; - p->scond |= C_PBIT; - } - } - - regfree(&dst); - regfree(&src); - regfree(&tmp); -} - -static int -cadable(Node *n) -{ - if(!n->addable) { - // dont know how it happens, - // but it does - return 0; - } - - switch(n->op) { - case ONAME: - return 1; - } - return 0; -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if cant. - */ -int -componentgen(Node *nr, Node *nl) -{ - Node nodl, nodr, tmp; - Type *t; - int freel, freer; - vlong fldcount; - vlong loffset, roffset; - - freel = 0; - freer = 0; - - switch(nl->type->etype) { - default: - goto no; - - case TARRAY: - t = nl->type; - - // Slices are ok. - if(isslice(t)) - break; - // Small arrays are ok. - if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) - break; - - goto no; - - case TSTRUCT: - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - fldcount = 0; - for(t=nl->type->type; t; t=t->down) { - if(isfat(t->type)) - goto no; - if(t->etype != TFIELD) - fatal("componentgen: not a TFIELD: %lT", t); - fldcount++; - } - if(fldcount == 0 || fldcount > 4) - goto no; - - break; - - case TSTRING: - case TINTER: - break; - } - - nodl = *nl; - if(!cadable(nl)) { - if(nr != N && !cadable(nr)) - goto no; - igen(nl, &nodl, N); - freel = 1; - } - - if(nr != N) { - nodr = *nr; - if(!cadable(nr)) { - igen(nr, &nodr, N); - freer = 1; - } - } else { - // When zeroing, prepare a register containing zero. - nodconst(&tmp, nl->type, 0); - regalloc(&nodr, types[TUINT], N); - gmove(&tmp, &nodr); - freer = 1; - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) - goto yes; - - switch(nl->type->etype) { - case TARRAY: - // componentgen for arrays. - if(nl->op == ONAME) - gvardef(nl); - t = nl->type; - if(!isslice(t)) { - nodl.type = t->type; - nodr.type = nodl.type; - for(fldcount=0; fldcount < t->bound; fldcount++) { - if(nr == N) - clearslim(&nodl); - else - gmove(&nodr, &nodl); - nodl.xoffset += t->type->width; - nodr.xoffset += t->type->width; - } - goto yes; - } - - // componentgen for slices. - nodl.xoffset += Array_array; - nodl.type = ptrto(nl->type->type); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_cap-Array_nel; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_cap-Array_nel; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRING: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TINTER: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRUCT: - if(nl->op == ONAME) - gvardef(nl); - loffset = nodl.xoffset; - roffset = nodr.xoffset; - // funarg structs may not begin at offset zero. - if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) - loffset -= nl->type->type->width; - if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) - roffset -= nr->type->type->width; - - for(t=nl->type->type; t; t=t->down) { - nodl.xoffset = loffset + t->width; - nodl.type = t->type; - - if(nr == N) - clearslim(&nodl); - else { - nodr.xoffset = roffset + t->width; - nodr.type = nodl.type; - gmove(&nodr, &nodl); - } - } - goto yes; - } - -no: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 0; - -yes: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 1; -} diff --git a/src/cmd/5g/cgen.go b/src/cmd/5g/cgen.go new file mode 100644 index 0000000000..bdee52aca6 --- /dev/null +++ b/src/cmd/5g/cgen.go @@ -0,0 +1,2003 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" + "fmt" +) +import "cmd/internal/gc" + +/* + * peep.c + */ +/* + * generate: + * res = n; + * simplifies and calls gmove. + */ +func cgen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var f0 gc.Node + var f1 gc.Node + var a int + var w int + var rg int + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var addr obj.Addr + + if gc.Debug['g'] != 0 { + gc.Dump("\ncgen-n", n) + gc.Dump("cgen-res", res) + } + + if n == nil || n.Type == nil { + goto ret + } + + if res == nil || res.Type == nil { + gc.Fatal("cgen: res nil") + } + + switch n.Op { + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_slice(n, res) + } + return + + case gc.OEFACE: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_eface(n, res) + } + return + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + if n.Ullman >= gc.UINF { + if n.Op == gc.OINDREG { + gc.Fatal("cgen: this is going to misscompile") + } + if res.Ullman >= gc.UINF { + gc.Tempname(&n1, n.Type) + cgen(n, &n1) + cgen(&n1, res) + goto ret + } + } + + if gc.Isfat(n.Type) { + if n.Type.Width < 0 { + gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) + } + sgen(n, res, n.Type.Width) + goto ret + } + + // update addressability for string, slice + // can't do in walk because n->left->addable + // changes if n->left is an escaping local variable. + switch n.Op { + case gc.OSPTR, + gc.OLEN: + if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { + n.Addable = n.Left.Addable + } + + case gc.OCAP: + if gc.Isslice(n.Left.Type) { + n.Addable = n.Left.Addable + } + + case gc.OITAB: + n.Addable = n.Left.Addable + } + + // if both are addressable, move + if n.Addable != 0 && res.Addable != 0 { + if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Op == gc.OREGISTER || res.Op == gc.OREGISTER || gc.Iscomplex[n.Type.Etype] != 0 || gc.Iscomplex[res.Type.Etype] != 0 { + gmove(n, res) + } else { + regalloc(&n1, n.Type, nil) + gmove(n, &n1) + cgen(&n1, res) + regfree(&n1) + } + + goto ret + } + + // if both are not addressable, use a temporary. + if n.Addable == 0 && res.Addable == 0 { + // could use regalloc here sometimes, + // but have to check for ullman >= UINF. + gc.Tempname(&n1, n.Type) + + cgen(n, &n1) + cgen(&n1, res) + return + } + + // if result is not addressable directly but n is, + // compute its address and then store via the address. + if res.Addable == 0 { + igen(res, &n1, nil) + cgen(n, &n1) + regfree(&n1) + return + } + + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + return + } + + // if n is sudoaddable generate addr and move + if !gc.Is64(n.Type) && !gc.Is64(res.Type) && gc.Iscomplex[n.Type.Etype] == 0 && gc.Iscomplex[res.Type.Etype] == 0 { + a = optoas(gc.OAS, n.Type) + if sudoaddable(a, n, &addr, &w) { + if res.Op != gc.OREGISTER { + regalloc(&n2, res.Type, nil) + p1 = gins(a, nil, &n2) + p1.From = addr + if gc.Debug['g'] != 0 { + fmt.Printf("%v [ignore previous line]\n", p1) + } + gmove(&n2, res) + regfree(&n2) + } else { + p1 = gins(a, nil, res) + p1.From = addr + if gc.Debug['g'] != 0 { + fmt.Printf("%v [ignore previous line]\n", p1) + } + } + + sudoclean() + goto ret + } + } + + // otherwise, the result is addressable but n is not. + // let's do some computation. + + nl = n.Left + + nr = n.Right + + if nl != nil && nl.Ullman >= gc.UINF { + if nr != nil && nr.Ullman >= gc.UINF { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + n2 = *n + n2.Left = &n1 + cgen(&n2, res) + goto ret + } + } + + // 64-bit ops are hard on 32-bit machine. + if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) { + switch n.Op { + // math goes to cgen64. + case gc.OMINUS, + gc.OCOM, + gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OLROT, + gc.OLSH, + gc.ORSH, + gc.OAND, + gc.OOR, + gc.OXOR: + cgen64(n, res) + + return + } + } + + if nl != nil && gc.Isfloat[n.Type.Etype] != 0 && gc.Isfloat[nl.Type.Etype] != 0 { + goto flt + } + switch n.Op { + default: + gc.Dump("cgen", n) + gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + case gc.OREAL, + gc.OIMAG, + gc.OCOMPLEX: + gc.Fatal("unexpected complex") + + // these call bgen to get a bool value + case gc.OOROR, + gc.OANDAND, + gc.OEQ, + gc.ONE, + gc.OLT, + gc.OLE, + gc.OGE, + gc.OGT, + gc.ONOT: + p1 = gc.Gbranch(arm.AB, nil, 0) + + p2 = gc.Pc + gmove(gc.Nodbool(true), res) + p3 = gc.Gbranch(arm.AB, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n, true, 0, p2) + gmove(gc.Nodbool(false), res) + gc.Patch(p3, gc.Pc) + goto ret + + case gc.OPLUS: + cgen(nl, res) + goto ret + + // unary + case gc.OCOM: + a = optoas(gc.OXOR, nl.Type) + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gc.Nodconst(&n2, nl.Type, -1) + gins(a, &n2, &n1) + goto norm + + case gc.OMINUS: + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gc.Nodconst(&n2, nl.Type, 0) + gins(optoas(gc.OMINUS, nl.Type), &n2, &n1) + goto norm + + // symmetric binary + case gc.OAND, + gc.OOR, + gc.OXOR, + gc.OADD, + gc.OMUL: + a = optoas(int(n.Op), nl.Type) + + goto sbop + + // asymmetric binary + case gc.OSUB: + a = optoas(int(n.Op), nl.Type) + + goto abop + + case gc.OHMUL: + cgen_hmul(nl, nr, res) + + case gc.OLROT, + gc.OLSH, + gc.ORSH: + cgen_shift(int(n.Op), n.Bounded, nl, nr, res) + + case gc.OCONV: + if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { + cgen(nl, res) + break + } + + if nl.Addable != 0 && !gc.Is64(nl.Type) { + regalloc(&n1, nl.Type, res) + gmove(nl, &n1) + } else { + if n.Type.Width > int64(gc.Widthptr) || gc.Is64(nl.Type) || gc.Isfloat[nl.Type.Etype] != 0 { + gc.Tempname(&n1, nl.Type) + } else { + regalloc(&n1, nl.Type, res) + } + cgen(nl, &n1) + } + + if n.Type.Width > int64(gc.Widthptr) || gc.Is64(n.Type) || gc.Isfloat[n.Type.Etype] != 0 { + gc.Tempname(&n2, n.Type) + } else { + regalloc(&n2, n.Type, nil) + } + gmove(&n1, &n2) + gmove(&n2, res) + if n1.Op == gc.OREGISTER { + regfree(&n1) + } + if n2.Op == gc.OREGISTER { + regfree(&n2) + } + + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: // PHEAP or PPARAMREF var + igen(n, &n1, res) + + gmove(&n1, res) + regfree(&n1) + + // interface table is first word of interface value + case gc.OITAB: + igen(nl, &n1, res) + + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + // pointer is the first word of string or slice. + case gc.OSPTR: + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n1, gc.Types[gc.Tptr], res) + p1 = gins(arm.AMOVW, nil, &n1) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + gmove(&n1, res) + regfree(&n1) + break + } + + igen(nl, &n1, res) + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + case gc.OLEN: + if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { + // map has len in the first 32-bit word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.TINT32] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { + // both slice and string have len one pointer into the struct. + igen(nl, &n1, res) + + n1.Type = gc.Types[gc.TUINT32] + n1.Xoffset += int64(gc.Array_nel) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OCAP: + if gc.Istype(nl.Type, gc.TCHAN) { + // chan has cap in the second 32-bit word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Xoffset = 4 + n2.Type = gc.Types[gc.TINT32] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Isslice(nl.Type) { + igen(nl, &n1, res) + n1.Type = gc.Types[gc.TUINT32] + n1.Xoffset += int64(gc.Array_cap) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OADDR: + agen(nl, res) + + // Release res so that it is available for cgen_call. + // Pick it up again after the call. + case gc.OCALLMETH, + gc.OCALLFUNC: + rg = -1 + + if n.Ullman >= gc.UINF { + if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { + rg = int(res.Val.U.Reg) + reg[rg]-- + } + } + + if n.Op == gc.OCALLMETH { + gc.Cgen_callmeth(n, 0) + } else { + cgen_call(n, 0) + } + if rg >= 0 { + reg[rg]++ + } + cgen_callret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_callret(n, res) + + case gc.OMOD, + gc.ODIV: + a = optoas(int(n.Op), nl.Type) + goto abop + } + + goto ret + +sbop: // symmetric binary + if nl.Ullman < nr.Ullman { + r = nl + nl = nr + nr = r + } + + // TODO(kaib): use fewer registers here. +abop: // asymmetric binary + if nl.Ullman >= nr.Ullman { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + switch n.Op { + case gc.OADD, + gc.OSUB, + gc.OAND, + gc.OOR, + gc.OXOR: + if gc.Smallintconst(nr) { + n2 = *nr + break + } + fallthrough + + default: + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + } + } else { + switch n.Op { + case gc.OADD, + gc.OSUB, + gc.OAND, + gc.OOR, + gc.OXOR: + if gc.Smallintconst(nr) { + n2 = *nr + break + } + fallthrough + + default: + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + } + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + } + + gins(a, &n2, &n1) + + // Normalize result for types smaller than word. +norm: + if n.Type.Width < int64(gc.Widthptr) { + switch n.Op { + case gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OCOM, + gc.OMINUS: + gins(optoas(gc.OAS, n.Type), &n1, &n1) + } + } + + gmove(&n1, res) + regfree(&n1) + if n2.Op != gc.OLITERAL { + regfree(&n2) + } + goto ret + +flt: // floating-point. + regalloc(&f0, nl.Type, res) + + if nr != nil { + goto flt2 + } + + if n.Op == gc.OMINUS { + nr = gc.Nodintconst(-1) + gc.Convlit(&nr, n.Type) + n.Op = gc.OMUL + goto flt2 + } + + // unary + cgen(nl, &f0) + + if n.Op != gc.OCONV && n.Op != gc.OPLUS { + gins(optoas(int(n.Op), n.Type), &f0, &f0) + } + gmove(&f0, res) + regfree(&f0) + goto ret + +flt2: // binary + if nl.Ullman >= nr.Ullman { + cgen(nl, &f0) + regalloc(&f1, n.Type, nil) + gmove(&f0, &f1) + cgen(nr, &f0) + gins(optoas(int(n.Op), n.Type), &f0, &f1) + } else { + cgen(nr, &f0) + regalloc(&f1, n.Type, nil) + cgen(nl, &f1) + gins(optoas(int(n.Op), n.Type), &f0, &f1) + } + + gmove(&f1, res) + regfree(&f0) + regfree(&f1) + goto ret + +ret: +} + +/* + * generate array index into res. + * n might be any size; res is 32-bit. + * returns Prog* to patch to panic call. + */ +func cgenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog { + var tmp gc.Node + var lo gc.Node + var hi gc.Node + var zero gc.Node + var n1 gc.Node + var n2 gc.Node + + if !gc.Is64(n.Type) { + cgen(n, res) + return nil + } + + gc.Tempname(&tmp, gc.Types[gc.TINT64]) + cgen(n, &tmp) + split64(&tmp, &lo, &hi) + gmove(&lo, res) + if bounded { + splitclean() + return nil + } + + regalloc(&n1, gc.Types[gc.TINT32], nil) + regalloc(&n2, gc.Types[gc.TINT32], nil) + gc.Nodconst(&zero, gc.Types[gc.TINT32], 0) + gmove(&hi, &n1) + gmove(&zero, &n2) + gcmp(arm.ACMP, &n1, &n2) + regfree(&n2) + regfree(&n1) + splitclean() + return gc.Gbranch(arm.ABNE, nil, -1) +} + +/* + * generate: + * res = &n; + * The generated code checks that the result is not nil. + */ +func agen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var r int + + if gc.Debug['g'] != 0 { + gc.Dump("\nagen-res", res) + gc.Dump("agen-r", n) + } + + if n == nil || n.Type == nil || res == nil || res.Type == nil { + gc.Fatal("agen") + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { + // Use of a nil interface or nil slice. + // Create a temporary we can take the address of and read. + // The generated code is just going to panic, so it need not + // be terribly efficient. See issue 3670. + gc.Tempname(&n1, n.Type) + + gc.Gvardef(&n1) + clearfat(&n1) + regalloc(&n2, gc.Types[gc.Tptr], res) + gins(arm.AMOVW, &n1, &n2) + gmove(&n2, res) + regfree(&n2) + goto ret + } + + if n.Addable != 0 { + n1 = gc.Node{} + n1.Op = gc.OADDR + n1.Left = n + regalloc(&n2, gc.Types[gc.Tptr], res) + gins(arm.AMOVW, &n1, &n2) + gmove(&n2, res) + regfree(&n2) + goto ret + } + + nl = n.Left + + switch n.Op { + default: + gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + // Release res so that it is available for cgen_call. + // Pick it up again after the call. + case gc.OCALLMETH, + gc.OCALLFUNC: + r = -1 + + if n.Ullman >= gc.UINF { + if res.Op == gc.OREGISTER || res.Op == gc.OINDREG { + r = int(res.Val.U.Reg) + reg[r]-- + } + } + + if n.Op == gc.OCALLMETH { + gc.Cgen_callmeth(n, 0) + } else { + cgen_call(n, 0) + } + if r >= 0 { + reg[r]++ + } + cgen_aret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_aret(n, res) + + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + agen(&n1, res) + + case gc.OEFACE: + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + agen(&n1, res) + + case gc.OINDEX: + agenr(n, &n1, res) + gmove(&n1, res) + regfree(&n1) + + // should only get here with names in this func. + case gc.ONAME: + if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) + } + + // should only get here for heap vars or paramref + if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME class %#x", n.Class) + } + + cgen(n.Heapaddr, res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) + regalloc(&n2, n1.Type, nil) + regalloc(&n3, gc.Types[gc.TINT32], nil) + gmove(&n1, &n2) + gmove(res, &n3) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + gmove(&n3, res) + regfree(&n2) + regfree(&n3) + } + + case gc.OIND: + cgen(nl, res) + gc.Cgen_checknil(res) + + case gc.ODOT: + agen(nl, res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) + regalloc(&n2, n1.Type, nil) + regalloc(&n3, gc.Types[gc.TINT32], nil) + gmove(&n1, &n2) + gmove(res, &n3) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + gmove(&n3, res) + regfree(&n2) + regfree(&n3) + } + + case gc.ODOTPTR: + cgen(nl, res) + gc.Cgen_checknil(res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) + regalloc(&n2, n1.Type, nil) + regalloc(&n3, gc.Types[gc.Tptr], nil) + gmove(&n1, &n2) + gmove(res, &n3) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + gmove(&n3, res) + regfree(&n2) + regfree(&n3) + } + } + +ret: +} + +/* + * generate: + * newreg = &n; + * res = newreg + * + * on exit, a has been changed to be *newreg. + * caller must regfree(a). + * The generated code checks that the result is not *nil. + */ +func igen(n *gc.Node, a *gc.Node, res *gc.Node) { + var n1 gc.Node + var r int + + if gc.Debug['g'] != 0 { + gc.Dump("\nigen-n", n) + } + + switch n.Op { + case gc.ONAME: + if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { + break + } + *a = *n + return + + // Increase the refcount of the register so that igen's caller + // has to call regfree. + case gc.OINDREG: + if n.Val.U.Reg != arm.REGSP { + reg[n.Val.U.Reg]++ + } + *a = *n + return + + case gc.ODOT: + igen(n.Left, a, res) + a.Xoffset += n.Xoffset + a.Type = n.Type + return + + case gc.ODOTPTR: + if n.Left.Addable != 0 || n.Left.Op == gc.OCALLFUNC || n.Left.Op == gc.OCALLMETH || n.Left.Op == gc.OCALLINTER { + // igen-able nodes. + igen(n.Left, &n1, res) + + regalloc(a, gc.Types[gc.Tptr], &n1) + gmove(&n1, a) + regfree(&n1) + } else { + regalloc(a, gc.Types[gc.Tptr], res) + cgen(n.Left, a) + } + + gc.Cgen_checknil(a) + a.Op = gc.OINDREG + a.Xoffset = n.Xoffset + a.Type = n.Type + return + + // Release res so that it is available for cgen_call. + // Pick it up again after the call. + case gc.OCALLMETH, + gc.OCALLFUNC, + gc.OCALLINTER: + r = -1 + + if n.Ullman >= gc.UINF { + if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { + r = int(res.Val.U.Reg) + reg[r]-- + } + } + + switch n.Op { + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + + case gc.OCALLFUNC: + cgen_call(n, 0) + + case gc.OCALLINTER: + cgen_callinter(n, nil, 0) + } + + if r >= 0 { + reg[r]++ + } + regalloc(a, gc.Types[gc.Tptr], res) + cgen_aret(n, a) + a.Op = gc.OINDREG + a.Type = n.Type + return + } + + agenr(n, a, res) + a.Op = gc.OINDREG + a.Type = n.Type +} + +/* + * allocate a register in res and generate + * newreg = &n + * The caller must call regfree(a). + */ +func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("cgenr-n", n) + } + + if gc.Isfat(n.Type) { + gc.Fatal("cgenr on fat node") + } + + if n.Addable != 0 { + regalloc(a, gc.Types[gc.Tptr], res) + gmove(n, a) + return + } + + switch n.Op { + case gc.ONAME, + gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + gmove(&n1, a) + regfree(&n1) + + default: + regalloc(a, n.Type, res) + cgen(n, a) + } +} + +/* + * generate: + * newreg = &n; + * + * caller must regfree(a). + * The generated code checks that the result is not nil. + */ +func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var tmp gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var w uint32 + var v uint64 + var bounded bool + + if gc.Debug['g'] != 0 { + gc.Dump("agenr-n", n) + } + + nl = n.Left + nr = n.Right + + switch n.Op { + case gc.ODOT, + gc.ODOTPTR, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + agen(&n1, a) + regfree(&n1) + + case gc.OIND: + cgenr(n.Left, a, res) + gc.Cgen_checknil(a) + + case gc.OINDEX: + p2 = nil // to be patched to panicindex. + w = uint32(n.Type.Width) + bounded = gc.Debug['B'] != 0 || n.Bounded + if nr.Addable != 0 { + if !gc.Isconst(nr, gc.CTINT) { + gc.Tempname(&tmp, gc.Types[gc.TINT32]) + } + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + if !gc.Isconst(nr, gc.CTINT) { + p2 = cgenindex(nr, &tmp, bounded) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + } else if nl.Addable != 0 { + if !gc.Isconst(nr, gc.CTINT) { + gc.Tempname(&tmp, gc.Types[gc.TINT32]) + p2 = cgenindex(nr, &tmp, bounded) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + } else { + gc.Tempname(&tmp, gc.Types[gc.TINT32]) + p2 = cgenindex(nr, &tmp, bounded) + nr = &tmp + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + regalloc(&n1, tmp.Type, nil) + gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) + } + + // &a is in &n3 (allocated in res) + // i is in &n1 (if not constant) + // w is width + + // constant index + if gc.Isconst(nr, gc.CTINT) { + if gc.Isconst(nl, gc.CTSTR) { + gc.Fatal("constant string constant index") + } + v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + if gc.Debug['B'] == 0 && !n.Bounded { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + regalloc(&n4, n1.Type, nil) + gmove(&n1, &n4) + gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v)) + gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n4, &n2) + regfree(&n4) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, &n3) + } + + gc.Nodconst(&n2, gc.Types[gc.Tptr], int64(v*uint64(w))) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + *a = n3 + break + } + + regalloc(&n2, gc.Types[gc.TINT32], &n1) // i + gmove(&n1, &n2) + regfree(&n1) + + if gc.Debug['B'] == 0 && !n.Bounded { + // check bounds + if gc.Isconst(nl, gc.CTSTR) { + gc.Nodconst(&n4, gc.Types[gc.TUINT32], int64(len(nl.Val.U.Sval.S))) + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + regalloc(&n4, gc.Types[gc.TUINT32], nil) + gmove(&n1, &n4) + } else { + gc.Nodconst(&n4, gc.Types[gc.TUINT32], nl.Type.Bound) + } + + gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n2, &n4) + if n4.Op == gc.OREGISTER { + regfree(&n4) + } + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + if p2 != nil { + gc.Patch(p2, gc.Pc) + } + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n3, gc.Types[gc.Tptr], res) + p1 = gins(arm.AMOVW, nil, &n3) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + p1.From.Type = obj.TYPE_ADDR + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, &n3) + } + + if w == 0 { + } else // nothing to do + if w == 1 || w == 2 || w == 4 || w == 8 { + n4 = gc.Node{} + n4.Op = gc.OADDR + n4.Left = &n2 + cgen(&n4, &n3) + if w == 1 { + gins(arm.AADD, &n2, &n3) + } else if w == 2 { + gshift(arm.AADD, &n2, arm.SHIFT_LL, 1, &n3) + } else if w == 4 { + gshift(arm.AADD, &n2, arm.SHIFT_LL, 2, &n3) + } else if w == 8 { + gshift(arm.AADD, &n2, arm.SHIFT_LL, 3, &n3) + } + } else { + regalloc(&n4, gc.Types[gc.TUINT32], nil) + gc.Nodconst(&n1, gc.Types[gc.TUINT32], int64(w)) + gmove(&n1, &n4) + gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &n4, &n2) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + regfree(&n4) + } + + *a = n3 + regfree(&n2) + + default: + regalloc(a, gc.Types[gc.Tptr], res) + agen(n, a) + } +} + +func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var a int + + regalloc(&n1, t, nil) + cgen(n, &n1) + a = optoas(gc.OCMP, t) + if a != arm.ACMP { + gc.Nodconst(&n2, t, 0) + regalloc(&n3, t, nil) + gmove(&n2, &n3) + gcmp(a, &n1, &n3) + regfree(&n3) + } else { + gins(arm.ATST, &n1, nil) + } + a = optoas(o, t) + gc.Patch(gc.Gbranch(a, t, likely), to) + regfree(&n1) +} + +/* + * generate: + * if(n == true) goto to; + */ +func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { + var et int + var a int + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var tmp gc.Node + var ll *gc.NodeList + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['g'] != 0 { + gc.Dump("\nbgen", n) + } + + if n == nil { + n = gc.Nodbool(true) + } + + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + + if n.Type == nil { + gc.Convlit(&n, gc.Types[gc.TBOOL]) + if n.Type == nil { + goto ret + } + } + + et = int(n.Type.Etype) + if et != gc.TBOOL { + gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) + gc.Patch(gins(obj.AEND, nil, nil), to) + goto ret + } + + nr = nil + + switch n.Op { + default: + a = gc.ONE + if !true_ { + a = gc.OEQ + } + gencmp0(n, n.Type, a, likely, to) + goto ret + + // need to ask if it is bool? + case gc.OLITERAL: + if !true_ == (n.Val.U.Bval == 0) { + gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) + } + goto ret + + case gc.OANDAND, + gc.OOROR: + if (n.Op == gc.OANDAND) == true_ { + p1 = gc.Gbranch(obj.AJMP, nil, 0) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n.Left, !true_, -likely, p2) + bgen(n.Right, !true_, -likely, p2) + p1 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, to) + gc.Patch(p2, gc.Pc) + } else { + bgen(n.Left, true_, likely, to) + bgen(n.Right, true_, likely, to) + } + + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + nr = n.Right + if nr == nil || nr.Type == nil { + goto ret + } + fallthrough + + case gc.ONOT: // unary + nl = n.Left + + if nl == nil || nl.Type == nil { + goto ret + } + } + + switch n.Op { + case gc.ONOT: + bgen(nl, !true_, likely, to) + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + a = int(n.Op) + if !true_ { + if gc.Isfloat[nl.Type.Etype] != 0 { + // brcom is not valid on floats when NaN is involved. + p1 = gc.Gbranch(arm.AB, nil, 0) + + p2 = gc.Gbranch(arm.AB, nil, 0) + gc.Patch(p1, gc.Pc) + ll = n.Ninit + n.Ninit = nil + bgen(n, true, -likely, p2) + n.Ninit = ll + gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) + gc.Patch(p2, gc.Pc) + goto ret + } + + a = gc.Brcom(a) + true_ = !true_ + } + + // make simplest on right + if nl.Op == gc.OLITERAL || (nl.Ullman < gc.UINF && nl.Ullman < nr.Ullman) { + a = gc.Brrev(a) + r = nl + nl = nr + nr = r + } + + if gc.Isslice(nl.Type) { + // only valid to cmp darray to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal array comparison") + break + } + + igen(nl, &n1, nil) + n1.Xoffset += int64(gc.Array_array) + n1.Type = gc.Types[gc.Tptr] + gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) + regfree(&n1) + break + } + + if gc.Isinter(nl.Type) { + // front end shold only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal interface comparison") + break + } + + igen(nl, &n1, nil) + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset += 0 + gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) + regfree(&n1) + break + } + + if gc.Iscomplex[nl.Type.Etype] != 0 { + gc.Complexbool(a, nl, nr, true_, likely, to) + break + } + + if gc.Is64(nr.Type) { + if nl.Addable == 0 { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + nl = &n1 + } + + if nr.Addable == 0 { + gc.Tempname(&n2, nr.Type) + cgen(nr, &n2) + nr = &n2 + } + + cmp64(nl, nr, a, likely, to) + break + } + + if nr.Op == gc.OLITERAL { + if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) == 0 { + gencmp0(nl, nl.Type, a, likely, to) + break + } + + if nr.Val.Ctype == gc.CTNIL { + gencmp0(nl, nl.Type, a, likely, to) + break + } + } + + a = optoas(a, nr.Type) + + if nr.Ullman >= gc.UINF { + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + + gc.Tempname(&tmp, nl.Type) + gmove(&n1, &tmp) + regfree(&n1) + + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + + regalloc(&n1, nl.Type, nil) + cgen(&tmp, &n1) + + gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) + gc.Patch(gc.Gbranch(a, nr.Type, likely), to) + + regfree(&n1) + regfree(&n2) + break + } + + gc.Tempname(&n3, nl.Type) + cgen(nl, &n3) + + gc.Tempname(&tmp, nr.Type) + cgen(nr, &tmp) + + regalloc(&n1, nl.Type, nil) + gmove(&n3, &n1) + + regalloc(&n2, nr.Type, nil) + gmove(&tmp, &n2) + + gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) + if gc.Isfloat[nl.Type.Etype] != 0 { + if n.Op == gc.ONE { + p1 = gc.Gbranch(arm.ABVS, nr.Type, likely) + gc.Patch(gc.Gbranch(a, nr.Type, likely), to) + gc.Patch(p1, to) + } else { + p1 = gc.Gbranch(arm.ABVS, nr.Type, -likely) + gc.Patch(gc.Gbranch(a, nr.Type, likely), to) + gc.Patch(p1, gc.Pc) + } + } else { + gc.Patch(gc.Gbranch(a, nr.Type, likely), to) + } + + regfree(&n1) + regfree(&n2) + } + + goto ret + +ret: +} + +/* + * n is on stack, either local variable + * or return value from function call. + * return n's offset from SP. + */ +func stkof(n *gc.Node) int32 { + var t *gc.Type + var flist gc.Iter + var off int32 + + switch n.Op { + case gc.OINDREG: + return int32(n.Xoffset) + + case gc.ODOT: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + return int32(int64(off) + n.Xoffset) + + case gc.OINDEX: + t = n.Left.Type + if !gc.Isfixedarray(t) { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + if gc.Isconst(n.Right, gc.CTINT) { + return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)) + } + return 1000 + + case gc.OCALLMETH, + gc.OCALLINTER, + gc.OCALLFUNC: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + t = gc.Structfirst(&flist, gc.Getoutarg(t)) + if t != nil { + return int32(t.Width + 4) // correct for LR + } + } + + // botch - probably failing to recognize address + // arithmetic on the above. eg INDEX and DOT + return -1000 +} + +/* + * block copy: + * memmove(&res, &n, w); + * NB: character copy assumed little endian architecture + */ +func sgen(n *gc.Node, res *gc.Node, w int64) { + var dst gc.Node + var src gc.Node + var tmp gc.Node + var nend gc.Node + var r0 gc.Node + var r1 gc.Node + var r2 gc.Node + var f *gc.Node + var c int32 + var odst int32 + var osrc int32 + var dir int + var align int + var op int + var p *obj.Prog + var ploop *obj.Prog + var l *gc.NodeList + + if gc.Debug['g'] != 0 { + fmt.Printf("\nsgen w=%d\n", w) + gc.Dump("r", n) + gc.Dump("res", res) + } + + if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { + gc.Fatal("sgen UINF") + } + + if w < 0 || int64(int32(w)) != w { + gc.Fatal("sgen copy %d", w) + } + + if n.Type == nil { + gc.Fatal("sgen: missing type") + } + + if w == 0 { + // evaluate side effects only. + regalloc(&dst, gc.Types[gc.Tptr], nil) + + agen(res, &dst) + agen(n, &dst) + regfree(&dst) + return + } + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if res.Op == gc.ONAME && res.Sym.Name == ".args" { + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + if l.N.Class == gc.PPARAMOUT { + gc.Gvardef(l.N) + } + } + } + + // Avoid taking the address for simple enough types. + if componentgen(n, res) { + return + } + + // determine alignment. + // want to avoid unaligned access, so have to use + // smaller operations for less aligned types. + // for example moving [4]byte must use 4 MOVB not 1 MOVW. + align = int(n.Type.Align) + + switch align { + default: + gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0)) + + case 1: + op = arm.AMOVB + + case 2: + op = arm.AMOVH + + case 4: + op = arm.AMOVW + } + + if w%int64(align) != 0 { + gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0)) + } + c = int32(w / int64(align)) + + // offset on the stack + osrc = stkof(n) + + odst = stkof(res) + if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + gc.Tempname(&tmp, n.Type) + + sgen(n, &tmp, w) + sgen(&tmp, res, w) + return + } + + if osrc%int32(align) != 0 || odst%int32(align) != 0 { + gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align) + } + + // if we are copying forward on the stack and + // the src and dst overlap, then reverse direction + dir = align + + if osrc < odst && int64(odst) < int64(osrc)+w { + dir = -dir + } + + if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 { + r0.Op = gc.OREGISTER + r0.Val.U.Reg = REGALLOC_R0 + r1.Op = gc.OREGISTER + r1.Val.U.Reg = REGALLOC_R0 + 1 + r2.Op = gc.OREGISTER + r2.Val.U.Reg = REGALLOC_R0 + 2 + + regalloc(&src, gc.Types[gc.Tptr], &r1) + regalloc(&dst, gc.Types[gc.Tptr], &r2) + if n.Ullman >= res.Ullman { + // eval n first + agen(n, &src) + + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agen(res, &dst) + } else { + // eval res first + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agen(res, &dst) + agen(n, &src) + } + + regalloc(&tmp, gc.Types[gc.Tptr], &r0) + f = gc.Sysfunc("duffcopy") + p = gins(obj.ADUFFCOPY, nil, f) + gc.Afunclit(&p.To, f) + + // 8 and 128 = magic constants: see ../../runtime/asm_arm.s + p.To.Offset = 8 * (128 - int64(c)) + + regfree(&tmp) + regfree(&src) + regfree(&dst) + return + } + + if n.Ullman >= res.Ullman { + agenr(n, &dst, res) // temporarily use dst + regalloc(&src, gc.Types[gc.Tptr], nil) + gins(arm.AMOVW, &dst, &src) + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agen(res, &dst) + } else { + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agenr(res, &dst, res) + agenr(n, &src, nil) + } + + regalloc(&tmp, gc.Types[gc.TUINT32], nil) + + // set up end marker + nend = gc.Node{} + + if c >= 4 { + regalloc(&nend, gc.Types[gc.TUINT32], nil) + + p = gins(arm.AMOVW, &src, &nend) + p.From.Type = obj.TYPE_ADDR + if dir < 0 { + p.From.Offset = int64(dir) + } else { + p.From.Offset = w + } + } + + // move src and dest to the end of block if necessary + if dir < 0 { + p = gins(arm.AMOVW, &src, &src) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = w + int64(dir) + + p = gins(arm.AMOVW, &dst, &dst) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = w + int64(dir) + } + + // move + if c >= 4 { + p = gins(op, &src, &tmp) + p.From.Type = obj.TYPE_MEM + p.From.Offset = int64(dir) + p.Scond |= arm.C_PBIT + ploop = p + + p = gins(op, &tmp, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(dir) + p.Scond |= arm.C_PBIT + + p = gins(arm.ACMP, &src, nil) + raddr(&nend, p) + + gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), ploop) + regfree(&nend) + } else { + for { + tmp14 := c + c-- + if tmp14 <= 0 { + break + } + p = gins(op, &src, &tmp) + p.From.Type = obj.TYPE_MEM + p.From.Offset = int64(dir) + p.Scond |= arm.C_PBIT + + p = gins(op, &tmp, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(dir) + p.Scond |= arm.C_PBIT + } + } + + regfree(&dst) + regfree(&src) + regfree(&tmp) +} + +func cadable(n *gc.Node) bool { + if n.Addable == 0 { + // dont know how it happens, + // but it does + return false + } + + switch n.Op { + case gc.ONAME: + return true + } + + return false +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * Small structs or arrays with elements of basic type are + * also supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if cant. + */ +func componentgen(nr *gc.Node, nl *gc.Node) bool { + var nodl gc.Node + var nodr gc.Node + var tmp gc.Node + var t *gc.Type + var freel int + var freer int + var fldcount int64 + var loffset int64 + var roffset int64 + + freel = 0 + freer = 0 + + switch nl.Type.Etype { + default: + goto no + + case gc.TARRAY: + t = nl.Type + + // Slices are ok. + if gc.Isslice(t) { + break + } + + // Small arrays are ok. + if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { + break + } + + goto no + + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + case gc.TSTRUCT: + fldcount = 0 + + for t = nl.Type.Type; t != nil; t = t.Down { + if gc.Isfat(t.Type) { + goto no + } + if t.Etype != gc.TFIELD { + gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) + } + fldcount++ + } + + if fldcount == 0 || fldcount > 4 { + goto no + } + + case gc.TSTRING, + gc.TINTER: + break + } + + nodl = *nl + if !cadable(nl) { + if nr != nil && !cadable(nr) { + goto no + } + igen(nl, &nodl, nil) + freel = 1 + } + + if nr != nil { + nodr = *nr + if !cadable(nr) { + igen(nr, &nodr, nil) + freer = 1 + } + } else { + // When zeroing, prepare a register containing zero. + gc.Nodconst(&tmp, nl.Type, 0) + + regalloc(&nodr, gc.Types[gc.TUINT], nil) + gmove(&tmp, &nodr) + freer = 1 + } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { + goto yes + } + + switch nl.Type.Etype { + // componentgen for arrays. + case gc.TARRAY: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + t = nl.Type + if !gc.Isslice(t) { + nodl.Type = t.Type + nodr.Type = nodl.Type + for fldcount = 0; fldcount < t.Bound; fldcount++ { + if nr == nil { + gc.Clearslim(&nodl) + } else { + gmove(&nodr, &nodl) + } + nodl.Xoffset += t.Type.Width + nodr.Xoffset += t.Type.Width + } + + goto yes + } + + // componentgen for slices. + nodl.Xoffset += int64(gc.Array_array) + + nodl.Type = gc.Ptrto(nl.Type.Type) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRING: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TINTER: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRUCT: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + loffset = nodl.Xoffset + roffset = nodr.Xoffset + + // funarg structs may not begin at offset zero. + if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { + loffset -= nl.Type.Type.Width + } + if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { + roffset -= nr.Type.Type.Width + } + + for t = nl.Type.Type; t != nil; t = t.Down { + nodl.Xoffset = loffset + t.Width + nodl.Type = t.Type + + if nr == nil { + gc.Clearslim(&nodl) + } else { + nodr.Xoffset = roffset + t.Width + nodr.Type = nodl.Type + gmove(&nodr, &nodl) + } + } + + goto yes + } + +no: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return false + +yes: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return true +} diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c deleted file mode 100644 index 9abab4c650..0000000000 --- a/src/cmd/5g/cgen64.c +++ /dev/null @@ -1,760 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -/* - * attempt to generate 64-bit - * res = n - * return 1 on success, 0 if op not handled. - */ -void -cgen64(Node *n, Node *res) -{ - Node t1, t2, *l, *r; - Node lo1, lo2, hi1, hi2; - Node al, ah, bl, bh, cl, ch, s, n1, creg; - Prog *p1, *p2, *p3, *p4, *p5, *p6; - - uint64 v; - - if(res->op != OINDREG && res->op != ONAME) { - dump("n", n); - dump("res", res); - fatal("cgen64 %O of %O", n->op, res->op); - } - - l = n->left; - if(!l->addable) { - tempname(&t1, l->type); - cgen(l, &t1); - l = &t1; - } - - split64(l, &lo1, &hi1); - switch(n->op) { - default: - fatal("cgen64 %O", n->op); - - case OMINUS: - split64(res, &lo2, &hi2); - - regalloc(&t1, lo1.type, N); - regalloc(&al, lo1.type, N); - regalloc(&ah, hi1.type, N); - - gins(AMOVW, &lo1, &al); - gins(AMOVW, &hi1, &ah); - - gmove(ncon(0), &t1); - p1 = gins(ASUB, &al, &t1); - p1->scond |= C_SBIT; - gins(AMOVW, &t1, &lo2); - - gmove(ncon(0), &t1); - gins(ASBC, &ah, &t1); - gins(AMOVW, &t1, &hi2); - - regfree(&t1); - regfree(&al); - regfree(&ah); - splitclean(); - splitclean(); - return; - - case OCOM: - regalloc(&t1, lo1.type, N); - gmove(ncon(-1), &t1); - - split64(res, &lo2, &hi2); - regalloc(&n1, lo1.type, N); - - gins(AMOVW, &lo1, &n1); - gins(AEOR, &t1, &n1); - gins(AMOVW, &n1, &lo2); - - gins(AMOVW, &hi1, &n1); - gins(AEOR, &t1, &n1); - gins(AMOVW, &n1, &hi2); - - regfree(&t1); - regfree(&n1); - splitclean(); - splitclean(); - return; - - case OADD: - case OSUB: - case OMUL: - case OLSH: - case ORSH: - case OAND: - case OOR: - case OXOR: - case OLROT: - // binary operators. - // common setup below. - break; - } - - // setup for binary operators - r = n->right; - if(r != N && !r->addable) { - tempname(&t2, r->type); - cgen(r, &t2); - r = &t2; - } - if(is64(r->type)) - split64(r, &lo2, &hi2); - - regalloc(&al, lo1.type, N); - regalloc(&ah, hi1.type, N); - - // Do op. Leave result in ah:al. - switch(n->op) { - default: - fatal("cgen64: not implemented: %N\n", n); - - case OADD: - // TODO: Constants - regalloc(&bl, types[TPTR32], N); - regalloc(&bh, types[TPTR32], N); - gins(AMOVW, &hi1, &ah); - gins(AMOVW, &lo1, &al); - gins(AMOVW, &hi2, &bh); - gins(AMOVW, &lo2, &bl); - p1 = gins(AADD, &bl, &al); - p1->scond |= C_SBIT; - gins(AADC, &bh, &ah); - regfree(&bl); - regfree(&bh); - break; - - case OSUB: - // TODO: Constants. - regalloc(&bl, types[TPTR32], N); - regalloc(&bh, types[TPTR32], N); - gins(AMOVW, &lo1, &al); - gins(AMOVW, &hi1, &ah); - gins(AMOVW, &lo2, &bl); - gins(AMOVW, &hi2, &bh); - p1 = gins(ASUB, &bl, &al); - p1->scond |= C_SBIT; - gins(ASBC, &bh, &ah); - regfree(&bl); - regfree(&bh); - break; - - case OMUL: - // TODO(kaib): this can be done with 4 regs and does not need 6 - regalloc(&bl, types[TPTR32], N); - regalloc(&bh, types[TPTR32], N); - regalloc(&cl, types[TPTR32], N); - regalloc(&ch, types[TPTR32], N); - - // load args into bh:bl and bh:bl. - gins(AMOVW, &hi1, &bh); - gins(AMOVW, &lo1, &bl); - gins(AMOVW, &hi2, &ch); - gins(AMOVW, &lo2, &cl); - - // bl * cl -> ah al - p1 = gins(AMULLU, N, N); - p1->from.type = TYPE_REG; - p1->from.reg = bl.val.u.reg; - p1->reg = cl.val.u.reg; - p1->to.type = TYPE_REGREG; - p1->to.reg = ah.val.u.reg; - p1->to.offset = al.val.u.reg; -//print("%P\n", p1); - - // bl * ch + ah -> ah - p1 = gins(AMULA, N, N); - p1->from.type = TYPE_REG; - p1->from.reg = bl.val.u.reg; - p1->reg = ch.val.u.reg; - p1->to.type = TYPE_REGREG2; - p1->to.reg = ah.val.u.reg; - p1->to.offset = ah.val.u.reg; -//print("%P\n", p1); - - // bh * cl + ah -> ah - p1 = gins(AMULA, N, N); - p1->from.type = TYPE_REG; - p1->from.reg = bh.val.u.reg; - p1->reg = cl.val.u.reg; - p1->to.type = TYPE_REGREG2; - p1->to.reg = ah.val.u.reg; - p1->to.offset = ah.val.u.reg; -//print("%P\n", p1); - - regfree(&bh); - regfree(&bl); - regfree(&ch); - regfree(&cl); - - break; - - case OLROT: - // We only rotate by a constant c in [0,64). - // if c >= 32: - // lo, hi = hi, lo - // c -= 32 - // if c == 0: - // no-op - // else: - // t = hi - // shld hi:lo, c - // shld lo:t, c - v = mpgetfix(r->val.u.xval); - regalloc(&bl, lo1.type, N); - regalloc(&bh, hi1.type, N); - if(v >= 32) { - // reverse during load to do the first 32 bits of rotate - v -= 32; - gins(AMOVW, &hi1, &bl); - gins(AMOVW, &lo1, &bh); - } else { - gins(AMOVW, &hi1, &bh); - gins(AMOVW, &lo1, &bl); - } - if(v == 0) { - gins(AMOVW, &bh, &ah); - gins(AMOVW, &bl, &al); - } else { - // rotate by 1 <= v <= 31 - // MOVW bl<>(32-v), ah - // OR bh>>(32-v), al - gshift(AMOVW, &bl, SHIFT_LL, v, &al); - gshift(AMOVW, &bh, SHIFT_LL, v, &ah); - gshift(AORR, &bl, SHIFT_LR, 32-v, &ah); - gshift(AORR, &bh, SHIFT_LR, 32-v, &al); - } - regfree(&bl); - regfree(&bh); - break; - - case OLSH: - regalloc(&bl, lo1.type, N); - regalloc(&bh, hi1.type, N); - gins(AMOVW, &hi1, &bh); - gins(AMOVW, &lo1, &bl); - - if(r->op == OLITERAL) { - v = mpgetfix(r->val.u.xval); - if(v >= 64) { - // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) - // here and below (verify it optimizes to EOR) - gins(AEOR, &al, &al); - gins(AEOR, &ah, &ah); - } else - if(v > 32) { - gins(AEOR, &al, &al); - // MOVW bl<<(v-32), ah - gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah); - } else - if(v == 32) { - gins(AEOR, &al, &al); - gins(AMOVW, &bl, &ah); - } else - if(v > 0) { - // MOVW bl<>(32-v), ah - gshift(AORR, &bl, SHIFT_LR, 32-v, &ah); - } else { - gins(AMOVW, &bl, &al); - gins(AMOVW, &bh, &ah); - } - goto olsh_break; - } - - regalloc(&s, types[TUINT32], N); - regalloc(&creg, types[TUINT32], N); - if (is64(r->type)) { - // shift is >= 1<<32 - split64(r, &cl, &ch); - gmove(&ch, &s); - gins(ATST, &s, N); - p6 = gbranch(ABNE, T, 0); - gmove(&cl, &s); - splitclean(); - } else { - gmove(r, &s); - p6 = P; - } - gins(ATST, &s, N); - - // shift == 0 - p1 = gins(AMOVW, &bl, &al); - p1->scond = C_SCOND_EQ; - p1 = gins(AMOVW, &bh, &ah); - p1->scond = C_SCOND_EQ; - p2 = gbranch(ABEQ, T, 0); - - // shift is < 32 - nodconst(&n1, types[TUINT32], 32); - gmove(&n1, &creg); - gcmp(ACMP, &s, &creg); - - // MOVW.LO bl<scond = C_SCOND_LO; - - // MOVW.LO bh<scond = C_SCOND_LO; - - // SUB.LO s, creg - p1 = gins(ASUB, &s, &creg); - p1->scond = C_SCOND_LO; - - // OR.LO bl>>creg, ah - p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah); - p1->scond = C_SCOND_LO; - - // BLO end - p3 = gbranch(ABLO, T, 0); - - // shift == 32 - p1 = gins(AEOR, &al, &al); - p1->scond = C_SCOND_EQ; - p1 = gins(AMOVW, &bl, &ah); - p1->scond = C_SCOND_EQ; - p4 = gbranch(ABEQ, T, 0); - - // shift is < 64 - nodconst(&n1, types[TUINT32], 64); - gmove(&n1, &creg); - gcmp(ACMP, &s, &creg); - - // EOR.LO al, al - p1 = gins(AEOR, &al, &al); - p1->scond = C_SCOND_LO; - - // MOVW.LO creg>>1, creg - p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg); - p1->scond = C_SCOND_LO; - - // SUB.LO creg, s - p1 = gins(ASUB, &creg, &s); - p1->scond = C_SCOND_LO; - - // MOVW bl<scond = C_SCOND_LO; - - p5 = gbranch(ABLO, T, 0); - - // shift >= 64 - if (p6 != P) patch(p6, pc); - gins(AEOR, &al, &al); - gins(AEOR, &ah, &ah); - - patch(p2, pc); - patch(p3, pc); - patch(p4, pc); - patch(p5, pc); - regfree(&s); - regfree(&creg); - -olsh_break: - regfree(&bl); - regfree(&bh); - break; - - - case ORSH: - regalloc(&bl, lo1.type, N); - regalloc(&bh, hi1.type, N); - gins(AMOVW, &hi1, &bh); - gins(AMOVW, &lo1, &bl); - - if(r->op == OLITERAL) { - v = mpgetfix(r->val.u.xval); - if(v >= 64) { - if(bh.type->etype == TINT32) { - // MOVW bh->31, al - gshift(AMOVW, &bh, SHIFT_AR, 31, &al); - - // MOVW bh->31, ah - gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); - } else { - gins(AEOR, &al, &al); - gins(AEOR, &ah, &ah); - } - } else - if(v > 32) { - if(bh.type->etype == TINT32) { - // MOVW bh->(v-32), al - gshift(AMOVW, &bh, SHIFT_AR, v-32, &al); - - // MOVW bh->31, ah - gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); - } else { - // MOVW bh>>(v-32), al - gshift(AMOVW, &bh, SHIFT_LR, v-32, &al); - gins(AEOR, &ah, &ah); - } - } else - if(v == 32) { - gins(AMOVW, &bh, &al); - if(bh.type->etype == TINT32) { - // MOVW bh->31, ah - gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); - } else { - gins(AEOR, &ah, &ah); - } - } else - if( v > 0) { - // MOVW bl>>v, al - gshift(AMOVW, &bl, SHIFT_LR, v, &al); - - // OR bh<<(32-v), al - gshift(AORR, &bh, SHIFT_LL, 32-v, &al); - - if(bh.type->etype == TINT32) { - // MOVW bh->v, ah - gshift(AMOVW, &bh, SHIFT_AR, v, &ah); - } else { - // MOVW bh>>v, ah - gshift(AMOVW, &bh, SHIFT_LR, v, &ah); - } - } else { - gins(AMOVW, &bl, &al); - gins(AMOVW, &bh, &ah); - } - goto orsh_break; - } - - regalloc(&s, types[TUINT32], N); - regalloc(&creg, types[TUINT32], N); - if(is64(r->type)) { - // shift is >= 1<<32 - split64(r, &cl, &ch); - gmove(&ch, &s); - gins(ATST, &s, N); - if(bh.type->etype == TINT32) - p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); - else - p1 = gins(AEOR, &ah, &ah); - p1->scond = C_SCOND_NE; - p6 = gbranch(ABNE, T, 0); - gmove(&cl, &s); - splitclean(); - } else { - gmove(r, &s); - p6 = P; - } - gins(ATST, &s, N); - - // shift == 0 - p1 = gins(AMOVW, &bl, &al); - p1->scond = C_SCOND_EQ; - p1 = gins(AMOVW, &bh, &ah); - p1->scond = C_SCOND_EQ; - p2 = gbranch(ABEQ, T, 0); - - // check if shift is < 32 - nodconst(&n1, types[TUINT32], 32); - gmove(&n1, &creg); - gcmp(ACMP, &s, &creg); - - // MOVW.LO bl>>s, al - p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al); - p1->scond = C_SCOND_LO; - - // SUB.LO s,creg - p1 = gins(ASUB, &s, &creg); - p1->scond = C_SCOND_LO; - - // OR.LO bh<<(32-s), al - p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al); - p1->scond = C_SCOND_LO; - - if(bh.type->etype == TINT32) { - // MOVW bh->s, ah - p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah); - } else { - // MOVW bh>>s, ah - p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah); - } - p1->scond = C_SCOND_LO; - - // BLO end - p3 = gbranch(ABLO, T, 0); - - // shift == 32 - p1 = gins(AMOVW, &bh, &al); - p1->scond = C_SCOND_EQ; - if(bh.type->etype == TINT32) - gshift(AMOVW, &bh, SHIFT_AR, 31, &ah); - else - gins(AEOR, &ah, &ah); - p4 = gbranch(ABEQ, T, 0); - - // check if shift is < 64 - nodconst(&n1, types[TUINT32], 64); - gmove(&n1, &creg); - gcmp(ACMP, &s, &creg); - - // MOVW.LO creg>>1, creg - p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg); - p1->scond = C_SCOND_LO; - - // SUB.LO creg, s - p1 = gins(ASUB, &creg, &s); - p1->scond = C_SCOND_LO; - - if(bh.type->etype == TINT32) { - // MOVW bh->(s-32), al - p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al); - p1->scond = C_SCOND_LO; - } else { - // MOVW bh>>(v-32), al - p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al); - p1->scond = C_SCOND_LO; - } - - // BLO end - p5 = gbranch(ABLO, T, 0); - - // s >= 64 - if(p6 != P) - patch(p6, pc); - if(bh.type->etype == TINT32) { - // MOVW bh->31, al - gshift(AMOVW, &bh, SHIFT_AR, 31, &al); - } else { - gins(AEOR, &al, &al); - } - - patch(p2, pc); - patch(p3, pc); - patch(p4, pc); - patch(p5, pc); - regfree(&s); - regfree(&creg); - - -orsh_break: - regfree(&bl); - regfree(&bh); - break; - - case OXOR: - case OAND: - case OOR: - // TODO(kaib): literal optimizations - // make constant the right side (it usually is anyway). -// if(lo1.op == OLITERAL) { -// nswap(&lo1, &lo2); -// nswap(&hi1, &hi2); -// } -// if(lo2.op == OLITERAL) { -// // special cases for constants. -// lv = mpgetfix(lo2.val.u.xval); -// hv = mpgetfix(hi2.val.u.xval); -// splitclean(); // right side -// split64(res, &lo2, &hi2); -// switch(n->op) { -// case OXOR: -// gmove(&lo1, &lo2); -// gmove(&hi1, &hi2); -// switch(lv) { -// case 0: -// break; -// case 0xffffffffu: -// gins(ANOTL, N, &lo2); -// break; -// default: -// gins(AXORL, ncon(lv), &lo2); -// break; -// } -// switch(hv) { -// case 0: -// break; -// case 0xffffffffu: -// gins(ANOTL, N, &hi2); -// break; -// default: -// gins(AXORL, ncon(hv), &hi2); -// break; -// } -// break; - -// case OAND: -// switch(lv) { -// case 0: -// gins(AMOVL, ncon(0), &lo2); -// break; -// default: -// gmove(&lo1, &lo2); -// if(lv != 0xffffffffu) -// gins(AANDL, ncon(lv), &lo2); -// break; -// } -// switch(hv) { -// case 0: -// gins(AMOVL, ncon(0), &hi2); -// break; -// default: -// gmove(&hi1, &hi2); -// if(hv != 0xffffffffu) -// gins(AANDL, ncon(hv), &hi2); -// break; -// } -// break; - -// case OOR: -// switch(lv) { -// case 0: -// gmove(&lo1, &lo2); -// break; -// case 0xffffffffu: -// gins(AMOVL, ncon(0xffffffffu), &lo2); -// break; -// default: -// gmove(&lo1, &lo2); -// gins(AORL, ncon(lv), &lo2); -// break; -// } -// switch(hv) { -// case 0: -// gmove(&hi1, &hi2); -// break; -// case 0xffffffffu: -// gins(AMOVL, ncon(0xffffffffu), &hi2); -// break; -// default: -// gmove(&hi1, &hi2); -// gins(AORL, ncon(hv), &hi2); -// break; -// } -// break; -// } -// splitclean(); -// splitclean(); -// goto out; -// } - regalloc(&n1, lo1.type, N); - gins(AMOVW, &lo1, &al); - gins(AMOVW, &hi1, &ah); - gins(AMOVW, &lo2, &n1); - gins(optoas(n->op, lo1.type), &n1, &al); - gins(AMOVW, &hi2, &n1); - gins(optoas(n->op, lo1.type), &n1, &ah); - regfree(&n1); - break; - } - if(is64(r->type)) - splitclean(); - splitclean(); - - split64(res, &lo1, &hi1); - gins(AMOVW, &al, &lo1); - gins(AMOVW, &ah, &hi1); - splitclean(); - -//out: - regfree(&al); - regfree(&ah); -} - -/* - * generate comparison of nl, nr, both 64-bit. - * nl is memory; nr is constant or memory. - */ -void -cmp64(Node *nl, Node *nr, int op, int likely, Prog *to) -{ - Node lo1, hi1, lo2, hi2, r1, r2; - Prog *br; - Type *t; - - split64(nl, &lo1, &hi1); - split64(nr, &lo2, &hi2); - - // compare most significant word; - // if they differ, we're done. - t = hi1.type; - regalloc(&r1, types[TINT32], N); - regalloc(&r2, types[TINT32], N); - gins(AMOVW, &hi1, &r1); - gins(AMOVW, &hi2, &r2); - gcmp(ACMP, &r1, &r2); - regfree(&r1); - regfree(&r2); - - br = P; - switch(op) { - default: - fatal("cmp64 %O %T", op, t); - case OEQ: - // cmp hi - // bne L - // cmp lo - // beq to - // L: - br = gbranch(ABNE, T, -likely); - break; - case ONE: - // cmp hi - // bne to - // cmp lo - // bne to - patch(gbranch(ABNE, T, likely), to); - break; - case OGE: - case OGT: - // cmp hi - // bgt to - // blt L - // cmp lo - // bge to (or bgt to) - // L: - patch(gbranch(optoas(OGT, t), T, likely), to); - br = gbranch(optoas(OLT, t), T, -likely); - break; - case OLE: - case OLT: - // cmp hi - // blt to - // bgt L - // cmp lo - // ble to (or jlt to) - // L: - patch(gbranch(optoas(OLT, t), T, likely), to); - br = gbranch(optoas(OGT, t), T, -likely); - break; - } - - // compare least significant word - t = lo1.type; - regalloc(&r1, types[TINT32], N); - regalloc(&r2, types[TINT32], N); - gins(AMOVW, &lo1, &r1); - gins(AMOVW, &lo2, &r2); - gcmp(ACMP, &r1, &r2); - regfree(&r1); - regfree(&r2); - - // jump again - patch(gbranch(optoas(op, t), T, likely), to); - - // point first branch down here if appropriate - if(br != P) - patch(br, pc); - - splitclean(); - splitclean(); -} diff --git a/src/cmd/5g/cgen64.go b/src/cmd/5g/cgen64.go new file mode 100644 index 0000000000..f89c21cf08 --- /dev/null +++ b/src/cmd/5g/cgen64.go @@ -0,0 +1,833 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" +) +import "cmd/internal/gc" + +/* + * attempt to generate 64-bit + * res = n + * return 1 on success, 0 if op not handled. + */ +func cgen64(n *gc.Node, res *gc.Node) { + var t1 gc.Node + var t2 gc.Node + var l *gc.Node + var r *gc.Node + var lo1 gc.Node + var lo2 gc.Node + var hi1 gc.Node + var hi2 gc.Node + var al gc.Node + var ah gc.Node + var bl gc.Node + var bh gc.Node + var cl gc.Node + var ch gc.Node + var s gc.Node + var n1 gc.Node + var creg gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var p4 *obj.Prog + var p5 *obj.Prog + var p6 *obj.Prog + var v uint64 + + if res.Op != gc.OINDREG && res.Op != gc.ONAME { + gc.Dump("n", n) + gc.Dump("res", res) + gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) + } + + l = n.Left + if l.Addable == 0 { + gc.Tempname(&t1, l.Type) + cgen(l, &t1) + l = &t1 + } + + split64(l, &lo1, &hi1) + switch n.Op { + default: + gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0)) + + case gc.OMINUS: + split64(res, &lo2, &hi2) + + regalloc(&t1, lo1.Type, nil) + regalloc(&al, lo1.Type, nil) + regalloc(&ah, hi1.Type, nil) + + gins(arm.AMOVW, &lo1, &al) + gins(arm.AMOVW, &hi1, &ah) + + gmove(ncon(0), &t1) + p1 = gins(arm.ASUB, &al, &t1) + p1.Scond |= arm.C_SBIT + gins(arm.AMOVW, &t1, &lo2) + + gmove(ncon(0), &t1) + gins(arm.ASBC, &ah, &t1) + gins(arm.AMOVW, &t1, &hi2) + + regfree(&t1) + regfree(&al) + regfree(&ah) + splitclean() + splitclean() + return + + case gc.OCOM: + regalloc(&t1, lo1.Type, nil) + gmove(ncon(^uint32(0)), &t1) + + split64(res, &lo2, &hi2) + regalloc(&n1, lo1.Type, nil) + + gins(arm.AMOVW, &lo1, &n1) + gins(arm.AEOR, &t1, &n1) + gins(arm.AMOVW, &n1, &lo2) + + gins(arm.AMOVW, &hi1, &n1) + gins(arm.AEOR, &t1, &n1) + gins(arm.AMOVW, &n1, &hi2) + + regfree(&t1) + regfree(&n1) + splitclean() + splitclean() + return + + // binary operators. + // common setup below. + case gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OLSH, + gc.ORSH, + gc.OAND, + gc.OOR, + gc.OXOR, + gc.OLROT: + break + } + + // setup for binary operators + r = n.Right + + if r != nil && r.Addable == 0 { + gc.Tempname(&t2, r.Type) + cgen(r, &t2) + r = &t2 + } + + if gc.Is64(r.Type) { + split64(r, &lo2, &hi2) + } + + regalloc(&al, lo1.Type, nil) + regalloc(&ah, hi1.Type, nil) + + // Do op. Leave result in ah:al. + switch n.Op { + default: + gc.Fatal("cgen64: not implemented: %v\n", gc.Nconv(n, 0)) + + // TODO: Constants + case gc.OADD: + regalloc(&bl, gc.Types[gc.TPTR32], nil) + + regalloc(&bh, gc.Types[gc.TPTR32], nil) + gins(arm.AMOVW, &hi1, &ah) + gins(arm.AMOVW, &lo1, &al) + gins(arm.AMOVW, &hi2, &bh) + gins(arm.AMOVW, &lo2, &bl) + p1 = gins(arm.AADD, &bl, &al) + p1.Scond |= arm.C_SBIT + gins(arm.AADC, &bh, &ah) + regfree(&bl) + regfree(&bh) + + // TODO: Constants. + case gc.OSUB: + regalloc(&bl, gc.Types[gc.TPTR32], nil) + + regalloc(&bh, gc.Types[gc.TPTR32], nil) + gins(arm.AMOVW, &lo1, &al) + gins(arm.AMOVW, &hi1, &ah) + gins(arm.AMOVW, &lo2, &bl) + gins(arm.AMOVW, &hi2, &bh) + p1 = gins(arm.ASUB, &bl, &al) + p1.Scond |= arm.C_SBIT + gins(arm.ASBC, &bh, &ah) + regfree(&bl) + regfree(&bh) + + // TODO(kaib): this can be done with 4 regs and does not need 6 + case gc.OMUL: + regalloc(&bl, gc.Types[gc.TPTR32], nil) + + regalloc(&bh, gc.Types[gc.TPTR32], nil) + regalloc(&cl, gc.Types[gc.TPTR32], nil) + regalloc(&ch, gc.Types[gc.TPTR32], nil) + + // load args into bh:bl and bh:bl. + gins(arm.AMOVW, &hi1, &bh) + + gins(arm.AMOVW, &lo1, &bl) + gins(arm.AMOVW, &hi2, &ch) + gins(arm.AMOVW, &lo2, &cl) + + // bl * cl -> ah al + p1 = gins(arm.AMULLU, nil, nil) + + p1.From.Type = obj.TYPE_REG + p1.From.Reg = bl.Val.U.Reg + p1.Reg = cl.Val.U.Reg + p1.To.Type = obj.TYPE_REGREG + p1.To.Reg = ah.Val.U.Reg + p1.To.Offset = int64(al.Val.U.Reg) + + //print("%P\n", p1); + + // bl * ch + ah -> ah + p1 = gins(arm.AMULA, nil, nil) + + p1.From.Type = obj.TYPE_REG + p1.From.Reg = bl.Val.U.Reg + p1.Reg = ch.Val.U.Reg + p1.To.Type = obj.TYPE_REGREG2 + p1.To.Reg = ah.Val.U.Reg + p1.To.Offset = int64(ah.Val.U.Reg) + + //print("%P\n", p1); + + // bh * cl + ah -> ah + p1 = gins(arm.AMULA, nil, nil) + + p1.From.Type = obj.TYPE_REG + p1.From.Reg = bh.Val.U.Reg + p1.Reg = cl.Val.U.Reg + p1.To.Type = obj.TYPE_REGREG2 + p1.To.Reg = ah.Val.U.Reg + p1.To.Offset = int64(ah.Val.U.Reg) + + //print("%P\n", p1); + + regfree(&bh) + + regfree(&bl) + regfree(&ch) + regfree(&cl) + + // We only rotate by a constant c in [0,64). + // if c >= 32: + // lo, hi = hi, lo + // c -= 32 + // if c == 0: + // no-op + // else: + // t = hi + // shld hi:lo, c + // shld lo:t, c + case gc.OLROT: + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + + regalloc(&bl, lo1.Type, nil) + regalloc(&bh, hi1.Type, nil) + if v >= 32 { + // reverse during load to do the first 32 bits of rotate + v -= 32 + + gins(arm.AMOVW, &hi1, &bl) + gins(arm.AMOVW, &lo1, &bh) + } else { + gins(arm.AMOVW, &hi1, &bh) + gins(arm.AMOVW, &lo1, &bl) + } + + if v == 0 { + gins(arm.AMOVW, &bh, &ah) + gins(arm.AMOVW, &bl, &al) + } else { + // rotate by 1 <= v <= 31 + // MOVW bl<>(32-v), ah + // OR bh>>(32-v), al + gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al) + + gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah) + gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) + gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al) + } + + regfree(&bl) + regfree(&bh) + + case gc.OLSH: + regalloc(&bl, lo1.Type, nil) + regalloc(&bh, hi1.Type, nil) + gins(arm.AMOVW, &hi1, &bh) + gins(arm.AMOVW, &lo1, &bl) + + if r.Op == gc.OLITERAL { + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + if v >= 64 { + // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) + // here and below (verify it optimizes to EOR) + gins(arm.AEOR, &al, &al) + + gins(arm.AEOR, &ah, &ah) + } else if v > 32 { + gins(arm.AEOR, &al, &al) + + // MOVW bl<<(v-32), ah + gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah) + } else if v == 32 { + gins(arm.AEOR, &al, &al) + gins(arm.AMOVW, &bl, &ah) + } else if v > 0 { + // MOVW bl<>(32-v), ah + gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) + } else { + gins(arm.AMOVW, &bl, &al) + gins(arm.AMOVW, &bh, &ah) + } + + goto olsh_break + } + + regalloc(&s, gc.Types[gc.TUINT32], nil) + regalloc(&creg, gc.Types[gc.TUINT32], nil) + if gc.Is64(r.Type) { + // shift is >= 1<<32 + split64(r, &cl, &ch) + + gmove(&ch, &s) + gins(arm.ATST, &s, nil) + p6 = gc.Gbranch(arm.ABNE, nil, 0) + gmove(&cl, &s) + splitclean() + } else { + gmove(r, &s) + p6 = nil + } + + gins(arm.ATST, &s, nil) + + // shift == 0 + p1 = gins(arm.AMOVW, &bl, &al) + + p1.Scond = arm.C_SCOND_EQ + p1 = gins(arm.AMOVW, &bh, &ah) + p1.Scond = arm.C_SCOND_EQ + p2 = gc.Gbranch(arm.ABEQ, nil, 0) + + // shift is < 32 + gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) + + gmove(&n1, &creg) + gcmp(arm.ACMP, &s, &creg) + + // MOVW.LO bl<>creg, ah + p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah) + + p1.Scond = arm.C_SCOND_LO + + // BLO end + p3 = gc.Gbranch(arm.ABLO, nil, 0) + + // shift == 32 + p1 = gins(arm.AEOR, &al, &al) + + p1.Scond = arm.C_SCOND_EQ + p1 = gins(arm.AMOVW, &bl, &ah) + p1.Scond = arm.C_SCOND_EQ + p4 = gc.Gbranch(arm.ABEQ, nil, 0) + + // shift is < 64 + gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) + + gmove(&n1, &creg) + gcmp(arm.ACMP, &s, &creg) + + // EOR.LO al, al + p1 = gins(arm.AEOR, &al, &al) + + p1.Scond = arm.C_SCOND_LO + + // MOVW.LO creg>>1, creg + p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) + + p1.Scond = arm.C_SCOND_LO + + // SUB.LO creg, s + p1 = gins(arm.ASUB, &creg, &s) + + p1.Scond = arm.C_SCOND_LO + + // MOVW bl<= 64 + if p6 != nil { + gc.Patch(p6, gc.Pc) + } + gins(arm.AEOR, &al, &al) + gins(arm.AEOR, &ah, &ah) + + gc.Patch(p2, gc.Pc) + gc.Patch(p3, gc.Pc) + gc.Patch(p4, gc.Pc) + gc.Patch(p5, gc.Pc) + regfree(&s) + regfree(&creg) + + olsh_break: + regfree(&bl) + regfree(&bh) + + case gc.ORSH: + regalloc(&bl, lo1.Type, nil) + regalloc(&bh, hi1.Type, nil) + gins(arm.AMOVW, &hi1, &bh) + gins(arm.AMOVW, &lo1, &bl) + + if r.Op == gc.OLITERAL { + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + if v >= 64 { + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->31, al + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) + + // MOVW bh->31, ah + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) + } else { + gins(arm.AEOR, &al, &al) + gins(arm.AEOR, &ah, &ah) + } + } else if v > 32 { + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->(v-32), al + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al) + + // MOVW bh->31, ah + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) + } else { + // MOVW bh>>(v-32), al + gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al) + + gins(arm.AEOR, &ah, &ah) + } + } else if v == 32 { + gins(arm.AMOVW, &bh, &al) + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->31, ah + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) + } else { + gins(arm.AEOR, &ah, &ah) + } + } else if v > 0 { + // MOVW bl>>v, al + gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al) + + // OR bh<<(32-v), al + gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al) + + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->v, ah + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah) + } else { + // MOVW bh>>v, ah + gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah) + } + } else { + gins(arm.AMOVW, &bl, &al) + gins(arm.AMOVW, &bh, &ah) + } + + goto orsh_break + } + + regalloc(&s, gc.Types[gc.TUINT32], nil) + regalloc(&creg, gc.Types[gc.TUINT32], nil) + if gc.Is64(r.Type) { + // shift is >= 1<<32 + split64(r, &cl, &ch) + + gmove(&ch, &s) + gins(arm.ATST, &s, nil) + if bh.Type.Etype == gc.TINT32 { + p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) + } else { + p1 = gins(arm.AEOR, &ah, &ah) + } + p1.Scond = arm.C_SCOND_NE + p6 = gc.Gbranch(arm.ABNE, nil, 0) + gmove(&cl, &s) + splitclean() + } else { + gmove(r, &s) + p6 = nil + } + + gins(arm.ATST, &s, nil) + + // shift == 0 + p1 = gins(arm.AMOVW, &bl, &al) + + p1.Scond = arm.C_SCOND_EQ + p1 = gins(arm.AMOVW, &bh, &ah) + p1.Scond = arm.C_SCOND_EQ + p2 = gc.Gbranch(arm.ABEQ, nil, 0) + + // check if shift is < 32 + gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) + + gmove(&n1, &creg) + gcmp(arm.ACMP, &s, &creg) + + // MOVW.LO bl>>s, al + p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al) + + p1.Scond = arm.C_SCOND_LO + + // SUB.LO s,creg + p1 = gins(arm.ASUB, &s, &creg) + + p1.Scond = arm.C_SCOND_LO + + // OR.LO bh<<(32-s), al + p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al) + + p1.Scond = arm.C_SCOND_LO + + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->s, ah + p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah) + } else { + // MOVW bh>>s, ah + p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah) + } + + p1.Scond = arm.C_SCOND_LO + + // BLO end + p3 = gc.Gbranch(arm.ABLO, nil, 0) + + // shift == 32 + p1 = gins(arm.AMOVW, &bh, &al) + + p1.Scond = arm.C_SCOND_EQ + if bh.Type.Etype == gc.TINT32 { + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) + } else { + gins(arm.AEOR, &ah, &ah) + } + p4 = gc.Gbranch(arm.ABEQ, nil, 0) + + // check if shift is < 64 + gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) + + gmove(&n1, &creg) + gcmp(arm.ACMP, &s, &creg) + + // MOVW.LO creg>>1, creg + p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) + + p1.Scond = arm.C_SCOND_LO + + // SUB.LO creg, s + p1 = gins(arm.ASUB, &creg, &s) + + p1.Scond = arm.C_SCOND_LO + + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->(s-32), al + p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al) + + p1.Scond = arm.C_SCOND_LO + } else { + // MOVW bh>>(v-32), al + p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al) + + p1.Scond = arm.C_SCOND_LO + } + + // BLO end + p5 = gc.Gbranch(arm.ABLO, nil, 0) + + // s >= 64 + if p6 != nil { + gc.Patch(p6, gc.Pc) + } + if bh.Type.Etype == gc.TINT32 { + // MOVW bh->31, al + gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) + } else { + gins(arm.AEOR, &al, &al) + } + + gc.Patch(p2, gc.Pc) + gc.Patch(p3, gc.Pc) + gc.Patch(p4, gc.Pc) + gc.Patch(p5, gc.Pc) + regfree(&s) + regfree(&creg) + + orsh_break: + regfree(&bl) + regfree(&bh) + + // TODO(kaib): literal optimizations + // make constant the right side (it usually is anyway). + // if(lo1.op == OLITERAL) { + // nswap(&lo1, &lo2); + // nswap(&hi1, &hi2); + // } + // if(lo2.op == OLITERAL) { + // // special cases for constants. + // lv = mpgetfix(lo2.val.u.xval); + // hv = mpgetfix(hi2.val.u.xval); + // splitclean(); // right side + // split64(res, &lo2, &hi2); + // switch(n->op) { + // case OXOR: + // gmove(&lo1, &lo2); + // gmove(&hi1, &hi2); + // switch(lv) { + // case 0: + // break; + // case 0xffffffffu: + // gins(ANOTL, N, &lo2); + // break; + // default: + // gins(AXORL, ncon(lv), &lo2); + // break; + // } + // switch(hv) { + // case 0: + // break; + // case 0xffffffffu: + // gins(ANOTL, N, &hi2); + // break; + // default: + // gins(AXORL, ncon(hv), &hi2); + // break; + // } + // break; + + // case OAND: + // switch(lv) { + // case 0: + // gins(AMOVL, ncon(0), &lo2); + // break; + // default: + // gmove(&lo1, &lo2); + // if(lv != 0xffffffffu) + // gins(AANDL, ncon(lv), &lo2); + // break; + // } + // switch(hv) { + // case 0: + // gins(AMOVL, ncon(0), &hi2); + // break; + // default: + // gmove(&hi1, &hi2); + // if(hv != 0xffffffffu) + // gins(AANDL, ncon(hv), &hi2); + // break; + // } + // break; + + // case OOR: + // switch(lv) { + // case 0: + // gmove(&lo1, &lo2); + // break; + // case 0xffffffffu: + // gins(AMOVL, ncon(0xffffffffu), &lo2); + // break; + // default: + // gmove(&lo1, &lo2); + // gins(AORL, ncon(lv), &lo2); + // break; + // } + // switch(hv) { + // case 0: + // gmove(&hi1, &hi2); + // break; + // case 0xffffffffu: + // gins(AMOVL, ncon(0xffffffffu), &hi2); + // break; + // default: + // gmove(&hi1, &hi2); + // gins(AORL, ncon(hv), &hi2); + // break; + // } + // break; + // } + // splitclean(); + // splitclean(); + // goto out; + // } + case gc.OXOR, + gc.OAND, + gc.OOR: + regalloc(&n1, lo1.Type, nil) + + gins(arm.AMOVW, &lo1, &al) + gins(arm.AMOVW, &hi1, &ah) + gins(arm.AMOVW, &lo2, &n1) + gins(optoas(int(n.Op), lo1.Type), &n1, &al) + gins(arm.AMOVW, &hi2, &n1) + gins(optoas(int(n.Op), lo1.Type), &n1, &ah) + regfree(&n1) + } + + if gc.Is64(r.Type) { + splitclean() + } + splitclean() + + split64(res, &lo1, &hi1) + gins(arm.AMOVW, &al, &lo1) + gins(arm.AMOVW, &ah, &hi1) + splitclean() + + //out: + regfree(&al) + + regfree(&ah) +} + +/* + * generate comparison of nl, nr, both 64-bit. + * nl is memory; nr is constant or memory. + */ +func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) { + var lo1 gc.Node + var hi1 gc.Node + var lo2 gc.Node + var hi2 gc.Node + var r1 gc.Node + var r2 gc.Node + var br *obj.Prog + var t *gc.Type + + split64(nl, &lo1, &hi1) + split64(nr, &lo2, &hi2) + + // compare most significant word; + // if they differ, we're done. + t = hi1.Type + + regalloc(&r1, gc.Types[gc.TINT32], nil) + regalloc(&r2, gc.Types[gc.TINT32], nil) + gins(arm.AMOVW, &hi1, &r1) + gins(arm.AMOVW, &hi2, &r2) + gcmp(arm.ACMP, &r1, &r2) + regfree(&r1) + regfree(&r2) + + br = nil + switch op { + default: + gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + // cmp hi + // bne L + // cmp lo + // beq to + // L: + case gc.OEQ: + br = gc.Gbranch(arm.ABNE, nil, -likely) + + // cmp hi + // bne to + // cmp lo + // bne to + case gc.ONE: + gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to) + + // cmp hi + // bgt to + // blt L + // cmp lo + // bge to (or bgt to) + // L: + case gc.OGE, + gc.OGT: + gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) + + br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) + + // cmp hi + // blt to + // bgt L + // cmp lo + // ble to (or jlt to) + // L: + case gc.OLE, + gc.OLT: + gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) + + br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) + } + + // compare least significant word + t = lo1.Type + + regalloc(&r1, gc.Types[gc.TINT32], nil) + regalloc(&r2, gc.Types[gc.TINT32], nil) + gins(arm.AMOVW, &lo1, &r1) + gins(arm.AMOVW, &lo2, &r2) + gcmp(arm.ACMP, &r1, &r2) + regfree(&r1) + regfree(&r2) + + // jump again + gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) + + // point first branch down here if appropriate + if br != nil { + gc.Patch(br, gc.Pc) + } + + splitclean() + splitclean() +} diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go deleted file mode 100644 index aebdcab712..0000000000 --- a/src/cmd/5g/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -5g is the version of the gc compiler for the ARM. -The $GOARCH for these tools is arm. - -It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go. - -*/ -package main diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c deleted file mode 100644 index c4d74f0a71..0000000000 --- a/src/cmd/5g/galign.c +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -int thechar = '5'; -char* thestring = "arm"; -LinkArch* thelinkarch = &linkarm; - -void -linkarchinit(void) -{ -} - -vlong MAXWIDTH = (1LL<<32) - 1; - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -Typedef typedefs[] = -{ - {"int", TINT, TINT32}, - {"uint", TUINT, TUINT32}, - {"uintptr", TUINTPTR, TUINT32}, - {0} -}; - -void -betypeinit(void) -{ - widthptr = 4; - widthint = 4; - widthreg = 4; - - listinit5(); -} - -void -main(int argc, char **argv) -{ - thearch.thechar = thechar; - thearch.thestring = thestring; - thearch.thelinkarch = thelinkarch; - thearch.typedefs = typedefs; - thearch.REGSP = REGSP; - thearch.REGCTXT = REGCTXT; - thearch.MAXWIDTH = MAXWIDTH; - thearch.anyregalloc = anyregalloc; - thearch.betypeinit = betypeinit; - thearch.bgen = bgen; - thearch.cgen = cgen; - thearch.cgen_call = cgen_call; - thearch.cgen_callinter = cgen_callinter; - thearch.cgen_ret = cgen_ret; - thearch.clearfat = clearfat; - thearch.defframe = defframe; - thearch.excise = excise; - thearch.expandchecks = expandchecks; - thearch.gclean = gclean; - thearch.ginit = ginit; - thearch.gins = gins; - thearch.ginscall = ginscall; - thearch.igen = igen; - thearch.linkarchinit = linkarchinit; - thearch.peep = peep; - thearch.proginfo = proginfo; - thearch.regalloc = regalloc; - thearch.regfree = regfree; - thearch.regtyp = regtyp; - thearch.sameaddr = sameaddr; - thearch.smallindir = smallindir; - thearch.stackaddr = stackaddr; - thearch.excludedregs = excludedregs; - thearch.RtoB = RtoB; - thearch.FtoB = RtoB; - thearch.BtoR = BtoR; - thearch.BtoF = BtoF; - thearch.optoas = optoas; - thearch.doregbits = doregbits; - thearch.regnames = regnames; - - gcmain(argc, argv); -} diff --git a/src/cmd/5g/galign.go b/src/cmd/5g/galign.go new file mode 100644 index 0000000000..d2eeeab456 --- /dev/null +++ b/src/cmd/5g/galign.go @@ -0,0 +1,85 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" +) +import "cmd/internal/gc" + +var thechar int = '5' + +var thestring string = "arm" + +var thelinkarch *obj.LinkArch = &arm.Linkarm + +func linkarchinit() { +} + +var MAXWIDTH int64 = (1 << 32) - 1 + +/* + * go declares several platform-specific type aliases: + * int, uint, float, and uintptr + */ +var typedefs = []gc.Typedef{ + gc.Typedef{"int", gc.TINT, gc.TINT32}, + gc.Typedef{"uint", gc.TUINT, gc.TUINT32}, + gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32}, +} + +func betypeinit() { + gc.Widthptr = 4 + gc.Widthint = 4 + gc.Widthreg = 4 + +} + +func main() { + gc.Thearch.Thechar = thechar + gc.Thearch.Thestring = thestring + gc.Thearch.Thelinkarch = thelinkarch + gc.Thearch.Typedefs = typedefs + gc.Thearch.REGSP = arm.REGSP + gc.Thearch.REGCTXT = arm.REGCTXT + gc.Thearch.MAXWIDTH = MAXWIDTH + gc.Thearch.Anyregalloc = anyregalloc + gc.Thearch.Betypeinit = betypeinit + gc.Thearch.Bgen = bgen + gc.Thearch.Cgen = cgen + gc.Thearch.Cgen_call = cgen_call + gc.Thearch.Cgen_callinter = cgen_callinter + gc.Thearch.Cgen_ret = cgen_ret + gc.Thearch.Clearfat = clearfat + gc.Thearch.Defframe = defframe + gc.Thearch.Excise = excise + gc.Thearch.Expandchecks = expandchecks + gc.Thearch.Gclean = gclean + gc.Thearch.Ginit = ginit + gc.Thearch.Gins = gins + gc.Thearch.Ginscall = ginscall + gc.Thearch.Igen = igen + gc.Thearch.Linkarchinit = linkarchinit + gc.Thearch.Peep = peep + gc.Thearch.Proginfo = proginfo + gc.Thearch.Regalloc = regalloc + gc.Thearch.Regfree = regfree + gc.Thearch.Regtyp = regtyp + gc.Thearch.Sameaddr = sameaddr + gc.Thearch.Smallindir = smallindir + gc.Thearch.Stackaddr = stackaddr + gc.Thearch.Excludedregs = excludedregs + gc.Thearch.RtoB = RtoB + gc.Thearch.FtoB = RtoB + gc.Thearch.BtoR = BtoR + gc.Thearch.BtoF = BtoF + gc.Thearch.Optoas = optoas + gc.Thearch.Doregbits = doregbits + gc.Thearch.Regnames = regnames + + gc.Main() + gc.Exit(0) +} diff --git a/src/cmd/5g/gg.go b/src/cmd/5g/gg.go new file mode 100644 index 0000000000..7a7fb3b774 --- /dev/null +++ b/src/cmd/5g/gg.go @@ -0,0 +1,32 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "cmd/internal/obj/arm" + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +const ( + REGALLOC_R0 = arm.REG_R0 + REGALLOC_RMAX = arm.REGEXT + REGALLOC_F0 = arm.REG_F0 + REGALLOC_FMAX = arm.FREGEXT +) + +var reg [REGALLOC_FMAX + 1]uint8 + +/* + * cgen + */ + +/* + * list.c + */ + +/* + * reg.c + */ diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h deleted file mode 100644 index b12c7e2561..0000000000 --- a/src/cmd/5g/gg.h +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef EXTERN -#define EXTERN extern -#endif - -#include "../gc/go.h" -#include "../5l/5.out.h" - -enum -{ - REGALLOC_R0 = REG_R0, - REGALLOC_RMAX = REGEXT, - REGALLOC_F0 = REG_F0, - REGALLOC_FMAX = FREGEXT, -}; - -EXTERN uchar reg[REGALLOC_FMAX+1]; -extern long unmappedzero; - -/* - * gen.c - */ -void compile(Node*); -void gen(Node*); -Node* lookdot(Node*, Node*, int); -void cgen_as(Node*, Node*); -void cgen_callmeth(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_proc(Node*, int); -void cgen_callret(Node*, Node*); -void cgen_dcl(Node*); -int needconvert(Type*, Type*); -void genconv(Type*, Type*); -void allocparams(void); -void checklabels(void); -void ginscall(Node*, int); - -/* - * cgen - */ -void agen(Node*, Node*); -Prog* cgenindex(Node *, Node *, int); -void igen(Node*, Node*, Node*); -void agenr(Node *n, Node *a, Node *res); -vlong fieldoffset(Type*, Node*); -void sgen(Node*, Node*, int64); -void gmove(Node*, Node*); -Prog* gins(int, Node*, Node*); -int samaddr(Node*, Node*); -void raddr(Node *n, Prog *p); -Prog* gcmp(int, Node*, Node*); -Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs); -Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs); -void naddr(Node*, Addr*, int); -void cgen_aret(Node*, Node*); -void cgen_hmul(Node*, Node*, Node*); -void cgen_shift(int, int, Node*, Node*, Node*); -int componentgen(Node*, Node*); - -/* - * cgen64.c - */ -void cmp64(Node*, Node*, int, int, Prog*); -void cgen64(Node*, Node*); - -/* - * gsubr.c - */ -void clearp(Prog*); -Prog* gbranch(int, Type*, int); -Prog* prog(int); -void gconv(int, int); -int conv2pt(Type*); -vlong convvtox(vlong, int); -void fnparam(Type*, int, int); -Prog* gop(int, Node*, Node*, Node*); -int optoas(int, Type*); -void ginit(void); -void gclean(void); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -Node* nodarg(Type*, int); -void nodreg(Node*, Type*, int); -void nodindreg(Node*, Type*, int); -void buildtxt(void); -Plist* newplist(void); -int isfat(Type*); -int dotaddable(Node*, Node*); -void sudoclean(void); -int sudoaddable(int, Node*, Addr*, int*); -void afunclit(Addr*, Node*); -void datagostring(Strlit*, Addr*); -void split64(Node*, Node*, Node*); -void splitclean(void); -Node* ncon(uint32 i); -void gtrack(Sym*); - -/* - * obj.c - */ -void datastring(char*, int, Addr*); - -/* - * list.c - */ -void listinit(void); - -void zaddr(Biobuf*, Addr*, int, int); - -void afunclit(Addr*, Node*); -int anyregalloc(void); -void betypeinit(void); -void bgen(Node*, int, int, Prog*); -void cgen(Node*, Node*); -void cgen_call(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_ret(Node*); -void clearfat(Node*); -void clearp(Prog*); -void defframe(Prog*); -int dgostringptr(Sym*, int, char*); -int dgostrlitptr(Sym*, int, Strlit*); -int dsname(Sym*, int, char*, int); -int dsymptr(Sym*, int, Sym*, int); -void dumpdata(void); -void dumpit(char*, Flow*, int); -void excise(Flow*); -void expandchecks(Prog*); -void fixautoused(Prog*); -void gclean(void); -void gdata(Node*, Node*, int); -void gdatacomplex(Node*, Mpcplx*); -void gdatastring(Node*, Strlit*); -void ggloblnod(Node *nam); -void ggloblsym(Sym *s, int32 width, int8 flags); -void ginit(void); -Prog* gins(int, Node*, Node*); -void ginscall(Node*, int); -Prog* gjmp(Prog*); -void gtrack(Sym*); -void gused(Node*); -void igen(Node*, Node*, Node*); -int isfat(Type*); -void linkarchinit(void); -void markautoused(Prog*); -void naddr(Node*, Addr*, int); -Plist* newplist(void); -Node* nodarg(Type*, int); -void patch(Prog*, Prog*); -void proginfo(ProgInfo*, Prog*); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -void regopt(Prog*); -int regtyp(Addr*); -int sameaddr(Addr*, Addr*); -int smallindir(Addr*, Addr*); -int stackaddr(Addr*); -Prog* unpatch(Prog*); - -/* - * reg.c - */ -uint64 excludedregs(void); -uint64 RtoB(int); -uint64 FtoB(int); -int BtoR(uint64); -int BtoF(uint64); -uint64 doregbits(int); -char** regnames(int*); - -/* - * peep.c - */ -void peep(Prog*); diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c deleted file mode 100644 index 62b9beadb0..0000000000 --- a/src/cmd/5g/ggen.c +++ /dev/null @@ -1,751 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#undef EXTERN -#define EXTERN -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32); -static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0); - -void -defframe(Prog *ptxt) -{ - uint32 frame, r0; - Prog *p; - vlong hi, lo; - NodeList *l; - Node *n; - - // fill in argument size, stack size - ptxt->to.type = TYPE_TEXTSIZE; - ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr); - frame = rnd(stksize+maxarg, widthreg); - ptxt->to.offset = frame; - - // insert code to contain ambiguously live variables - // so that garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt; - lo = hi = 0; - r0 = 0; - for(l=curfn->dcl; l != nil; l = l->next) { - n = l->n; - if(!n->needzero) - continue; - if(n->class != PAUTO) - fatal("needzero class %d", n->class); - if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) - fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); - if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) { - // merge with range we already have - lo = rnd(n->xoffset, widthptr); - continue; - } - // zero old range - p = zerorange(p, frame, lo, hi, &r0); - - // set new range - hi = n->xoffset + n->type->width; - lo = n->xoffset; - } - // zero final range - zerorange(p, frame, lo, hi, &r0); -} - -static Prog* -zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0) -{ - vlong cnt, i; - Prog *p1; - Node *f; - - cnt = hi - lo; - if(cnt == 0) - return p; - if(*r0 == 0) { - p = appendpp(p, AMOVW, TYPE_CONST, 0, 0, TYPE_REG, REG_R0, 0); - *r0 = 1; - } - if(cnt < 4*widthptr) { - for(i = 0; i < cnt; i += widthptr) - p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REGSP, 4+frame+lo+i); - } else if(!nacl && (cnt <= 128*widthptr)) { - p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0); - p->reg = REGSP; - p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0); - f = sysfunc("duffzero"); - naddr(f, &p->to, 1); - afunclit(&p->to, f); - p->to.offset = 4*(128-cnt/widthptr); - } else { - p = appendpp(p, AADD, TYPE_CONST, 0, 4+frame+lo, TYPE_REG, REG_R1, 0); - p->reg = REGSP; - p = appendpp(p, AADD, TYPE_CONST, 0, cnt, TYPE_REG, REG_R2, 0); - p->reg = REG_R1; - p1 = p = appendpp(p, AMOVW, TYPE_REG, REG_R0, 0, TYPE_MEM, REG_R1, 4); - p->scond |= C_PBIT; - p = appendpp(p, ACMP, TYPE_REG, REG_R1, 0, TYPE_NONE, 0, 0); - p->reg = REG_R2; - p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0); - patch(p, p1); - } - return p; -} - -static Prog* -appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset) -{ - Prog *q; - - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) - */ -void -ginscall(Node *f, int proc) -{ - Prog *p; - Node r, r1, con; - int32 extra; - - if(f->type != T) { - extra = 0; - if(proc == 1 || proc == 2) - extra = 2 * widthptr; - setmaxarg(f->type, extra); - } - - switch(proc) { - default: - fatal("ginscall: bad proc %d", proc); - break; - - case 0: // normal call - case -1: // normal call but no return - if(f->op == ONAME && f->class == PFUNC) { - if(f == deferreturn) { - // Deferred calls will appear to be returning to - // the BL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction before that return PC. - // To avoid that instruction being an unrelated instruction, - // insert a NOP so that we will have the right line number. - // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0. - // Use the latter form because the NOP pseudo-instruction - // would be removed by the linker. - nodreg(&r, types[TINT], REG_R0); - p = gins(AAND, &r, &r); - p->scond = C_SCOND_EQ; - } - p = gins(ABL, N, f); - afunclit(&p->to, f); - if(proc == -1 || noreturn(p)) - gins(AUNDEF, N, N); - break; - } - nodreg(&r, types[tptr], REG_R7); - nodreg(&r1, types[tptr], REG_R1); - gmove(f, &r); - r.op = OINDREG; - gmove(&r, &r1); - r.op = OREGISTER; - r1.op = OINDREG; - gins(ABL, &r, &r1); - break; - - case 3: // normal call of c function pointer - gins(ABL, N, f); - break; - - case 1: // call in new proc (go) - case 2: // deferred call (defer) - regalloc(&r, types[tptr], N); - nodconst(&con, types[TINT32], argsize(f->type)); - gins(AMOVW, &con, &r); - p = gins(AMOVW, &r, N); - p->to.type = TYPE_MEM; - p->to.reg = REGSP; - p->to.offset = 4; - - gins(AMOVW, f, &r); - p = gins(AMOVW, &r, N); - p->to.type = TYPE_MEM; - p->to.reg = REGSP; - p->to.offset = 8; - - regfree(&r); - - if(proc == 1) - ginscall(newproc, 0); - else - ginscall(deferproc, 0); - - if(proc == 2) { - nodconst(&con, types[TINT32], 0); - p = gins(ACMP, &con, N); - p->reg = REG_R0; - p = gbranch(ABEQ, T, +1); - cgen_ret(N); - patch(p, pc); - } - break; - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -void -cgen_callinter(Node *n, Node *res, int proc) -{ - int r; - Node *i, *f; - Node tmpi, nodo, nodr, nodsp; - Prog *p; - - i = n->left; - if(i->op != ODOTINTER) - fatal("cgen_callinter: not ODOTINTER %O", i->op); - - f = i->right; // field - if(f->op != ONAME) - fatal("cgen_callinter: not ONAME %O", f->op); - - i = i->left; // interface - - // Release res register during genlist and cgen, - // which might have their own function calls. - r = -1; - if(res != N && (res->op == OREGISTER || res->op == OINDREG)) { - r = res->val.u.reg; - reg[r]--; - } - - if(!i->addable) { - tempname(&tmpi, i->type); - cgen(i, &tmpi); - i = &tmpi; - } - - genlist(n->list); // args - if(r >= 0) - reg[r]++; - - regalloc(&nodr, types[tptr], res); - regalloc(&nodo, types[tptr], &nodr); - nodo.op = OINDREG; - - agen(i, &nodr); // REG = &inter - - nodindreg(&nodsp, types[tptr], REGSP); - nodsp.xoffset = widthptr; - if(proc != 0) - nodsp.xoffset += 2 * widthptr; // leave room for size & fn - nodo.xoffset += widthptr; - cgen(&nodo, &nodsp); // {4 or 12}(SP) = 4(REG) -- i.data - - nodo.xoffset -= widthptr; - cgen(&nodo, &nodr); // REG = 0(REG) -- i.tab - cgen_checknil(&nodr); // in case offset is huge - - nodo.xoffset = n->left->xoffset + 3*widthptr + 8; - - if(proc == 0) { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] - nodr.op = OINDREG; - proc = 3; - } else { - // go/defer. generate go func value. - p = gins(AMOVW, &nodo, &nodr); - p->from.type = TYPE_ADDR; // REG = &(20+offset(REG)) -- i.tab->fun[f] - } - - nodr.type = n->left->type; - ginscall(&nodr, proc); - - regfree(&nodr); - regfree(&nodo); -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -void -cgen_call(Node *n, int proc) -{ - Type *t; - Node nod, afun; - - if(n == N) - return; - - if(n->left->ullman >= UINF) { - // if name involves a fn call - // precompute the address of the fn - tempname(&afun, types[tptr]); - cgen(n->left, &afun); - } - - genlist(n->list); // assign the args - t = n->left->type; - - // call tempname pointer - if(n->left->ullman >= UINF) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, &afun); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - goto ret; - } - - // call pointer - if(n->left->op != ONAME || n->left->class != PFUNC) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, n->left); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - goto ret; - } - - // call direct - n->left->method = 1; - ginscall(n->left, proc); - - -ret: - ; -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -void -cgen_callret(Node *n, Node *res) -{ - Node nod; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(t->etype == TPTR32 || t->etype == TPTR64) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_callret: nil"); - - memset(&nod, 0, sizeof(nod)); - nod.op = OINDREG; - nod.val.u.reg = REGSP; - nod.addable = 1; - - nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP) - nod.type = fp->type; - cgen_as(res, &nod); -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -void -cgen_aret(Node *n, Node *res) -{ - Node nod1, nod2; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_aret: nil"); - - memset(&nod1, 0, sizeof(nod1)); - nod1.op = OINDREG; - nod1.val.u.reg = REGSP; - nod1.addable = 1; - - nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP) - nod1.type = fp->type; - - if(res->op != OREGISTER) { - regalloc(&nod2, types[tptr], res); - agen(&nod1, &nod2); - gins(AMOVW, &nod2, res); - regfree(&nod2); - } else - agen(&nod1, res); -} - -/* - * generate return. - * n->left is assignments to return values. - */ -void -cgen_ret(Node *n) -{ - Prog *p; - - if(n != N) - genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - genlist(curfn->exit); - p = gins(ARET, N, N); - if(n != N && n->op == ORETJMP) { - p->to.name = NAME_EXTERN; - p->to.type = TYPE_ADDR; - p->to.sym = linksym(n->left->sym); - } -} - -/* - * generate high multiply - * res = (nl * nr) >> wordsize - */ -void -cgen_hmul(Node *nl, Node *nr, Node *res) -{ - int w; - Node n1, n2, *tmp; - Type *t; - Prog *p; - - if(nl->ullman < nr->ullman) { - tmp = nl; - nl = nr; - nr = tmp; - } - t = nl->type; - w = t->width * 8; - regalloc(&n1, t, res); - cgen(nl, &n1); - regalloc(&n2, t, N); - cgen(nr, &n2); - switch(simtype[t->etype]) { - case TINT8: - case TINT16: - gins(optoas(OMUL, t), &n2, &n1); - gshift(AMOVW, &n1, SHIFT_AR, w, &n1); - break; - case TUINT8: - case TUINT16: - gins(optoas(OMUL, t), &n2, &n1); - gshift(AMOVW, &n1, SHIFT_LR, w, &n1); - break; - case TINT32: - case TUINT32: - // perform a long multiplication. - if(issigned[t->etype]) - p = gins(AMULL, &n2, N); - else - p = gins(AMULLU, &n2, N); - // n2 * n1 -> (n1 n2) - p->reg = n1.val.u.reg; - p->to.type = TYPE_REGREG; - p->to.reg = n1.val.u.reg; - p->to.offset = n2.val.u.reg; - break; - default: - fatal("cgen_hmul %T", t); - break; - } - cgen(&n1, res); - regfree(&n1); - regfree(&n2); -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -void -cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3, nt, t, lo, hi; - int w, v; - Prog *p1, *p2, *p3; - Type *tr; - uvlong sc; - - USED(bounded); - if(nl->type->width > 4) - fatal("cgen_shift %T", nl->type); - - w = nl->type->width * 8; - - if(op == OLROT) { - v = mpgetfix(nr->val.u.xval); - regalloc(&n1, nl->type, res); - if(w == 32) { - cgen(nl, &n1); - gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1); - } else { - regalloc(&n2, nl->type, N); - cgen(nl, &n2); - gshift(AMOVW, &n2, SHIFT_LL, v, &n1); - gshift(AORR, &n2, SHIFT_LR, w-v, &n1); - regfree(&n2); - // Ensure sign/zero-extended result. - gins(optoas(OAS, nl->type), &n1, &n1); - } - gmove(&n1, res); - regfree(&n1); - return; - } - - if(nr->op == OLITERAL) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - sc = mpgetfix(nr->val.u.xval); - if(sc == 0) { - // nothing to do - } else if(sc >= nl->type->width*8) { - if(op == ORSH && issigned[nl->type->etype]) - gshift(AMOVW, &n1, SHIFT_AR, w, &n1); - else - gins(AEOR, &n1, &n1); - } else { - if(op == ORSH && issigned[nl->type->etype]) - gshift(AMOVW, &n1, SHIFT_AR, sc, &n1); - else if(op == ORSH) - gshift(AMOVW, &n1, SHIFT_LR, sc, &n1); - else // OLSH - gshift(AMOVW, &n1, SHIFT_LL, sc, &n1); - } - if(w < 32 && op == OLSH) - gins(optoas(OAS, nl->type), &n1, &n1); - gmove(&n1, res); - regfree(&n1); - return; - } - - tr = nr->type; - if(tr->width > 4) { - tempname(&nt, nr->type); - if(nl->ullman >= nr->ullman) { - regalloc(&n2, nl->type, res); - cgen(nl, &n2); - cgen(nr, &nt); - n1 = nt; - } else { - cgen(nr, &nt); - regalloc(&n2, nl->type, res); - cgen(nl, &n2); - } - split64(&nt, &lo, &hi); - regalloc(&n1, types[TUINT32], N); - regalloc(&n3, types[TUINT32], N); - gmove(&lo, &n1); - gmove(&hi, &n3); - splitclean(); - gins(ATST, &n3, N); - nodconst(&t, types[TUINT32], w); - p1 = gins(AMOVW, &t, &n1); - p1->scond = C_SCOND_NE; - tr = types[TUINT32]; - regfree(&n3); - } else { - if(nl->ullman >= nr->ullman) { - regalloc(&n2, nl->type, res); - cgen(nl, &n2); - regalloc(&n1, nr->type, N); - cgen(nr, &n1); - } else { - regalloc(&n1, nr->type, N); - cgen(nr, &n1); - regalloc(&n2, nl->type, res); - cgen(nl, &n2); - } - } - - // test for shift being 0 - gins(ATST, &n1, N); - p3 = gbranch(ABEQ, T, -1); - - // test and fix up large shifts - // TODO: if(!bounded), don't emit some of this. - regalloc(&n3, tr, N); - nodconst(&t, types[TUINT32], w); - gmove(&t, &n3); - gcmp(ACMP, &n1, &n3); - if(op == ORSH) { - if(issigned[nl->type->etype]) { - p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2); - p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2); - } else { - p1 = gins(AEOR, &n2, &n2); - p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2); - } - p1->scond = C_SCOND_HS; - p2->scond = C_SCOND_LO; - } else { - p1 = gins(AEOR, &n2, &n2); - p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2); - p1->scond = C_SCOND_HS; - p2->scond = C_SCOND_LO; - } - regfree(&n3); - - patch(p3, pc); - // Left-shift of smaller word must be sign/zero-extended. - if(w < 32 && op == OLSH) - gins(optoas(OAS, nl->type), &n2, &n2); - gmove(&n2, res); - - regfree(&n1); - regfree(&n2); -} - -void -clearfat(Node *nl) -{ - uint32 w, c, q; - Node dst, nc, nz, end, r0, r1, *f; - Prog *p, *pl; - - /* clear a fat object */ - if(debug['g']) - dump("\nclearfat", nl); - - w = nl->type->width; - // Avoid taking the address for simple enough types. - if(componentgen(N, nl)) - return; - - c = w % 4; // bytes - q = w / 4; // quads - - r0.op = OREGISTER; - r0.val.u.reg = REGALLOC_R0; - r1.op = OREGISTER; - r1.val.u.reg = REGALLOC_R0 + 1; - regalloc(&dst, types[tptr], &r1); - agen(nl, &dst); - nodconst(&nc, types[TUINT32], 0); - regalloc(&nz, types[TUINT32], &r0); - cgen(&nc, &nz); - - if(q > 128) { - regalloc(&end, types[tptr], N); - p = gins(AMOVW, &dst, &end); - p->from.type = TYPE_ADDR; - p->from.offset = q*4; - - p = gins(AMOVW, &nz, &dst); - p->to.type = TYPE_MEM; - p->to.offset = 4; - p->scond |= C_PBIT; - pl = p; - - p = gins(ACMP, &dst, N); - raddr(&end, p); - patch(gbranch(ABNE, T, 0), pl); - - regfree(&end); - } else if(q >= 4 && !nacl) { - f = sysfunc("duffzero"); - p = gins(ADUFFZERO, N, f); - afunclit(&p->to, f); - // 4 and 128 = magic constants: see ../../runtime/asm_arm.s - p->to.offset = 4*(128-q); - } else - while(q > 0) { - p = gins(AMOVW, &nz, &dst); - p->to.type = TYPE_MEM; - p->to.offset = 4; - p->scond |= C_PBIT; -//print("1. %P\n", p); - q--; - } - - while(c > 0) { - p = gins(AMOVB, &nz, &dst); - p->to.type = TYPE_MEM; - p->to.offset = 1; - p->scond |= C_PBIT; -//print("2. %P\n", p); - c--; - } - regfree(&dst); - regfree(&nz); -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -void -expandchecks(Prog *firstp) -{ - int reg; - Prog *p, *p1; - - for(p = firstp; p != P; p = p->link) { - if(p->as != ACHECKNIL) - continue; - if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers - warnl(p->lineno, "generated nil check"); - if(p->from.type != TYPE_REG) - fatal("invalid nil check %P", p); - reg = p->from.reg; - // check is - // CMP arg, $0 - // MOV.EQ arg, 0(arg) - p1 = mal(sizeof *p1); - clearp(p1); - p1->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - p1->pc = 9999; - p1->as = AMOVW; - p1->from.type = TYPE_REG; - p1->from.reg = reg; - p1->to.type = TYPE_MEM; - p1->to.reg = reg; - p1->to.offset = 0; - p1->scond = C_SCOND_EQ; - p->as = ACMP; - p->from.type = TYPE_CONST; - p->from.reg = 0; - p->from.offset = 0; - p->reg = reg; - } -} diff --git a/src/cmd/5g/ggen.go b/src/cmd/5g/ggen.go new file mode 100644 index 0000000000..3b007d8484 --- /dev/null +++ b/src/cmd/5g/ggen.go @@ -0,0 +1,822 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" +) +import "cmd/internal/gc" + +func defframe(ptxt *obj.Prog) { + var frame uint32 + var r0 uint32 + var p *obj.Prog + var hi int64 + var lo int64 + var l *gc.NodeList + var n *gc.Node + + // fill in argument size, stack size + ptxt.To.Type = obj.TYPE_TEXTSIZE + + ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) + frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) + ptxt.To.Offset = int64(frame) + + // insert code to contain ambiguously live variables + // so that garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt + + hi = 0 + lo = hi + r0 = 0 + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + n = l.N + if n.Needzero == 0 { + continue + } + if n.Class != gc.PAUTO { + gc.Fatal("needzero class %d", n.Class) + } + if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { + gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) + } + if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) { + // merge with range we already have + lo = gc.Rnd(n.Xoffset, int64(gc.Widthptr)) + + continue + } + + // zero old range + p = zerorange(p, int64(frame), lo, hi, &r0) + + // set new range + hi = n.Xoffset + n.Type.Width + + lo = n.Xoffset + } + + // zero final range + zerorange(p, int64(frame), lo, hi, &r0) +} + +func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Prog { + var cnt int64 + var i int64 + var p1 *obj.Prog + var f *gc.Node + + cnt = hi - lo + if cnt == 0 { + return p + } + if *r0 == 0 { + p = appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0) + *r0 = 1 + } + + if cnt < int64(4*gc.Widthptr) { + for i = 0; i < cnt; i += int64(gc.Widthptr) { + p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, int32(4+frame+lo+i)) + } + } else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) { + p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0) + p.Reg = arm.REGSP + p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) + f = gc.Sysfunc("duffzero") + gc.Naddr(f, &p.To, 1) + gc.Afunclit(&p.To, f) + p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) + } else { + p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0) + p.Reg = arm.REGSP + p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(cnt), obj.TYPE_REG, arm.REG_R2, 0) + p.Reg = arm.REG_R1 + p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4) + p1 = p + p.Scond |= arm.C_PBIT + p = appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0) + p.Reg = arm.REG_R2 + p = appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0) + gc.Patch(p, p1) + } + + return p +} + +func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int32, ttype int, treg int, toffset int32) *obj.Prog { + var q *obj.Prog + + q = gc.Ctxt.NewProg() + gc.Clearp(q) + q.As = int16(as) + q.Lineno = p.Lineno + q.From.Type = int16(ftype) + q.From.Reg = int16(freg) + q.From.Offset = int64(foffset) + q.To.Type = int16(ttype) + q.To.Reg = int16(treg) + q.To.Offset = int64(toffset) + q.Link = p.Link + p.Link = q + return q +} + +/* + * generate: + * call f + * proc=-1 normal call but no return + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + * proc=3 normal call to C pointer (not Go func value) +*/ +func ginscall(f *gc.Node, proc int) { + var p *obj.Prog + var r gc.Node + var r1 gc.Node + var con gc.Node + var extra int32 + + if f.Type != nil { + extra = 0 + if proc == 1 || proc == 2 { + extra = 2 * int32(gc.Widthptr) + } + gc.Setmaxarg(f.Type, extra) + } + + switch proc { + default: + gc.Fatal("ginscall: bad proc %d", proc) + + case 0, // normal call + -1: // normal call but no return + if f.Op == gc.ONAME && f.Class == gc.PFUNC { + if f == gc.Deferreturn { + // Deferred calls will appear to be returning to + // the BL deferreturn(SB) that we are about to emit. + // However, the stack trace code will show the line + // of the instruction before that return PC. + // To avoid that instruction being an unrelated instruction, + // insert a NOP so that we will have the right line number. + // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0. + // Use the latter form because the NOP pseudo-instruction + // would be removed by the linker. + gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0) + + p = gins(arm.AAND, &r, &r) + p.Scond = arm.C_SCOND_EQ + } + + p = gins(arm.ABL, nil, f) + gc.Afunclit(&p.To, f) + if proc == -1 || gc.Noreturn(p) { + gins(obj.AUNDEF, nil, nil) + } + break + } + + gc.Nodreg(&r, gc.Types[gc.Tptr], arm.REG_R7) + gc.Nodreg(&r1, gc.Types[gc.Tptr], arm.REG_R1) + gmove(f, &r) + r.Op = gc.OINDREG + gmove(&r, &r1) + r.Op = gc.OREGISTER + r1.Op = gc.OINDREG + gins(arm.ABL, &r, &r1) + + case 3: // normal call of c function pointer + gins(arm.ABL, nil, f) + + case 1, // call in new proc (go) + 2: // deferred call (defer) + regalloc(&r, gc.Types[gc.Tptr], nil) + + gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type))) + gins(arm.AMOVW, &con, &r) + p = gins(arm.AMOVW, &r, nil) + p.To.Type = obj.TYPE_MEM + p.To.Reg = arm.REGSP + p.To.Offset = 4 + + gins(arm.AMOVW, f, &r) + p = gins(arm.AMOVW, &r, nil) + p.To.Type = obj.TYPE_MEM + p.To.Reg = arm.REGSP + p.To.Offset = 8 + + regfree(&r) + + if proc == 1 { + ginscall(gc.Newproc, 0) + } else { + ginscall(gc.Deferproc, 0) + } + + if proc == 2 { + gc.Nodconst(&con, gc.Types[gc.TINT32], 0) + p = gins(arm.ACMP, &con, nil) + p.Reg = arm.REG_R0 + p = gc.Gbranch(arm.ABEQ, nil, +1) + cgen_ret(nil) + gc.Patch(p, gc.Pc) + } + } +} + +/* + * n is call to interface method. + * generate res = n. + */ +func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { + var r int + var i *gc.Node + var f *gc.Node + var tmpi gc.Node + var nodo gc.Node + var nodr gc.Node + var nodsp gc.Node + var p *obj.Prog + + i = n.Left + if i.Op != gc.ODOTINTER { + gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) + } + + f = i.Right // field + if f.Op != gc.ONAME { + gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) + } + + i = i.Left // interface + + // Release res register during genlist and cgen, + // which might have their own function calls. + r = -1 + + if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { + r = int(res.Val.U.Reg) + reg[r]-- + } + + if i.Addable == 0 { + gc.Tempname(&tmpi, i.Type) + cgen(i, &tmpi) + i = &tmpi + } + + gc.Genlist(n.List) // args + if r >= 0 { + reg[r]++ + } + + regalloc(&nodr, gc.Types[gc.Tptr], res) + regalloc(&nodo, gc.Types[gc.Tptr], &nodr) + nodo.Op = gc.OINDREG + + agen(i, &nodr) // REG = &inter + + gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], arm.REGSP) + + nodsp.Xoffset = int64(gc.Widthptr) + if proc != 0 { + nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn + } + nodo.Xoffset += int64(gc.Widthptr) + cgen(&nodo, &nodsp) // {4 or 12}(SP) = 4(REG) -- i.data + + nodo.Xoffset -= int64(gc.Widthptr) + + cgen(&nodo, &nodr) // REG = 0(REG) -- i.tab + gc.Cgen_checknil(&nodr) // in case offset is huge + + nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 + + if proc == 0 { + // plain call: use direct c function pointer - more efficient + cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] + nodr.Op = gc.OINDREG + proc = 3 + } else { + // go/defer. generate go func value. + p = gins(arm.AMOVW, &nodo, &nodr) + + p.From.Type = obj.TYPE_ADDR // REG = &(20+offset(REG)) -- i.tab->fun[f] + } + + nodr.Type = n.Left.Type + ginscall(&nodr, proc) + + regfree(&nodr) + regfree(&nodo) +} + +/* + * generate function call; + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + */ +func cgen_call(n *gc.Node, proc int) { + var t *gc.Type + var nod gc.Node + var afun gc.Node + + if n == nil { + return + } + + if n.Left.Ullman >= gc.UINF { + // if name involves a fn call + // precompute the address of the fn + gc.Tempname(&afun, gc.Types[gc.Tptr]) + + cgen(n.Left, &afun) + } + + gc.Genlist(n.List) // assign the args + t = n.Left.Type + + // call tempname pointer + if n.Left.Ullman >= gc.UINF { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, &afun) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + goto ret + } + + // call pointer + if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, n.Left) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + goto ret + } + + // call direct + n.Left.Method = 1 + + ginscall(n.Left, proc) + +ret: +} + +/* + * call to n has already been generated. + * generate: + * res = return value from call. + */ +func cgen_callret(n *gc.Node, res *gc.Node) { + var nod gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_callret: nil") + } + + nod = gc.Node{} + nod.Op = gc.OINDREG + nod.Val.U.Reg = arm.REGSP + nod.Addable = 1 + + nod.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP) + nod.Type = fp.Type + gc.Cgen_as(res, &nod) +} + +/* + * call to n has already been generated. + * generate: + * res = &return value from call. + */ +func cgen_aret(n *gc.Node, res *gc.Node) { + var nod1 gc.Node + var nod2 gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_aret: nil") + } + + nod1 = gc.Node{} + nod1.Op = gc.OINDREG + nod1.Val.U.Reg = arm.REGSP + nod1.Addable = 1 + + nod1.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP) + nod1.Type = fp.Type + + if res.Op != gc.OREGISTER { + regalloc(&nod2, gc.Types[gc.Tptr], res) + agen(&nod1, &nod2) + gins(arm.AMOVW, &nod2, res) + regfree(&nod2) + } else { + agen(&nod1, res) + } +} + +/* + * generate return. + * n->left is assignments to return values. + */ +func cgen_ret(n *gc.Node) { + var p *obj.Prog + + if n != nil { + gc.Genlist(n.List) // copy out args + } + if gc.Hasdefer != 0 { + ginscall(gc.Deferreturn, 0) + } + gc.Genlist(gc.Curfn.Exit) + p = gins(obj.ARET, nil, nil) + if n != nil && n.Op == gc.ORETJMP { + p.To.Name = obj.NAME_EXTERN + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(n.Left.Sym) + } +} + +/* + * generate high multiply + * res = (nl * nr) >> wordsize + */ +func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { + var w int + var n1 gc.Node + var n2 gc.Node + var tmp *gc.Node + var t *gc.Type + var p *obj.Prog + + if nl.Ullman < nr.Ullman { + tmp = nl + nl = nr + nr = tmp + } + + t = nl.Type + w = int(t.Width * 8) + regalloc(&n1, t, res) + cgen(nl, &n1) + regalloc(&n2, t, nil) + cgen(nr, &n2) + switch gc.Simtype[t.Etype] { + case gc.TINT8, + gc.TINT16: + gins(optoas(gc.OMUL, t), &n2, &n1) + gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1) + + case gc.TUINT8, + gc.TUINT16: + gins(optoas(gc.OMUL, t), &n2, &n1) + gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(w), &n1) + + // perform a long multiplication. + case gc.TINT32, + gc.TUINT32: + if gc.Issigned[t.Etype] != 0 { + p = gins(arm.AMULL, &n2, nil) + } else { + p = gins(arm.AMULLU, &n2, nil) + } + + // n2 * n1 -> (n1 n2) + p.Reg = n1.Val.U.Reg + + p.To.Type = obj.TYPE_REGREG + p.To.Reg = n1.Val.U.Reg + p.To.Offset = int64(n2.Val.U.Reg) + + default: + gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0)) + } + + cgen(&n1, res) + regfree(&n1) + regfree(&n2) +} + +/* + * generate shift according to op, one of: + * res = nl << nr + * res = nl >> nr + */ +func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var nt gc.Node + var t gc.Node + var lo gc.Node + var hi gc.Node + var w int + var v int + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var tr *gc.Type + var sc uint64 + + if nl.Type.Width > 4 { + gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0)) + } + + w = int(nl.Type.Width * 8) + + if op == gc.OLROT { + v = int(gc.Mpgetfix(nr.Val.U.Xval)) + regalloc(&n1, nl.Type, res) + if w == 32 { + cgen(nl, &n1) + gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1) + } else { + regalloc(&n2, nl.Type, nil) + cgen(nl, &n2) + gshift(arm.AMOVW, &n2, arm.SHIFT_LL, int32(v), &n1) + gshift(arm.AORR, &n2, arm.SHIFT_LR, int32(w)-int32(v), &n1) + regfree(&n2) + + // Ensure sign/zero-extended result. + gins(optoas(gc.OAS, nl.Type), &n1, &n1) + } + + gmove(&n1, res) + regfree(&n1) + return + } + + if nr.Op == gc.OLITERAL { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if sc == 0 { + } else // nothing to do + if sc >= uint64(nl.Type.Width*8) { + if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { + gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1) + } else { + gins(arm.AEOR, &n1, &n1) + } + } else { + if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { + gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(sc), &n1) + } else if op == gc.ORSH { + gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(sc), &n1) // OLSH + } else { + gshift(arm.AMOVW, &n1, arm.SHIFT_LL, int32(sc), &n1) + } + } + + if w < 32 && op == gc.OLSH { + gins(optoas(gc.OAS, nl.Type), &n1, &n1) + } + gmove(&n1, res) + regfree(&n1) + return + } + + tr = nr.Type + if tr.Width > 4 { + gc.Tempname(&nt, nr.Type) + if nl.Ullman >= nr.Ullman { + regalloc(&n2, nl.Type, res) + cgen(nl, &n2) + cgen(nr, &nt) + n1 = nt + } else { + cgen(nr, &nt) + regalloc(&n2, nl.Type, res) + cgen(nl, &n2) + } + + split64(&nt, &lo, &hi) + regalloc(&n1, gc.Types[gc.TUINT32], nil) + regalloc(&n3, gc.Types[gc.TUINT32], nil) + gmove(&lo, &n1) + gmove(&hi, &n3) + splitclean() + gins(arm.ATST, &n3, nil) + gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w)) + p1 = gins(arm.AMOVW, &t, &n1) + p1.Scond = arm.C_SCOND_NE + tr = gc.Types[gc.TUINT32] + regfree(&n3) + } else { + if nl.Ullman >= nr.Ullman { + regalloc(&n2, nl.Type, res) + cgen(nl, &n2) + regalloc(&n1, nr.Type, nil) + cgen(nr, &n1) + } else { + regalloc(&n1, nr.Type, nil) + cgen(nr, &n1) + regalloc(&n2, nl.Type, res) + cgen(nl, &n2) + } + } + + // test for shift being 0 + gins(arm.ATST, &n1, nil) + + p3 = gc.Gbranch(arm.ABEQ, nil, -1) + + // test and fix up large shifts + // TODO: if(!bounded), don't emit some of this. + regalloc(&n3, tr, nil) + + gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w)) + gmove(&t, &n3) + gcmp(arm.ACMP, &n1, &n3) + if op == gc.ORSH { + if gc.Issigned[nl.Type.Etype] != 0 { + p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2) + p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2) + } else { + p1 = gins(arm.AEOR, &n2, &n2) + p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LR, &n1, &n2) + } + + p1.Scond = arm.C_SCOND_HS + p2.Scond = arm.C_SCOND_LO + } else { + p1 = gins(arm.AEOR, &n2, &n2) + p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LL, &n1, &n2) + p1.Scond = arm.C_SCOND_HS + p2.Scond = arm.C_SCOND_LO + } + + regfree(&n3) + + gc.Patch(p3, gc.Pc) + + // Left-shift of smaller word must be sign/zero-extended. + if w < 32 && op == gc.OLSH { + gins(optoas(gc.OAS, nl.Type), &n2, &n2) + } + gmove(&n2, res) + + regfree(&n1) + regfree(&n2) +} + +func clearfat(nl *gc.Node) { + var w uint32 + var c uint32 + var q uint32 + var dst gc.Node + var nc gc.Node + var nz gc.Node + var end gc.Node + var r0 gc.Node + var r1 gc.Node + var f *gc.Node + var p *obj.Prog + var pl *obj.Prog + + /* clear a fat object */ + if gc.Debug['g'] != 0 { + gc.Dump("\nclearfat", nl) + } + + w = uint32(nl.Type.Width) + + // Avoid taking the address for simple enough types. + if componentgen(nil, nl) { + return + } + + c = w % 4 // bytes + q = w / 4 // quads + + r0.Op = gc.OREGISTER + + r0.Val.U.Reg = REGALLOC_R0 + r1.Op = gc.OREGISTER + r1.Val.U.Reg = REGALLOC_R0 + 1 + regalloc(&dst, gc.Types[gc.Tptr], &r1) + agen(nl, &dst) + gc.Nodconst(&nc, gc.Types[gc.TUINT32], 0) + regalloc(&nz, gc.Types[gc.TUINT32], &r0) + cgen(&nc, &nz) + + if q > 128 { + regalloc(&end, gc.Types[gc.Tptr], nil) + p = gins(arm.AMOVW, &dst, &end) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = int64(q) * 4 + + p = gins(arm.AMOVW, &nz, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = 4 + p.Scond |= arm.C_PBIT + pl = p + + p = gins(arm.ACMP, &dst, nil) + raddr(&end, p) + gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl) + + regfree(&end) + } else if q >= 4 && !gc.Nacl { + f = gc.Sysfunc("duffzero") + p = gins(obj.ADUFFZERO, nil, f) + gc.Afunclit(&p.To, f) + + // 4 and 128 = magic constants: see ../../runtime/asm_arm.s + p.To.Offset = 4 * (128 - int64(q)) + } else { + for q > 0 { + p = gins(arm.AMOVW, &nz, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = 4 + p.Scond |= arm.C_PBIT + + //print("1. %P\n", p); + q-- + } + } + + for c > 0 { + p = gins(arm.AMOVB, &nz, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = 1 + p.Scond |= arm.C_PBIT + + //print("2. %P\n", p); + c-- + } + + regfree(&dst) + regfree(&nz) +} + +// Called after regopt and peep have run. +// Expand CHECKNIL pseudo-op into actual nil pointer check. +func expandchecks(firstp *obj.Prog) { + var reg int + var p *obj.Prog + var p1 *obj.Prog + + for p = firstp; p != nil; p = p.Link { + if p.As != obj.ACHECKNIL { + continue + } + if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers + gc.Warnl(int(p.Lineno), "generated nil check") + } + if p.From.Type != obj.TYPE_REG { + gc.Fatal("invalid nil check %v", p) + } + reg = int(p.From.Reg) + + // check is + // CMP arg, $0 + // MOV.EQ arg, 0(arg) + p1 = gc.Ctxt.NewProg() + + gc.Clearp(p1) + p1.Link = p.Link + p.Link = p1 + p1.Lineno = p.Lineno + p1.Pc = 9999 + p1.As = arm.AMOVW + p1.From.Type = obj.TYPE_REG + p1.From.Reg = int16(reg) + p1.To.Type = obj.TYPE_MEM + p1.To.Reg = int16(reg) + p1.To.Offset = 0 + p1.Scond = arm.C_SCOND_EQ + p.As = arm.ACMP + p.From.Type = obj.TYPE_CONST + p.From.Reg = 0 + p.From.Offset = 0 + p.Reg = int16(reg) + } +} diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c deleted file mode 100644 index bdb70270a8..0000000000 --- a/src/cmd/5g/gsubr.c +++ /dev/null @@ -1,1527 +0,0 @@ -// Derived from Inferno utils/5c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../../runtime/funcdata.h" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 5l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -long unmappedzero = 4096; - -static int resvd[] = -{ - 9, // reserved for m - 10, // reserved for g - REGSP, // reserved for SP -}; - -void -ginit(void) -{ - int i; - - for(i=0; ietype]; - if(is64(t)) - fatal("regalloc: 64 bit type %T"); - - switch(et) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TPTR32: - case TBOOL: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX) - goto out; - } - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) { - regpc[i] = (uintptr)getcallerpc(&n); - goto out; - } - print("registers allocated at\n"); - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - print("%d %p\n", i, regpc[i]); - fatal("out of fixed registers"); - goto err; - - case TFLOAT32: - case TFLOAT64: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX) - goto out; - } - for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) - if(reg[i] == 0) - goto out; - fatal("out of floating point registers"); - goto err; - - case TCOMPLEX64: - case TCOMPLEX128: - tempname(n, t); - return; - } - yyerror("regalloc: unknown type %T", t); - -err: - nodreg(n, t, REG_R0); - return; - -out: - reg[i]++; - nodreg(n, t, i); -} - -void -regfree(Node *n) -{ - int i, fixfree, floatfree; - - if(0 && debug['r']) { - fixfree = 0; - for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++) - if(reg[i] == 0) - fixfree++; - floatfree = 0; - for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++) - if(reg[i] == 0) - floatfree++; - print("regalloc fix %d float %d\n", fixfree, floatfree); - } - - if(n->op == ONAME) - return; - if(n->op != OREGISTER && n->op != OINDREG) - fatal("regfree: not a register"); - i = n->val.u.reg; - if(i == REGSP) - return; - if(i < 0 || i >= nelem(reg) || i >= nelem(regpc)) - fatal("regfree: reg out of range"); - if(reg[i] <= 0) - fatal("regfree: reg %R not allocated", i); - reg[i]--; - if(reg[i] == 0) - regpc[i] = 0; -} - -/* - * return constant i node. - * overwritten by next call, but useful in calls to gins. - */ -Node* -ncon(uint32 i) -{ - static Node n; - - if(n.type == T) - nodconst(&n, types[TUINT32], 0); - mpmovecfix(n.val.u.xval, i); - return &n; -} - -Node sclean[10]; -int nsclean; - -/* - * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. - */ -void -split64(Node *n, Node *lo, Node *hi) -{ - Node n1; - int64 i; - - if(!is64(n->type)) - fatal("split64 %T", n->type); - - if(nsclean >= nelem(sclean)) - fatal("split64 clean"); - sclean[nsclean].op = OEMPTY; - nsclean++; - switch(n->op) { - default: - switch(n->op) { - default: - if(!dotaddable(n, &n1)) { - igen(n, &n1, N); - sclean[nsclean-1] = n1; - } - n = &n1; - break; - case ONAME: - if(n->class == PPARAMREF) { - cgen(n->heapaddr, &n1); - sclean[nsclean-1] = n1; - n = &n1; - } - break; - case OINDREG: - // nothing - break; - } - *lo = *n; - *hi = *n; - lo->type = types[TUINT32]; - if(n->type->etype == TINT64) - hi->type = types[TINT32]; - else - hi->type = types[TUINT32]; - hi->xoffset += 4; - break; - - case OLITERAL: - convconst(&n1, n->type, &n->val); - i = mpgetfix(n1.val.u.xval); - nodconst(lo, types[TUINT32], (uint32)i); - i >>= 32; - if(n->type->etype == TINT64) - nodconst(hi, types[TINT32], (int32)i); - else - nodconst(hi, types[TUINT32], (uint32)i); - break; - } -} - -void -splitclean(void) -{ - if(nsclean <= 0) - fatal("splitclean"); - nsclean--; - if(sclean[nsclean].op != OEMPTY) - regfree(&sclean[nsclean]); -} - -#define CASE(a,b) (((a)<<16)|((b)<<0)) -/*c2go int CASE(int, int); */ - -void -gmove(Node *f, Node *t) -{ - int a, ft, tt, fa, ta; - Type *cvt; - Node r1, r2, flo, fhi, tlo, thi, con; - Prog *p1; - - if(debug['M']) - print("gmove %N -> %N\n", f, t); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); - return; - } - - // cannot have two memory operands; - // except 64-bit, which always copies via registers anyway. - if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - switch(tt) { - default: - convconst(&con, t->type, &f->val); - break; - - case TINT16: - case TINT8: - convconst(&con, types[TINT32], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVW, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - - case TUINT16: - case TUINT8: - convconst(&con, types[TUINT32], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVW, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - } - - f = &con; - ft = simsimtype(con.type); - - // constants can't move directly to memory - if(ismem(t) && !is64(t->type)) goto hard; - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - goto fatal; - - /* - * integer copy and truncate - */ - case CASE(TINT8, TINT8): // same size - if(!ismem(f)) { - a = AMOVB; - break; - } - case CASE(TUINT8, TINT8): - case CASE(TINT16, TINT8): // truncate - case CASE(TUINT16, TINT8): - case CASE(TINT32, TINT8): - case CASE(TUINT32, TINT8): - a = AMOVBS; - break; - - case CASE(TUINT8, TUINT8): - if(!ismem(f)) { - a = AMOVB; - break; - } - case CASE(TINT8, TUINT8): - case CASE(TINT16, TUINT8): - case CASE(TUINT16, TUINT8): - case CASE(TINT32, TUINT8): - case CASE(TUINT32, TUINT8): - a = AMOVBU; - break; - - case CASE(TINT64, TINT8): // truncate low word - case CASE(TUINT64, TINT8): - a = AMOVBS; - goto trunc64; - - case CASE(TINT64, TUINT8): - case CASE(TUINT64, TUINT8): - a = AMOVBU; - goto trunc64; - - case CASE(TINT16, TINT16): // same size - if(!ismem(f)) { - a = AMOVH; - break; - } - case CASE(TUINT16, TINT16): - case CASE(TINT32, TINT16): // truncate - case CASE(TUINT32, TINT16): - a = AMOVHS; - break; - - case CASE(TUINT16, TUINT16): - if(!ismem(f)) { - a = AMOVH; - break; - } - case CASE(TINT16, TUINT16): - case CASE(TINT32, TUINT16): - case CASE(TUINT32, TUINT16): - a = AMOVHU; - break; - - case CASE(TINT64, TINT16): // truncate low word - case CASE(TUINT64, TINT16): - a = AMOVHS; - goto trunc64; - - case CASE(TINT64, TUINT16): - case CASE(TUINT64, TUINT16): - a = AMOVHU; - goto trunc64; - - case CASE(TINT32, TINT32): // same size - case CASE(TINT32, TUINT32): - case CASE(TUINT32, TINT32): - case CASE(TUINT32, TUINT32): - a = AMOVW; - break; - - case CASE(TINT64, TINT32): // truncate - case CASE(TUINT64, TINT32): - case CASE(TINT64, TUINT32): - case CASE(TUINT64, TUINT32): - split64(f, &flo, &fhi); - regalloc(&r1, t->type, N); - gins(AMOVW, &flo, &r1); - gins(AMOVW, &r1, t); - regfree(&r1); - splitclean(); - return; - - case CASE(TINT64, TINT64): // same size - case CASE(TINT64, TUINT64): - case CASE(TUINT64, TINT64): - case CASE(TUINT64, TUINT64): - split64(f, &flo, &fhi); - split64(t, &tlo, &thi); - regalloc(&r1, flo.type, N); - regalloc(&r2, fhi.type, N); - gins(AMOVW, &flo, &r1); - gins(AMOVW, &fhi, &r2); - gins(AMOVW, &r1, &tlo); - gins(AMOVW, &r2, &thi); - regfree(&r1); - regfree(&r2); - splitclean(); - splitclean(); - return; - - /* - * integer up-conversions - */ - case CASE(TINT8, TINT16): // sign extend int8 - case CASE(TINT8, TUINT16): - case CASE(TINT8, TINT32): - case CASE(TINT8, TUINT32): - a = AMOVBS; - goto rdst; - case CASE(TINT8, TINT64): // convert via int32 - case CASE(TINT8, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT8, TINT16): // zero extend uint8 - case CASE(TUINT8, TUINT16): - case CASE(TUINT8, TINT32): - case CASE(TUINT8, TUINT32): - a = AMOVBU; - goto rdst; - case CASE(TUINT8, TINT64): // convert via uint32 - case CASE(TUINT8, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT16, TINT32): // sign extend int16 - case CASE(TINT16, TUINT32): - a = AMOVHS; - goto rdst; - case CASE(TINT16, TINT64): // convert via int32 - case CASE(TINT16, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT16, TINT32): // zero extend uint16 - case CASE(TUINT16, TUINT32): - a = AMOVHU; - goto rdst; - case CASE(TUINT16, TINT64): // convert via uint32 - case CASE(TUINT16, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT32, TINT64): // sign extend int32 - case CASE(TINT32, TUINT64): - split64(t, &tlo, &thi); - regalloc(&r1, tlo.type, N); - regalloc(&r2, thi.type, N); - gmove(f, &r1); - p1 = gins(AMOVW, &r1, &r2); - p1->from.type = TYPE_SHIFT; - p1->from.offset = 2 << 5 | 31 << 7 | (r1.val.u.reg&15); // r1->31 - p1->from.reg = 0; -//print("gmove: %P\n", p1); - gins(AMOVW, &r1, &tlo); - gins(AMOVW, &r2, &thi); - regfree(&r1); - regfree(&r2); - splitclean(); - return; - - case CASE(TUINT32, TINT64): // zero extend uint32 - case CASE(TUINT32, TUINT64): - split64(t, &tlo, &thi); - gmove(f, &tlo); - regalloc(&r1, thi.type, N); - gins(AMOVW, ncon(0), &r1); - gins(AMOVW, &r1, &thi); - regfree(&r1); - splitclean(); - return; - - /* - * float to integer - */ - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TINT32): - case CASE(TFLOAT32, TUINT32): -// case CASE(TFLOAT32, TUINT64): - - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TINT32): - case CASE(TFLOAT64, TUINT32): -// case CASE(TFLOAT64, TUINT64): - fa = AMOVF; - a = AMOVFW; - if(ft == TFLOAT64) { - fa = AMOVD; - a = AMOVDW; - } - ta = AMOVW; - switch(tt) { - case TINT8: - ta = AMOVBS; - break; - case TUINT8: - ta = AMOVBU; - break; - case TINT16: - ta = AMOVHS; - break; - case TUINT16: - ta = AMOVHU; - break; - } - - regalloc(&r1, types[ft], f); - regalloc(&r2, types[tt], t); - gins(fa, f, &r1); // load to fpu - p1 = gins(a, &r1, &r1); // convert to w - switch(tt) { - case TUINT8: - case TUINT16: - case TUINT32: - p1->scond |= C_UBIT; - } - gins(AMOVW, &r1, &r2); // copy to cpu - gins(ta, &r2, t); // store - regfree(&r1); - regfree(&r2); - return; - - /* - * integer to float - */ - case CASE(TINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT32): - case CASE(TINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT32): - case CASE(TINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT8, TFLOAT64): - case CASE(TINT16, TFLOAT64): - case CASE(TUINT16, TFLOAT64): - case CASE(TINT32, TFLOAT64): - case CASE(TUINT32, TFLOAT64): - fa = AMOVW; - switch(ft) { - case TINT8: - fa = AMOVBS; - break; - case TUINT8: - fa = AMOVBU; - break; - case TINT16: - fa = AMOVHS; - break; - case TUINT16: - fa = AMOVHU; - break; - } - a = AMOVWF; - ta = AMOVF; - if(tt == TFLOAT64) { - a = AMOVWD; - ta = AMOVD; - } - regalloc(&r1, types[ft], f); - regalloc(&r2, types[tt], t); - gins(fa, f, &r1); // load to cpu - gins(AMOVW, &r1, &r2); // copy to fpu - p1 = gins(a, &r2, &r2); // convert - switch(ft) { - case TUINT8: - case TUINT16: - case TUINT32: - p1->scond |= C_UBIT; - } - gins(ta, &r2, t); // store - regfree(&r1); - regfree(&r2); - return; - - case CASE(TUINT64, TFLOAT32): - case CASE(TUINT64, TFLOAT64): - fatal("gmove UINT64, TFLOAT not implemented"); - return; - - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - a = AMOVF; - break; - - case CASE(TFLOAT64, TFLOAT64): - a = AMOVD; - break; - - case CASE(TFLOAT32, TFLOAT64): - regalloc(&r1, types[TFLOAT64], t); - gins(AMOVF, f, &r1); - gins(AMOVFD, &r1, &r1); - gins(AMOVD, &r1, t); - regfree(&r1); - return; - - case CASE(TFLOAT64, TFLOAT32): - regalloc(&r1, types[TFLOAT64], t); - gins(AMOVD, f, &r1); - gins(AMOVDF, &r1, &r1); - gins(AMOVF, &r1, t); - regfree(&r1); - return; - } - - gins(a, f, t); - return; - -rdst: - // TODO(kaib): we almost always require a register dest anyway, this can probably be - // removed. - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -trunc64: - // truncate 64 bit integer - split64(f, &flo, &fhi); - regalloc(&r1, t->type, N); - gins(a, &flo, &r1); - gins(a, &r1, t); - regfree(&r1); - splitclean(); - return; - -fatal: - // should not happen - fatal("gmove %N -> %N", f, t); -} - -int -samaddr(Node *f, Node *t) -{ - - if(f->op != t->op) - return 0; - - switch(f->op) { - case OREGISTER: - if(f->val.u.reg != t->val.u.reg) - break; - return 1; - } - return 0; -} - -/* - * generate one instruction: - * as f, t - */ -Prog* -gins(int as, Node *f, Node *t) -{ -// Node nod; -// int32 v; - Prog *p; - Addr af, at; - - if(f != N && f->op == OINDEX) { - fatal("gins OINDEX not implemented"); -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(f->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); - } - if(t != N && t->op == OINDEX) { - fatal("gins OINDEX not implemented"); -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(t->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); - } - - memset(&af, 0, sizeof af); - memset(&at, 0, sizeof at); - if(f != N) - naddr(f, &af, 1); - if(t != N) - naddr(t, &at, 1); - p = prog(as); - if(f != N) - p->from = af; - if(t != N) - p->to = at; - if(debug['g']) - print("%P\n", p); - return p; -} - -/* - * insert n into reg slot of p - */ -void -raddr(Node *n, Prog *p) -{ - Addr a; - - naddr(n, &a, 1); - if(a.type != TYPE_REG) { - if(n) - fatal("bad in raddr: %O", n->op); - else - fatal("bad in raddr: "); - p->reg = 0; - } else - p->reg = a.reg; -} - -/* generate a comparison -TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites. - */ -Prog* -gcmp(int as, Node *lhs, Node *rhs) -{ - Prog *p; - - if(lhs->op != OREGISTER) - fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op); - - p = gins(as, rhs, N); - raddr(lhs, p); - return p; -} - -/* generate a constant shift - * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal. -*/ -Prog* -gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs) -{ - Prog *p; - - if(sval <= 0 || sval > 32) - fatal("bad shift value: %d", sval); - - sval = sval&0x1f; - - p = gins(as, N, rhs); - p->from.type = TYPE_SHIFT; - p->from.offset = stype | sval<<7 | (lhs->val.u.reg&15); - return p; -} - -/* generate a register shift -*/ -Prog * -gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs) -{ - Prog *p; - p = gins(as, N, rhs); - p->from.type = TYPE_SHIFT; - p->from.offset = stype | (reg->val.u.reg&15) << 8 | 1<<4 | (lhs->val.u.reg&15); - return p; -} - -/* - * return Axxx for Oxxx on type t. - */ -int -optoas(int op, Type *t) -{ - int a; - - if(t == T) - fatal("optoas: t is nil"); - - a = AXXX; - switch(CASE(op, simtype[t->etype])) { - default: - fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]); - break; - -/* case CASE(OADDR, TPTR32): - a = ALEAL; - break; - - case CASE(OADDR, TPTR64): - a = ALEAQ; - break; -*/ - // TODO(kaib): make sure the conditional branches work on all edge cases - case CASE(OEQ, TBOOL): - case CASE(OEQ, TINT8): - case CASE(OEQ, TUINT8): - case CASE(OEQ, TINT16): - case CASE(OEQ, TUINT16): - case CASE(OEQ, TINT32): - case CASE(OEQ, TUINT32): - case CASE(OEQ, TINT64): - case CASE(OEQ, TUINT64): - case CASE(OEQ, TPTR32): - case CASE(OEQ, TPTR64): - case CASE(OEQ, TFLOAT32): - case CASE(OEQ, TFLOAT64): - a = ABEQ; - break; - - case CASE(ONE, TBOOL): - case CASE(ONE, TINT8): - case CASE(ONE, TUINT8): - case CASE(ONE, TINT16): - case CASE(ONE, TUINT16): - case CASE(ONE, TINT32): - case CASE(ONE, TUINT32): - case CASE(ONE, TINT64): - case CASE(ONE, TUINT64): - case CASE(ONE, TPTR32): - case CASE(ONE, TPTR64): - case CASE(ONE, TFLOAT32): - case CASE(ONE, TFLOAT64): - a = ABNE; - break; - - case CASE(OLT, TINT8): - case CASE(OLT, TINT16): - case CASE(OLT, TINT32): - case CASE(OLT, TINT64): - case CASE(OLT, TFLOAT32): - case CASE(OLT, TFLOAT64): - a = ABLT; - break; - - case CASE(OLT, TUINT8): - case CASE(OLT, TUINT16): - case CASE(OLT, TUINT32): - case CASE(OLT, TUINT64): - a = ABLO; - break; - - case CASE(OLE, TINT8): - case CASE(OLE, TINT16): - case CASE(OLE, TINT32): - case CASE(OLE, TINT64): - case CASE(OLE, TFLOAT32): - case CASE(OLE, TFLOAT64): - a = ABLE; - break; - - case CASE(OLE, TUINT8): - case CASE(OLE, TUINT16): - case CASE(OLE, TUINT32): - case CASE(OLE, TUINT64): - a = ABLS; - break; - - case CASE(OGT, TINT8): - case CASE(OGT, TINT16): - case CASE(OGT, TINT32): - case CASE(OGT, TINT64): - case CASE(OGT, TFLOAT32): - case CASE(OGT, TFLOAT64): - a = ABGT; - break; - - case CASE(OGT, TUINT8): - case CASE(OGT, TUINT16): - case CASE(OGT, TUINT32): - case CASE(OGT, TUINT64): - a = ABHI; - break; - - case CASE(OGE, TINT8): - case CASE(OGE, TINT16): - case CASE(OGE, TINT32): - case CASE(OGE, TINT64): - case CASE(OGE, TFLOAT32): - case CASE(OGE, TFLOAT64): - a = ABGE; - break; - - case CASE(OGE, TUINT8): - case CASE(OGE, TUINT16): - case CASE(OGE, TUINT32): - case CASE(OGE, TUINT64): - a = ABHS; - break; - - case CASE(OCMP, TBOOL): - case CASE(OCMP, TINT8): - case CASE(OCMP, TUINT8): - case CASE(OCMP, TINT16): - case CASE(OCMP, TUINT16): - case CASE(OCMP, TINT32): - case CASE(OCMP, TUINT32): - case CASE(OCMP, TPTR32): - a = ACMP; - break; - - case CASE(OCMP, TFLOAT32): - a = ACMPF; - break; - - case CASE(OCMP, TFLOAT64): - a = ACMPD; - break; - - case CASE(OAS, TBOOL): - a = AMOVB; - break; - - case CASE(OAS, TINT8): - a = AMOVBS; - break; - - case CASE(OAS, TUINT8): - a = AMOVBU; - break; - - case CASE(OAS, TINT16): - a = AMOVHS; - break; - - case CASE(OAS, TUINT16): - a = AMOVHU; - break; - - case CASE(OAS, TINT32): - case CASE(OAS, TUINT32): - case CASE(OAS, TPTR32): - a = AMOVW; - break; - - case CASE(OAS, TFLOAT32): - a = AMOVF; - break; - - case CASE(OAS, TFLOAT64): - a = AMOVD; - break; - - case CASE(OADD, TINT8): - case CASE(OADD, TUINT8): - case CASE(OADD, TINT16): - case CASE(OADD, TUINT16): - case CASE(OADD, TINT32): - case CASE(OADD, TUINT32): - case CASE(OADD, TPTR32): - a = AADD; - break; - - case CASE(OADD, TFLOAT32): - a = AADDF; - break; - - case CASE(OADD, TFLOAT64): - a = AADDD; - break; - - case CASE(OSUB, TINT8): - case CASE(OSUB, TUINT8): - case CASE(OSUB, TINT16): - case CASE(OSUB, TUINT16): - case CASE(OSUB, TINT32): - case CASE(OSUB, TUINT32): - case CASE(OSUB, TPTR32): - a = ASUB; - break; - - case CASE(OSUB, TFLOAT32): - a = ASUBF; - break; - - case CASE(OSUB, TFLOAT64): - a = ASUBD; - break; - - case CASE(OMINUS, TINT8): - case CASE(OMINUS, TUINT8): - case CASE(OMINUS, TINT16): - case CASE(OMINUS, TUINT16): - case CASE(OMINUS, TINT32): - case CASE(OMINUS, TUINT32): - case CASE(OMINUS, TPTR32): - a = ARSB; - break; - - case CASE(OAND, TINT8): - case CASE(OAND, TUINT8): - case CASE(OAND, TINT16): - case CASE(OAND, TUINT16): - case CASE(OAND, TINT32): - case CASE(OAND, TUINT32): - case CASE(OAND, TPTR32): - a = AAND; - break; - - case CASE(OOR, TINT8): - case CASE(OOR, TUINT8): - case CASE(OOR, TINT16): - case CASE(OOR, TUINT16): - case CASE(OOR, TINT32): - case CASE(OOR, TUINT32): - case CASE(OOR, TPTR32): - a = AORR; - break; - - case CASE(OXOR, TINT8): - case CASE(OXOR, TUINT8): - case CASE(OXOR, TINT16): - case CASE(OXOR, TUINT16): - case CASE(OXOR, TINT32): - case CASE(OXOR, TUINT32): - case CASE(OXOR, TPTR32): - a = AEOR; - break; - - case CASE(OLSH, TINT8): - case CASE(OLSH, TUINT8): - case CASE(OLSH, TINT16): - case CASE(OLSH, TUINT16): - case CASE(OLSH, TINT32): - case CASE(OLSH, TUINT32): - case CASE(OLSH, TPTR32): - a = ASLL; - break; - - case CASE(ORSH, TUINT8): - case CASE(ORSH, TUINT16): - case CASE(ORSH, TUINT32): - case CASE(ORSH, TPTR32): - a = ASRL; - break; - - case CASE(ORSH, TINT8): - case CASE(ORSH, TINT16): - case CASE(ORSH, TINT32): - a = ASRA; - break; - - case CASE(OMUL, TUINT8): - case CASE(OMUL, TUINT16): - case CASE(OMUL, TUINT32): - case CASE(OMUL, TPTR32): - a = AMULU; - break; - - case CASE(OMUL, TINT8): - case CASE(OMUL, TINT16): - case CASE(OMUL, TINT32): - a = AMUL; - break; - - case CASE(OMUL, TFLOAT32): - a = AMULF; - break; - - case CASE(OMUL, TFLOAT64): - a = AMULD; - break; - - case CASE(ODIV, TUINT8): - case CASE(ODIV, TUINT16): - case CASE(ODIV, TUINT32): - case CASE(ODIV, TPTR32): - a = ADIVU; - break; - - case CASE(ODIV, TINT8): - case CASE(ODIV, TINT16): - case CASE(ODIV, TINT32): - a = ADIV; - break; - - case CASE(OMOD, TUINT8): - case CASE(OMOD, TUINT16): - case CASE(OMOD, TUINT32): - case CASE(OMOD, TPTR32): - a = AMODU; - break; - - case CASE(OMOD, TINT8): - case CASE(OMOD, TINT16): - case CASE(OMOD, TINT32): - a = AMOD; - break; - -// case CASE(OEXTEND, TINT16): -// a = ACWD; -// break; - -// case CASE(OEXTEND, TINT32): -// a = ACDQ; -// break; - -// case CASE(OEXTEND, TINT64): -// a = ACQO; -// break; - - case CASE(ODIV, TFLOAT32): - a = ADIVF; - break; - - case CASE(ODIV, TFLOAT64): - a = ADIVD; - break; - - } - return a; -} - -enum -{ - ODynam = 1<<0, - OPtrto = 1<<1, -}; - -static Node clean[20]; -static int cleani = 0; - -void -sudoclean(void) -{ - if(clean[cleani-1].op != OEMPTY) - regfree(&clean[cleani-1]); - if(clean[cleani-2].op != OEMPTY) - regfree(&clean[cleani-2]); - cleani -= 2; -} - -int -dotaddable(Node *n, Node *n1) -{ - int o; - int64 oary[10]; - Node *nn; - - if(n->op != ODOT) - return 0; - - o = dotoffset(n, oary, &nn); - if(nn != N && nn->addable && o == 1 && oary[0] >= 0) { - *n1 = *nn; - n1->type = n->type; - n1->xoffset += oary[0]; - return 1; - } - return 0; -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -int -sudoaddable(int as, Node *n, Addr *a, int *w) -{ - int o, i; - int64 oary[10]; - int64 v; - Node n1, n2, n3, n4, *nn, *l, *r; - Node *reg, *reg1; - Prog *p1, *p2; - Type *t; - - if(n->type == T) - return 0; - - memset(a, 0, sizeof *a); - - switch(n->op) { - case OLITERAL: - if(!isconst(n, CTINT)) - break; - v = mpgetfix(n->val.u.xval); - if(v >= 32000 || v <= -32000) - break; - goto lit; - - case ODOT: - case ODOTPTR: - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - goto odot; - - case OINDEX: - return 0; - // disabled: OINDEX case is now covered by agenr - // for a more suitable register allocation pattern. - if(n->left->type->etype == TSTRING) - return 0; - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - goto oindex; - } - return 0; - -lit: - switch(as) { - default: - return 0; - case AADD: case ASUB: case AAND: case AORR: case AEOR: - case AMOVB: case AMOVBS: case AMOVBU: - case AMOVH: case AMOVHS: case AMOVHU: - case AMOVW: - break; - } - - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - naddr(n, a, 1); - goto yes; - -odot: - o = dotoffset(n, oary, &nn); - if(nn == N) - goto no; - - if(nn->addable && o == 1 && oary[0] >= 0) { - // directly addressable set of DOTs - n1 = *nn; - n1.type = n->type; - n1.xoffset += oary[0]; - naddr(&n1, a, 1); - goto yes; - } - - regalloc(reg, types[tptr], N); - n1 = *reg; - n1.op = OINDREG; - if(oary[0] >= 0) { - agen(nn, reg); - n1.xoffset = oary[0]; - } else { - cgen(nn, reg); - cgen_checknil(reg); - n1.xoffset = -(oary[0]+1); - } - - for(i=1; i= 0) - fatal("can't happen"); - gins(AMOVW, &n1, reg); - cgen_checknil(reg); - n1.xoffset = -(oary[i]+1); - } - - a->type = TYPE_NONE; - a->name = NAME_NONE; - n1.type = n->type; - naddr(&n1, a, 1); - goto yes; - -oindex: - l = n->left; - r = n->right; - if(l->ullman >= UINF && r->ullman >= UINF) - goto no; - - // set o to type of array - o = 0; - if(isptr[l->type->etype]) { - o += OPtrto; - if(l->type->type->etype != TARRAY) - fatal("not ptr ary"); - if(l->type->type->bound < 0) - o += ODynam; - } else { - if(l->type->etype != TARRAY) - fatal("not ary"); - if(l->type->bound < 0) - o += ODynam; - } - - *w = n->type->width; - if(isconst(r, CTINT)) - goto oindex_const; - - switch(*w) { - default: - goto no; - case 1: - case 2: - case 4: - case 8: - break; - } - - // load the array (reg) - if(l->ullman > r->ullman) { - regalloc(reg, types[tptr], N); - if(o & OPtrto) { - cgen(l, reg); - cgen_checknil(reg); - } else - agen(l, reg); - } - - // load the index (reg1) - t = types[TUINT32]; - if(issigned[r->type->etype]) - t = types[TINT32]; - regalloc(reg1, t, N); - regalloc(&n3, types[TINT32], reg1); - p2 = cgenindex(r, &n3, debug['B'] || n->bounded); - gmove(&n3, reg1); - regfree(&n3); - - // load the array (reg) - if(l->ullman <= r->ullman) { - regalloc(reg, types[tptr], N); - if(o & OPtrto) { - cgen(l, reg); - cgen_checknil(reg); - } else - agen(l, reg); - } - - // check bounds - if(!debug['B']) { - if(o & ODynam) { - n2 = *reg; - n2.op = OINDREG; - n2.type = types[tptr]; - n2.xoffset = Array_nel; - } else { - if(o & OPtrto) - nodconst(&n2, types[TUINT32], l->type->type->bound); - else - nodconst(&n2, types[TUINT32], l->type->bound); - } - regalloc(&n3, n2.type, N); - cgen(&n2, &n3); - gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3); - regfree(&n3); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - if(p2) - patch(p2, pc); - ginscall(panicindex, 0); - patch(p1, pc); - } - - if(o & ODynam) { - n2 = *reg; - n2.op = OINDREG; - n2.type = types[tptr]; - n2.xoffset = Array_array; - gmove(&n2, reg); - } - - switch(*w) { - case 1: - gins(AADD, reg1, reg); - break; - case 2: - gshift(AADD, reg1, SHIFT_LL, 1, reg); - break; - case 4: - gshift(AADD, reg1, SHIFT_LL, 2, reg); - break; - case 8: - gshift(AADD, reg1, SHIFT_LL, 3, reg); - break; - } - - naddr(reg1, a, 1); - a->type = TYPE_MEM; - a->reg = reg->val.u.reg; - a->offset = 0; - goto yes; - -oindex_const: - // index is constant - // can check statically and - // can multiply by width statically - - regalloc(reg, types[tptr], N); - if(o & OPtrto) { - cgen(l, reg); - cgen_checknil(reg); - } else - agen(l, reg); - - v = mpgetfix(r->val.u.xval); - if(o & ODynam) { - if(!debug['B'] && !n->bounded) { - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - nodconst(&n2, types[TUINT32], v); - regalloc(&n3, types[TUINT32], N); - cgen(&n2, &n3); - regalloc(&n4, n1.type, N); - cgen(&n1, &n4); - gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3); - regfree(&n4); - regfree(&n3); - p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); - ginscall(panicindex, 0); - patch(p1, pc); - } - - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, reg); - } - - n2 = *reg; - n2.op = OINDREG; - n2.xoffset = v * (*w); - a->type = TYPE_NONE; - a->name = NAME_NONE; - naddr(&n2, a, 1); - goto yes; - -yes: - return 1; - -no: - sudoclean(); - return 0; -} diff --git a/src/cmd/5g/gsubr.go b/src/cmd/5g/gsubr.go new file mode 100644 index 0000000000..857bafaf64 --- /dev/null +++ b/src/cmd/5g/gsubr.go @@ -0,0 +1,1599 @@ +// Derived from Inferno utils/5c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" + "fmt" +) +import "cmd/internal/gc" + +// TODO(rsc): Can make this bigger if we move +// the text segment up higher in 5l for all GOOS. +// At the same time, can raise StackBig in ../../runtime/stack.h. +var unmappedzero int = 4096 + +var resvd = []int{ + 9, // reserved for m + 10, // reserved for g + arm.REGSP, // reserved for SP +} + +func ginit() { + var i int + + for i = 0; i < len(reg); i++ { + reg[i] = 0 + } + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]++ + } +} + +func gclean() { + var i int + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]-- + } + + for i = 0; i < len(reg); i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) + } + } +} + +func anyregalloc() bool { + var i int + var j int + + for i = 0; i < len(reg); i++ { + if reg[i] == 0 { + goto ok + } + for j = 0; j < len(resvd); j++ { + if resvd[j] == i { + goto ok + } + } + return true + ok: + } + + return false +} + +var regpc [REGALLOC_FMAX + 1]uint32 + +/* + * allocate register of type t, leave in n. + * if o != N, o is desired fixed register. + * caller must regfree(n). + */ +func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { + var i int + var et int + var fixfree int + var floatfree int + + if false && gc.Debug['r'] != 0 { + fixfree = 0 + for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { + if reg[i] == 0 { + fixfree++ + } + } + floatfree = 0 + for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { + if reg[i] == 0 { + floatfree++ + } + } + fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree) + } + + if t == nil { + gc.Fatal("regalloc: t nil") + } + et = int(gc.Simtype[t.Etype]) + if gc.Is64(t) { + gc.Fatal("regalloc: 64 bit type %v") + } + + switch et { + case gc.TINT8, + gc.TUINT8, + gc.TINT16, + gc.TUINT16, + gc.TINT32, + gc.TUINT32, + gc.TPTR32, + gc.TBOOL: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= REGALLOC_R0 && i <= REGALLOC_RMAX { + goto out + } + } + + for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { + if reg[i] == 0 { + regpc[i] = uint32(obj.Getcallerpc(&n)) + goto out + } + } + + fmt.Printf("registers allocated at\n") + for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { + fmt.Printf("%d %p\n", i, regpc[i]) + } + gc.Fatal("out of fixed registers") + goto err + + case gc.TFLOAT32, + gc.TFLOAT64: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= REGALLOC_F0 && i <= REGALLOC_FMAX { + goto out + } + } + + for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { + if reg[i] == 0 { + goto out + } + } + gc.Fatal("out of floating point registers") + goto err + + case gc.TCOMPLEX64, + gc.TCOMPLEX128: + gc.Tempname(n, t) + return + } + + gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0)) + +err: + gc.Nodreg(n, t, arm.REG_R0) + return + +out: + reg[i]++ + gc.Nodreg(n, t, i) +} + +func regfree(n *gc.Node) { + var i int + var fixfree int + var floatfree int + + if false && gc.Debug['r'] != 0 { + fixfree = 0 + for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { + if reg[i] == 0 { + fixfree++ + } + } + floatfree = 0 + for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { + if reg[i] == 0 { + floatfree++ + } + } + fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree) + } + + if n.Op == gc.ONAME { + return + } + if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { + gc.Fatal("regfree: not a register") + } + i = int(n.Val.U.Reg) + if i == arm.REGSP { + return + } + if i < 0 || i >= len(reg) || i >= len(regpc) { + gc.Fatal("regfree: reg out of range") + } + if reg[i] <= 0 { + gc.Fatal("regfree: reg %v not allocated", gc.Ctxt.Rconv(i)) + } + reg[i]-- + if reg[i] == 0 { + regpc[i] = 0 + } +} + +/* + * return constant i node. + * overwritten by next call, but useful in calls to gins. + */ + +var ncon_n gc.Node + +func ncon(i uint32) *gc.Node { + if ncon_n.Type == nil { + gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) + } + gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + return &ncon_n +} + +var sclean [10]gc.Node + +var nsclean int + +/* + * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. + */ +func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { + var n1 gc.Node + var i int64 + + if !gc.Is64(n.Type) { + gc.Fatal("split64 %v", gc.Tconv(n.Type, 0)) + } + + if nsclean >= len(sclean) { + gc.Fatal("split64 clean") + } + sclean[nsclean].Op = gc.OEMPTY + nsclean++ + switch n.Op { + default: + switch n.Op { + default: + if !dotaddable(n, &n1) { + igen(n, &n1, nil) + sclean[nsclean-1] = n1 + } + + n = &n1 + + case gc.ONAME: + if n.Class == gc.PPARAMREF { + cgen(n.Heapaddr, &n1) + sclean[nsclean-1] = n1 + n = &n1 + } + + // nothing + case gc.OINDREG: + break + } + + *lo = *n + *hi = *n + lo.Type = gc.Types[gc.TUINT32] + if n.Type.Etype == gc.TINT64 { + hi.Type = gc.Types[gc.TINT32] + } else { + hi.Type = gc.Types[gc.TUINT32] + } + hi.Xoffset += 4 + + case gc.OLITERAL: + gc.Convconst(&n1, n.Type, &n.Val) + i = gc.Mpgetfix(n1.Val.U.Xval) + gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) + i >>= 32 + if n.Type.Etype == gc.TINT64 { + gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i))) + } else { + gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i))) + } + } +} + +func splitclean() { + if nsclean <= 0 { + gc.Fatal("splitclean") + } + nsclean-- + if sclean[nsclean].Op != gc.OEMPTY { + regfree(&sclean[nsclean]) + } +} + +func gmove(f *gc.Node, t *gc.Node) { + var a int + var ft int + var tt int + var fa int + var ta int + var cvt *gc.Type + var r1 gc.Node + var r2 gc.Node + var flo gc.Node + var fhi gc.Node + var tlo gc.Node + var thi gc.Node + var con gc.Node + var p1 *obj.Prog + + if gc.Debug['M'] != 0 { + fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0)) + } + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { + gc.Complexmove(f, t) + return + } + + // cannot have two memory operands; + // except 64-bit, which always copies via registers anyway. + if !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + + // convert constant to desired type + if f.Op == gc.OLITERAL { + switch tt { + default: + gc.Convconst(&con, t.Type, &f.Val) + + case gc.TINT16, + gc.TINT8: + gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val) + regalloc(&r1, con.Type, t) + gins(arm.AMOVW, &con, &r1) + gmove(&r1, t) + regfree(&r1) + return + + case gc.TUINT16, + gc.TUINT8: + gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val) + regalloc(&r1, con.Type, t) + gins(arm.AMOVW, &con, &r1) + gmove(&r1, t) + regfree(&r1) + return + } + + f = &con + ft = gc.Simsimtype(con.Type) + + // constants can't move directly to memory + if gc.Ismem(t) && !gc.Is64(t.Type) { + goto hard + } + } + + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + + switch uint32(ft)<<16 | uint32(tt) { + default: + goto fatal + + /* + * integer copy and truncate + */ + case gc.TINT8<<16 | gc.TINT8: // same size + if !gc.Ismem(f) { + a = arm.AMOVB + break + } + fallthrough + + case gc.TUINT8<<16 | gc.TINT8, + gc.TINT16<<16 | gc.TINT8, // truncate + gc.TUINT16<<16 | gc.TINT8, + gc.TINT32<<16 | gc.TINT8, + gc.TUINT32<<16 | gc.TINT8: + a = arm.AMOVBS + + case gc.TUINT8<<16 | gc.TUINT8: + if !gc.Ismem(f) { + a = arm.AMOVB + break + } + fallthrough + + case gc.TINT8<<16 | gc.TUINT8, + gc.TINT16<<16 | gc.TUINT8, + gc.TUINT16<<16 | gc.TUINT8, + gc.TINT32<<16 | gc.TUINT8, + gc.TUINT32<<16 | gc.TUINT8: + a = arm.AMOVBU + + case gc.TINT64<<16 | gc.TINT8, // truncate low word + gc.TUINT64<<16 | gc.TINT8: + a = arm.AMOVBS + + goto trunc64 + + case gc.TINT64<<16 | gc.TUINT8, + gc.TUINT64<<16 | gc.TUINT8: + a = arm.AMOVBU + goto trunc64 + + case gc.TINT16<<16 | gc.TINT16: // same size + if !gc.Ismem(f) { + a = arm.AMOVH + break + } + fallthrough + + case gc.TUINT16<<16 | gc.TINT16, + gc.TINT32<<16 | gc.TINT16, // truncate + gc.TUINT32<<16 | gc.TINT16: + a = arm.AMOVHS + + case gc.TUINT16<<16 | gc.TUINT16: + if !gc.Ismem(f) { + a = arm.AMOVH + break + } + fallthrough + + case gc.TINT16<<16 | gc.TUINT16, + gc.TINT32<<16 | gc.TUINT16, + gc.TUINT32<<16 | gc.TUINT16: + a = arm.AMOVHU + + case gc.TINT64<<16 | gc.TINT16, // truncate low word + gc.TUINT64<<16 | gc.TINT16: + a = arm.AMOVHS + + goto trunc64 + + case gc.TINT64<<16 | gc.TUINT16, + gc.TUINT64<<16 | gc.TUINT16: + a = arm.AMOVHU + goto trunc64 + + case gc.TINT32<<16 | gc.TINT32, // same size + gc.TINT32<<16 | gc.TUINT32, + gc.TUINT32<<16 | gc.TINT32, + gc.TUINT32<<16 | gc.TUINT32: + a = arm.AMOVW + + case gc.TINT64<<16 | gc.TINT32, // truncate + gc.TUINT64<<16 | gc.TINT32, + gc.TINT64<<16 | gc.TUINT32, + gc.TUINT64<<16 | gc.TUINT32: + split64(f, &flo, &fhi) + + regalloc(&r1, t.Type, nil) + gins(arm.AMOVW, &flo, &r1) + gins(arm.AMOVW, &r1, t) + regfree(&r1) + splitclean() + return + + case gc.TINT64<<16 | gc.TINT64, // same size + gc.TINT64<<16 | gc.TUINT64, + gc.TUINT64<<16 | gc.TINT64, + gc.TUINT64<<16 | gc.TUINT64: + split64(f, &flo, &fhi) + + split64(t, &tlo, &thi) + regalloc(&r1, flo.Type, nil) + regalloc(&r2, fhi.Type, nil) + gins(arm.AMOVW, &flo, &r1) + gins(arm.AMOVW, &fhi, &r2) + gins(arm.AMOVW, &r1, &tlo) + gins(arm.AMOVW, &r2, &thi) + regfree(&r1) + regfree(&r2) + splitclean() + splitclean() + return + + /* + * integer up-conversions + */ + case gc.TINT8<<16 | gc.TINT16, // sign extend int8 + gc.TINT8<<16 | gc.TUINT16, + gc.TINT8<<16 | gc.TINT32, + gc.TINT8<<16 | gc.TUINT32: + a = arm.AMOVBS + + goto rdst + + case gc.TINT8<<16 | gc.TINT64, // convert via int32 + gc.TINT8<<16 | gc.TUINT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 + gc.TUINT8<<16 | gc.TUINT16, + gc.TUINT8<<16 | gc.TINT32, + gc.TUINT8<<16 | gc.TUINT32: + a = arm.AMOVBU + + goto rdst + + case gc.TUINT8<<16 | gc.TINT64, // convert via uint32 + gc.TUINT8<<16 | gc.TUINT64: + cvt = gc.Types[gc.TUINT32] + + goto hard + + case gc.TINT16<<16 | gc.TINT32, // sign extend int16 + gc.TINT16<<16 | gc.TUINT32: + a = arm.AMOVHS + + goto rdst + + case gc.TINT16<<16 | gc.TINT64, // convert via int32 + gc.TINT16<<16 | gc.TUINT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 + gc.TUINT16<<16 | gc.TUINT32: + a = arm.AMOVHU + + goto rdst + + case gc.TUINT16<<16 | gc.TINT64, // convert via uint32 + gc.TUINT16<<16 | gc.TUINT64: + cvt = gc.Types[gc.TUINT32] + + goto hard + + case gc.TINT32<<16 | gc.TINT64, // sign extend int32 + gc.TINT32<<16 | gc.TUINT64: + split64(t, &tlo, &thi) + + regalloc(&r1, tlo.Type, nil) + regalloc(&r2, thi.Type, nil) + gmove(f, &r1) + p1 = gins(arm.AMOVW, &r1, &r2) + p1.From.Type = obj.TYPE_SHIFT + p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Val.U.Reg)&15 // r1->31 + p1.From.Reg = 0 + + //print("gmove: %P\n", p1); + gins(arm.AMOVW, &r1, &tlo) + + gins(arm.AMOVW, &r2, &thi) + regfree(&r1) + regfree(&r2) + splitclean() + return + + case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 + gc.TUINT32<<16 | gc.TUINT64: + split64(t, &tlo, &thi) + + gmove(f, &tlo) + regalloc(&r1, thi.Type, nil) + gins(arm.AMOVW, ncon(0), &r1) + gins(arm.AMOVW, &r1, &thi) + regfree(&r1) + splitclean() + return + + // case CASE(TFLOAT64, TUINT64): + /* + * float to integer + */ + case gc.TFLOAT32<<16 | gc.TINT8, + gc.TFLOAT32<<16 | gc.TUINT8, + gc.TFLOAT32<<16 | gc.TINT16, + gc.TFLOAT32<<16 | gc.TUINT16, + gc.TFLOAT32<<16 | gc.TINT32, + gc.TFLOAT32<<16 | gc.TUINT32, + + // case CASE(TFLOAT32, TUINT64): + + gc.TFLOAT64<<16 | gc.TINT8, + gc.TFLOAT64<<16 | gc.TUINT8, + gc.TFLOAT64<<16 | gc.TINT16, + gc.TFLOAT64<<16 | gc.TUINT16, + gc.TFLOAT64<<16 | gc.TINT32, + gc.TFLOAT64<<16 | gc.TUINT32: + fa = arm.AMOVF + + a = arm.AMOVFW + if ft == gc.TFLOAT64 { + fa = arm.AMOVD + a = arm.AMOVDW + } + + ta = arm.AMOVW + switch tt { + case gc.TINT8: + ta = arm.AMOVBS + + case gc.TUINT8: + ta = arm.AMOVBU + + case gc.TINT16: + ta = arm.AMOVHS + + case gc.TUINT16: + ta = arm.AMOVHU + } + + regalloc(&r1, gc.Types[ft], f) + regalloc(&r2, gc.Types[tt], t) + gins(fa, f, &r1) // load to fpu + p1 = gins(a, &r1, &r1) // convert to w + switch tt { + case gc.TUINT8, + gc.TUINT16, + gc.TUINT32: + p1.Scond |= arm.C_UBIT + } + + gins(arm.AMOVW, &r1, &r2) // copy to cpu + gins(ta, &r2, t) // store + regfree(&r1) + regfree(&r2) + return + + /* + * integer to float + */ + case gc.TINT8<<16 | gc.TFLOAT32, + gc.TUINT8<<16 | gc.TFLOAT32, + gc.TINT16<<16 | gc.TFLOAT32, + gc.TUINT16<<16 | gc.TFLOAT32, + gc.TINT32<<16 | gc.TFLOAT32, + gc.TUINT32<<16 | gc.TFLOAT32, + gc.TINT8<<16 | gc.TFLOAT64, + gc.TUINT8<<16 | gc.TFLOAT64, + gc.TINT16<<16 | gc.TFLOAT64, + gc.TUINT16<<16 | gc.TFLOAT64, + gc.TINT32<<16 | gc.TFLOAT64, + gc.TUINT32<<16 | gc.TFLOAT64: + fa = arm.AMOVW + + switch ft { + case gc.TINT8: + fa = arm.AMOVBS + + case gc.TUINT8: + fa = arm.AMOVBU + + case gc.TINT16: + fa = arm.AMOVHS + + case gc.TUINT16: + fa = arm.AMOVHU + } + + a = arm.AMOVWF + ta = arm.AMOVF + if tt == gc.TFLOAT64 { + a = arm.AMOVWD + ta = arm.AMOVD + } + + regalloc(&r1, gc.Types[ft], f) + regalloc(&r2, gc.Types[tt], t) + gins(fa, f, &r1) // load to cpu + gins(arm.AMOVW, &r1, &r2) // copy to fpu + p1 = gins(a, &r2, &r2) // convert + switch ft { + case gc.TUINT8, + gc.TUINT16, + gc.TUINT32: + p1.Scond |= arm.C_UBIT + } + + gins(ta, &r2, t) // store + regfree(&r1) + regfree(&r2) + return + + case gc.TUINT64<<16 | gc.TFLOAT32, + gc.TUINT64<<16 | gc.TFLOAT64: + gc.Fatal("gmove UINT64, TFLOAT not implemented") + return + + /* + * float to float + */ + case gc.TFLOAT32<<16 | gc.TFLOAT32: + a = arm.AMOVF + + case gc.TFLOAT64<<16 | gc.TFLOAT64: + a = arm.AMOVD + + case gc.TFLOAT32<<16 | gc.TFLOAT64: + regalloc(&r1, gc.Types[gc.TFLOAT64], t) + gins(arm.AMOVF, f, &r1) + gins(arm.AMOVFD, &r1, &r1) + gins(arm.AMOVD, &r1, t) + regfree(&r1) + return + + case gc.TFLOAT64<<16 | gc.TFLOAT32: + regalloc(&r1, gc.Types[gc.TFLOAT64], t) + gins(arm.AMOVD, f, &r1) + gins(arm.AMOVDF, &r1, &r1) + gins(arm.AMOVF, &r1, t) + regfree(&r1) + return + } + + gins(a, f, t) + return + + // TODO(kaib): we almost always require a register dest anyway, this can probably be + // removed. + // requires register destination +rdst: + regalloc(&r1, t.Type, t) + + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // truncate 64 bit integer +trunc64: + split64(f, &flo, &fhi) + + regalloc(&r1, t.Type, nil) + gins(a, &flo, &r1) + gins(a, &r1, t) + regfree(&r1) + splitclean() + return + + // should not happen +fatal: + gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) +} + +func samaddr(f *gc.Node, t *gc.Node) bool { + if f.Op != t.Op { + return false + } + + switch f.Op { + case gc.OREGISTER: + if f.Val.U.Reg != t.Val.U.Reg { + break + } + return true + } + + return false +} + +/* + * generate one instruction: + * as f, t + */ +func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { + var p *obj.Prog + var af obj.Addr + // Node nod; + // int32 v; + + var at obj.Addr + + if f != nil && f.Op == gc.OINDEX { + gc.Fatal("gins OINDEX not implemented") + } + + // regalloc(&nod, ®node, Z); + // v = constnode.vconst; + // cgen(f->right, &nod); + // constnode.vconst = v; + // idx.reg = nod.reg; + // regfree(&nod); + if t != nil && t.Op == gc.OINDEX { + gc.Fatal("gins OINDEX not implemented") + } + + // regalloc(&nod, ®node, Z); + // v = constnode.vconst; + // cgen(t->right, &nod); + // constnode.vconst = v; + // idx.reg = nod.reg; + // regfree(&nod); + af = obj.Addr{} + + at = obj.Addr{} + if f != nil { + gc.Naddr(f, &af, 1) + } + if t != nil { + gc.Naddr(t, &at, 1) + } + p = gc.Prog(as) + if f != nil { + p.From = af + } + if t != nil { + p.To = at + } + if gc.Debug['g'] != 0 { + fmt.Printf("%v\n", p) + } + return p +} + +/* + * insert n into reg slot of p + */ +func raddr(n *gc.Node, p *obj.Prog) { + var a obj.Addr + + gc.Naddr(n, &a, 1) + if a.Type != obj.TYPE_REG { + if n != nil { + gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0)) + } else { + gc.Fatal("bad in raddr: ") + } + p.Reg = 0 + } else { + p.Reg = a.Reg + } +} + +/* generate a comparison +TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites. +*/ +func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog { + var p *obj.Prog + + if lhs.Op != gc.OREGISTER { + gc.Fatal("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0)) + } + + p = gins(as, rhs, nil) + raddr(lhs, p) + return p +} + +/* generate a constant shift + * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal. + */ +func gshift(as int, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Prog { + var p *obj.Prog + + if sval <= 0 || sval > 32 { + gc.Fatal("bad shift value: %d", sval) + } + + sval = sval & 0x1f + + p = gins(as, nil, rhs) + p.From.Type = obj.TYPE_SHIFT + p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Val.U.Reg)&15 + return p +} + +/* generate a register shift + */ +func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog { + var p *obj.Prog + p = gins(as, nil, rhs) + p.From.Type = obj.TYPE_SHIFT + p.From.Offset = int64(stype) | (int64(reg.Val.U.Reg)&15)<<8 | 1<<4 | int64(lhs.Val.U.Reg)&15 + return p +} + +/* + * return Axxx for Oxxx on type t. + */ +func optoas(op int, t *gc.Type) int { + var a int + + if t == nil { + gc.Fatal("optoas: t is nil") + } + + a = obj.AXXX + switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { + default: + gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0), gc.Tconv(gc.Types[t.Etype], 0), gc.Tconv(gc.Types[gc.Simtype[t.Etype]], 0)) + + /* case CASE(OADDR, TPTR32): + a = ALEAL; + break; + + case CASE(OADDR, TPTR64): + a = ALEAQ; + break; + */ + // TODO(kaib): make sure the conditional branches work on all edge cases + case gc.OEQ<<16 | gc.TBOOL, + gc.OEQ<<16 | gc.TINT8, + gc.OEQ<<16 | gc.TUINT8, + gc.OEQ<<16 | gc.TINT16, + gc.OEQ<<16 | gc.TUINT16, + gc.OEQ<<16 | gc.TINT32, + gc.OEQ<<16 | gc.TUINT32, + gc.OEQ<<16 | gc.TINT64, + gc.OEQ<<16 | gc.TUINT64, + gc.OEQ<<16 | gc.TPTR32, + gc.OEQ<<16 | gc.TPTR64, + gc.OEQ<<16 | gc.TFLOAT32, + gc.OEQ<<16 | gc.TFLOAT64: + a = arm.ABEQ + + case gc.ONE<<16 | gc.TBOOL, + gc.ONE<<16 | gc.TINT8, + gc.ONE<<16 | gc.TUINT8, + gc.ONE<<16 | gc.TINT16, + gc.ONE<<16 | gc.TUINT16, + gc.ONE<<16 | gc.TINT32, + gc.ONE<<16 | gc.TUINT32, + gc.ONE<<16 | gc.TINT64, + gc.ONE<<16 | gc.TUINT64, + gc.ONE<<16 | gc.TPTR32, + gc.ONE<<16 | gc.TPTR64, + gc.ONE<<16 | gc.TFLOAT32, + gc.ONE<<16 | gc.TFLOAT64: + a = arm.ABNE + + case gc.OLT<<16 | gc.TINT8, + gc.OLT<<16 | gc.TINT16, + gc.OLT<<16 | gc.TINT32, + gc.OLT<<16 | gc.TINT64, + gc.OLT<<16 | gc.TFLOAT32, + gc.OLT<<16 | gc.TFLOAT64: + a = arm.ABLT + + case gc.OLT<<16 | gc.TUINT8, + gc.OLT<<16 | gc.TUINT16, + gc.OLT<<16 | gc.TUINT32, + gc.OLT<<16 | gc.TUINT64: + a = arm.ABLO + + case gc.OLE<<16 | gc.TINT8, + gc.OLE<<16 | gc.TINT16, + gc.OLE<<16 | gc.TINT32, + gc.OLE<<16 | gc.TINT64, + gc.OLE<<16 | gc.TFLOAT32, + gc.OLE<<16 | gc.TFLOAT64: + a = arm.ABLE + + case gc.OLE<<16 | gc.TUINT8, + gc.OLE<<16 | gc.TUINT16, + gc.OLE<<16 | gc.TUINT32, + gc.OLE<<16 | gc.TUINT64: + a = arm.ABLS + + case gc.OGT<<16 | gc.TINT8, + gc.OGT<<16 | gc.TINT16, + gc.OGT<<16 | gc.TINT32, + gc.OGT<<16 | gc.TINT64, + gc.OGT<<16 | gc.TFLOAT32, + gc.OGT<<16 | gc.TFLOAT64: + a = arm.ABGT + + case gc.OGT<<16 | gc.TUINT8, + gc.OGT<<16 | gc.TUINT16, + gc.OGT<<16 | gc.TUINT32, + gc.OGT<<16 | gc.TUINT64: + a = arm.ABHI + + case gc.OGE<<16 | gc.TINT8, + gc.OGE<<16 | gc.TINT16, + gc.OGE<<16 | gc.TINT32, + gc.OGE<<16 | gc.TINT64, + gc.OGE<<16 | gc.TFLOAT32, + gc.OGE<<16 | gc.TFLOAT64: + a = arm.ABGE + + case gc.OGE<<16 | gc.TUINT8, + gc.OGE<<16 | gc.TUINT16, + gc.OGE<<16 | gc.TUINT32, + gc.OGE<<16 | gc.TUINT64: + a = arm.ABHS + + case gc.OCMP<<16 | gc.TBOOL, + gc.OCMP<<16 | gc.TINT8, + gc.OCMP<<16 | gc.TUINT8, + gc.OCMP<<16 | gc.TINT16, + gc.OCMP<<16 | gc.TUINT16, + gc.OCMP<<16 | gc.TINT32, + gc.OCMP<<16 | gc.TUINT32, + gc.OCMP<<16 | gc.TPTR32: + a = arm.ACMP + + case gc.OCMP<<16 | gc.TFLOAT32: + a = arm.ACMPF + + case gc.OCMP<<16 | gc.TFLOAT64: + a = arm.ACMPD + + case gc.OAS<<16 | gc.TBOOL: + a = arm.AMOVB + + case gc.OAS<<16 | gc.TINT8: + a = arm.AMOVBS + + case gc.OAS<<16 | gc.TUINT8: + a = arm.AMOVBU + + case gc.OAS<<16 | gc.TINT16: + a = arm.AMOVHS + + case gc.OAS<<16 | gc.TUINT16: + a = arm.AMOVHU + + case gc.OAS<<16 | gc.TINT32, + gc.OAS<<16 | gc.TUINT32, + gc.OAS<<16 | gc.TPTR32: + a = arm.AMOVW + + case gc.OAS<<16 | gc.TFLOAT32: + a = arm.AMOVF + + case gc.OAS<<16 | gc.TFLOAT64: + a = arm.AMOVD + + case gc.OADD<<16 | gc.TINT8, + gc.OADD<<16 | gc.TUINT8, + gc.OADD<<16 | gc.TINT16, + gc.OADD<<16 | gc.TUINT16, + gc.OADD<<16 | gc.TINT32, + gc.OADD<<16 | gc.TUINT32, + gc.OADD<<16 | gc.TPTR32: + a = arm.AADD + + case gc.OADD<<16 | gc.TFLOAT32: + a = arm.AADDF + + case gc.OADD<<16 | gc.TFLOAT64: + a = arm.AADDD + + case gc.OSUB<<16 | gc.TINT8, + gc.OSUB<<16 | gc.TUINT8, + gc.OSUB<<16 | gc.TINT16, + gc.OSUB<<16 | gc.TUINT16, + gc.OSUB<<16 | gc.TINT32, + gc.OSUB<<16 | gc.TUINT32, + gc.OSUB<<16 | gc.TPTR32: + a = arm.ASUB + + case gc.OSUB<<16 | gc.TFLOAT32: + a = arm.ASUBF + + case gc.OSUB<<16 | gc.TFLOAT64: + a = arm.ASUBD + + case gc.OMINUS<<16 | gc.TINT8, + gc.OMINUS<<16 | gc.TUINT8, + gc.OMINUS<<16 | gc.TINT16, + gc.OMINUS<<16 | gc.TUINT16, + gc.OMINUS<<16 | gc.TINT32, + gc.OMINUS<<16 | gc.TUINT32, + gc.OMINUS<<16 | gc.TPTR32: + a = arm.ARSB + + case gc.OAND<<16 | gc.TINT8, + gc.OAND<<16 | gc.TUINT8, + gc.OAND<<16 | gc.TINT16, + gc.OAND<<16 | gc.TUINT16, + gc.OAND<<16 | gc.TINT32, + gc.OAND<<16 | gc.TUINT32, + gc.OAND<<16 | gc.TPTR32: + a = arm.AAND + + case gc.OOR<<16 | gc.TINT8, + gc.OOR<<16 | gc.TUINT8, + gc.OOR<<16 | gc.TINT16, + gc.OOR<<16 | gc.TUINT16, + gc.OOR<<16 | gc.TINT32, + gc.OOR<<16 | gc.TUINT32, + gc.OOR<<16 | gc.TPTR32: + a = arm.AORR + + case gc.OXOR<<16 | gc.TINT8, + gc.OXOR<<16 | gc.TUINT8, + gc.OXOR<<16 | gc.TINT16, + gc.OXOR<<16 | gc.TUINT16, + gc.OXOR<<16 | gc.TINT32, + gc.OXOR<<16 | gc.TUINT32, + gc.OXOR<<16 | gc.TPTR32: + a = arm.AEOR + + case gc.OLSH<<16 | gc.TINT8, + gc.OLSH<<16 | gc.TUINT8, + gc.OLSH<<16 | gc.TINT16, + gc.OLSH<<16 | gc.TUINT16, + gc.OLSH<<16 | gc.TINT32, + gc.OLSH<<16 | gc.TUINT32, + gc.OLSH<<16 | gc.TPTR32: + a = arm.ASLL + + case gc.ORSH<<16 | gc.TUINT8, + gc.ORSH<<16 | gc.TUINT16, + gc.ORSH<<16 | gc.TUINT32, + gc.ORSH<<16 | gc.TPTR32: + a = arm.ASRL + + case gc.ORSH<<16 | gc.TINT8, + gc.ORSH<<16 | gc.TINT16, + gc.ORSH<<16 | gc.TINT32: + a = arm.ASRA + + case gc.OMUL<<16 | gc.TUINT8, + gc.OMUL<<16 | gc.TUINT16, + gc.OMUL<<16 | gc.TUINT32, + gc.OMUL<<16 | gc.TPTR32: + a = arm.AMULU + + case gc.OMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TINT32: + a = arm.AMUL + + case gc.OMUL<<16 | gc.TFLOAT32: + a = arm.AMULF + + case gc.OMUL<<16 | gc.TFLOAT64: + a = arm.AMULD + + case gc.ODIV<<16 | gc.TUINT8, + gc.ODIV<<16 | gc.TUINT16, + gc.ODIV<<16 | gc.TUINT32, + gc.ODIV<<16 | gc.TPTR32: + a = arm.ADIVU + + case gc.ODIV<<16 | gc.TINT8, + gc.ODIV<<16 | gc.TINT16, + gc.ODIV<<16 | gc.TINT32: + a = arm.ADIV + + case gc.OMOD<<16 | gc.TUINT8, + gc.OMOD<<16 | gc.TUINT16, + gc.OMOD<<16 | gc.TUINT32, + gc.OMOD<<16 | gc.TPTR32: + a = arm.AMODU + + case gc.OMOD<<16 | gc.TINT8, + gc.OMOD<<16 | gc.TINT16, + gc.OMOD<<16 | gc.TINT32: + a = arm.AMOD + + // case CASE(OEXTEND, TINT16): + // a = ACWD; + // break; + + // case CASE(OEXTEND, TINT32): + // a = ACDQ; + // break; + + // case CASE(OEXTEND, TINT64): + // a = ACQO; + // break; + + case gc.ODIV<<16 | gc.TFLOAT32: + a = arm.ADIVF + + case gc.ODIV<<16 | gc.TFLOAT64: + a = arm.ADIVD + } + + return a +} + +const ( + ODynam = 1 << 0 + OPtrto = 1 << 1 +) + +var clean [20]gc.Node + +var cleani int = 0 + +func sudoclean() { + if clean[cleani-1].Op != gc.OEMPTY { + regfree(&clean[cleani-1]) + } + if clean[cleani-2].Op != gc.OEMPTY { + regfree(&clean[cleani-2]) + } + cleani -= 2 +} + +func dotaddable(n *gc.Node, n1 *gc.Node) bool { + var o int + var oary [10]int64 + var nn *gc.Node + + if n.Op != gc.ODOT { + return false + } + + o = gc.Dotoffset(n, oary[:], &nn) + if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 { + *n1 = *nn + n1.Type = n.Type + n1.Xoffset += oary[0] + return true + } + + return false +} + +/* + * generate code to compute address of n, + * a reference to a (perhaps nested) field inside + * an array or struct. + * return 0 on failure, 1 on success. + * on success, leaves usable address in a. + * + * caller is responsible for calling sudoclean + * after successful sudoaddable, + * to release the register used for a. + */ +func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool { + var o int + var i int + var oary [10]int64 + var v int64 + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var nn *gc.Node + var l *gc.Node + var r *gc.Node + var reg *gc.Node + var reg1 *gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var t *gc.Type + + if n.Type == nil { + return false + } + + *a = obj.Addr{} + + switch n.Op { + case gc.OLITERAL: + if !gc.Isconst(n, gc.CTINT) { + break + } + v = gc.Mpgetfix(n.Val.U.Xval) + if v >= 32000 || v <= -32000 { + break + } + goto lit + + case gc.ODOT, + gc.ODOTPTR: + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + goto odot + + case gc.OINDEX: + return false + + // disabled: OINDEX case is now covered by agenr + // for a more suitable register allocation pattern. + if n.Left.Type.Etype == gc.TSTRING { + return false + } + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + goto oindex + } + + return false + +lit: + switch as { + default: + return false + + case arm.AADD, + arm.ASUB, + arm.AAND, + arm.AORR, + arm.AEOR, + arm.AMOVB, + arm.AMOVBS, + arm.AMOVBU, + arm.AMOVH, + arm.AMOVHS, + arm.AMOVHU, + arm.AMOVW: + break + } + + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + gc.Naddr(n, a, 1) + goto yes + +odot: + o = gc.Dotoffset(n, oary[:], &nn) + if nn == nil { + goto no + } + + if nn.Addable != 0 && o == 1 && oary[0] >= 0 { + // directly addressable set of DOTs + n1 = *nn + + n1.Type = n.Type + n1.Xoffset += oary[0] + gc.Naddr(&n1, a, 1) + goto yes + } + + regalloc(reg, gc.Types[gc.Tptr], nil) + n1 = *reg + n1.Op = gc.OINDREG + if oary[0] >= 0 { + agen(nn, reg) + n1.Xoffset = oary[0] + } else { + cgen(nn, reg) + gc.Cgen_checknil(reg) + n1.Xoffset = -(oary[0] + 1) + } + + for i = 1; i < o; i++ { + if oary[i] >= 0 { + gc.Fatal("can't happen") + } + gins(arm.AMOVW, &n1, reg) + gc.Cgen_checknil(reg) + n1.Xoffset = -(oary[i] + 1) + } + + a.Type = obj.TYPE_NONE + a.Name = obj.NAME_NONE + n1.Type = n.Type + gc.Naddr(&n1, a, 1) + goto yes + +oindex: + l = n.Left + r = n.Right + if l.Ullman >= gc.UINF && r.Ullman >= gc.UINF { + goto no + } + + // set o to type of array + o = 0 + + if gc.Isptr[l.Type.Etype] != 0 { + o += OPtrto + if l.Type.Type.Etype != gc.TARRAY { + gc.Fatal("not ptr ary") + } + if l.Type.Type.Bound < 0 { + o += ODynam + } + } else { + if l.Type.Etype != gc.TARRAY { + gc.Fatal("not ary") + } + if l.Type.Bound < 0 { + o += ODynam + } + } + + *w = int(n.Type.Width) + if gc.Isconst(r, gc.CTINT) { + goto oindex_const + } + + switch *w { + default: + goto no + + case 1, + 2, + 4, + 8: + break + } + + // load the array (reg) + if l.Ullman > r.Ullman { + regalloc(reg, gc.Types[gc.Tptr], nil) + if o&OPtrto != 0 { + cgen(l, reg) + gc.Cgen_checknil(reg) + } else { + agen(l, reg) + } + } + + // load the index (reg1) + t = gc.Types[gc.TUINT32] + + if gc.Issigned[r.Type.Etype] != 0 { + t = gc.Types[gc.TINT32] + } + regalloc(reg1, t, nil) + regalloc(&n3, gc.Types[gc.TINT32], reg1) + p2 = cgenindex(r, &n3, gc.Debug['B'] != 0 || n.Bounded) + gmove(&n3, reg1) + regfree(&n3) + + // load the array (reg) + if l.Ullman <= r.Ullman { + regalloc(reg, gc.Types[gc.Tptr], nil) + if o&OPtrto != 0 { + cgen(l, reg) + gc.Cgen_checknil(reg) + } else { + agen(l, reg) + } + } + + // check bounds + if gc.Debug['B'] == 0 { + if o&ODynam != 0 { + n2 = *reg + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.Tptr] + n2.Xoffset = int64(gc.Array_nel) + } else { + if o&OPtrto != 0 { + gc.Nodconst(&n2, gc.Types[gc.TUINT32], l.Type.Type.Bound) + } else { + gc.Nodconst(&n2, gc.Types[gc.TUINT32], l.Type.Bound) + } + } + + regalloc(&n3, n2.Type, nil) + cgen(&n2, &n3) + gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), reg1, &n3) + regfree(&n3) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + if p2 != nil { + gc.Patch(p2, gc.Pc) + } + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + if o&ODynam != 0 { + n2 = *reg + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.Tptr] + n2.Xoffset = int64(gc.Array_array) + gmove(&n2, reg) + } + + switch *w { + case 1: + gins(arm.AADD, reg1, reg) + + case 2: + gshift(arm.AADD, reg1, arm.SHIFT_LL, 1, reg) + + case 4: + gshift(arm.AADD, reg1, arm.SHIFT_LL, 2, reg) + + case 8: + gshift(arm.AADD, reg1, arm.SHIFT_LL, 3, reg) + } + + gc.Naddr(reg1, a, 1) + a.Type = obj.TYPE_MEM + a.Reg = reg.Val.U.Reg + a.Offset = 0 + goto yes + + // index is constant + // can check statically and + // can multiply by width statically + +oindex_const: + regalloc(reg, gc.Types[gc.Tptr], nil) + + if o&OPtrto != 0 { + cgen(l, reg) + gc.Cgen_checknil(reg) + } else { + agen(l, reg) + } + + v = gc.Mpgetfix(r.Val.U.Xval) + if o&ODynam != 0 { + if gc.Debug['B'] == 0 && !n.Bounded { + n1 = *reg + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + gc.Nodconst(&n2, gc.Types[gc.TUINT32], v) + regalloc(&n3, gc.Types[gc.TUINT32], nil) + cgen(&n2, &n3) + regalloc(&n4, n1.Type, nil) + cgen(&n1, &n4) + gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n4, &n3) + regfree(&n4) + regfree(&n3) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + n1 = *reg + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, reg) + } + + n2 = *reg + n2.Op = gc.OINDREG + n2.Xoffset = v * int64(*w) + a.Type = obj.TYPE_NONE + a.Name = obj.NAME_NONE + gc.Naddr(&n2, a, 1) + goto yes + +yes: + return true + +no: + sudoclean() + return false +} diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c deleted file mode 100644 index 7fe3e1071f..0000000000 --- a/src/cmd/5g/peep.c +++ /dev/null @@ -1,1619 +0,0 @@ -// Inferno utils/5c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static int xtramodes(Graph*, Flow*, Adr*); -static int shortprop(Flow *r); -static int subprop(Flow*); -static int copyprop(Graph*, Flow*); -static int copy1(Adr*, Adr*, Flow*, int); -static int copyas(Adr*, Adr*); -static int copyau(Adr*, Adr*); -static int copysub(Adr*, Adr*, Adr*, int); -static int copysub1(Prog*, Adr*, Adr*, int); -static Flow* findpre(Flow *r, Adr *v); -static int copyau1(Prog *p, Adr *v); -static int isdconst(Addr *a); -static int isfloatreg(Addr*); -static int copyu(Prog *p, Adr *v, Adr *s); - -static uint32 gactive; - -// UNUSED -int shiftprop(Flow *r); -void constprop(Adr *c1, Adr *v1, Flow *r); -void predicate(Graph*); - - -void -peep(Prog *firstp) -{ - Flow *r; - Graph *g; - Prog *p; - int t; - - g = flowstart(firstp, 0); - if(g == nil) - return; - gactive = 0; - -loop1: - if(debug['P'] && debug['v']) - dumpit("loop1", g->start, 0); - - t = 0; - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case ASLL: - case ASRL: - case ASRA: - /* - * elide shift into TYPE_SHIFT operand of subsequent instruction - */ -// if(shiftprop(r)) { -// excise(r); -// t++; -// break; -// } - break; - - case AMOVB: - case AMOVH: - case AMOVW: - case AMOVF: - case AMOVD: - if(regtyp(&p->from)) - if(p->from.type == p->to.type && isfloatreg(&p->from) == isfloatreg(&p->to)) - if(p->scond == C_SCOND_NONE) { - if(copyprop(g, r)) { - excise(r); - t++; - break; - } - if(subprop(r) && copyprop(g, r)) { - excise(r); - t++; - break; - } - } - break; - - case AMOVHS: - case AMOVHU: - case AMOVBS: - case AMOVBU: - if(p->from.type == TYPE_REG) { - if(shortprop(r)) - t++; - } - break; - - /* - if(p->scond == C_SCOND_NONE) - if(regtyp(&p->to)) - if(isdconst(&p->from)) { - constprop(&p->from, &p->to, r->s1); - } - break; - */ - } - } - if(t) - goto loop1; - - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case AEOR: - /* - * EOR -1,x,y => MVN x,y - */ - if(isdconst(&p->from) && p->from.offset == -1) { - p->as = AMVN; - p->from.type = TYPE_REG; - if(p->reg != 0) - p->from.reg = p->reg; - else - p->from.reg = p->to.reg; - p->reg = 0; - } - break; - } - } - - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case AMOVW: - case AMOVB: - case AMOVBS: - case AMOVBU: - if(p->from.type == TYPE_MEM && p->from.offset == 0) - xtramodes(g, r, &p->from); - else - if(p->to.type == TYPE_MEM && p->to.offset == 0) - xtramodes(g, r, &p->to); - else - continue; - break; -// case ACMP: -// /* -// * elide CMP $0,x if calculation of x can set condition codes -// */ -// if(isdconst(&p->from) || p->from.offset != 0) -// continue; -// r2 = r->s1; -// if(r2 == nil) -// continue; -// t = r2->prog->as; -// switch(t) { -// default: -// continue; -// case ABEQ: -// case ABNE: -// case ABMI: -// case ABPL: -// break; -// case ABGE: -// t = ABPL; -// break; -// case ABLT: -// t = ABMI; -// break; -// case ABHI: -// t = ABNE; -// break; -// case ABLS: -// t = ABEQ; -// break; -// } -// r1 = r; -// do -// r1 = uniqp(r1); -// while (r1 != nil && r1->prog->as == ANOP); -// if(r1 == nil) -// continue; -// p1 = r1->prog; -// if(p1->to.type != TYPE_REG) -// continue; -// if(p1->to.reg != p->reg) -// if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg)) -// continue; -// -// switch(p1->as) { -// default: -// continue; -// case AMOVW: -// if(p1->from.type != TYPE_REG) -// continue; -// case AAND: -// case AEOR: -// case AORR: -// case ABIC: -// case AMVN: -// case ASUB: -// case ARSB: -// case AADD: -// case AADC: -// case ASBC: -// case ARSC: -// break; -// } -// p1->scond |= C_SBIT; -// r2->prog->as = t; -// excise(r); -// continue; - } - } - -// predicate(g); - - flowend(g); -} - -int -regtyp(Adr *a) -{ - return a->type == TYPE_REG && (REG_R0 <= a->reg && a->reg <= REG_R15 || REG_F0 <= a->reg && a->reg <= REG_F15); -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -static int -subprop(Flow *r0) -{ - Prog *p; - Adr *v1, *v2; - Flow *r; - int t; - ProgInfo info; - - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) - return 0; - v2 = &p->to; - if(!regtyp(v2)) - return 0; - for(r=uniqp(r0); r!=nil; r=uniqp(r)) { - if(uniqs(r) == nil) - break; - p = r->prog; - if(p->as == AVARDEF || p->as == AVARKILL) - continue; - proginfo(&info, p); - if(info.flags & Call) - return 0; - - if((info.flags & CanRegRead) && p->to.type == TYPE_REG) { - info.flags |= RegRead; - info.flags &= ~(CanRegRead | RightRead); - p->reg = p->to.reg; - } - - switch(p->as) { - case AMULLU: - case AMULA: - case AMVN: - return 0; - } - - if((info.flags & (RightRead|RightWrite)) == RightWrite) { - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) - if(p->scond == C_SCOND_NONE) - goto gotit; - } - - if(copyau(&p->from, v2) || - copyau1(p, v2) || - copyau(&p->to, v2)) - break; - if(copysub(&p->from, v1, v2, 0) || - copysub1(p, v1, v2, 0) || - copysub(&p->to, v1, v2, 0)) - break; - } - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub1(p, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -static int -copyprop(Graph *g, Flow *r0) -{ - Prog *p; - Adr *v1, *v2; - - USED(g); - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) - return 1; - gactive++; - return copy1(v1, v2, r0->s1, 0); -} - -static int -copy1(Adr *v1, Adr *v2, Flow *r, int f) -{ - int t; - Prog *p; - - if(r->active == gactive) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = gactive; - if(debug['P']) - print("copy %D->%D f=%d\n", v1, v2, f); - for(; r != nil; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == nil) { - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, can't split */ - if(debug['P']) - print("; %Drar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %Dset; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %Dused+set and f=%d; return 0\n", v2, f); - else - print("; %Dused and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub%D/%D", v2, v1); - if(t == 4) { - if(debug['P']) - print("; %Dused+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %Dset and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -// UNUSED -/* - * The idea is to remove redundant constants. - * $c1->v1 - * ($c1->v2 s/$c1/v1)* - * set v1 return - * The v1->v2 should be eliminated by copy propagation. - */ -void -constprop(Adr *c1, Adr *v1, Flow *r) -{ - Prog *p; - - if(debug['P']) - print("constprop %D->%D\n", c1, v1); - for(; r != nil; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(uniqp(r) == nil) { - if(debug['P']) - print("; merge; return\n"); - return; - } - if(p->as == AMOVW && copyas(&p->from, c1)) { - if(debug['P']) - print("; sub%D/%D", &p->from, v1); - p->from = *v1; - } else if(copyu(p, v1, nil) > 1) { - if(debug['P']) - print("; %Dset; return\n", v1); - return; - } - if(debug['P']) - print("\n"); - if(r->s2) - constprop(c1, v1, r->s2); - } -} - -/* - * shortprop eliminates redundant zero/sign extensions. - * - * MOVBS x, R - * - * MOVBS R, R' - * - * changed to - * - * MOVBS x, R - * ... - * MOVB R, R' (compiled to mov) - * - * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU. - */ -static int -shortprop(Flow *r) -{ - Prog *p, *p1; - Flow *r1; - - p = r->prog; - r1 = findpre(r, &p->from); - if(r1 == nil) - return 0; - - p1 = r1->prog; - if(p1->as == p->as) { - // Two consecutive extensions. - goto gotit; - } - - if(p1->as == AMOVW && isdconst(&p1->from) - && p1->from.offset >= 0 && p1->from.offset < 128) { - // Loaded an immediate. - goto gotit; - } - - return 0; - -gotit: - if(debug['P']) - print("shortprop\n%P\n%P", p1, p); - switch(p->as) { - case AMOVBS: - case AMOVBU: - p->as = AMOVB; - break; - case AMOVHS: - case AMOVHU: - p->as = AMOVH; - break; - } - if(debug['P']) - print(" => %A\n", p->as); - return 1; -} - -// UNUSED -/* - * ASLL x,y,w - * .. (not use w, not set x y w) - * AXXX w,a,b (a != w) - * .. (not use w) - * (set w) - * ----------- changed to - * .. - * AXXX (x<prog; - if(p->to.type != TYPE_REG) { - if(debug['P']) - print("\tBOTCH: result not reg; FAILURE\n"); - return 0; - } - n = p->to.reg; - a = zprog.from; - if(p->reg != 0 && p->reg != p->to.reg) { - a.type = TYPE_REG; - a.reg = p->reg; - } - if(debug['P']) - print("shiftprop\n%P", p); - r1 = r; - for(;;) { - /* find first use of shift result; abort if shift operands or result are changed */ - r1 = uniqs(r1); - if(r1 == nil) { - if(debug['P']) - print("\tbranch; FAILURE\n"); - return 0; - } - if(uniqp(r1) == nil) { - if(debug['P']) - print("\tmerge; FAILURE\n"); - return 0; - } - p1 = r1->prog; - if(debug['P']) - print("\n%P", p1); - switch(copyu(p1, &p->to, nil)) { - case 0: /* not used or set */ - if((p->from.type == TYPE_REG && copyu(p1, &p->from, nil) > 1) || - (a.type == TYPE_REG && copyu(p1, &a, nil) > 1)) { - if(debug['P']) - print("\targs modified; FAILURE\n"); - return 0; - } - continue; - case 3: /* set, not used */ { - if(debug['P']) - print("\tBOTCH: noref; FAILURE\n"); - return 0; - } - } - break; - } - /* check whether substitution can be done */ - switch(p1->as) { - default: - if(debug['P']) - print("\tnon-dpi; FAILURE\n"); - return 0; - - case AAND: - case AEOR: - case AADD: - case AADC: - case AORR: - case ASUB: - case ASBC: - case ARSB: - case ARSC: - if(p1->reg == n || (p1->reg == 0 && p1->to.type == TYPE_REG && p1->to.reg == n)) { - if(p1->from.type != TYPE_REG) { - if(debug['P']) - print("\tcan't swap; FAILURE\n"); - return 0; - } - p1->reg = p1->from.reg; - p1->from.reg = n; - switch(p1->as) { - case ASUB: - p1->as = ARSB; - break; - case ARSB: - p1->as = ASUB; - break; - case ASBC: - p1->as = ARSC; - break; - case ARSC: - p1->as = ASBC; - break; - } - if(debug['P']) - print("\t=>%P", p1); - } - case ABIC: - case ATST: - case ACMP: - case ACMN: - if(p1->reg == n) { - if(debug['P']) - print("\tcan't swap; FAILURE\n"); - return 0; - } - if(p1->reg == 0 && p1->to.reg == n) { - if(debug['P']) - print("\tshift result used twice; FAILURE\n"); - return 0; - } -// case AMVN: - if(p1->from.type == TYPE_SHIFT) { - if(debug['P']) - print("\tshift result used in shift; FAILURE\n"); - return 0; - } - if(p1->from.type != TYPE_REG || p1->from.reg != n) { - if(debug['P']) - print("\tBOTCH: where is it used?; FAILURE\n"); - return 0; - } - break; - } - /* check whether shift result is used subsequently */ - p2 = p1; - if(p1->to.reg != n) - for (;;) { - r1 = uniqs(r1); - if(r1 == nil) { - if(debug['P']) - print("\tinconclusive; FAILURE\n"); - return 0; - } - p1 = r1->prog; - if(debug['P']) - print("\n%P", p1); - switch(copyu(p1, &p->to, nil)) { - case 0: /* not used or set */ - continue; - case 3: /* set, not used */ - break; - default:/* used */ - if(debug['P']) - print("\treused; FAILURE\n"); - return 0; - } - break; - } - - /* make the substitution */ - p2->from.reg = 0; - o = p->reg; - if(o == 0) - o = p->to.reg; - o &= 15; - - switch(p->from.type){ - case TYPE_CONST: - o |= (p->from.offset&0x1f)<<7; - break; - case TYPE_REG: - o |= (1<<4) | ((p->from.reg&15)<<8); - break; - } - switch(p->as){ - case ASLL: - o |= 0<<5; - break; - case ASRL: - o |= 1<<5; - break; - case ASRA: - o |= 2<<5; - break; - } - p2->from = zprog.from; - p2->from.type = TYPE_SHIFT; - p2->from.offset = o; - if(debug['P']) - print("\t=>%P\tSUCCEED\n", p2); - return 1; -} - -/* - * findpre returns the last instruction mentioning v - * before r. It must be a set, and there must be - * a unique path from that instruction to r. - */ -static Flow* -findpre(Flow *r, Adr *v) -{ - Flow *r1; - - for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) { - if(uniqs(r1) != r) - return nil; - switch(copyu(r1->prog, v, nil)) { - case 1: /* used */ - case 2: /* read-alter-rewrite */ - return nil; - case 3: /* set */ - case 4: /* set and used */ - return r1; - } - } - return nil; -} - -/* - * findinc finds ADD instructions with a constant - * argument which falls within the immed_12 range. - */ -static Flow* -findinc(Flow *r, Flow *r2, Adr *v) -{ - Flow *r1; - Prog *p; - - - for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) { - if(uniqp(r1) != r) - return nil; - switch(copyu(r1->prog, v, nil)) { - case 0: /* not touched */ - continue; - case 4: /* set and used */ - p = r1->prog; - if(p->as == AADD) - if(isdconst(&p->from)) - if(p->from.offset > -4096 && p->from.offset < 4096) - return r1; - default: - return nil; - } - } - return nil; -} - -static int -nochange(Flow *r, Flow *r2, Prog *p) -{ - Adr a[3]; - int i, n; - - if(r == r2) - return 1; - n = 0; - if(p->reg != 0 && p->reg != p->to.reg) { - a[n].type = TYPE_REG; - a[n++].reg = p->reg; - } - switch(p->from.type) { - case TYPE_SHIFT: - a[n].type = TYPE_REG; - a[n++].reg = REG_R0 + (p->from.offset&0xf); - case TYPE_REG: - a[n].type = TYPE_REG; - a[n++].reg = p->from.reg; - } - if(n == 0) - return 1; - for(; r!=nil && r!=r2; r=uniqs(r)) { - p = r->prog; - for(i=0; i 1) - return 0; - } - return 1; -} - -static int -findu1(Flow *r, Adr *v) -{ - for(; r != nil; r = r->s1) { - if(r->active) - return 0; - r->active = 1; - switch(copyu(r->prog, v, nil)) { - case 1: /* used */ - case 2: /* read-alter-rewrite */ - case 4: /* set and used */ - return 1; - case 3: /* set */ - return 0; - } - if(r->s2) - if (findu1(r->s2, v)) - return 1; - } - return 0; -} - -static int -finduse(Graph *g, Flow *r, Adr *v) -{ - Flow *r1; - - for(r1=g->start; r1!=nil; r1=r1->link) - r1->active = 0; - return findu1(r, v); -} - -/* - * xtramodes enables the ARM post increment and - * shift offset addressing modes to transform - * MOVW 0(R3),R1 - * ADD $4,R3,R3 - * into - * MOVW.P 4(R3),R1 - * and - * ADD R0,R1 - * MOVBU 0(R1),R0 - * into - * MOVBU R0<<0(R1),R0 - */ -static int -xtramodes(Graph *g, Flow *r, Adr *a) -{ - Flow *r1, *r2, *r3; - Prog *p, *p1; - Adr v; - - p = r->prog; - v = *a; - v.type = TYPE_REG; - r1 = findpre(r, &v); - if(r1 != nil) { - p1 = r1->prog; - if(p1->to.type == TYPE_REG && p1->to.reg == v.reg) - switch(p1->as) { - case AADD: - if(p1->scond & C_SBIT) - // avoid altering ADD.S/ADC sequences. - break; - if(p1->from.type == TYPE_REG || - (p1->from.type == TYPE_SHIFT && (p1->from.offset&(1<<4)) == 0 && - ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) || - ((p1->from.type == TYPE_ADDR || p1->from.type == TYPE_CONST) && - p1->from.offset > -4096 && p1->from.offset < 4096)) - if(nochange(uniqs(r1), r, p1)) { - if(a != &p->from || v.reg != p->to.reg) - if (finduse(g, r->s1, &v)) { - if(p1->reg == 0 || p1->reg == v.reg) - /* pre-indexing */ - p->scond |= C_WBIT; - else return 0; - } - switch (p1->from.type) { - case TYPE_REG: - /* register offset */ - if(nacl) - return 0; - *a = zprog.from; - a->type = TYPE_SHIFT; - a->offset = p1->from.reg&15; - break; - case TYPE_SHIFT: - /* scaled register offset */ - if(nacl) - return 0; - *a = zprog.from; - a->type = TYPE_SHIFT; - case TYPE_CONST: - case TYPE_ADDR: - /* immediate offset */ - a->offset = p1->from.offset; - break; - } - if(p1->reg != 0) - a->reg = p1->reg; - excise(r1); - return 1; - } - break; - case AMOVW: - if(p1->from.type == TYPE_REG) - if((r2 = findinc(r1, r, &p1->from)) != nil) { - for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) - ; - if(r3 == r) { - /* post-indexing */ - p1 = r2->prog; - a->reg = p1->to.reg; - a->offset = p1->from.offset; - p->scond |= C_PBIT; - if(!finduse(g, r, &r1->prog->to)) - excise(r1); - excise(r2); - return 1; - } - } - break; - } - } - if(a != &p->from || a->reg != p->to.reg) - if((r1 = findinc(r, nil, &v)) != nil) { - /* post-indexing */ - p1 = r1->prog; - a->offset = p1->from.offset; - p->scond |= C_PBIT; - excise(r1); - return 1; - } - return 0; -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -static int -copyu(Prog *p, Adr *v, Adr *s) -{ - switch(p->as) { - - default: - print("copyu: can't find %A\n", p->as); - return 2; - - case AMOVM: - if(v->type != TYPE_REG) - return 0; - if(p->from.type == TYPE_CONST) { /* read reglist, read/rar */ - if(s != nil) { - if(p->from.offset&(1<reg)) - return 1; - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) { - if(p->scond&C_WBIT) - return 2; - return 1; - } - if(p->from.offset&(1<reg)) - return 1; - } else { /* read/rar, write reglist */ - if(s != nil) { - if(p->to.offset&(1<reg)) - return 1; - if(copysub(&p->from, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->from, v)) { - if(p->scond&C_WBIT) - return 2; - if(p->to.offset&(1<reg)) - return 4; - return 1; - } - if(p->to.offset&(1<reg)) - return 3; - } - return 0; - - case ANOP: /* read,, write */ - case AMOVW: - case AMOVF: - case AMOVD: - case AMOVH: - case AMOVHS: - case AMOVHU: - case AMOVB: - case AMOVBS: - case AMOVBU: - case AMOVFW: - case AMOVWF: - case AMOVDW: - case AMOVWD: - case AMOVFD: - case AMOVDF: - if(p->scond&(C_WBIT|C_PBIT)) - if(v->type == TYPE_REG) { - if(p->from.type == TYPE_MEM || p->from.type == TYPE_SHIFT) { - if(p->from.reg == v->reg) - return 2; - } else { - if(p->to.reg == v->reg) - return 2; - } - } - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(p->scond != C_SCOND_NONE) - return 2; - if(copyau(&p->from, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case AMULLU: /* read, read, write, write */ - case AMULL: - case AMULA: - case AMVN: - return 2; - - case AADD: /* read, read, write */ - case AADC: - case ASUB: - case ASBC: - case ARSB: - case ASLL: - case ASRL: - case ASRA: - case AORR: - case AAND: - case AEOR: - case AMUL: - case AMULU: - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - - case ACHECKNIL: /* read */ - case ACMPF: /* read, read, */ - case ACMPD: - case ACMP: - case ACMN: - case ACASE: - case ATST: /* read,, */ - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(copysub1(p, v, s, 1)) - return 1; - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(p->scond != C_SCOND_NONE) - return 2; - if(p->reg == 0) - p->reg = p->to.reg; - if(copyau(&p->from, v)) - return 4; - if(copyau1(p, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau1(p, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ABEQ: /* read, read */ - case ABNE: - case ABCS: - case ABHS: - case ABCC: - case ABLO: - case ABMI: - case ABPL: - case ABVS: - case ABVC: - case ABHI: - case ABLS: - case ABGE: - case ABLT: - case ABGT: - case ABLE: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub1(p, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau1(p, v)) - return 1; - return 0; - - case AB: /* funny */ - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARET: /* funny */ - if(s != nil) - return 1; - return 3; - - case ABL: /* funny */ - if(v->type == TYPE_REG) { - // TODO(rsc): REG_R0 and REG_F0 used to be - // (when register numbers started at 0) exregoffset and exfregoffset, - // which are unset entirely. - // It's strange that this handles R0 and F0 differently from the other - // registers. Possible failure to optimize? - if(REG_R0 < v->reg && v->reg <= REGEXT) - return 2; - if(v->reg == REGARG) - return 2; - if(REG_F0 < v->reg && v->reg <= FREGEXT) - return 2; - } - if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg) - return 2; - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - case ADUFFZERO: - // R0 is zero, used by DUFFZERO, cannot be substituted. - // R1 is ptr to memory, used and set, cannot be substituted. - if(v->type == TYPE_REG) { - if(v->reg == REGALLOC_R0) - return 1; - if(v->reg == REGALLOC_R0+1) - return 2; - } - return 0; - case ADUFFCOPY: - // R0 is scratch, set by DUFFCOPY, cannot be substituted. - // R1, R2 areptr to src, dst, used and set, cannot be substituted. - if(v->type == TYPE_REG) { - if(v->reg == REGALLOC_R0) - return 3; - if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2) - return 2; - } - return 0; - - case ATEXT: /* funny */ - if(v->type == TYPE_REG) - if(v->reg == REGARG) - return 3; - return 0; - - case APCDATA: - case AFUNCDATA: - case AVARDEF: - case AVARKILL: - return 0; - } -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -static int -copyas(Adr *a, Adr *v) -{ - - if(regtyp(v)) { - if(a->type == v->type) - if(a->reg == v->reg) - return 1; - } else - if(v->type == TYPE_CONST) { /* for constprop */ - if(a->type == v->type) - if(a->name == v->name) - if(a->sym == v->sym) - if(a->reg == v->reg) - if(a->offset == v->offset) - return 1; - } - return 0; -} - -int -sameaddr(Adr *a, Adr *v) -{ - if(a->type != v->type) - return 0; - if(regtyp(v) && a->reg == v->reg) - return 1; - // TODO(rsc): Change v->type to v->name and enable. - //if(v->type == NAME_AUTO || v->type == NAME_PARAM) { - // if(v->offset == a->offset) - // return 1; - //} - return 0; -} - -/* - * either direct or indirect - */ -static int -copyau(Adr *a, Adr *v) -{ - - if(copyas(a, v)) - return 1; - if(v->type == TYPE_REG) { - if(a->type == TYPE_ADDR && a->reg != 0) { - if(a->reg == v->reg) - return 1; - } else - if(a->type == TYPE_MEM) { - if(a->reg == v->reg) - return 1; - } else - if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) { - if(a->reg == v->reg) - return 1; - if(a->offset == v->reg) - return 1; - } else - if(a->type == TYPE_SHIFT) { - if((a->offset&0xf) == v->reg - REG_R0) - return 1; - if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0) - return 1; - } - } - return 0; -} - -/* - * compare v to the center - * register in p (p->reg) - */ -static int -copyau1(Prog *p, Adr *v) -{ - if(v->type == TYPE_REG && v->reg == 0) - return 0; - return p->reg == v->reg; -} - -/* - * substitute s for v in a - * return failure to substitute - */ -static int -copysub(Adr *a, Adr *v, Adr *s, int f) -{ - - if(f) - if(copyau(a, v)) { - if(a->type == TYPE_SHIFT) { - if((a->offset&0xf) == v->reg - REG_R0) - a->offset = (a->offset&~0xf)|(s->reg&0xf); - if((a->offset&(1<<4)) && ((a->offset>>8)&0xf) == v->reg - REG_R0) - a->offset = (a->offset&~(0xf<<8))|((s->reg&0xf)<<8); - } else - if(a->type == TYPE_REGREG || a->type == TYPE_REGREG2) { - if(a->offset == v->reg) - a->offset = s->reg; - if(a->reg == v->reg) - a->reg = s->reg; - } else - a->reg = s->reg; - } - return 0; -} - -static int -copysub1(Prog *p1, Adr *v, Adr *s, int f) -{ - - if(f) - if(copyau1(p1, v)) - p1->reg = s->reg; - return 0; -} - -struct { - int opcode; - int notopcode; - int scond; - int notscond; -} predinfo[] = { - { ABEQ, ABNE, 0x0, 0x1, }, - { ABNE, ABEQ, 0x1, 0x0, }, - { ABCS, ABCC, 0x2, 0x3, }, - { ABHS, ABLO, 0x2, 0x3, }, - { ABCC, ABCS, 0x3, 0x2, }, - { ABLO, ABHS, 0x3, 0x2, }, - { ABMI, ABPL, 0x4, 0x5, }, - { ABPL, ABMI, 0x5, 0x4, }, - { ABVS, ABVC, 0x6, 0x7, }, - { ABVC, ABVS, 0x7, 0x6, }, - { ABHI, ABLS, 0x8, 0x9, }, - { ABLS, ABHI, 0x9, 0x8, }, - { ABGE, ABLT, 0xA, 0xB, }, - { ABLT, ABGE, 0xB, 0xA, }, - { ABGT, ABLE, 0xC, 0xD, }, - { ABLE, ABGT, 0xD, 0xC, }, -}; - -typedef struct { - Flow *start; - Flow *last; - Flow *end; - int len; -} Joininfo; - -enum { - Join, - Split, - End, - Branch, - Setcond, - Toolong -}; - -enum { - Falsecond, - Truecond, - Delbranch, - Keepbranch -}; - -static int -isbranch(Prog *p) -{ - return (ABEQ <= p->as) && (p->as <= ABLE); -} - -static int -predicable(Prog *p) -{ - switch(p->as) { - case ANOP: - case AXXX: - case ADATA: - case AGLOBL: - case ATEXT: - case AWORD: - case ABCASE: - case ACASE: - return 0; - } - if(isbranch(p)) - return 0; - return 1; -} - -/* - * Depends on an analysis of the encodings performed by 5l. - * These seem to be all of the opcodes that lead to the "S" bit - * being set in the instruction encodings. - * - * C_SBIT may also have been set explicitly in p->scond. - */ -static int -modifiescpsr(Prog *p) -{ - switch(p->as) { - case AMULLU: - case AMULA: - case AMULU: - case ADIVU: - - case ATEQ: - case ACMN: - case ATST: - case ACMP: - case AMUL: - case ADIV: - case AMOD: - case AMODU: - case ABL: - return 1; - } - if(p->scond & C_SBIT) - return 1; - return 0; -} - -/* - * Find the maximal chain of instructions starting with r which could - * be executed conditionally - */ -static int -joinsplit(Flow *r, Joininfo *j) -{ - j->start = r; - j->last = r; - j->len = 0; - do { - if (r->p2 && (r->p1 || r->p2->p2link)) { - j->end = r; - return Join; - } - if (r->s1 && r->s2) { - j->end = r; - return Split; - } - j->last = r; - if (r->prog->as != ANOP) - j->len++; - if (!r->s1 && !r->s2) { - j->end = r->link; - return End; - } - if (r->s2) { - j->end = r->s2; - return Branch; - } - if (modifiescpsr(r->prog)) { - j->end = r->s1; - return Setcond; - } - r = r->s1; - } while (j->len < 4); - j->end = r; - return Toolong; -} - -static Flow* -successor(Flow *r) -{ - if(r->s1) - return r->s1; - else - return r->s2; -} - -static void -applypred(Flow *rstart, Joininfo *j, int cond, int branch) -{ - int pred; - Flow *r; - - if(j->len == 0) - return; - if(cond == Truecond) - pred = predinfo[rstart->prog->as - ABEQ].scond; - else - pred = predinfo[rstart->prog->as - ABEQ].notscond; - - for(r = j->start;; r = successor(r)) { - if(r->prog->as == AB) { - if(r != j->last || branch == Delbranch) - excise(r); - else { - if(cond == Truecond) - r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; - else - r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; - } - } - else - if(predicable(r->prog)) - r->prog->scond = (r->prog->scond&~C_SCOND)|pred; - if(r->s1 != r->link) { - r->s1 = r->link; - r->link->p1 = r; - } - if(r == j->last) - break; - } -} - -void -predicate(Graph *g) -{ - Flow *r; - int t1, t2; - Joininfo j1, j2; - - for(r=g->start; r!=nil; r=r->link) { - if (isbranch(r->prog)) { - t1 = joinsplit(r->s1, &j1); - t2 = joinsplit(r->s2, &j2); - if(j1.last->link != j2.start) - continue; - if(j1.end == j2.end) - if((t1 == Branch && (t2 == Join || t2 == Setcond)) || - (t2 == Join && (t1 == Join || t1 == Setcond))) { - applypred(r, &j1, Falsecond, Delbranch); - applypred(r, &j2, Truecond, Delbranch); - excise(r); - continue; - } - if(t1 == End || t1 == Branch) { - applypred(r, &j1, Falsecond, Keepbranch); - excise(r); - continue; - } - } - } -} - -static int -isdconst(Addr *a) -{ - return a->type == TYPE_CONST; -} - -static int -isfloatreg(Addr *a) -{ - return REG_F0 <= a->reg && a->reg <= REG_F15; -} - -int -stackaddr(Addr *a) -{ - return regtyp(a) && a->reg == REGSP; -} - -int -smallindir(Addr *a, Addr *reg) -{ - return reg->type == TYPE_REG && a->type == TYPE_MEM && - a->reg == reg->reg && - 0 <= a->offset && a->offset < 4096; -} - -void -excise(Flow *r) -{ - Prog *p; - - p = r->prog; - nopout(p); -} diff --git a/src/cmd/5g/peep.go b/src/cmd/5g/peep.go new file mode 100644 index 0000000000..2fbb1e5285 --- /dev/null +++ b/src/cmd/5g/peep.go @@ -0,0 +1,1868 @@ +// Inferno utils/5c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" + "fmt" +) +import "cmd/internal/gc" + +var gactive uint32 + +// UNUSED +func peep(firstp *obj.Prog) { + var r *gc.Flow + var g *gc.Graph + var p *obj.Prog + var t int + + g = gc.Flowstart(firstp, nil) + if g == nil { + return + } + gactive = 0 + +loop1: + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + gc.Dumpit("loop1", g.Start, 0) + } + + t = 0 + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + /* + * elide shift into TYPE_SHIFT operand of subsequent instruction + */ + // if(shiftprop(r)) { + // excise(r); + // t++; + // break; + // } + case arm.ASLL, + arm.ASRL, + arm.ASRA: + break + + case arm.AMOVB, + arm.AMOVH, + arm.AMOVW, + arm.AMOVF, + arm.AMOVD: + if regtyp(&p.From) { + if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) { + if p.Scond == arm.C_SCOND_NONE { + if copyprop(g, r) { + excise(r) + t++ + break + } + + if subprop(r) && copyprop(g, r) { + excise(r) + t++ + break + } + } + } + } + + case arm.AMOVHS, + arm.AMOVHU, + arm.AMOVBS, + arm.AMOVBU: + if p.From.Type == obj.TYPE_REG { + if shortprop(r) { + t++ + } + } + } + } + + /* + if(p->scond == C_SCOND_NONE) + if(regtyp(&p->to)) + if(isdconst(&p->from)) { + constprop(&p->from, &p->to, r->s1); + } + break; + */ + if t != 0 { + goto loop1 + } + + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + /* + * EOR -1,x,y => MVN x,y + */ + case arm.AEOR: + if isdconst(&p.From) && p.From.Offset == -1 { + p.As = arm.AMVN + p.From.Type = obj.TYPE_REG + if p.Reg != 0 { + p.From.Reg = p.Reg + } else { + p.From.Reg = p.To.Reg + } + p.Reg = 0 + } + } + } + + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case arm.AMOVW, + arm.AMOVB, + arm.AMOVBS, + arm.AMOVBU: + if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 { + xtramodes(g, r, &p.From) + } else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 { + xtramodes(g, r, &p.To) + } else { + continue + } + } + } + + // case ACMP: + // /* + // * elide CMP $0,x if calculation of x can set condition codes + // */ + // if(isdconst(&p->from) || p->from.offset != 0) + // continue; + // r2 = r->s1; + // if(r2 == nil) + // continue; + // t = r2->prog->as; + // switch(t) { + // default: + // continue; + // case ABEQ: + // case ABNE: + // case ABMI: + // case ABPL: + // break; + // case ABGE: + // t = ABPL; + // break; + // case ABLT: + // t = ABMI; + // break; + // case ABHI: + // t = ABNE; + // break; + // case ABLS: + // t = ABEQ; + // break; + // } + // r1 = r; + // do + // r1 = uniqp(r1); + // while (r1 != nil && r1->prog->as == ANOP); + // if(r1 == nil) + // continue; + // p1 = r1->prog; + // if(p1->to.type != TYPE_REG) + // continue; + // if(p1->to.reg != p->reg) + // if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg)) + // continue; + // + // switch(p1->as) { + // default: + // continue; + // case AMOVW: + // if(p1->from.type != TYPE_REG) + // continue; + // case AAND: + // case AEOR: + // case AORR: + // case ABIC: + // case AMVN: + // case ASUB: + // case ARSB: + // case AADD: + // case AADC: + // case ASBC: + // case ARSC: + // break; + // } + // p1->scond |= C_SBIT; + // r2->prog->as = t; + // excise(r); + // continue; + + // predicate(g); + + gc.Flowend(g) +} + +func regtyp(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15) +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +func subprop(r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + var r *gc.Flow + var t int + var info gc.ProgInfo + + p = r0.Prog + v1 = &p.From + if !regtyp(v1) { + return false + } + v2 = &p.To + if !regtyp(v2) { + return false + } + for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { + if gc.Uniqs(r) == nil { + break + } + p = r.Prog + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + continue + } + proginfo(&info, p) + if info.Flags&gc.Call != 0 { + return false + } + + if (info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG { + info.Flags |= gc.RegRead + info.Flags &^= (gc.CanRegRead | gc.RightRead) + p.Reg = p.To.Reg + } + + switch p.As { + case arm.AMULLU, + arm.AMULA, + arm.AMVN: + return false + } + + if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite { + if p.To.Type == v1.Type { + if p.To.Reg == v1.Reg { + if p.Scond == arm.C_SCOND_NONE { + goto gotit + } + } + } + } + + if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) { + break + } + if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { + break + } + } + + return false + +gotit: + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) + if p.From.Type == v2.Type { + fmt.Printf(" excise") + } + fmt.Printf("\n") + } + + for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { + p = r.Prog + copysub(&p.From, v1, v2, 1) + copysub1(p, v1, v2, 1) + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("%v\n", r.Prog) + } + } + + t = int(v1.Reg) + v1.Reg = v2.Reg + v2.Reg = int16(t) + if gc.Debug['P'] != 0 { + fmt.Printf("%v last\n", r.Prog) + } + return true +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +func copyprop(g *gc.Graph, r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + + p = r0.Prog + v1 = &p.From + v2 = &p.To + if copyas(v1, v2) { + return true + } + gactive++ + return copy1(v1, v2, r0.S1, 0) +} + +func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { + var t int + var p *obj.Prog + + if uint32(r.Active) == gactive { + if gc.Debug['P'] != 0 { + fmt.Printf("act set; return 1\n") + } + return true + } + + r.Active = int32(gactive) + if gc.Debug['P'] != 0 { + fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) + } + for ; r != nil; r = r.S1 { + p = r.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("%v", p) + } + if f == 0 && gc.Uniqp(r) == nil { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; merge; f=%d", f) + } + } + + t = copyu(p, v2, nil) + switch t { + case 2: /* rar, can't split */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2)) + } + return false + + case 3: /* set */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + + case 1, /* used, substitute */ + 4: /* use and set */ + if f != 0 { + if gc.Debug['P'] == 0 { + return false + } + if t == 4 { + fmt.Printf("; %vused+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } else { + fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } + return false + } + + if copyu(p, v2, v1) != 0 { + if gc.Debug['P'] != 0 { + fmt.Printf("; sub fail; return 0\n") + } + return false + } + + if gc.Debug['P'] != 0 { + fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) + } + if t == 4 { + if gc.Debug['P'] != 0 { + fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + } + } + + if f == 0 { + t = copyu(p, v1, nil) + if f == 0 && (t == 2 || t == 3 || t == 4) { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f) + } + } + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\n") + } + if r.S2 != nil { + if !copy1(v1, v2, r.S2, f) { + return false + } + } + } + + return true +} + +// UNUSED +/* + * The idea is to remove redundant constants. + * $c1->v1 + * ($c1->v2 s/$c1/v1)* + * set v1 return + * The v1->v2 should be eliminated by copy propagation. + */ +func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) { + var p *obj.Prog + + if gc.Debug['P'] != 0 { + fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1)) + } + for ; r != nil; r = r.S1 { + p = r.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("%v", p) + } + if gc.Uniqp(r) == nil { + if gc.Debug['P'] != 0 { + fmt.Printf("; merge; return\n") + } + return + } + + if p.As == arm.AMOVW && copyas(&p.From, c1) { + if gc.Debug['P'] != 0 { + fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1)) + } + p.From = *v1 + } else if copyu(p, v1, nil) > 1 { + if gc.Debug['P'] != 0 { + fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1)) + } + return + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\n") + } + if r.S2 != nil { + constprop(c1, v1, r.S2) + } + } +} + +/* + * shortprop eliminates redundant zero/sign extensions. + * + * MOVBS x, R + * + * MOVBS R, R' + * + * changed to + * + * MOVBS x, R + * ... + * MOVB R, R' (compiled to mov) + * + * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU. + */ +func shortprop(r *gc.Flow) bool { + var p *obj.Prog + var p1 *obj.Prog + var r1 *gc.Flow + + p = r.Prog + r1 = findpre(r, &p.From) + if r1 == nil { + return false + } + + p1 = r1.Prog + if p1.As == p.As { + // Two consecutive extensions. + goto gotit + } + + if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 { + // Loaded an immediate. + goto gotit + } + + return false + +gotit: + if gc.Debug['P'] != 0 { + fmt.Printf("shortprop\n%v\n%v", p1, p) + } + switch p.As { + case arm.AMOVBS, + arm.AMOVBU: + p.As = arm.AMOVB + + case arm.AMOVHS, + arm.AMOVHU: + p.As = arm.AMOVH + } + + if gc.Debug['P'] != 0 { + fmt.Printf(" => %v\n", arm.Aconv(int(p.As))) + } + return true +} + +// UNUSED +/* + * ASLL x,y,w + * .. (not use w, not set x y w) + * AXXX w,a,b (a != w) + * .. (not use w) + * (set w) + * ----------- changed to + * .. + * AXXX (x< 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) { + if gc.Debug['P'] != 0 { + fmt.Printf("\targs modified; FAILURE\n") + } + return false + } + + continue + case 3: /* set, not used */ + { + if gc.Debug['P'] != 0 { + fmt.Printf("\tBOTCH: noref; FAILURE\n") + } + return false + } + } + + break + } + + /* check whether substitution can be done */ + switch p1.As { + default: + if gc.Debug['P'] != 0 { + fmt.Printf("\tnon-dpi; FAILURE\n") + } + return false + + case arm.AAND, + arm.AEOR, + arm.AADD, + arm.AADC, + arm.AORR, + arm.ASUB, + arm.ASBC, + arm.ARSB, + arm.ARSC: + if int(p1.Reg) == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && int(p1.To.Reg) == n) { + if p1.From.Type != obj.TYPE_REG { + if gc.Debug['P'] != 0 { + fmt.Printf("\tcan't swap; FAILURE\n") + } + return false + } + + p1.Reg = p1.From.Reg + p1.From.Reg = int16(n) + switch p1.As { + case arm.ASUB: + p1.As = arm.ARSB + + case arm.ARSB: + p1.As = arm.ASUB + + case arm.ASBC: + p1.As = arm.ARSC + + case arm.ARSC: + p1.As = arm.ASBC + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\t=>%v", p1) + } + } + fallthrough + + case arm.ABIC, + arm.ATST, + arm.ACMP, + arm.ACMN: + if int(p1.Reg) == n { + if gc.Debug['P'] != 0 { + fmt.Printf("\tcan't swap; FAILURE\n") + } + return false + } + + if p1.Reg == 0 && int(p1.To.Reg) == n { + if gc.Debug['P'] != 0 { + fmt.Printf("\tshift result used twice; FAILURE\n") + } + return false + } + + // case AMVN: + if p1.From.Type == obj.TYPE_SHIFT { + if gc.Debug['P'] != 0 { + fmt.Printf("\tshift result used in shift; FAILURE\n") + } + return false + } + + if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n { + if gc.Debug['P'] != 0 { + fmt.Printf("\tBOTCH: where is it used?; FAILURE\n") + } + return false + } + } + + /* check whether shift result is used subsequently */ + p2 = p1 + + if int(p1.To.Reg) != n { + for { + r1 = gc.Uniqs(r1) + if r1 == nil { + if gc.Debug['P'] != 0 { + fmt.Printf("\tinconclusive; FAILURE\n") + } + return false + } + + p1 = r1.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("\n%v", p1) + } + switch copyu(p1, &p.To, nil) { + case 0: /* not used or set */ + continue + + case 3: /* set, not used */ + break + + default: /* used */ + if gc.Debug['P'] != 0 { + fmt.Printf("\treused; FAILURE\n") + } + return false + } + + break + } + } + + /* make the substitution */ + p2.From.Reg = 0 + + o = int(p.Reg) + if o == 0 { + o = int(p.To.Reg) + } + o &= 15 + + switch p.From.Type { + case obj.TYPE_CONST: + o |= int((p.From.Offset & 0x1f) << 7) + + case obj.TYPE_REG: + o |= 1<<4 | (int(p.From.Reg)&15)<<8 + } + + switch p.As { + case arm.ASLL: + o |= 0 << 5 + + case arm.ASRL: + o |= 1 << 5 + + case arm.ASRA: + o |= 2 << 5 + } + + p2.From = obj.Addr{} + p2.From.Type = obj.TYPE_SHIFT + p2.From.Offset = int64(o) + if gc.Debug['P'] != 0 { + fmt.Printf("\t=>%v\tSUCCEED\n", p2) + } + return true +} + +/* + * findpre returns the last instruction mentioning v + * before r. It must be a set, and there must be + * a unique path from that instruction to r. + */ +func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow { + var r1 *gc.Flow + + for r1 = gc.Uniqp(r); r1 != nil; (func() { r = r1; r1 = gc.Uniqp(r) })() { + if gc.Uniqs(r1) != r { + return nil + } + switch copyu(r1.Prog, v, nil) { + case 1, /* used */ + 2: /* read-alter-rewrite */ + return nil + + case 3, /* set */ + 4: /* set and used */ + return r1 + } + } + + return nil +} + +/* + * findinc finds ADD instructions with a constant + * argument which falls within the immed_12 range. + */ +func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow { + var r1 *gc.Flow + var p *obj.Prog + + for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; (func() { r = r1; r1 = gc.Uniqs(r) })() { + if gc.Uniqp(r1) != r { + return nil + } + switch copyu(r1.Prog, v, nil) { + case 0: /* not touched */ + continue + + case 4: /* set and used */ + p = r1.Prog + + if p.As == arm.AADD { + if isdconst(&p.From) { + if p.From.Offset > -4096 && p.From.Offset < 4096 { + return r1 + } + } + } + fallthrough + + default: + return nil + } + } + + return nil +} + +func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool { + var a [3]obj.Addr + var i int + var n int + + if r == r2 { + return true + } + n = 0 + if p.Reg != 0 && p.Reg != p.To.Reg { + a[n].Type = obj.TYPE_REG + a[n].Reg = p.Reg + n++ + } + + switch p.From.Type { + case obj.TYPE_SHIFT: + a[n].Type = obj.TYPE_REG + a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf)) + n++ + fallthrough + + case obj.TYPE_REG: + a[n].Type = obj.TYPE_REG + a[n].Reg = p.From.Reg + n++ + } + + if n == 0 { + return true + } + for ; r != nil && r != r2; r = gc.Uniqs(r) { + p = r.Prog + for i = 0; i < n; i++ { + if copyu(p, &a[i], nil) > 1 { + return false + } + } + } + + return true +} + +func findu1(r *gc.Flow, v *obj.Addr) bool { + for ; r != nil; r = r.S1 { + if r.Active != 0 { + return false + } + r.Active = 1 + switch copyu(r.Prog, v, nil) { + case 1, /* used */ + 2, /* read-alter-rewrite */ + 4: /* set and used */ + return true + + case 3: /* set */ + return false + } + + if r.S2 != nil { + if findu1(r.S2, v) { + return true + } + } + } + + return false +} + +func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool { + var r1 *gc.Flow + + for r1 = g.Start; r1 != nil; r1 = r1.Link { + r1.Active = 0 + } + return findu1(r, v) +} + +/* + * xtramodes enables the ARM post increment and + * shift offset addressing modes to transform + * MOVW 0(R3),R1 + * ADD $4,R3,R3 + * into + * MOVW.P 4(R3),R1 + * and + * ADD R0,R1 + * MOVBU 0(R1),R0 + * into + * MOVBU R0<<0(R1),R0 + */ +func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool { + var r1 *gc.Flow + var r2 *gc.Flow + var r3 *gc.Flow + var p *obj.Prog + var p1 *obj.Prog + var v obj.Addr + + p = r.Prog + v = *a + v.Type = obj.TYPE_REG + r1 = findpre(r, &v) + if r1 != nil { + p1 = r1.Prog + if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg { + switch p1.As { + case arm.AADD: + if p1.Scond&arm.C_SBIT != 0 { + // avoid altering ADD.S/ADC sequences. + break + } + + if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) { + if nochange(gc.Uniqs(r1), r, p1) { + if a != &p.From || v.Reg != p.To.Reg { + if finduse(g, r.S1, &v) { + if p1.Reg == 0 || p1.Reg == v.Reg { + /* pre-indexing */ + p.Scond |= arm.C_WBIT + } else { + return false + } + } + } + + switch p1.From.Type { + /* register offset */ + case obj.TYPE_REG: + if gc.Nacl { + return false + } + *a = obj.Addr{} + a.Type = obj.TYPE_SHIFT + a.Offset = int64(p1.From.Reg) & 15 + + /* scaled register offset */ + case obj.TYPE_SHIFT: + if gc.Nacl { + return false + } + *a = obj.Addr{} + a.Type = obj.TYPE_SHIFT + fallthrough + + /* immediate offset */ + case obj.TYPE_CONST, + obj.TYPE_ADDR: + a.Offset = p1.From.Offset + } + + if p1.Reg != 0 { + a.Reg = p1.Reg + } + excise(r1) + return true + } + } + + case arm.AMOVW: + if p1.From.Type == obj.TYPE_REG { + r2 = findinc(r1, r, &p1.From) + if r2 != nil { + for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) { + } + if r3 == r { + /* post-indexing */ + p1 = r2.Prog + + a.Reg = p1.To.Reg + a.Offset = p1.From.Offset + p.Scond |= arm.C_PBIT + if !finduse(g, r, &r1.Prog.To) { + excise(r1) + } + excise(r2) + return true + } + } + } + } + } + } + + if a != &p.From || a.Reg != p.To.Reg { + r1 = findinc(r, nil, &v) + if r1 != nil { + /* post-indexing */ + p1 = r1.Prog + + a.Offset = p1.From.Offset + p.Scond |= arm.C_PBIT + excise(r1) + return true + } + } + + return false +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { + switch p.As { + default: + fmt.Printf("copyu: can't find %v\n", arm.Aconv(int(p.As))) + return 2 + + case arm.AMOVM: + if v.Type != obj.TYPE_REG { + return 0 + } + if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */ + if s != nil { + if p.From.Offset&(1<type to v->name and enable. + //if(v->type == NAME_AUTO || v->type == NAME_PARAM) { + // if(v->offset == a->offset) + // return 1; + //} + return false +} + +/* + * either direct or indirect + */ +func copyau(a *obj.Addr, v *obj.Addr) bool { + if copyas(a, v) { + return true + } + if v.Type == obj.TYPE_REG { + if a.Type == obj.TYPE_ADDR && a.Reg != 0 { + if a.Reg == v.Reg { + return true + } + } else if a.Type == obj.TYPE_MEM { + if a.Reg == v.Reg { + return true + } + } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 { + if a.Reg == v.Reg { + return true + } + if a.Offset == int64(v.Reg) { + return true + } + } else if a.Type == obj.TYPE_SHIFT { + if a.Offset&0xf == int64(v.Reg-arm.REG_R0) { + return true + } + if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) { + return true + } + } + } + + return false +} + +/* + * compare v to the center + * register in p (p->reg) + */ +func copyau1(p *obj.Prog, v *obj.Addr) bool { + if v.Type == obj.TYPE_REG && v.Reg == 0 { + return false + } + return p.Reg == v.Reg +} + +/* + * substitute s for v in a + * return failure to substitute + */ +func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { + if f != 0 { + if copyau(a, v) { + if a.Type == obj.TYPE_SHIFT { + if a.Offset&0xf == int64(v.Reg-arm.REG_R0) { + a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf + } + if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) { + a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8 + } + } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 { + if a.Offset == int64(v.Reg) { + a.Offset = int64(s.Reg) + } + if a.Reg == v.Reg { + a.Reg = s.Reg + } + } else { + a.Reg = s.Reg + } + } + } + + return 0 +} + +func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int { + if f != 0 { + if copyau1(p1, v) { + p1.Reg = s.Reg + } + } + return 0 +} + +var predinfo = []struct { + opcode int + notopcode int + scond int + notscond int +}{ + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABEQ, arm.ABNE, 0x0, 0x1}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABNE, arm.ABEQ, 0x1, 0x0}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABCS, arm.ABCC, 0x2, 0x3}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABHS, arm.ABLO, 0x2, 0x3}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABCC, arm.ABCS, 0x3, 0x2}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABLO, arm.ABHS, 0x3, 0x2}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABMI, arm.ABPL, 0x4, 0x5}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABPL, arm.ABMI, 0x5, 0x4}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABVS, arm.ABVC, 0x6, 0x7}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABVC, arm.ABVS, 0x7, 0x6}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABHI, arm.ABLS, 0x8, 0x9}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABLS, arm.ABHI, 0x9, 0x8}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABGE, arm.ABLT, 0xA, 0xB}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABLT, arm.ABGE, 0xB, 0xA}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABGT, arm.ABLE, 0xC, 0xD}, + struct { + opcode int + notopcode int + scond int + notscond int + }{arm.ABLE, arm.ABGT, 0xD, 0xC}, +} + +type Joininfo struct { + start *gc.Flow + last *gc.Flow + end *gc.Flow + len int +} + +const ( + Join = iota + Split + End + Branch + Setcond + Toolong +) + +const ( + Falsecond = iota + Truecond + Delbranch + Keepbranch +) + +func isbranch(p *obj.Prog) bool { + return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE) +} + +func predicable(p *obj.Prog) bool { + switch p.As { + case obj.ANOP, + obj.AXXX, + obj.ADATA, + obj.AGLOBL, + obj.ATEXT, + arm.AWORD, + arm.ABCASE, + arm.ACASE: + return false + } + + if isbranch(p) { + return false + } + return true +} + +/* + * Depends on an analysis of the encodings performed by 5l. + * These seem to be all of the opcodes that lead to the "S" bit + * being set in the instruction encodings. + * + * C_SBIT may also have been set explicitly in p->scond. + */ +func modifiescpsr(p *obj.Prog) bool { + switch p.As { + case arm.AMULLU, + arm.AMULA, + arm.AMULU, + arm.ADIVU, + arm.ATEQ, + arm.ACMN, + arm.ATST, + arm.ACMP, + arm.AMUL, + arm.ADIV, + arm.AMOD, + arm.AMODU, + arm.ABL: + return true + } + + if p.Scond&arm.C_SBIT != 0 { + return true + } + return false +} + +/* + * Find the maximal chain of instructions starting with r which could + * be executed conditionally + */ +func joinsplit(r *gc.Flow, j *Joininfo) int { + j.start = r + j.last = r + j.len = 0 + for { + if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) { + j.end = r + return Join + } + + if r.S1 != nil && r.S2 != nil { + j.end = r + return Split + } + + j.last = r + if r.Prog.As != obj.ANOP { + j.len++ + } + if r.S1 == nil && r.S2 == nil { + j.end = r.Link + return End + } + + if r.S2 != nil { + j.end = r.S2 + return Branch + } + + if modifiescpsr(r.Prog) { + j.end = r.S1 + return Setcond + } + + r = r.S1 + if j.len >= 4 { + break + } + } + + j.end = r + return Toolong +} + +func successor(r *gc.Flow) *gc.Flow { + if r.S1 != nil { + return r.S1 + } else { + return r.S2 + } +} + +func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) { + var pred int + var r *gc.Flow + + if j.len == 0 { + return + } + if cond == Truecond { + pred = predinfo[rstart.Prog.As-arm.ABEQ].scond + } else { + pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond + } + + for r = j.start; ; r = successor(r) { + if r.Prog.As == arm.AB { + if r != j.last || branch == Delbranch { + excise(r) + } else { + if cond == Truecond { + r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode) + } else { + r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode) + } + } + } else if predicable(r.Prog) { + r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred) + } + if r.S1 != r.Link { + r.S1 = r.Link + r.Link.P1 = r + } + + if r == j.last { + break + } + } +} + +func predicate(g *gc.Graph) { + var r *gc.Flow + var t1 int + var t2 int + var j1 Joininfo + var j2 Joininfo + + for r = g.Start; r != nil; r = r.Link { + if isbranch(r.Prog) { + t1 = joinsplit(r.S1, &j1) + t2 = joinsplit(r.S2, &j2) + if j1.last.Link != j2.start { + continue + } + if j1.end == j2.end { + if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) { + applypred(r, &j1, Falsecond, Delbranch) + applypred(r, &j2, Truecond, Delbranch) + excise(r) + continue + } + } + + if t1 == End || t1 == Branch { + applypred(r, &j1, Falsecond, Keepbranch) + excise(r) + continue + } + } + } +} + +func isdconst(a *obj.Addr) bool { + return a.Type == obj.TYPE_CONST +} + +func isfloatreg(a *obj.Addr) bool { + return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15 +} + +func stackaddr(a *obj.Addr) bool { + return regtyp(a) && a.Reg == arm.REGSP +} + +func smallindir(a *obj.Addr, reg *obj.Addr) bool { + return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096 +} + +func excise(r *gc.Flow) { + var p *obj.Prog + + p = r.Prog + obj.Nopout(p) +} diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c deleted file mode 100644 index 9d5adefe69..0000000000 --- a/src/cmd/5g/prog.c +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -enum -{ - RightRdwr = RightRead | RightWrite, -}; - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -static ProgInfo progtable[ALAST] = { - [ATYPE]= {Pseudo | Skip}, - [ATEXT]= {Pseudo}, - [AFUNCDATA]= {Pseudo}, - [APCDATA]= {Pseudo}, - [AUNDEF]= {Break}, - [AUSEFIELD]= {OK}, - [ACHECKNIL]= {LeftRead}, - [AVARDEF]= {Pseudo | RightWrite}, - [AVARKILL]= {Pseudo | RightWrite}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - [ANOP]= {LeftRead | RightWrite}, - - // Integer. - [AADC]= {SizeL | LeftRead | RegRead | RightWrite}, - [AADD]= {SizeL | LeftRead | RegRead | RightWrite}, - [AAND]= {SizeL | LeftRead | RegRead | RightWrite}, - [ABIC]= {SizeL | LeftRead | RegRead | RightWrite}, - [ACMN]= {SizeL | LeftRead | RightRead}, - [ACMP]= {SizeL | LeftRead | RightRead}, - [ADIVU]= {SizeL | LeftRead | RegRead | RightWrite}, - [ADIV]= {SizeL | LeftRead | RegRead | RightWrite}, - [AEOR]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMODU]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMOD]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMULALU]= {SizeL | LeftRead | RegRead | RightRdwr}, - [AMULAL]= {SizeL | LeftRead | RegRead | RightRdwr}, - [AMULA]= {SizeL | LeftRead | RegRead | RightRdwr}, - [AMULU]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMUL]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMULL]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMULLU]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMVN]= {SizeL | LeftRead | RightWrite}, - [AORR]= {SizeL | LeftRead | RegRead | RightWrite}, - [ARSB]= {SizeL | LeftRead | RegRead | RightWrite}, - [ARSC]= {SizeL | LeftRead | RegRead | RightWrite}, - [ASBC]= {SizeL | LeftRead | RegRead | RightWrite}, - [ASLL]= {SizeL | LeftRead | RegRead | RightWrite}, - [ASRA]= {SizeL | LeftRead | RegRead | RightWrite}, - [ASRL]= {SizeL | LeftRead | RegRead | RightWrite}, - [ASUB]= {SizeL | LeftRead | RegRead | RightWrite}, - [ATEQ]= {SizeL | LeftRead | RightRead}, - [ATST]= {SizeL | LeftRead | RightRead}, - - // Floating point. - [AADDD]= {SizeD | LeftRead | RightRdwr}, - [AADDF]= {SizeF | LeftRead | RightRdwr}, - [ACMPD]= {SizeD | LeftRead | RightRead}, - [ACMPF]= {SizeF | LeftRead | RightRead}, - [ADIVD]= {SizeD | LeftRead | RightRdwr}, - [ADIVF]= {SizeF | LeftRead | RightRdwr}, - [AMULD]= {SizeD | LeftRead | RightRdwr}, - [AMULF]= {SizeF | LeftRead | RightRdwr}, - [ASUBD]= {SizeD | LeftRead | RightRdwr}, - [ASUBF]= {SizeF | LeftRead | RightRdwr}, - - // Conversions. - [AMOVWD]= {SizeD | LeftRead | RightWrite | Conv}, - [AMOVWF]= {SizeF | LeftRead | RightWrite | Conv}, - [AMOVDF]= {SizeF | LeftRead | RightWrite | Conv}, - [AMOVDW]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVFD]= {SizeD | LeftRead | RightWrite | Conv}, - [AMOVFW]= {SizeL | LeftRead | RightWrite | Conv}, - - // Moves. - [AMOVB]= {SizeB | LeftRead | RightWrite | Move}, - [AMOVD]= {SizeD | LeftRead | RightWrite | Move}, - [AMOVF]= {SizeF | LeftRead | RightWrite | Move}, - [AMOVH]= {SizeW | LeftRead | RightWrite | Move}, - [AMOVW]= {SizeL | LeftRead | RightWrite | Move}, - // In addtion, duffzero reads R0,R1 and writes R1. This fact is - // encoded in peep.c - [ADUFFZERO]= {Call}, - // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is - // encoded in peep.c - [ADUFFCOPY]= {Call}, - - // These should be split into the two different conversions instead - // of overloading the one. - [AMOVBS]= {SizeB | LeftRead | RightWrite | Conv}, - [AMOVBU]= {SizeB | LeftRead | RightWrite | Conv}, - [AMOVHS]= {SizeW | LeftRead | RightWrite | Conv}, - [AMOVHU]= {SizeW | LeftRead | RightWrite | Conv}, - - // Jumps. - [AB]= {Jump | Break}, - [ABL]= {Call}, - [ABEQ]= {Cjmp}, - [ABNE]= {Cjmp}, - [ABCS]= {Cjmp}, - [ABHS]= {Cjmp}, - [ABCC]= {Cjmp}, - [ABLO]= {Cjmp}, - [ABMI]= {Cjmp}, - [ABPL]= {Cjmp}, - [ABVS]= {Cjmp}, - [ABVC]= {Cjmp}, - [ABHI]= {Cjmp}, - [ABLS]= {Cjmp}, - [ABGE]= {Cjmp}, - [ABLT]= {Cjmp}, - [ABGT]= {Cjmp}, - [ABLE]= {Cjmp}, - [ARET]= {Break}, -}; - -void -proginfo(ProgInfo *info, Prog *p) -{ - *info = progtable[p->as]; - if(info->flags == 0) - fatal("unknown instruction %P", p); - - if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) { - info->flags &= ~LeftRead; - info->flags |= LeftAddr; - } - - if((info->flags & RegRead) && p->reg == 0) { - info->flags &= ~RegRead; - info->flags |= CanRegRead | RightRead; - } - - if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite)) - info->flags |= RightRead; - - switch(p->as) { - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - info->regset |= RtoB(REG_R12); - break; - } -} diff --git a/src/cmd/5g/prog.go b/src/cmd/5g/prog.go new file mode 100644 index 0000000000..3f7715f1fc --- /dev/null +++ b/src/cmd/5g/prog.go @@ -0,0 +1,163 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/arm" +) +import "cmd/internal/gc" + +const ( + RightRdwr = gc.RightRead | gc.RightWrite +) + +// This table gives the basic information about instruction +// generated by the compiler and processed in the optimizer. +// See opt.h for bit definitions. +// +// Instructions not generated need not be listed. +// As an exception to that rule, we typically write down all the +// size variants of an operation even if we just use a subset. +// +// The table is formatted for 8-space tabs. +var progtable = [arm.ALAST]gc.ProgInfo{ + obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, + obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, + obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, + obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, + obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + + // NOP is an internal no-op that also stands + // for USED and SET annotations, not the Intel opcode. + obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, + + // Integer. + arm.AADC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AADD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AAND: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ABIC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ACMN: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, + arm.ACMP: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, + arm.ADIVU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ADIV: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AEOR: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMODU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMOD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMULALU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, + arm.AMULAL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, + arm.AMULA: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, + arm.AMULU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMUL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMULLU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.AMVN: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite, 0, 0, 0}, + arm.AORR: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ARSB: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ARSC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ASBC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ASLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ASRA: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ASRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ASUB: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, + arm.ATEQ: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, + arm.ATST: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, + + // Floating point. + arm.AADDD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.AADDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.ACMPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, + arm.ACMPF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, + arm.ADIVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.ADIVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.AMULD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.AMULF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.ASUBD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + arm.ASUBF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + + // Conversions. + arm.AMOVWD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVWF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVDW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVFD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVFW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + + // Moves. + arm.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + arm.AMOVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + arm.AMOVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + arm.AMOVH: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + arm.AMOVW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + + // In addtion, duffzero reads R0,R1 and writes R1. This fact is + // encoded in peep.c + obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0}, + + // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is + // encoded in peep.c + obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0}, + + // These should be split into the two different conversions instead + // of overloading the one. + arm.AMOVBS: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVHS: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + arm.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + + // Jumps. + arm.AB: gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0}, + arm.ABL: gc.ProgInfo{gc.Call, 0, 0, 0}, + arm.ABEQ: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABNE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABCS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABHS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABCC: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABLO: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABMI: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABPL: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABVS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABVC: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABHI: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABLS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABGE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABLT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABGT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + arm.ABLE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, + obj.ARET: gc.ProgInfo{gc.Break, 0, 0, 0}, +} + +func proginfo(info *gc.ProgInfo, p *obj.Prog) { + *info = progtable[p.As] + if info.Flags == 0 { + gc.Fatal("unknown instruction %v", p) + } + + if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) { + info.Flags &^= gc.LeftRead + info.Flags |= gc.LeftAddr + } + + if (info.Flags&gc.RegRead != 0) && p.Reg == 0 { + info.Flags &^= gc.RegRead + info.Flags |= gc.CanRegRead | gc.RightRead + } + + if (p.Scond&arm.C_SCOND != arm.C_SCOND_NONE) && (info.Flags&gc.RightWrite != 0) { + info.Flags |= gc.RightRead + } + + switch p.As { + case arm.ADIV, + arm.ADIVU, + arm.AMOD, + arm.AMODU: + info.Regset |= RtoB(arm.REG_R12) + } +} diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c deleted file mode 100644 index 1216e01bd5..0000000000 --- a/src/cmd/5g/reg.c +++ /dev/null @@ -1,146 +0,0 @@ -// Inferno utils/5c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -enum { - NREGVAR = 32, -}; - -static char* regname[] = { - ".R0", - ".R1", - ".R2", - ".R3", - ".R4", - ".R5", - ".R6", - ".R7", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".F0", - ".F1", - ".F2", - ".F3", - ".F4", - ".F5", - ".F6", - ".F7", - ".F8", - ".F9", - ".F10", - ".F11", - ".F12", - ".F13", - ".F14", - ".F15", -}; - -char** -regnames(int *n) -{ - *n = NREGVAR; - return regname; -} - -uint64 -excludedregs(void) -{ - return RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC); -} - -uint64 -doregbits(int r) -{ - USED(r); - return 0; -} - -/* - * bit reg - * 0 R0 - * 1 R1 - * ... ... - * 10 R10 - * 12 R12 - * - * bit reg - * 18 F2 - * 19 F3 - * ... ... - * 31 F15 - */ -uint64 -RtoB(int r) -{ - if(REG_R0 <= r && r <= REG_R15) { - if(r >= REGTMP-2 && r != REG_R12) // excluded R9 and R10 for m and g, but not R12 - return 0; - return 1ULL << (r - REG_R0); - } - - if(REG_F0 <= r && r <= REG_F15) { - if(r < REG_F2 || r > REG_F0+NFREG-1) - return 0; - return 1ULL << ((r - REG_F0) + 16); - } - - return 0; -} - -int -BtoR(uint64 b) -{ - // TODO Allow R0 and R1, but be careful with a 0 return - // TODO Allow R9. Only R10 is reserved now (just g, not m). - b &= 0x11fcL; // excluded R9 and R10 for m and g, but not R12 - if(b == 0) - return 0; - return bitno(b) + REG_R0; -} - -int -BtoF(uint64 b) -{ - b &= 0xfffc0000L; - if(b == 0) - return 0; - return bitno(b) - 16 + REG_F0; -} diff --git a/src/cmd/5g/reg.go b/src/cmd/5g/reg.go new file mode 100644 index 0000000000..2afdf12416 --- /dev/null +++ b/src/cmd/5g/reg.go @@ -0,0 +1,136 @@ +// Inferno utils/5c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import "cmd/internal/obj/arm" +import "cmd/internal/gc" + +const ( + NREGVAR = 32 +) + +var regname = []string{ + ".R0", + ".R1", + ".R2", + ".R3", + ".R4", + ".R5", + ".R6", + ".R7", + ".R8", + ".R9", + ".R10", + ".R11", + ".R12", + ".R13", + ".R14", + ".R15", + ".F0", + ".F1", + ".F2", + ".F3", + ".F4", + ".F5", + ".F6", + ".F7", + ".F8", + ".F9", + ".F10", + ".F11", + ".F12", + ".F13", + ".F14", + ".F15", +} + +func regnames(n *int) []string { + *n = NREGVAR + return regname +} + +func excludedregs() uint64 { + return RtoB(arm.REGSP) | RtoB(arm.REGLINK) | RtoB(arm.REGPC) +} + +func doregbits(r int) uint64 { + return 0 +} + +/* + * bit reg + * 0 R0 + * 1 R1 + * ... ... + * 10 R10 + * 12 R12 + * + * bit reg + * 18 F2 + * 19 F3 + * ... ... + * 31 F15 + */ +func RtoB(r int) uint64 { + if arm.REG_R0 <= r && r <= arm.REG_R15 { + if r >= arm.REGTMP-2 && r != arm.REG_R12 { // excluded R9 and R10 for m and g, but not R12 + return 0 + } + return 1 << uint(r-arm.REG_R0) + } + + if arm.REG_F0 <= r && r <= arm.REG_F15 { + if r < arm.REG_F2 || r > arm.REG_F0+arm.NFREG-1 { + return 0 + } + return 1 << uint((r-arm.REG_F0)+16) + } + + return 0 +} + +func BtoR(b uint64) int { + // TODO Allow R0 and R1, but be careful with a 0 return + // TODO Allow R9. Only R10 is reserved now (just g, not m). + b &= 0x11fc // excluded R9 and R10 for m and g, but not R12 + if b == 0 { + return 0 + } + return gc.Bitno(b) + arm.REG_R0 +} + +func BtoF(b uint64) int { + b &= 0xfffc0000 + if b == 0 { + return 0 + } + return gc.Bitno(b) - 16 + arm.REG_F0 +} diff --git a/src/cmd/5g/util.go b/src/cmd/5g/util.go new file mode 100644 index 0000000000..bb5eedb15a --- /dev/null +++ b/src/cmd/5g/util.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func bool2int(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile deleted file mode 100644 index 27290ddd71..0000000000 --- a/src/cmd/6a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist - -install: y.tab.h - -y.tab.h: a.y - LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h deleted file mode 100644 index 95c4babdfc..0000000000 --- a/src/cmd/6a/a.h +++ /dev/null @@ -1,188 +0,0 @@ -// Inferno utils/6a/a.h -// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "../6l/6.out.h" - -#ifndef EXTERN -#define EXTERN extern -#endif - -#undef getc -#undef ungetc -#undef BUFSIZ - -#define getc ccgetc -#define ungetc ccungetc - -typedef struct Sym Sym; -typedef struct Ref Ref; -typedef struct Io Io; -typedef struct Addr2 Addr2; - -#define MAXALIGN 7 -#define FPCHIP 1 -#define NSYMB 500 -#define BUFSIZ 8192 -#define HISTSZ 20 -#ifndef EOF -#define EOF (-1) -#endif -#define IGN (-2) -#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) -#define NHASH 503 -#define STRINGSZ 200 -#define NMACRO 10 - -struct Sym -{ - Sym* link; - Ref* ref; - char* macro; - vlong value; - ushort type; - char *name; - char* labelname; - char sym; -}; -#define S ((Sym*)0) - -struct Ref -{ - int class; -}; - -EXTERN struct -{ - char* p; - int c; -} fi; - -struct Io -{ - Io* link; - char b[BUFSIZ]; - char* p; - short c; - short f; -}; -#define I ((Io*)0) - -struct Addr2 -{ - Addr from; - Addr to; -}; - -enum -{ - CLAST, - CMACARG, - CMACRO, - CPREPROC, -}; - -EXTERN int debug[256]; -EXTERN Sym* hash[NHASH]; -EXTERN char** Dlist; -EXTERN int nDlist; -EXTERN int newflag; -EXTERN char* hunk; -EXTERN char** include; -EXTERN Io* iofree; -EXTERN Io* ionext; -EXTERN Io* iostack; -EXTERN int32 lineno; -EXTERN int nerrors; -EXTERN int32 nhunk; -EXTERN int ninclude; -EXTERN int32 nsymb; -EXTERN Addr nullgen; -EXTERN char* outfile; -EXTERN int pass; -EXTERN int32 pc; -EXTERN int peekc; -EXTERN int32 stmtline; -EXTERN int sym; -EXTERN char* symb; -EXTERN int thechar; -EXTERN char* thestring; -EXTERN int32 thunk; -EXTERN Biobuf obuf; -EXTERN Link* ctxt; -EXTERN Biobuf bstdout; -EXTERN Prog* lastpc; - -void* alloc(int32); -void* allocn(void*, int32, int32); -void ensuresymb(int32); -void errorexit(void); -void pushio(void); -void newio(void); -void newfile(char*, int); -Sym* slookup(char*); -Sym* lookup(void); -Sym* labellookup(Sym*); -void settext(LSym*); -void syminit(Sym*); -int32 yylex(void); -int getc(void); -int getnsc(void); -void unget(int); -int escchar(int); -void cinit(void); -void checkscale(int); -void pinit(char*); -void cclean(void); -int isreg(Addr*); -void outcode(int, Addr2*); -void outhist(void); -void zaddr(Addr*, int); -void zname(char*, int, int); -int filbuf(void); -Sym* getsym(void); -void domacro(void); -void macund(void); -void macdef(void); -void macexpand(Sym*, char*); -void macinc(void); -void macprag(void); -void maclin(void); -void macif(int); -void macend(void); -void dodefine(char*); -void prfile(int32); -void linehist(char*, int); -void gethunk(void); -void yyerror(char*, ...); -int yyparse(void); -void setinclude(char*); -int assemble(char*); diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y index df3ca40b2c..bd59a1faba 100644 --- a/src/cmd/6a/a.y +++ b/src/cmd/6a/a.y @@ -29,20 +29,24 @@ // THE SOFTWARE. %{ -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/x86" +) %} -%union { - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; + +%union { + sym *asm.Sym + lval int64 + dval float64 + sval string + addr obj.Addr + addr2 Addr2 } + %left '|' %left '^' %left '&' @@ -58,7 +62,7 @@ %token LSCONST LSP %token LNAME LLAB LVAR %type con expr pointer offset -%type mem imm reg nam rel rem rim rom omem nmem textsize +%type mem imm textsize reg nam rel rem rim rom omem nmem %type nonnon nonrel nonrem rimnon rimrem remrim %type spec3 spec4 spec5 spec6 spec7 spec8 spec9 %type spec10 spec12 spec13 @@ -66,18 +70,19 @@ prog: | prog { - stmtline = lineno; + stmtline = asm.Lineno; } line line: LNAME ':' { - $1 = labellookup($1); - if($1->type == LLAB && $1->value != pc) - yyerror("redeclaration of %s (%s)", $1->labelname, $1->name); - $1->type = LLAB; - $1->value = pc; + $1 = asm.LabelLookup($1); + if $1.Type == LLAB && $1.Value != int64(asm.PC) { + yyerror("redeclaration of %s (%s)", $1.Labelname, $1.Name); + } + $1.Type = LLAB; + $1.Value = int64(asm.PC) } line | ';' @@ -87,34 +92,35 @@ line: inst: LNAME '=' expr { - $1->type = LVAR; - $1->value = $3; + $1.Type = LVAR; + $1.Value = $3; } | LVAR '=' expr { - if($1->value != $3) - yyerror("redeclaration of %s", $1->name); - $1->value = $3; - } -| LTYPE0 nonnon { outcode($1, &$2); } -| LTYPE1 nonrem { outcode($1, &$2); } -| LTYPE2 rimnon { outcode($1, &$2); } -| LTYPE3 rimrem { outcode($1, &$2); } -| LTYPE4 remrim { outcode($1, &$2); } -| LTYPER nonrel { outcode($1, &$2); } + if $1.Value != $3 { + yyerror("redeclaration of %s", $1.Name); + } + $1.Value = $3; + } +| LTYPE0 nonnon { outcode(int($1), &$2); } +| LTYPE1 nonrem { outcode(int($1), &$2); } +| LTYPE2 rimnon { outcode(int($1), &$2); } +| LTYPE3 rimrem { outcode(int($1), &$2); } +| LTYPE4 remrim { outcode(int($1), &$2); } +| LTYPER nonrel { outcode(int($1), &$2); } | spec1 | spec2 -| LTYPEC spec3 { outcode($1, &$2); } -| LTYPEN spec4 { outcode($1, &$2); } -| LTYPES spec5 { outcode($1, &$2); } -| LTYPEM spec6 { outcode($1, &$2); } -| LTYPEI spec7 { outcode($1, &$2); } -| LTYPEXC spec8 { outcode($1, &$2); } -| LTYPEX spec9 { outcode($1, &$2); } -| LTYPERT spec10 { outcode($1, &$2); } +| LTYPEC spec3 { outcode(int($1), &$2); } +| LTYPEN spec4 { outcode(int($1), &$2); } +| LTYPES spec5 { outcode(int($1), &$2); } +| LTYPEM spec6 { outcode(int($1), &$2); } +| LTYPEI spec7 { outcode(int($1), &$2); } +| LTYPEXC spec8 { outcode(int($1), &$2); } +| LTYPEX spec9 { outcode(int($1), &$2); } +| LTYPERT spec10 { outcode(int($1), &$2); } | spec11 -| LTYPEPC spec12 { outcode($1, &$2); } -| LTYPEF spec13 { outcode($1, &$2); } +| LTYPEPC spec12 { outcode(int($1), &$2); } +| LTYPEF spec13 { outcode(int($1), &$2); } nonnon: { @@ -185,57 +191,45 @@ nonrel: spec1: /* DATA */ LTYPED nam '/' con ',' imm { - Addr2 a; - a.from = $2; - a.to = $6; - outcode(ADATA, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + var a Addr2 + a.from = $2 + a.to = $6 + outcode(obj.ADATA, &a) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } spec2: /* TEXT */ LTYPET mem ',' '$' textsize { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $5; - outcode(ATEXT, &a); + asm.Settext($2.Sym); + outcode(obj.ATEXT, &Addr2{$2, $5}) } | LTYPET mem ',' con ',' '$' textsize { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $7; - outcode(ATEXT, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym); + outcode(obj.ATEXT, &Addr2{$2, $7}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } spec11: /* GLOBL */ LTYPEG mem ',' imm { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $4; - outcode(AGLOBL, &a); + asm.Settext($2.Sym) + outcode(obj.AGLOBL, &Addr2{$2, $4}) } | LTYPEG mem ',' con ',' imm { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $6; - outcode(AGLOBL, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym) + outcode(obj.AGLOBL, &Addr2{$2, $6}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } @@ -265,9 +259,10 @@ spec5: /* SHL/SHR */ { $$.from = $1; $$.to = $3; - if($$.from.index != TYPE_NONE) + if $$.from.Index != obj.TYPE_NONE { yyerror("dp shift with lhs index"); - $$.from.index = $5; + } + $$.from.Index = int16($5); } spec6: /* MOVW/MOVL */ @@ -280,9 +275,10 @@ spec6: /* MOVW/MOVL */ { $$.from = $1; $$.to = $3; - if($$.to.index != TYPE_NONE) + if $$.to.Index != obj.TYPE_NONE { yyerror("dp move with lhs index"); - $$.to.index = $5; + } + $$.to.Index = int16($5); } spec7: @@ -307,7 +303,7 @@ spec8: /* CMPPS/CMPPD */ { $$.from = $1; $$.to = $3; - $$.to.offset = $5; + $$.to.Offset = $5; } spec9: /* shufl */ @@ -315,9 +311,10 @@ spec9: /* shufl */ { $$.from = $3; $$.to = $5; - if($1.type != TYPE_CONST) + if $1.Type != obj.TYPE_CONST { yyerror("illegal constant"); - $$.to.offset = $1.offset; + } + $$.to.Offset = $1.Offset; } spec10: /* RET/RETF */ @@ -331,11 +328,12 @@ spec10: /* RET/RETF */ $$.to = nullgen; } -spec12: /* PCDATA */ +spec12: /* asm.PCDATA */ rim ',' rim { - if($1.type != TYPE_CONST || $3.type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); + if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST { + yyerror("arguments to asm.PCDATA must be integer constants"); + } $$.from = $1; $$.to = $3; } @@ -343,10 +341,12 @@ spec12: /* PCDATA */ spec13: /* FUNCDATA */ rim ',' rim { - if($1.type != TYPE_CONST) + if $1.Type != obj.TYPE_CONST { yyerror("index for FUNCDATA must be integer constant"); - if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC)) + } + if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) { yyerror("value for FUNCDATA must be symbol reference"); + } $$.from = $1; $$.to = $3; } @@ -377,109 +377,110 @@ rel: con '(' LPC ')' { $$ = nullgen; - $$.type = TYPE_BRANCH; - $$.offset = $1 + pc; + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1 + int64(asm.PC); } | LNAME offset { - $1 = labellookup($1); + $1 = asm.LabelLookup($1); $$ = nullgen; - if(pass == 2 && $1->type != LLAB) - yyerror("undefined label: %s", $1->labelname); - $$.type = TYPE_BRANCH; - $$.offset = $1->value + $2; + if asm.Pass == 2 && $1.Type != LLAB { + yyerror("undefined label: %s", $1.Labelname); + } + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1.Value + $2; } reg: LBREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LFREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LLREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LMREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LSP { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = REG_SP; + $$.Type = obj.TYPE_REG + $$.Reg = x86.REG_SP; } | LSREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LXREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } imm: '$' con { $$ = nullgen; - $$.type = TYPE_CONST; - $$.offset = $2; + $$.Type = obj.TYPE_CONST; + $$.Offset = $2; } | '$' nam { $$ = $2; - $$.type = TYPE_ADDR; + $$.Type = obj.TYPE_ADDR; /* - if($2.type == D_AUTO || $2.type == D_PARAM) + if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM) yyerror("constant cannot be automatic: %s", - $2.sym->name); + $2.sym.Name); */ } | '$' LSCONST { $$ = nullgen; - $$.type = TYPE_SCONST; - memcpy($$.u.sval, $2, sizeof($$.u.sval)); + $$.Type = obj.TYPE_SCONST; + $$.U.Sval = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8] } | '$' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $2; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $2; } | '$' '(' LFCONST ')' { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $3; } | '$' '(' '-' LFCONST ')' { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$4; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$4; } | '$' '-' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$3; } mem: @@ -490,87 +491,87 @@ omem: con { $$ = nullgen; - $$.type = TYPE_MEM; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Offset = $1; } | con '(' LLREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; } | con '(' LSP ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_SP; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = x86.REG_SP + $$.Offset = $1; } | con '(' LSREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; } | con '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.offset = $1; - $$.index = $3; - $$.scale = $5; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Offset = $1; + $$.Index = int16($3); + $$.Scale = int8($5); + checkscale($$.Scale); } | con '(' LLREG ')' '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; - $$.index = $6; - $$.scale = $8; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; + $$.Index = int16($6); + $$.Scale = int8($8); + checkscale($$.Scale); } | con '(' LLREG ')' '(' LSREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; - $$.index = $6; - $$.scale = $8; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; + $$.Index = int16($6); + $$.Scale = int8($8); + checkscale($$.Scale); } | '(' LLREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($2) } | '(' LSP ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_SP; + $$.Type = obj.TYPE_MEM + $$.Reg = x86.REG_SP } | '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.index = $2; - $$.scale = $4; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Index = int16($2); + $$.Scale = int8($4); + checkscale($$.Scale); } | '(' LLREG ')' '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; - $$.index = $5; - $$.scale = $7; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($2) + $$.Index = int16($5); + $$.Scale = int8($7); + checkscale($$.Scale); } nmem: @@ -581,27 +582,27 @@ nmem: | nam '(' LLREG '*' con ')' { $$ = $1; - $$.index = $3; - $$.scale = $5; - checkscale($$.scale); + $$.Index = int16($3); + $$.Scale = int8($5); + checkscale($$.Scale); } nam: LNAME offset '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $4; - $$.sym = linklookup(ctxt, $1->name, 0); - $$.offset = $2; + $$.Type = obj.TYPE_MEM + $$.Name = int8($4) + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); + $$.Offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = NAME_STATIC; - $$.sym = linklookup(ctxt, $1->name, 1); - $$.offset = $4; + $$.Type = obj.TYPE_MEM + $$.Name = obj.NAME_STATIC + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); + $$.Offset = $4; } offset: @@ -621,7 +622,7 @@ pointer: LSB | LSP { - $$ = NAME_AUTO; + $$ = obj.NAME_AUTO; } | LFP @@ -629,7 +630,7 @@ con: LCONST | LVAR { - $$ = $1->value; + $$ = $1.Value; } | '-' con { @@ -641,7 +642,7 @@ con: } | '~' con { - $$ = ~$2; + $$ = ^$2; } | '(' expr ')' { @@ -652,30 +653,30 @@ textsize: LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = $1; + $$.U.Argsize = obj.ArgsSizeUnknown; } | '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -$2; + $$.U.Argsize = obj.ArgsSizeUnknown; } | LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = $3; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = $1; + $$.U.Argsize = int32($3); } | '-' LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = $4; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -$2; + $$.U.Argsize = int32($4); } expr: @@ -702,11 +703,11 @@ expr: } | expr '<' '<' expr { - $$ = $1 << $4; + $$ = $1 << uint($4); } | expr '>' '>' expr { - $$ = $1 >> $4; + $$ = $1 >> uint($4); } | expr '&' expr { diff --git a/src/cmd/6a/doc.go b/src/cmd/6a/doc.go deleted file mode 100644 index 9f14cc0d05..0000000000 --- a/src/cmd/6a/doc.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -6a is a version of the Plan 9 assembler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8a - -Go-specific considerations are documented at - - http://golang.org/doc/asm - -Its target architecture is the x86-64, referred to by these tools as amd64. - -*/ -package main diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c deleted file mode 100644 index c600796cd0..0000000000 --- a/src/cmd/6a/lex.c +++ /dev/null @@ -1,1137 +0,0 @@ -// Inferno utils/6a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include -#include -#include "a.h" -#include "y.tab.h" - -enum -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; - -int -systemtype(int sys) -{ -#ifdef _WIN32 - return sys&Windows; -#else - return sys&Plan9; -#endif -} - -int -pathchar(void) -{ - return '/'; -} - -int -Lconv(Fmt *fp) -{ - return linklinefmt(ctxt, fp); -} - -void -dodef(char *p) -{ - if(nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; -} - -LinkArch* thelinkarch = &linkamd64; - -void -usage(void) -{ - print("usage: %ca [options] file.c...\n", thechar); - flagprint(1); - errorexit(); -} - -void -main(int argc, char *argv[]) -{ - char *p; - - thechar = '6'; - thestring = "amd64"; - - // Allow GOARCH=thestring or GOARCH=thestringsuffix, - // but not other values. - p = getgoarch(); - if(strncmp(p, thestring, strlen(thestring)) != 0) - sysfatal("cannot use %cc with GOARCH=%s", thechar, p); - if(strcmp(p, "amd64p32") == 0) - thelinkarch = &linkamd64p32; - - ctxt = linknew(thelinkarch); - ctxt->diag = yyerror; - ctxt->bso = &bstdout; - ctxt->enforce_data_order = 1; - Binit(&bstdout, 1, OWRITE); - listinit6(); - fmtinstall('L', Lconv); - - ensuresymb(NSYMB); - memset(debug, 0, sizeof(debug)); - cinit(); - outfile = 0; - setinclude("."); - - flagfn1("D", "name[=value]: add #define", dodef); - flagfn1("I", "dir: add dir to include path", setinclude); - flagcount("S", "print assembly and machine code", &debug['S']); - flagcount("m", "debug preprocessor macros", &debug['m']); - flagstr("o", "file: set output file", &outfile); - flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - - flagparse(&argc, &argv, usage); - ctxt->debugasm = debug['S']; - - if(argc < 1) - usage(); - if(argc > 1){ - print("can't assemble multiple files\n"); - errorexit(); - } - - if(assemble(argv[0])) - errorexit(); - Bflush(&bstdout); - if(nerrors > 0) - errorexit(); - exits(0); -} - -int -assemble(char *file) -{ - char *ofile, *p; - int i, of; - - ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) - strcpy(ofile, file); - p = utfrrune(ofile, pathchar()); - if(p) { - include[0] = ofile; - *p++ = 0; - } else - p = ofile; - if(outfile == 0) { - outfile = p; - if(outfile){ - p = utfrrune(outfile, '.'); - if(p) - if(p[1] == 's' && p[2] == 0) - p[0] = 0; - p = utfrune(outfile, 0); - p[0] = '.'; - p[1] = thechar; - p[2] = 0; - } else - outfile = "/dev/null"; - } - - of = create(outfile, OWRITE, 0664); - if(of < 0) { - yyerror("%ca: cannot create %s", thechar, outfile); - errorexit(); - } - Binit(&obuf, of, OWRITE); - Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - Bprint(&obuf, "!\n"); - - for(pass = 1; pass <= 2; pass++) { - pinit(file); - for(i=0; itype != LNAME) - yyerror("double initialization %s", itab[i].name); - s->type = itab[i].type; - s->value = itab[i].value; - } -} - -void -checkscale(int scale) -{ - - switch(scale) { - case 1: - case 2: - case 4: - case 8: - return; - } - yyerror("scale must be 1248: %d", scale); -} - -void -syminit(Sym *s) -{ - - s->type = LNAME; - s->value = 0; -} - -void -cclean(void) -{ - Addr2 g2; - - g2.from = nullgen; - g2.to = nullgen; - outcode(AEND, &g2); -} - -void -outcode(int a, Addr2 *g2) -{ - Prog *p; - Plist *pl; - - if(pass == 1) - goto out; - - p = malloc(sizeof *p); - memset(p, 0, sizeof *p); - p->as = a; - p->lineno = stmtline; - p->from = g2->from; - p->to = g2->to; - p->pc = pc; - - if(lastpc == nil) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastpc->link = p; - lastpc = p; - -out: - if(a != AGLOBL && a != ADATA) - pc++; -} - -#include "../cc/lexbody" -#include "../cc/macbody" diff --git a/src/cmd/6a/lex.go b/src/cmd/6a/lex.go new file mode 100644 index 0000000000..db4247f045 --- /dev/null +++ b/src/cmd/6a/lex.go @@ -0,0 +1,978 @@ +// Inferno utils/6a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//go:generate go tool yacc a.y + +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/x86" +) + +var ( + yyerror = asm.Yyerror + nullgen obj.Addr + stmtline int32 +) + +func main() { + cinit() + + asm.LSCONST = LSCONST + asm.LCONST = LCONST + asm.LFCONST = LFCONST + asm.LNAME = LNAME + asm.LVAR = LVAR + asm.LLAB = LLAB + + asm.Thechar = '6' + asm.Thestring = "amd64" + asm.Thelinkarch = &x86.Linkamd64 + asm.Arches = map[string]*obj.LinkArch{ + "amd64p32": &x86.Linkamd64p32, + } + + asm.Lexinit = lexinit + asm.Cclean = cclean + asm.Yyparse = yyparse + + asm.Main() +} + +type yy struct{} + +func (yy) Lex(v *yySymType) int { + var av asm.Yylval + tok := asm.Yylex(&av) + v.sym = av.Sym + v.lval = av.Lval + v.sval = av.Sval + v.dval = av.Dval + return tok +} + +func (yy) Error(msg string) { + asm.Yyerror("%s", msg) +} + +func yyparse() { + yyParse(yy{}) +} + +var lexinit = []asm.Lextab{ + {"SP", LSP, obj.NAME_AUTO}, + {"SB", LSB, obj.NAME_EXTERN}, + {"FP", LFP, obj.NAME_PARAM}, + {"PC", LPC, obj.TYPE_BRANCH}, + + {"AL", LBREG, x86.REG_AL}, + {"CL", LBREG, x86.REG_CL}, + {"DL", LBREG, x86.REG_DL}, + {"BL", LBREG, x86.REG_BL}, + /* "SPB", LBREG, REG_SPB, */ + {"SIB", LBREG, x86.REG_SIB}, + {"DIB", LBREG, x86.REG_DIB}, + {"BPB", LBREG, x86.REG_BPB}, + {"R8B", LBREG, x86.REG_R8B}, + {"R9B", LBREG, x86.REG_R9B}, + {"R10B", LBREG, x86.REG_R10B}, + {"R11B", LBREG, x86.REG_R11B}, + {"R12B", LBREG, x86.REG_R12B}, + {"R13B", LBREG, x86.REG_R13B}, + {"R14B", LBREG, x86.REG_R14B}, + {"R15B", LBREG, x86.REG_R15B}, + {"AH", LBREG, x86.REG_AH}, + {"CH", LBREG, x86.REG_CH}, + {"DH", LBREG, x86.REG_DH}, + {"BH", LBREG, x86.REG_BH}, + {"AX", LLREG, x86.REG_AX}, + {"CX", LLREG, x86.REG_CX}, + {"DX", LLREG, x86.REG_DX}, + {"BX", LLREG, x86.REG_BX}, + + /* "SP", LLREG, REG_SP, */ + {"BP", LLREG, x86.REG_BP}, + {"SI", LLREG, x86.REG_SI}, + {"DI", LLREG, x86.REG_DI}, + {"R8", LLREG, x86.REG_R8}, + {"R9", LLREG, x86.REG_R9}, + {"R10", LLREG, x86.REG_R10}, + {"R11", LLREG, x86.REG_R11}, + {"R12", LLREG, x86.REG_R12}, + {"R13", LLREG, x86.REG_R13}, + {"R14", LLREG, x86.REG_R14}, + {"R15", LLREG, x86.REG_R15}, + {"RARG", LLREG, x86.REGARG}, + {"F0", LFREG, x86.REG_F0 + 0}, + {"F1", LFREG, x86.REG_F0 + 1}, + {"F2", LFREG, x86.REG_F0 + 2}, + {"F3", LFREG, x86.REG_F0 + 3}, + {"F4", LFREG, x86.REG_F0 + 4}, + {"F5", LFREG, x86.REG_F0 + 5}, + {"F6", LFREG, x86.REG_F0 + 6}, + {"F7", LFREG, x86.REG_F0 + 7}, + {"M0", LMREG, x86.REG_M0 + 0}, + {"M1", LMREG, x86.REG_M0 + 1}, + {"M2", LMREG, x86.REG_M0 + 2}, + {"M3", LMREG, x86.REG_M0 + 3}, + {"M4", LMREG, x86.REG_M0 + 4}, + {"M5", LMREG, x86.REG_M0 + 5}, + {"M6", LMREG, x86.REG_M0 + 6}, + {"M7", LMREG, x86.REG_M0 + 7}, + {"X0", LXREG, x86.REG_X0 + 0}, + {"X1", LXREG, x86.REG_X0 + 1}, + {"X2", LXREG, x86.REG_X0 + 2}, + {"X3", LXREG, x86.REG_X0 + 3}, + {"X4", LXREG, x86.REG_X0 + 4}, + {"X5", LXREG, x86.REG_X0 + 5}, + {"X6", LXREG, x86.REG_X0 + 6}, + {"X7", LXREG, x86.REG_X0 + 7}, + {"X8", LXREG, x86.REG_X0 + 8}, + {"X9", LXREG, x86.REG_X0 + 9}, + {"X10", LXREG, x86.REG_X0 + 10}, + {"X11", LXREG, x86.REG_X0 + 11}, + {"X12", LXREG, x86.REG_X0 + 12}, + {"X13", LXREG, x86.REG_X0 + 13}, + {"X14", LXREG, x86.REG_X0 + 14}, + {"X15", LXREG, x86.REG_X0 + 15}, + {"CS", LSREG, x86.REG_CS}, + {"SS", LSREG, x86.REG_SS}, + {"DS", LSREG, x86.REG_DS}, + {"ES", LSREG, x86.REG_ES}, + {"FS", LSREG, x86.REG_FS}, + {"GS", LSREG, x86.REG_GS}, + {"GDTR", LBREG, x86.REG_GDTR}, + {"IDTR", LBREG, x86.REG_IDTR}, + {"LDTR", LBREG, x86.REG_LDTR}, + {"MSW", LBREG, x86.REG_MSW}, + {"TASK", LBREG, x86.REG_TASK}, + {"CR0", LBREG, x86.REG_CR + 0}, + {"CR1", LBREG, x86.REG_CR + 1}, + {"CR2", LBREG, x86.REG_CR + 2}, + {"CR3", LBREG, x86.REG_CR + 3}, + {"CR4", LBREG, x86.REG_CR + 4}, + {"CR5", LBREG, x86.REG_CR + 5}, + {"CR6", LBREG, x86.REG_CR + 6}, + {"CR7", LBREG, x86.REG_CR + 7}, + {"CR8", LBREG, x86.REG_CR + 8}, + {"CR9", LBREG, x86.REG_CR + 9}, + {"CR10", LBREG, x86.REG_CR + 10}, + {"CR11", LBREG, x86.REG_CR + 11}, + {"CR12", LBREG, x86.REG_CR + 12}, + {"CR13", LBREG, x86.REG_CR + 13}, + {"CR14", LBREG, x86.REG_CR + 14}, + {"CR15", LBREG, x86.REG_CR + 15}, + {"DR0", LBREG, x86.REG_DR + 0}, + {"DR1", LBREG, x86.REG_DR + 1}, + {"DR2", LBREG, x86.REG_DR + 2}, + {"DR3", LBREG, x86.REG_DR + 3}, + {"DR4", LBREG, x86.REG_DR + 4}, + {"DR5", LBREG, x86.REG_DR + 5}, + {"DR6", LBREG, x86.REG_DR + 6}, + {"DR7", LBREG, x86.REG_DR + 7}, + {"TR0", LBREG, x86.REG_TR + 0}, + {"TR1", LBREG, x86.REG_TR + 1}, + {"TR2", LBREG, x86.REG_TR + 2}, + {"TR3", LBREG, x86.REG_TR + 3}, + {"TR4", LBREG, x86.REG_TR + 4}, + {"TR5", LBREG, x86.REG_TR + 5}, + {"TR6", LBREG, x86.REG_TR + 6}, + {"TR7", LBREG, x86.REG_TR + 7}, + {"TLS", LSREG, x86.REG_TLS}, + {"AAA", LTYPE0, x86.AAAA}, + {"AAD", LTYPE0, x86.AAAD}, + {"AAM", LTYPE0, x86.AAAM}, + {"AAS", LTYPE0, x86.AAAS}, + {"ADCB", LTYPE3, x86.AADCB}, + {"ADCL", LTYPE3, x86.AADCL}, + {"ADCQ", LTYPE3, x86.AADCQ}, + {"ADCW", LTYPE3, x86.AADCW}, + {"ADDB", LTYPE3, x86.AADDB}, + {"ADDL", LTYPE3, x86.AADDL}, + {"ADDQ", LTYPE3, x86.AADDQ}, + {"ADDW", LTYPE3, x86.AADDW}, + {"ADJSP", LTYPE2, x86.AADJSP}, + {"ANDB", LTYPE3, x86.AANDB}, + {"ANDL", LTYPE3, x86.AANDL}, + {"ANDQ", LTYPE3, x86.AANDQ}, + {"ANDW", LTYPE3, x86.AANDW}, + {"ARPL", LTYPE3, x86.AARPL}, + {"BOUNDL", LTYPE3, x86.ABOUNDL}, + {"BOUNDW", LTYPE3, x86.ABOUNDW}, + {"BSFL", LTYPE3, x86.ABSFL}, + {"BSFQ", LTYPE3, x86.ABSFQ}, + {"BSFW", LTYPE3, x86.ABSFW}, + {"BSRL", LTYPE3, x86.ABSRL}, + {"BSRQ", LTYPE3, x86.ABSRQ}, + {"BSRW", LTYPE3, x86.ABSRW}, + {"BSWAPL", LTYPE1, x86.ABSWAPL}, + {"BSWAPQ", LTYPE1, x86.ABSWAPQ}, + {"BTCL", LTYPE3, x86.ABTCL}, + {"BTCQ", LTYPE3, x86.ABTCQ}, + {"BTCW", LTYPE3, x86.ABTCW}, + {"BTL", LTYPE3, x86.ABTL}, + {"BTQ", LTYPE3, x86.ABTQ}, + {"BTRL", LTYPE3, x86.ABTRL}, + {"BTRQ", LTYPE3, x86.ABTRQ}, + {"BTRW", LTYPE3, x86.ABTRW}, + {"BTSL", LTYPE3, x86.ABTSL}, + {"BTSQ", LTYPE3, x86.ABTSQ}, + {"BTSW", LTYPE3, x86.ABTSW}, + {"BTW", LTYPE3, x86.ABTW}, + {"BYTE", LTYPE2, x86.ABYTE}, + {"CALL", LTYPEC, obj.ACALL}, + {"CLC", LTYPE0, x86.ACLC}, + {"CLD", LTYPE0, x86.ACLD}, + {"CLI", LTYPE0, x86.ACLI}, + {"CLTS", LTYPE0, x86.ACLTS}, + {"CMC", LTYPE0, x86.ACMC}, + {"CMPB", LTYPE4, x86.ACMPB}, + {"CMPL", LTYPE4, x86.ACMPL}, + {"CMPQ", LTYPE4, x86.ACMPQ}, + {"CMPW", LTYPE4, x86.ACMPW}, + {"CMPSB", LTYPE0, x86.ACMPSB}, + {"CMPSL", LTYPE0, x86.ACMPSL}, + {"CMPSQ", LTYPE0, x86.ACMPSQ}, + {"CMPSW", LTYPE0, x86.ACMPSW}, + {"CMPXCHG8B", LTYPE1, x86.ACMPXCHG8B}, + {"CMPXCHGB", LTYPE3, x86.ACMPXCHGB}, /* LTYPE3? */ + {"CMPXCHGL", LTYPE3, x86.ACMPXCHGL}, + {"CMPXCHGQ", LTYPE3, x86.ACMPXCHGQ}, + {"CMPXCHGW", LTYPE3, x86.ACMPXCHGW}, + {"CPUID", LTYPE0, x86.ACPUID}, + {"DAA", LTYPE0, x86.ADAA}, + {"DAS", LTYPE0, x86.ADAS}, + {"DATA", LTYPED, obj.ADATA}, + {"DECB", LTYPE1, x86.ADECB}, + {"DECL", LTYPE1, x86.ADECL}, + {"DECQ", LTYPE1, x86.ADECQ}, + {"DECW", LTYPE1, x86.ADECW}, + {"DIVB", LTYPE2, x86.ADIVB}, + {"DIVL", LTYPE2, x86.ADIVL}, + {"DIVQ", LTYPE2, x86.ADIVQ}, + {"DIVW", LTYPE2, x86.ADIVW}, + {"EMMS", LTYPE0, x86.AEMMS}, + {"END", LTYPE0, obj.AEND}, + {"ENTER", LTYPE2, x86.AENTER}, + {"GLOBL", LTYPEG, obj.AGLOBL}, + {"HLT", LTYPE0, x86.AHLT}, + {"IDIVB", LTYPE2, x86.AIDIVB}, + {"IDIVL", LTYPE2, x86.AIDIVL}, + {"IDIVQ", LTYPE2, x86.AIDIVQ}, + {"IDIVW", LTYPE2, x86.AIDIVW}, + {"IMULB", LTYPEI, x86.AIMULB}, + {"IMULL", LTYPEI, x86.AIMULL}, + {"IMULQ", LTYPEI, x86.AIMULQ}, + {"IMUL3Q", LTYPEX, x86.AIMUL3Q}, + {"IMULW", LTYPEI, x86.AIMULW}, + {"INB", LTYPE0, x86.AINB}, + {"INL", LTYPE0, x86.AINL}, + {"INW", LTYPE0, x86.AINW}, + {"INCB", LTYPE1, x86.AINCB}, + {"INCL", LTYPE1, x86.AINCL}, + {"INCQ", LTYPE1, x86.AINCQ}, + {"INCW", LTYPE1, x86.AINCW}, + {"INSB", LTYPE0, x86.AINSB}, + {"INSL", LTYPE0, x86.AINSL}, + {"INSW", LTYPE0, x86.AINSW}, + {"INT", LTYPE2, x86.AINT}, + {"INTO", LTYPE0, x86.AINTO}, + {"INVD", LTYPE0, x86.AINVD}, + {"INVLPG", LTYPE2, x86.AINVLPG}, + {"IRETL", LTYPE0, x86.AIRETL}, + {"IRETQ", LTYPE0, x86.AIRETQ}, + {"IRETW", LTYPE0, x86.AIRETW}, + {"JOS", LTYPER, x86.AJOS}, /* overflow set (OF = 1) */ + {"JO", LTYPER, x86.AJOS}, /* alternate */ + {"JOC", LTYPER, x86.AJOC}, /* overflow clear (OF = 0) */ + {"JNO", LTYPER, x86.AJOC}, /* alternate */ + {"JCS", LTYPER, x86.AJCS}, /* carry set (CF = 1) */ + {"JB", LTYPER, x86.AJCS}, /* alternate */ + {"JC", LTYPER, x86.AJCS}, /* alternate */ + {"JNAE", LTYPER, x86.AJCS}, /* alternate */ + {"JLO", LTYPER, x86.AJCS}, /* alternate */ + {"JCC", LTYPER, x86.AJCC}, /* carry clear (CF = 0) */ + {"JAE", LTYPER, x86.AJCC}, /* alternate */ + {"JNB", LTYPER, x86.AJCC}, /* alternate */ + {"JNC", LTYPER, x86.AJCC}, /* alternate */ + {"JHS", LTYPER, x86.AJCC}, /* alternate */ + {"JEQ", LTYPER, x86.AJEQ}, /* equal (ZF = 1) */ + {"JE", LTYPER, x86.AJEQ}, /* alternate */ + {"JZ", LTYPER, x86.AJEQ}, /* alternate */ + {"JNE", LTYPER, x86.AJNE}, /* not equal (ZF = 0) */ + {"JNZ", LTYPER, x86.AJNE}, /* alternate */ + {"JLS", LTYPER, x86.AJLS}, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ + {"JBE", LTYPER, x86.AJLS}, /* alternate */ + {"JNA", LTYPER, x86.AJLS}, /* alternate */ + {"JHI", LTYPER, x86.AJHI}, /* higher (unsigned) (CF = 0 && ZF = 0) */ + {"JA", LTYPER, x86.AJHI}, /* alternate */ + {"JNBE", LTYPER, x86.AJHI}, /* alternate */ + {"JMI", LTYPER, x86.AJMI}, /* negative (minus) (SF = 1) */ + {"JS", LTYPER, x86.AJMI}, /* alternate */ + {"JPL", LTYPER, x86.AJPL}, /* non-negative (plus) (SF = 0) */ + {"JNS", LTYPER, x86.AJPL}, /* alternate */ + {"JPS", LTYPER, x86.AJPS}, /* parity set (PF = 1) */ + {"JP", LTYPER, x86.AJPS}, /* alternate */ + {"JPE", LTYPER, x86.AJPS}, /* alternate */ + {"JPC", LTYPER, x86.AJPC}, /* parity clear (PF = 0) */ + {"JNP", LTYPER, x86.AJPC}, /* alternate */ + {"JPO", LTYPER, x86.AJPC}, /* alternate */ + {"JLT", LTYPER, x86.AJLT}, /* less than (signed) (SF != OF) */ + {"JL", LTYPER, x86.AJLT}, /* alternate */ + {"JNGE", LTYPER, x86.AJLT}, /* alternate */ + {"JGE", LTYPER, x86.AJGE}, /* greater than or equal (signed) (SF = OF) */ + {"JNL", LTYPER, x86.AJGE}, /* alternate */ + {"JLE", LTYPER, x86.AJLE}, /* less than or equal (signed) (ZF = 1 || SF != OF) */ + {"JNG", LTYPER, x86.AJLE}, /* alternate */ + {"JGT", LTYPER, x86.AJGT}, /* greater than (signed) (ZF = 0 && SF = OF) */ + {"JG", LTYPER, x86.AJGT}, /* alternate */ + {"JNLE", LTYPER, x86.AJGT}, /* alternate */ + {"JCXZL", LTYPER, x86.AJCXZL}, + {"JCXZQ", LTYPER, x86.AJCXZQ}, + {"JMP", LTYPEC, obj.AJMP}, + {"LAHF", LTYPE0, x86.ALAHF}, + {"LARL", LTYPE3, x86.ALARL}, + {"LARW", LTYPE3, x86.ALARW}, + {"LEAL", LTYPE3, x86.ALEAL}, + {"LEAQ", LTYPE3, x86.ALEAQ}, + {"LEAW", LTYPE3, x86.ALEAW}, + {"LEAVEL", LTYPE0, x86.ALEAVEL}, + {"LEAVEQ", LTYPE0, x86.ALEAVEQ}, + {"LEAVEW", LTYPE0, x86.ALEAVEW}, + {"LFENCE", LTYPE0, x86.ALFENCE}, + {"LOCK", LTYPE0, x86.ALOCK}, + {"LODSB", LTYPE0, x86.ALODSB}, + {"LODSL", LTYPE0, x86.ALODSL}, + {"LODSQ", LTYPE0, x86.ALODSQ}, + {"LODSW", LTYPE0, x86.ALODSW}, + {"LONG", LTYPE2, x86.ALONG}, + {"LOOP", LTYPER, x86.ALOOP}, + {"LOOPEQ", LTYPER, x86.ALOOPEQ}, + {"LOOPNE", LTYPER, x86.ALOOPNE}, + {"LSLL", LTYPE3, x86.ALSLL}, + {"LSLW", LTYPE3, x86.ALSLW}, + {"MFENCE", LTYPE0, x86.AMFENCE}, + {"MODE", LTYPE2, x86.AMODE}, + {"MOVB", LTYPE3, x86.AMOVB}, + {"MOVL", LTYPEM, x86.AMOVL}, + {"MOVQ", LTYPEM, x86.AMOVQ}, + {"MOVW", LTYPEM, x86.AMOVW}, + {"MOVBLSX", LTYPE3, x86.AMOVBLSX}, + {"MOVBLZX", LTYPE3, x86.AMOVBLZX}, + {"MOVBQSX", LTYPE3, x86.AMOVBQSX}, + {"MOVBQZX", LTYPE3, x86.AMOVBQZX}, + {"MOVBWSX", LTYPE3, x86.AMOVBWSX}, + {"MOVBWZX", LTYPE3, x86.AMOVBWZX}, + {"MOVLQSX", LTYPE3, x86.AMOVLQSX}, + {"MOVLQZX", LTYPE3, x86.AMOVLQZX}, + {"MOVNTIL", LTYPE3, x86.AMOVNTIL}, + {"MOVNTIQ", LTYPE3, x86.AMOVNTIQ}, + {"MOVQL", LTYPE3, x86.AMOVQL}, + {"MOVWLSX", LTYPE3, x86.AMOVWLSX}, + {"MOVWLZX", LTYPE3, x86.AMOVWLZX}, + {"MOVWQSX", LTYPE3, x86.AMOVWQSX}, + {"MOVWQZX", LTYPE3, x86.AMOVWQZX}, + {"MOVSB", LTYPE0, x86.AMOVSB}, + {"MOVSL", LTYPE0, x86.AMOVSL}, + {"MOVSQ", LTYPE0, x86.AMOVSQ}, + {"MOVSW", LTYPE0, x86.AMOVSW}, + {"MULB", LTYPE2, x86.AMULB}, + {"MULL", LTYPE2, x86.AMULL}, + {"MULQ", LTYPE2, x86.AMULQ}, + {"MULW", LTYPE2, x86.AMULW}, + {"NEGB", LTYPE1, x86.ANEGB}, + {"NEGL", LTYPE1, x86.ANEGL}, + {"NEGQ", LTYPE1, x86.ANEGQ}, + {"NEGW", LTYPE1, x86.ANEGW}, + {"NOP", LTYPEN, obj.ANOP}, + {"NOTB", LTYPE1, x86.ANOTB}, + {"NOTL", LTYPE1, x86.ANOTL}, + {"NOTQ", LTYPE1, x86.ANOTQ}, + {"NOTW", LTYPE1, x86.ANOTW}, + {"ORB", LTYPE3, x86.AORB}, + {"ORL", LTYPE3, x86.AORL}, + {"ORQ", LTYPE3, x86.AORQ}, + {"ORW", LTYPE3, x86.AORW}, + {"OUTB", LTYPE0, x86.AOUTB}, + {"OUTL", LTYPE0, x86.AOUTL}, + {"OUTW", LTYPE0, x86.AOUTW}, + {"OUTSB", LTYPE0, x86.AOUTSB}, + {"OUTSL", LTYPE0, x86.AOUTSL}, + {"OUTSW", LTYPE0, x86.AOUTSW}, + {"PAUSE", LTYPEN, x86.APAUSE}, + {"POPAL", LTYPE0, x86.APOPAL}, + {"POPAW", LTYPE0, x86.APOPAW}, + {"POPFL", LTYPE0, x86.APOPFL}, + {"POPFQ", LTYPE0, x86.APOPFQ}, + {"POPFW", LTYPE0, x86.APOPFW}, + {"POPL", LTYPE1, x86.APOPL}, + {"POPQ", LTYPE1, x86.APOPQ}, + {"POPW", LTYPE1, x86.APOPW}, + {"PUSHAL", LTYPE0, x86.APUSHAL}, + {"PUSHAW", LTYPE0, x86.APUSHAW}, + {"PUSHFL", LTYPE0, x86.APUSHFL}, + {"PUSHFQ", LTYPE0, x86.APUSHFQ}, + {"PUSHFW", LTYPE0, x86.APUSHFW}, + {"PUSHL", LTYPE2, x86.APUSHL}, + {"PUSHQ", LTYPE2, x86.APUSHQ}, + {"PUSHW", LTYPE2, x86.APUSHW}, + {"RCLB", LTYPE3, x86.ARCLB}, + {"RCLL", LTYPE3, x86.ARCLL}, + {"RCLQ", LTYPE3, x86.ARCLQ}, + {"RCLW", LTYPE3, x86.ARCLW}, + {"RCRB", LTYPE3, x86.ARCRB}, + {"RCRL", LTYPE3, x86.ARCRL}, + {"RCRQ", LTYPE3, x86.ARCRQ}, + {"RCRW", LTYPE3, x86.ARCRW}, + {"RDMSR", LTYPE0, x86.ARDMSR}, + {"RDPMC", LTYPE0, x86.ARDPMC}, + {"RDTSC", LTYPE0, x86.ARDTSC}, + {"REP", LTYPE0, x86.AREP}, + {"REPN", LTYPE0, x86.AREPN}, + {"RET", LTYPE0, obj.ARET}, + {"RETFL", LTYPERT, x86.ARETFL}, + {"RETFW", LTYPERT, x86.ARETFW}, + {"RETFQ", LTYPERT, x86.ARETFQ}, + {"ROLB", LTYPE3, x86.AROLB}, + {"ROLL", LTYPE3, x86.AROLL}, + {"ROLQ", LTYPE3, x86.AROLQ}, + {"ROLW", LTYPE3, x86.AROLW}, + {"RORB", LTYPE3, x86.ARORB}, + {"RORL", LTYPE3, x86.ARORL}, + {"RORQ", LTYPE3, x86.ARORQ}, + {"RORW", LTYPE3, x86.ARORW}, + {"RSM", LTYPE0, x86.ARSM}, + {"SAHF", LTYPE0, x86.ASAHF}, + {"SALB", LTYPE3, x86.ASALB}, + {"SALL", LTYPE3, x86.ASALL}, + {"SALQ", LTYPE3, x86.ASALQ}, + {"SALW", LTYPE3, x86.ASALW}, + {"SARB", LTYPE3, x86.ASARB}, + {"SARL", LTYPE3, x86.ASARL}, + {"SARQ", LTYPE3, x86.ASARQ}, + {"SARW", LTYPE3, x86.ASARW}, + {"SBBB", LTYPE3, x86.ASBBB}, + {"SBBL", LTYPE3, x86.ASBBL}, + {"SBBQ", LTYPE3, x86.ASBBQ}, + {"SBBW", LTYPE3, x86.ASBBW}, + {"SCASB", LTYPE0, x86.ASCASB}, + {"SCASL", LTYPE0, x86.ASCASL}, + {"SCASQ", LTYPE0, x86.ASCASQ}, + {"SCASW", LTYPE0, x86.ASCASW}, + {"SETCC", LTYPE1, x86.ASETCC}, /* see JCC etc above for condition codes */ + {"SETCS", LTYPE1, x86.ASETCS}, + {"SETEQ", LTYPE1, x86.ASETEQ}, + {"SETGE", LTYPE1, x86.ASETGE}, + {"SETGT", LTYPE1, x86.ASETGT}, + {"SETHI", LTYPE1, x86.ASETHI}, + {"SETLE", LTYPE1, x86.ASETLE}, + {"SETLS", LTYPE1, x86.ASETLS}, + {"SETLT", LTYPE1, x86.ASETLT}, + {"SETMI", LTYPE1, x86.ASETMI}, + {"SETNE", LTYPE1, x86.ASETNE}, + {"SETOC", LTYPE1, x86.ASETOC}, + {"SETOS", LTYPE1, x86.ASETOS}, + {"SETPC", LTYPE1, x86.ASETPC}, + {"SETPL", LTYPE1, x86.ASETPL}, + {"SETPS", LTYPE1, x86.ASETPS}, + {"SFENCE", LTYPE0, x86.ASFENCE}, + {"CDQ", LTYPE0, x86.ACDQ}, + {"CWD", LTYPE0, x86.ACWD}, + {"CQO", LTYPE0, x86.ACQO}, + {"SHLB", LTYPE3, x86.ASHLB}, + {"SHLL", LTYPES, x86.ASHLL}, + {"SHLQ", LTYPES, x86.ASHLQ}, + {"SHLW", LTYPES, x86.ASHLW}, + {"SHRB", LTYPE3, x86.ASHRB}, + {"SHRL", LTYPES, x86.ASHRL}, + {"SHRQ", LTYPES, x86.ASHRQ}, + {"SHRW", LTYPES, x86.ASHRW}, + {"STC", LTYPE0, x86.ASTC}, + {"STD", LTYPE0, x86.ASTD}, + {"STI", LTYPE0, x86.ASTI}, + {"STOSB", LTYPE0, x86.ASTOSB}, + {"STOSL", LTYPE0, x86.ASTOSL}, + {"STOSQ", LTYPE0, x86.ASTOSQ}, + {"STOSW", LTYPE0, x86.ASTOSW}, + {"SUBB", LTYPE3, x86.ASUBB}, + {"SUBL", LTYPE3, x86.ASUBL}, + {"SUBQ", LTYPE3, x86.ASUBQ}, + {"SUBW", LTYPE3, x86.ASUBW}, + {"SYSCALL", LTYPE0, x86.ASYSCALL}, + {"SYSRET", LTYPE0, x86.ASYSRET}, + {"SWAPGS", LTYPE0, x86.ASWAPGS}, + {"TESTB", LTYPE3, x86.ATESTB}, + {"TESTL", LTYPE3, x86.ATESTL}, + {"TESTQ", LTYPE3, x86.ATESTQ}, + {"TESTW", LTYPE3, x86.ATESTW}, + {"TEXT", LTYPET, obj.ATEXT}, + {"VERR", LTYPE2, x86.AVERR}, + {"VERW", LTYPE2, x86.AVERW}, + {"QUAD", LTYPE2, x86.AQUAD}, + {"WAIT", LTYPE0, x86.AWAIT}, + {"WBINVD", LTYPE0, x86.AWBINVD}, + {"WRMSR", LTYPE0, x86.AWRMSR}, + {"WORD", LTYPE2, x86.AWORD}, + {"XADDB", LTYPE3, x86.AXADDB}, + {"XADDL", LTYPE3, x86.AXADDL}, + {"XADDQ", LTYPE3, x86.AXADDQ}, + {"XADDW", LTYPE3, x86.AXADDW}, + {"XCHGB", LTYPE3, x86.AXCHGB}, + {"XCHGL", LTYPE3, x86.AXCHGL}, + {"XCHGQ", LTYPE3, x86.AXCHGQ}, + {"XCHGW", LTYPE3, x86.AXCHGW}, + {"XLAT", LTYPE2, x86.AXLAT}, + {"XORB", LTYPE3, x86.AXORB}, + {"XORL", LTYPE3, x86.AXORL}, + {"XORQ", LTYPE3, x86.AXORQ}, + {"XORW", LTYPE3, x86.AXORW}, + {"CMOVLCC", LTYPE3, x86.ACMOVLCC}, + {"CMOVLCS", LTYPE3, x86.ACMOVLCS}, + {"CMOVLEQ", LTYPE3, x86.ACMOVLEQ}, + {"CMOVLGE", LTYPE3, x86.ACMOVLGE}, + {"CMOVLGT", LTYPE3, x86.ACMOVLGT}, + {"CMOVLHI", LTYPE3, x86.ACMOVLHI}, + {"CMOVLLE", LTYPE3, x86.ACMOVLLE}, + {"CMOVLLS", LTYPE3, x86.ACMOVLLS}, + {"CMOVLLT", LTYPE3, x86.ACMOVLLT}, + {"CMOVLMI", LTYPE3, x86.ACMOVLMI}, + {"CMOVLNE", LTYPE3, x86.ACMOVLNE}, + {"CMOVLOC", LTYPE3, x86.ACMOVLOC}, + {"CMOVLOS", LTYPE3, x86.ACMOVLOS}, + {"CMOVLPC", LTYPE3, x86.ACMOVLPC}, + {"CMOVLPL", LTYPE3, x86.ACMOVLPL}, + {"CMOVLPS", LTYPE3, x86.ACMOVLPS}, + {"CMOVQCC", LTYPE3, x86.ACMOVQCC}, + {"CMOVQCS", LTYPE3, x86.ACMOVQCS}, + {"CMOVQEQ", LTYPE3, x86.ACMOVQEQ}, + {"CMOVQGE", LTYPE3, x86.ACMOVQGE}, + {"CMOVQGT", LTYPE3, x86.ACMOVQGT}, + {"CMOVQHI", LTYPE3, x86.ACMOVQHI}, + {"CMOVQLE", LTYPE3, x86.ACMOVQLE}, + {"CMOVQLS", LTYPE3, x86.ACMOVQLS}, + {"CMOVQLT", LTYPE3, x86.ACMOVQLT}, + {"CMOVQMI", LTYPE3, x86.ACMOVQMI}, + {"CMOVQNE", LTYPE3, x86.ACMOVQNE}, + {"CMOVQOC", LTYPE3, x86.ACMOVQOC}, + {"CMOVQOS", LTYPE3, x86.ACMOVQOS}, + {"CMOVQPC", LTYPE3, x86.ACMOVQPC}, + {"CMOVQPL", LTYPE3, x86.ACMOVQPL}, + {"CMOVQPS", LTYPE3, x86.ACMOVQPS}, + {"CMOVWCC", LTYPE3, x86.ACMOVWCC}, + {"CMOVWCS", LTYPE3, x86.ACMOVWCS}, + {"CMOVWEQ", LTYPE3, x86.ACMOVWEQ}, + {"CMOVWGE", LTYPE3, x86.ACMOVWGE}, + {"CMOVWGT", LTYPE3, x86.ACMOVWGT}, + {"CMOVWHI", LTYPE3, x86.ACMOVWHI}, + {"CMOVWLE", LTYPE3, x86.ACMOVWLE}, + {"CMOVWLS", LTYPE3, x86.ACMOVWLS}, + {"CMOVWLT", LTYPE3, x86.ACMOVWLT}, + {"CMOVWMI", LTYPE3, x86.ACMOVWMI}, + {"CMOVWNE", LTYPE3, x86.ACMOVWNE}, + {"CMOVWOC", LTYPE3, x86.ACMOVWOC}, + {"CMOVWOS", LTYPE3, x86.ACMOVWOS}, + {"CMOVWPC", LTYPE3, x86.ACMOVWPC}, + {"CMOVWPL", LTYPE3, x86.ACMOVWPL}, + {"CMOVWPS", LTYPE3, x86.ACMOVWPS}, + {"FMOVB", LTYPE3, x86.AFMOVB}, + {"FMOVBP", LTYPE3, x86.AFMOVBP}, + {"FMOVD", LTYPE3, x86.AFMOVD}, + {"FMOVDP", LTYPE3, x86.AFMOVDP}, + {"FMOVF", LTYPE3, x86.AFMOVF}, + {"FMOVFP", LTYPE3, x86.AFMOVFP}, + {"FMOVL", LTYPE3, x86.AFMOVL}, + {"FMOVLP", LTYPE3, x86.AFMOVLP}, + {"FMOVV", LTYPE3, x86.AFMOVV}, + {"FMOVVP", LTYPE3, x86.AFMOVVP}, + {"FMOVW", LTYPE3, x86.AFMOVW}, + {"FMOVWP", LTYPE3, x86.AFMOVWP}, + {"FMOVX", LTYPE3, x86.AFMOVX}, + {"FMOVXP", LTYPE3, x86.AFMOVXP}, + {"FCOMB", LTYPE3, x86.AFCOMB}, + {"FCOMBP", LTYPE3, x86.AFCOMBP}, + {"FCOMD", LTYPE3, x86.AFCOMD}, + {"FCOMDP", LTYPE3, x86.AFCOMDP}, + {"FCOMDPP", LTYPE3, x86.AFCOMDPP}, + {"FCOMF", LTYPE3, x86.AFCOMF}, + {"FCOMFP", LTYPE3, x86.AFCOMFP}, + {"FCOML", LTYPE3, x86.AFCOML}, + {"FCOMLP", LTYPE3, x86.AFCOMLP}, + {"FCOMW", LTYPE3, x86.AFCOMW}, + {"FCOMWP", LTYPE3, x86.AFCOMWP}, + {"FUCOM", LTYPE3, x86.AFUCOM}, + {"FUCOMP", LTYPE3, x86.AFUCOMP}, + {"FUCOMPP", LTYPE3, x86.AFUCOMPP}, + {"FADDW", LTYPE3, x86.AFADDW}, + {"FADDL", LTYPE3, x86.AFADDL}, + {"FADDF", LTYPE3, x86.AFADDF}, + {"FADDD", LTYPE3, x86.AFADDD}, + {"FADDDP", LTYPE3, x86.AFADDDP}, + {"FSUBDP", LTYPE3, x86.AFSUBDP}, + {"FSUBW", LTYPE3, x86.AFSUBW}, + {"FSUBL", LTYPE3, x86.AFSUBL}, + {"FSUBF", LTYPE3, x86.AFSUBF}, + {"FSUBD", LTYPE3, x86.AFSUBD}, + {"FSUBRDP", LTYPE3, x86.AFSUBRDP}, + {"FSUBRW", LTYPE3, x86.AFSUBRW}, + {"FSUBRL", LTYPE3, x86.AFSUBRL}, + {"FSUBRF", LTYPE3, x86.AFSUBRF}, + {"FSUBRD", LTYPE3, x86.AFSUBRD}, + {"FMULDP", LTYPE3, x86.AFMULDP}, + {"FMULW", LTYPE3, x86.AFMULW}, + {"FMULL", LTYPE3, x86.AFMULL}, + {"FMULF", LTYPE3, x86.AFMULF}, + {"FMULD", LTYPE3, x86.AFMULD}, + {"FDIVDP", LTYPE3, x86.AFDIVDP}, + {"FDIVW", LTYPE3, x86.AFDIVW}, + {"FDIVL", LTYPE3, x86.AFDIVL}, + {"FDIVF", LTYPE3, x86.AFDIVF}, + {"FDIVD", LTYPE3, x86.AFDIVD}, + {"FDIVRDP", LTYPE3, x86.AFDIVRDP}, + {"FDIVRW", LTYPE3, x86.AFDIVRW}, + {"FDIVRL", LTYPE3, x86.AFDIVRL}, + {"FDIVRF", LTYPE3, x86.AFDIVRF}, + {"FDIVRD", LTYPE3, x86.AFDIVRD}, + {"FXCHD", LTYPE3, x86.AFXCHD}, + {"FFREE", LTYPE1, x86.AFFREE}, + {"FLDCW", LTYPE2, x86.AFLDCW}, + {"FLDENV", LTYPE1, x86.AFLDENV}, + {"FRSTOR", LTYPE2, x86.AFRSTOR}, + {"FSAVE", LTYPE1, x86.AFSAVE}, + {"FSTCW", LTYPE1, x86.AFSTCW}, + {"FSTENV", LTYPE1, x86.AFSTENV}, + {"FSTSW", LTYPE1, x86.AFSTSW}, + {"F2XM1", LTYPE0, x86.AF2XM1}, + {"FABS", LTYPE0, x86.AFABS}, + {"FCHS", LTYPE0, x86.AFCHS}, + {"FCLEX", LTYPE0, x86.AFCLEX}, + {"FCOS", LTYPE0, x86.AFCOS}, + {"FDECSTP", LTYPE0, x86.AFDECSTP}, + {"FINCSTP", LTYPE0, x86.AFINCSTP}, + {"FINIT", LTYPE0, x86.AFINIT}, + {"FLD1", LTYPE0, x86.AFLD1}, + {"FLDL2E", LTYPE0, x86.AFLDL2E}, + {"FLDL2T", LTYPE0, x86.AFLDL2T}, + {"FLDLG2", LTYPE0, x86.AFLDLG2}, + {"FLDLN2", LTYPE0, x86.AFLDLN2}, + {"FLDPI", LTYPE0, x86.AFLDPI}, + {"FLDZ", LTYPE0, x86.AFLDZ}, + {"FNOP", LTYPE0, x86.AFNOP}, + {"FPATAN", LTYPE0, x86.AFPATAN}, + {"FPREM", LTYPE0, x86.AFPREM}, + {"FPREM1", LTYPE0, x86.AFPREM1}, + {"FPTAN", LTYPE0, x86.AFPTAN}, + {"FRNDINT", LTYPE0, x86.AFRNDINT}, + {"FSCALE", LTYPE0, x86.AFSCALE}, + {"FSIN", LTYPE0, x86.AFSIN}, + {"FSINCOS", LTYPE0, x86.AFSINCOS}, + {"FSQRT", LTYPE0, x86.AFSQRT}, + {"FTST", LTYPE0, x86.AFTST}, + {"FXAM", LTYPE0, x86.AFXAM}, + {"FXTRACT", LTYPE0, x86.AFXTRACT}, + {"FYL2X", LTYPE0, x86.AFYL2X}, + {"FYL2XP1", LTYPE0, x86.AFYL2XP1}, + {"ADDPD", LTYPE3, x86.AADDPD}, + {"ADDPS", LTYPE3, x86.AADDPS}, + {"ADDSD", LTYPE3, x86.AADDSD}, + {"ADDSS", LTYPE3, x86.AADDSS}, + {"ANDNPD", LTYPE3, x86.AANDNPD}, + {"ANDNPS", LTYPE3, x86.AANDNPS}, + {"ANDPD", LTYPE3, x86.AANDPD}, + {"ANDPS", LTYPE3, x86.AANDPS}, + {"CMPPD", LTYPEXC, x86.ACMPPD}, + {"CMPPS", LTYPEXC, x86.ACMPPS}, + {"CMPSD", LTYPEXC, x86.ACMPSD}, + {"CMPSS", LTYPEXC, x86.ACMPSS}, + {"COMISD", LTYPE3, x86.ACOMISD}, + {"COMISS", LTYPE3, x86.ACOMISS}, + {"CVTPL2PD", LTYPE3, x86.ACVTPL2PD}, + {"CVTPL2PS", LTYPE3, x86.ACVTPL2PS}, + {"CVTPD2PL", LTYPE3, x86.ACVTPD2PL}, + {"CVTPD2PS", LTYPE3, x86.ACVTPD2PS}, + {"CVTPS2PL", LTYPE3, x86.ACVTPS2PL}, + {"PF2IW", LTYPE3, x86.APF2IW}, + {"PF2IL", LTYPE3, x86.APF2IL}, + {"PF2ID", LTYPE3, x86.APF2IL}, /* syn */ + {"PI2FL", LTYPE3, x86.API2FL}, + {"PI2FD", LTYPE3, x86.API2FL}, /* syn */ + {"PI2FW", LTYPE3, x86.API2FW}, + {"CVTPS2PD", LTYPE3, x86.ACVTPS2PD}, + {"CVTSD2SL", LTYPE3, x86.ACVTSD2SL}, + {"CVTSD2SQ", LTYPE3, x86.ACVTSD2SQ}, + {"CVTSD2SS", LTYPE3, x86.ACVTSD2SS}, + {"CVTSL2SD", LTYPE3, x86.ACVTSL2SD}, + {"CVTSQ2SD", LTYPE3, x86.ACVTSQ2SD}, + {"CVTSL2SS", LTYPE3, x86.ACVTSL2SS}, + {"CVTSQ2SS", LTYPE3, x86.ACVTSQ2SS}, + {"CVTSS2SD", LTYPE3, x86.ACVTSS2SD}, + {"CVTSS2SL", LTYPE3, x86.ACVTSS2SL}, + {"CVTSS2SQ", LTYPE3, x86.ACVTSS2SQ}, + {"CVTTPD2PL", LTYPE3, x86.ACVTTPD2PL}, + {"CVTTPS2PL", LTYPE3, x86.ACVTTPS2PL}, + {"CVTTSD2SL", LTYPE3, x86.ACVTTSD2SL}, + {"CVTTSD2SQ", LTYPE3, x86.ACVTTSD2SQ}, + {"CVTTSS2SL", LTYPE3, x86.ACVTTSS2SL}, + {"CVTTSS2SQ", LTYPE3, x86.ACVTTSS2SQ}, + {"DIVPD", LTYPE3, x86.ADIVPD}, + {"DIVPS", LTYPE3, x86.ADIVPS}, + {"DIVSD", LTYPE3, x86.ADIVSD}, + {"DIVSS", LTYPE3, x86.ADIVSS}, + {"FXRSTOR", LTYPE2, x86.AFXRSTOR}, + {"FXRSTOR64", LTYPE2, x86.AFXRSTOR64}, + {"FXSAVE", LTYPE1, x86.AFXSAVE}, + {"FXSAVE64", LTYPE1, x86.AFXSAVE64}, + {"LDMXCSR", LTYPE2, x86.ALDMXCSR}, + {"MASKMOVOU", LTYPE3, x86.AMASKMOVOU}, + {"MASKMOVDQU", LTYPE3, x86.AMASKMOVOU}, /* syn */ + {"MASKMOVQ", LTYPE3, x86.AMASKMOVQ}, + {"MAXPD", LTYPE3, x86.AMAXPD}, + {"MAXPS", LTYPE3, x86.AMAXPS}, + {"MAXSD", LTYPE3, x86.AMAXSD}, + {"MAXSS", LTYPE3, x86.AMAXSS}, + {"MINPD", LTYPE3, x86.AMINPD}, + {"MINPS", LTYPE3, x86.AMINPS}, + {"MINSD", LTYPE3, x86.AMINSD}, + {"MINSS", LTYPE3, x86.AMINSS}, + {"MOVAPD", LTYPE3, x86.AMOVAPD}, + {"MOVAPS", LTYPE3, x86.AMOVAPS}, + {"MOVD", LTYPE3, x86.AMOVQ}, /* syn */ + {"MOVDQ2Q", LTYPE3, x86.AMOVQ}, /* syn */ + {"MOVO", LTYPE3, x86.AMOVO}, + {"MOVOA", LTYPE3, x86.AMOVO}, /* syn */ + {"MOVOU", LTYPE3, x86.AMOVOU}, + {"MOVHLPS", LTYPE3, x86.AMOVHLPS}, + {"MOVHPD", LTYPE3, x86.AMOVHPD}, + {"MOVHPS", LTYPE3, x86.AMOVHPS}, + {"MOVLHPS", LTYPE3, x86.AMOVLHPS}, + {"MOVLPD", LTYPE3, x86.AMOVLPD}, + {"MOVLPS", LTYPE3, x86.AMOVLPS}, + {"MOVMSKPD", LTYPE3, x86.AMOVMSKPD}, + {"MOVMSKPS", LTYPE3, x86.AMOVMSKPS}, + {"MOVNTO", LTYPE3, x86.AMOVNTO}, + {"MOVNTDQ", LTYPE3, x86.AMOVNTO}, /* syn */ + {"MOVNTPD", LTYPE3, x86.AMOVNTPD}, + {"MOVNTPS", LTYPE3, x86.AMOVNTPS}, + {"MOVNTQ", LTYPE3, x86.AMOVNTQ}, + {"MOVQOZX", LTYPE3, x86.AMOVQOZX}, + {"MOVSD", LTYPE3, x86.AMOVSD}, + {"MOVSS", LTYPE3, x86.AMOVSS}, + {"MOVUPD", LTYPE3, x86.AMOVUPD}, + {"MOVUPS", LTYPE3, x86.AMOVUPS}, + {"MULPD", LTYPE3, x86.AMULPD}, + {"MULPS", LTYPE3, x86.AMULPS}, + {"MULSD", LTYPE3, x86.AMULSD}, + {"MULSS", LTYPE3, x86.AMULSS}, + {"ORPD", LTYPE3, x86.AORPD}, + {"ORPS", LTYPE3, x86.AORPS}, + {"PACKSSLW", LTYPE3, x86.APACKSSLW}, + {"PACKSSWB", LTYPE3, x86.APACKSSWB}, + {"PACKUSWB", LTYPE3, x86.APACKUSWB}, + {"PADDB", LTYPE3, x86.APADDB}, + {"PADDL", LTYPE3, x86.APADDL}, + {"PADDQ", LTYPE3, x86.APADDQ}, + {"PADDSB", LTYPE3, x86.APADDSB}, + {"PADDSW", LTYPE3, x86.APADDSW}, + {"PADDUSB", LTYPE3, x86.APADDUSB}, + {"PADDUSW", LTYPE3, x86.APADDUSW}, + {"PADDW", LTYPE3, x86.APADDW}, + {"PAND", LTYPE3, x86.APAND}, + {"PANDB", LTYPE3, x86.APANDB}, + {"PANDL", LTYPE3, x86.APANDL}, + {"PANDSB", LTYPE3, x86.APANDSB}, + {"PANDSW", LTYPE3, x86.APANDSW}, + {"PANDUSB", LTYPE3, x86.APANDUSB}, + {"PANDUSW", LTYPE3, x86.APANDUSW}, + {"PANDW", LTYPE3, x86.APANDW}, + {"PANDN", LTYPE3, x86.APANDN}, + {"PAVGB", LTYPE3, x86.APAVGB}, + {"PAVGW", LTYPE3, x86.APAVGW}, + {"PCMPEQB", LTYPE3, x86.APCMPEQB}, + {"PCMPEQL", LTYPE3, x86.APCMPEQL}, + {"PCMPEQW", LTYPE3, x86.APCMPEQW}, + {"PCMPGTB", LTYPE3, x86.APCMPGTB}, + {"PCMPGTL", LTYPE3, x86.APCMPGTL}, + {"PCMPGTW", LTYPE3, x86.APCMPGTW}, + {"PEXTRW", LTYPEX, x86.APEXTRW}, + {"PINSRW", LTYPEX, x86.APINSRW}, + {"PINSRD", LTYPEX, x86.APINSRD}, + {"PINSRQ", LTYPEX, x86.APINSRQ}, + {"PMADDWL", LTYPE3, x86.APMADDWL}, + {"PMAXSW", LTYPE3, x86.APMAXSW}, + {"PMAXUB", LTYPE3, x86.APMAXUB}, + {"PMINSW", LTYPE3, x86.APMINSW}, + {"PMINUB", LTYPE3, x86.APMINUB}, + {"PMOVMSKB", LTYPE3, x86.APMOVMSKB}, + {"PMULHRW", LTYPE3, x86.APMULHRW}, + {"PMULHUW", LTYPE3, x86.APMULHUW}, + {"PMULHW", LTYPE3, x86.APMULHW}, + {"PMULLW", LTYPE3, x86.APMULLW}, + {"PMULULQ", LTYPE3, x86.APMULULQ}, + {"POR", LTYPE3, x86.APOR}, + {"PSADBW", LTYPE3, x86.APSADBW}, + {"PSHUFHW", LTYPEX, x86.APSHUFHW}, + {"PSHUFL", LTYPEX, x86.APSHUFL}, + {"PSHUFLW", LTYPEX, x86.APSHUFLW}, + {"PSHUFW", LTYPEX, x86.APSHUFW}, + {"PSHUFB", LTYPEM, x86.APSHUFB}, + {"PSLLO", LTYPE3, x86.APSLLO}, + {"PSLLDQ", LTYPE3, x86.APSLLO}, /* syn */ + {"PSLLL", LTYPE3, x86.APSLLL}, + {"PSLLQ", LTYPE3, x86.APSLLQ}, + {"PSLLW", LTYPE3, x86.APSLLW}, + {"PSRAL", LTYPE3, x86.APSRAL}, + {"PSRAW", LTYPE3, x86.APSRAW}, + {"PSRLO", LTYPE3, x86.APSRLO}, + {"PSRLDQ", LTYPE3, x86.APSRLO}, /* syn */ + {"PSRLL", LTYPE3, x86.APSRLL}, + {"PSRLQ", LTYPE3, x86.APSRLQ}, + {"PSRLW", LTYPE3, x86.APSRLW}, + {"PSUBB", LTYPE3, x86.APSUBB}, + {"PSUBL", LTYPE3, x86.APSUBL}, + {"PSUBQ", LTYPE3, x86.APSUBQ}, + {"PSUBSB", LTYPE3, x86.APSUBSB}, + {"PSUBSW", LTYPE3, x86.APSUBSW}, + {"PSUBUSB", LTYPE3, x86.APSUBUSB}, + {"PSUBUSW", LTYPE3, x86.APSUBUSW}, + {"PSUBW", LTYPE3, x86.APSUBW}, + {"PUNPCKHBW", LTYPE3, x86.APUNPCKHBW}, + {"PUNPCKHLQ", LTYPE3, x86.APUNPCKHLQ}, + {"PUNPCKHQDQ", LTYPE3, x86.APUNPCKHQDQ}, + {"PUNPCKHWL", LTYPE3, x86.APUNPCKHWL}, + {"PUNPCKLBW", LTYPE3, x86.APUNPCKLBW}, + {"PUNPCKLLQ", LTYPE3, x86.APUNPCKLLQ}, + {"PUNPCKLQDQ", LTYPE3, x86.APUNPCKLQDQ}, + {"PUNPCKLWL", LTYPE3, x86.APUNPCKLWL}, + {"PXOR", LTYPE3, x86.APXOR}, + {"RCPPS", LTYPE3, x86.ARCPPS}, + {"RCPSS", LTYPE3, x86.ARCPSS}, + {"RSQRTPS", LTYPE3, x86.ARSQRTPS}, + {"RSQRTSS", LTYPE3, x86.ARSQRTSS}, + {"SHUFPD", LTYPEX, x86.ASHUFPD}, + {"SHUFPS", LTYPEX, x86.ASHUFPS}, + {"SQRTPD", LTYPE3, x86.ASQRTPD}, + {"SQRTPS", LTYPE3, x86.ASQRTPS}, + {"SQRTSD", LTYPE3, x86.ASQRTSD}, + {"SQRTSS", LTYPE3, x86.ASQRTSS}, + {"STMXCSR", LTYPE1, x86.ASTMXCSR}, + {"SUBPD", LTYPE3, x86.ASUBPD}, + {"SUBPS", LTYPE3, x86.ASUBPS}, + {"SUBSD", LTYPE3, x86.ASUBSD}, + {"SUBSS", LTYPE3, x86.ASUBSS}, + {"UCOMISD", LTYPE3, x86.AUCOMISD}, + {"UCOMISS", LTYPE3, x86.AUCOMISS}, + {"UNPCKHPD", LTYPE3, x86.AUNPCKHPD}, + {"UNPCKHPS", LTYPE3, x86.AUNPCKHPS}, + {"UNPCKLPD", LTYPE3, x86.AUNPCKLPD}, + {"UNPCKLPS", LTYPE3, x86.AUNPCKLPS}, + {"XORPD", LTYPE3, x86.AXORPD}, + {"XORPS", LTYPE3, x86.AXORPS}, + {"CRC32B", LTYPE4, x86.ACRC32B}, + {"CRC32Q", LTYPE4, x86.ACRC32Q}, + {"PREFETCHT0", LTYPE2, x86.APREFETCHT0}, + {"PREFETCHT1", LTYPE2, x86.APREFETCHT1}, + {"PREFETCHT2", LTYPE2, x86.APREFETCHT2}, + {"PREFETCHNTA", LTYPE2, x86.APREFETCHNTA}, + {"UNDEF", LTYPE0, obj.AUNDEF}, + {"AESENC", LTYPE3, x86.AAESENC}, + {"AESENCLAST", LTYPE3, x86.AAESENCLAST}, + {"AESDEC", LTYPE3, x86.AAESDEC}, + {"AESDECLAST", LTYPE3, x86.AAESDECLAST}, + {"AESIMC", LTYPE3, x86.AAESIMC}, + {"AESKEYGENASSIST", LTYPEX, x86.AAESKEYGENASSIST}, + {"PSHUFD", LTYPEX, x86.APSHUFD}, + {"USEFIELD", LTYPEN, obj.AUSEFIELD}, + {"PCLMULQDQ", LTYPEX, x86.APCLMULQDQ}, + {"PCDATA", LTYPEPC, obj.APCDATA}, + {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, +} + +func cinit() { +} + +func checkscale(scale int8) { + switch scale { + case 1, + 2, + 4, + 8: + return + } + + yyerror("scale must be 1248: %d", scale) +} + +func cclean() { + var g2 Addr2 + + g2.from = nullgen + g2.to = nullgen + outcode(obj.AEND, &g2) +} + +var lastpc *obj.Prog + +type Addr2 struct { + from obj.Addr + to obj.Addr +} + +func outcode(a int, g2 *Addr2) { + var p *obj.Prog + var pl *obj.Plist + + if asm.Pass == 1 { + goto out + } + + p = new(obj.Prog) + *p = obj.Prog{} + p.Ctxt = asm.Ctxt + p.As = int16(a) + p.Lineno = stmtline + p.From = g2.from + p.To = g2.to + p.Pc = int64(asm.PC) + + if lastpc == nil { + pl = obj.Linknewplist(asm.Ctxt) + pl.Firstpc = p + } else { + + lastpc.Link = p + } + lastpc = p + +out: + if a != obj.AGLOBL && a != obj.ADATA { + asm.PC++ + } +} diff --git a/src/cmd/6a/y.go b/src/cmd/6a/y.go new file mode 100644 index 0000000000..0b78d2e1e2 --- /dev/null +++ b/src/cmd/6a/y.go @@ -0,0 +1,1330 @@ +//line a.y:32 +package main + +import __yyfmt__ "fmt" + +//line a.y:32 +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/x86" +) + +//line a.y:41 +type yySymType struct { + yys int + sym *asm.Sym + lval int64 + dval float64 + sval string + addr obj.Addr + addr2 Addr2 +} + +const LTYPE0 = 57346 +const LTYPE1 = 57347 +const LTYPE2 = 57348 +const LTYPE3 = 57349 +const LTYPE4 = 57350 +const LTYPEC = 57351 +const LTYPED = 57352 +const LTYPEN = 57353 +const LTYPER = 57354 +const LTYPET = 57355 +const LTYPEG = 57356 +const LTYPEPC = 57357 +const LTYPES = 57358 +const LTYPEM = 57359 +const LTYPEI = 57360 +const LTYPEXC = 57361 +const LTYPEX = 57362 +const LTYPERT = 57363 +const LTYPEF = 57364 +const LCONST = 57365 +const LFP = 57366 +const LPC = 57367 +const LSB = 57368 +const LBREG = 57369 +const LLREG = 57370 +const LSREG = 57371 +const LFREG = 57372 +const LMREG = 57373 +const LXREG = 57374 +const LFCONST = 57375 +const LSCONST = 57376 +const LSP = 57377 +const LNAME = 57378 +const LLAB = 57379 +const LVAR = 57380 + +var yyToknames = []string{ + "'|'", + "'^'", + "'&'", + "'<'", + "'>'", + "'+'", + "'-'", + "'*'", + "'/'", + "'%'", + "LTYPE0", + "LTYPE1", + "LTYPE2", + "LTYPE3", + "LTYPE4", + "LTYPEC", + "LTYPED", + "LTYPEN", + "LTYPER", + "LTYPET", + "LTYPEG", + "LTYPEPC", + "LTYPES", + "LTYPEM", + "LTYPEI", + "LTYPEXC", + "LTYPEX", + "LTYPERT", + "LTYPEF", + "LCONST", + "LFP", + "LPC", + "LSB", + "LBREG", + "LLREG", + "LSREG", + "LFREG", + "LMREG", + "LXREG", + "LFCONST", + "LSCONST", + "LSP", + "LNAME", + "LLAB", + "LVAR", +} +var yyStatenames = []string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyMaxDepth = 200 + +//line yacctab:1 +var yyExca = []int{ + -1, 1, + 1, -1, + -2, 2, +} + +const yyNprod = 133 +const yyPrivate = 57344 + +var yyTokenNames []string +var yyStates []string + +const yyLast = 593 + +var yyAct = []int{ + + 52, 227, 41, 3, 80, 208, 269, 64, 123, 50, + 51, 79, 54, 170, 268, 74, 267, 118, 85, 72, + 83, 263, 73, 255, 253, 98, 241, 84, 81, 239, + 237, 100, 102, 112, 221, 219, 112, 210, 209, 171, + 240, 107, 234, 62, 211, 174, 143, 138, 65, 207, + 111, 119, 115, 113, 112, 231, 67, 169, 120, 121, + 122, 249, 230, 92, 94, 96, 128, 226, 225, 224, + 104, 106, 74, 58, 57, 154, 136, 112, 129, 85, + 153, 83, 151, 150, 139, 141, 149, 148, 84, 81, + 140, 147, 142, 146, 145, 144, 63, 55, 58, 57, + 137, 43, 45, 48, 44, 46, 49, 40, 135, 47, + 69, 134, 56, 127, 155, 40, 34, 37, 53, 31, + 59, 32, 55, 35, 33, 223, 176, 177, 222, 217, + 60, 215, 220, 112, 120, 243, 114, 56, 74, 242, + 216, 236, 183, 76, 173, 59, 58, 57, 256, 166, + 168, 251, 252, 192, 194, 196, 167, 112, 112, 112, + 112, 112, 195, 184, 112, 112, 112, 264, 58, 57, + 55, 212, 257, 248, 197, 198, 199, 200, 201, 182, + 120, 204, 205, 206, 218, 56, 42, 114, 152, 38, + 65, 76, 55, 59, 190, 191, 184, 261, 260, 166, + 168, 229, 258, 112, 112, 75, 167, 56, 89, 235, + 36, 71, 65, 76, 238, 59, 108, 109, 254, 213, + 232, 233, 125, 126, 228, 244, 247, 203, 245, 88, + 124, 181, 125, 126, 246, 158, 159, 160, 175, 250, + 202, 25, 185, 186, 187, 188, 189, 16, 15, 6, + 110, 259, 7, 2, 1, 262, 156, 157, 158, 159, + 160, 265, 266, 105, 9, 10, 11, 12, 13, 17, + 28, 18, 14, 29, 30, 26, 19, 20, 21, 22, + 23, 24, 27, 58, 57, 82, 165, 164, 163, 161, + 162, 156, 157, 158, 159, 160, 4, 103, 8, 101, + 5, 99, 97, 58, 57, 95, 93, 55, 91, 87, + 77, 43, 45, 48, 44, 46, 49, 68, 66, 47, + 86, 61, 56, 70, 214, 0, 78, 55, 53, 0, + 59, 43, 45, 48, 44, 46, 49, 172, 0, 47, + 60, 0, 56, 58, 57, 82, 0, 65, 53, 0, + 59, 43, 45, 48, 44, 46, 49, 0, 0, 47, + 0, 0, 0, 58, 57, 0, 0, 55, 0, 0, + 0, 43, 45, 48, 44, 46, 49, 0, 0, 47, + 86, 0, 56, 58, 57, 0, 0, 55, 53, 0, + 59, 43, 45, 48, 44, 46, 49, 0, 0, 47, + 60, 0, 56, 58, 57, 0, 90, 55, 53, 0, + 59, 43, 45, 48, 44, 46, 49, 58, 133, 47, + 60, 0, 56, 0, 0, 0, 39, 55, 53, 0, + 59, 43, 45, 48, 44, 46, 49, 58, 57, 47, + 60, 55, 56, 0, 58, 57, 0, 0, 53, 0, + 59, 131, 130, 0, 60, 0, 56, 58, 57, 0, + 0, 55, 132, 0, 59, 0, 116, 0, 55, 58, + 57, 0, 0, 117, 0, 0, 56, 0, 0, 0, + 0, 55, 76, 56, 59, 58, 179, 0, 193, 76, + 0, 59, 0, 55, 75, 0, 56, 58, 57, 0, + 0, 0, 76, 180, 59, 0, 0, 0, 56, 55, + 0, 58, 57, 0, 76, 0, 59, 0, 0, 178, + 0, 55, 0, 0, 56, 0, 0, 0, 0, 0, + 76, 0, 59, 0, 60, 55, 56, 0, 0, 0, + 0, 0, 53, 0, 59, 0, 0, 0, 0, 0, + 56, 0, 0, 0, 0, 0, 76, 0, 59, 165, + 164, 163, 161, 162, 156, 157, 158, 159, 160, 164, + 163, 161, 162, 156, 157, 158, 159, 160, 163, 161, + 162, 156, 157, 158, 159, 160, 161, 162, 156, 157, + 158, 159, 160, +} +var yyPact = []int{ + + -1000, -1000, 250, -1000, 70, -1000, 74, 66, 72, 65, + 374, 294, 294, 394, 159, -1000, -1000, 274, 354, 294, + 294, 294, 314, -5, -5, -1000, 294, 294, 84, 488, + 488, -1000, 502, -1000, -1000, 502, -1000, -1000, -1000, 394, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -2, 428, -3, -1000, -1000, 502, 502, 502, + 223, -1000, 61, -1000, -1000, 408, -1000, 59, -1000, 56, + -1000, 448, -1000, 48, -7, 213, 502, -1000, 334, -1000, + -1000, -1000, 64, -1000, -1000, -8, 223, -1000, -1000, -1000, + 394, -1000, 42, -1000, 41, -1000, 39, -1000, 35, -1000, + 34, -1000, -1000, -1000, 31, -1000, 30, 176, 28, 23, + 250, 555, -1000, 555, -1000, 111, 2, -16, 282, 106, + -1000, -1000, -1000, -9, 230, 502, 502, -1000, -1000, -1000, + -1000, -1000, 476, 460, 394, 294, -1000, 448, 128, -1000, + -1000, -1000, -1000, 161, -9, 394, 394, 394, 394, 394, + 294, 294, 502, 435, 137, -1000, 502, 502, 502, 502, + 502, 233, 219, 502, 502, 502, -6, -17, -18, -10, + 502, -1000, -1000, 208, 95, 213, -1000, -1000, -20, 89, + -1000, -1000, -1000, -1000, -21, 79, 76, -1000, 17, 16, + -1000, -1000, 15, 191, 10, -1000, 3, 224, 224, -1000, + -1000, -1000, 502, 502, 579, 572, 564, -12, 502, -1000, + -1000, 103, -25, 502, -26, -1000, -1000, -1000, -14, -1000, + -29, -1000, 101, 96, 502, 314, -5, -1000, 216, 140, + 8, -5, 247, 247, 113, -31, 207, -1000, -32, -1000, + 112, -1000, -1000, -1000, -1000, -1000, -1000, 139, 192, 191, + -1000, 187, 186, -1000, 502, -1000, -34, -1000, 134, -1000, + 502, 502, -39, -1000, -1000, -41, -49, -1000, -1000, -1000, +} +var yyPgo = []int{ + + 0, 0, 17, 324, 8, 186, 7, 1, 2, 12, + 4, 96, 43, 11, 9, 10, 210, 323, 189, 321, + 318, 317, 310, 309, 308, 306, 305, 302, 301, 299, + 297, 263, 254, 253, 3, 250, 249, 248, 247, 241, +} +var yyR1 = []int{ + + 0, 32, 33, 32, 35, 34, 34, 34, 34, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 16, 16, 20, 21, 19, 19, 18, 18, 17, 17, + 17, 37, 38, 38, 39, 39, 22, 22, 23, 23, + 24, 24, 25, 25, 26, 26, 26, 27, 28, 29, + 29, 30, 31, 11, 11, 13, 13, 13, 13, 13, + 13, 12, 12, 10, 10, 8, 8, 8, 8, 8, + 8, 8, 6, 6, 6, 6, 6, 6, 6, 5, + 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 9, 9, 4, 4, 4, 3, + 3, 3, 1, 1, 1, 1, 1, 1, 7, 7, + 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, +} +var yyR2 = []int{ + + 0, 0, 0, 3, 0, 4, 1, 2, 2, 3, + 3, 2, 2, 2, 2, 2, 2, 1, 1, 2, + 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, + 0, 1, 3, 3, 2, 1, 2, 1, 2, 1, + 3, 6, 5, 7, 4, 6, 2, 1, 1, 1, + 3, 5, 3, 5, 2, 1, 3, 5, 5, 0, + 1, 3, 3, 1, 1, 1, 1, 2, 2, 1, + 1, 1, 1, 4, 2, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 2, 2, 4, 5, 3, 1, + 1, 1, 4, 4, 4, 6, 9, 9, 3, 3, + 5, 8, 1, 6, 5, 7, 0, 2, 2, 1, + 1, 1, 1, 1, 2, 2, 2, 3, 1, 2, + 3, 4, 1, 3, 3, 3, 3, 3, 4, 4, + 3, 3, 3, +} +var yyChk = []int{ + + -1000, -32, -33, -34, 46, 50, -36, 2, 48, 14, + 15, 16, 17, 18, 22, -37, -38, 19, 21, 26, + 27, 28, 29, 30, 31, -39, 25, 32, 20, 23, + 24, 49, 51, 50, 50, 51, -16, 52, -18, 52, + -11, -8, -5, 37, 40, 38, 41, 45, 39, 42, + -14, -15, -1, 54, -9, 33, 48, 10, 9, 56, + 46, -19, -12, -11, -6, 53, -20, -12, -21, -11, + -17, 52, -10, -6, -1, 46, 54, -22, 52, -13, + -10, -15, 11, -8, -14, -1, 46, -23, -16, -18, + 52, -24, -12, -25, -12, -26, -12, -27, -8, -28, + -6, -29, -6, -30, -12, -31, -12, -9, -5, -5, + -35, -2, -1, -2, -11, 54, 38, 45, -2, 54, + -1, -1, -1, -4, 7, 9, 10, 52, -1, -9, + 44, 43, 54, 10, 52, 52, -10, 52, 54, -4, + -13, -8, -14, 54, -4, 52, 52, 52, 52, 52, + 52, 52, 12, 52, 52, -34, 9, 10, 11, 12, + 13, 7, 8, 6, 5, 4, 38, 45, 39, 55, + 11, 55, 55, 38, 54, 8, -1, -1, 43, 10, + 43, -11, -12, -10, 35, -11, -11, -11, -11, -11, + -12, -12, -1, 53, -1, -6, -1, -2, -2, -2, + -2, -2, 7, 8, -2, -2, -2, 55, 11, 55, + 55, 54, -1, 11, -3, 36, 45, 34, -4, 55, + 43, 55, 49, 49, 52, 52, 52, -7, 33, 10, + 52, 52, -2, -2, 54, -1, 38, 55, -1, 55, + 54, 55, 38, 39, -1, -8, -6, 10, 33, 53, + -6, 38, 39, 55, 11, 55, 36, 33, 10, -7, + 11, 11, -1, 55, 33, -1, -1, 55, 55, 55, +} +var yyDef = []int{ + + 1, -2, 0, 3, 0, 6, 0, 0, 0, 30, + 0, 0, 0, 0, 0, 17, 18, 0, 30, 0, + 0, 0, 0, 0, 59, 27, 0, 0, 0, 0, + 0, 4, 0, 7, 8, 0, 11, 31, 12, 0, + 37, 63, 64, 75, 76, 77, 78, 79, 80, 81, + 89, 90, 91, 0, 102, 112, 113, 0, 0, 0, + 106, 13, 35, 71, 72, 0, 14, 0, 15, 0, + 16, 0, 39, 0, 0, 106, 0, 19, 0, 47, + 65, 66, 0, 69, 70, 91, 106, 20, 48, 49, + 31, 21, 0, 22, 0, 23, 55, 24, 0, 25, + 0, 26, 60, 28, 0, 29, 0, 0, 0, 0, + 0, 9, 122, 10, 36, 0, 0, 0, 0, 0, + 114, 115, 116, 0, 0, 0, 0, 34, 82, 83, + 84, 85, 0, 0, 0, 0, 38, 0, 0, 74, + 46, 67, 68, 0, 74, 0, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 0, 99, 117, 0, 0, 106, 107, 108, 0, 0, + 88, 32, 33, 40, 0, 50, 52, 56, 0, 0, + 61, 62, 0, 0, 0, 44, 0, 123, 124, 125, + 126, 127, 0, 0, 130, 131, 132, 92, 0, 93, + 94, 0, 0, 0, 0, 109, 110, 111, 0, 86, + 0, 73, 0, 0, 0, 0, 0, 42, 118, 0, + 0, 0, 128, 129, 0, 0, 0, 100, 0, 104, + 0, 87, 51, 53, 57, 58, 41, 0, 119, 0, + 45, 0, 0, 95, 0, 103, 0, 120, 0, 43, + 0, 0, 0, 105, 121, 0, 0, 101, 96, 97, +} +var yyTok1 = []int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 53, 13, 6, 3, + 54, 55, 11, 9, 52, 10, 3, 12, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 49, 50, + 7, 51, 8, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 3, 56, +} +var yyTok2 = []int{ + + 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, +} +var yyTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yylex1(lex yyLexer, lval *yySymType) int { + c := 0 + char := lex.Lex(lval) + if char <= 0 { + c = yyTok1[0] + goto out + } + if char < len(yyTok1) { + c = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + c = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + c = yyTok3[i+0] + if c == char { + c = yyTok3[i+1] + goto out + } + } + +out: + if c == 0 { + c = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) + } + return c +} + +func yyParse(yylex yyLexer) int { + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, yyMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yychar := -1 + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + yyn += yychar + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yychar { /* valid shift */ + yychar = -1 + yyVAL = yylval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yychar { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error("syntax error") + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) + } + if yychar == yyEofCode { + goto ret1 + } + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 2: + //line a.y:72 + { + stmtline = asm.Lineno + } + case 4: + //line a.y:79 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { + yyerror("redeclaration of %s (%s)", yyS[yypt-1].sym.Labelname, yyS[yypt-1].sym.Name) + } + yyS[yypt-1].sym.Type = LLAB + yyS[yypt-1].sym.Value = int64(asm.PC) + } + case 9: + //line a.y:94 + { + yyS[yypt-2].sym.Type = LVAR + yyS[yypt-2].sym.Value = yyS[yypt-0].lval + } + case 10: + //line a.y:99 + { + if yyS[yypt-2].sym.Value != yyS[yypt-0].lval { + yyerror("redeclaration of %s", yyS[yypt-2].sym.Name) + } + yyS[yypt-2].sym.Value = yyS[yypt-0].lval + } + case 11: + //line a.y:105 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 12: + //line a.y:106 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 13: + //line a.y:107 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 14: + //line a.y:108 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 15: + //line a.y:109 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 16: + //line a.y:110 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 19: + //line a.y:113 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 20: + //line a.y:114 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 21: + //line a.y:115 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 22: + //line a.y:116 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 23: + //line a.y:117 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 24: + //line a.y:118 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 25: + //line a.y:119 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 26: + //line a.y:120 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 28: + //line a.y:122 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 29: + //line a.y:123 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 30: + //line a.y:126 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = nullgen + } + case 31: + //line a.y:131 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = nullgen + } + case 32: + //line a.y:138 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 33: + //line a.y:145 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 34: + //line a.y:152 + { + yyVAL.addr2.from = yyS[yypt-1].addr + yyVAL.addr2.to = nullgen + } + case 35: + //line a.y:157 + { + yyVAL.addr2.from = yyS[yypt-0].addr + yyVAL.addr2.to = nullgen + } + case 36: + //line a.y:164 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 37: + //line a.y:169 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 38: + //line a.y:176 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 39: + //line a.y:181 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 40: + //line a.y:186 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 41: + //line a.y:193 + { + var a Addr2 + a.from = yyS[yypt-4].addr + a.to = yyS[yypt-0].addr + outcode(obj.ADATA, &a) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-2].lval + } + } + case 42: + //line a.y:206 + { + asm.Settext(yyS[yypt-3].addr.Sym) + outcode(obj.ATEXT, &Addr2{yyS[yypt-3].addr, yyS[yypt-0].addr}) + } + case 43: + //line a.y:211 + { + asm.Settext(yyS[yypt-5].addr.Sym) + outcode(obj.ATEXT, &Addr2{yyS[yypt-5].addr, yyS[yypt-0].addr}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-3].lval + } + } + case 44: + //line a.y:222 + { + asm.Settext(yyS[yypt-2].addr.Sym) + outcode(obj.AGLOBL, &Addr2{yyS[yypt-2].addr, yyS[yypt-0].addr}) + } + case 45: + //line a.y:227 + { + asm.Settext(yyS[yypt-4].addr.Sym) + outcode(obj.AGLOBL, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-2].lval + } + } + case 46: + //line a.y:238 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 47: + //line a.y:243 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 48: + yyVAL.addr2 = yyS[yypt-0].addr2 + case 49: + yyVAL.addr2 = yyS[yypt-0].addr2 + case 50: + //line a.y:254 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 51: + //line a.y:259 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + if yyVAL.addr2.from.Index != obj.TYPE_NONE { + yyerror("dp shift with lhs index") + } + yyVAL.addr2.from.Index = int16(yyS[yypt-0].lval) + } + case 52: + //line a.y:270 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 53: + //line a.y:275 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + if yyVAL.addr2.to.Index != obj.TYPE_NONE { + yyerror("dp move with lhs index") + } + yyVAL.addr2.to.Index = int16(yyS[yypt-0].lval) + } + case 54: + //line a.y:286 + { + yyVAL.addr2.from = yyS[yypt-1].addr + yyVAL.addr2.to = nullgen + } + case 55: + //line a.y:291 + { + yyVAL.addr2.from = yyS[yypt-0].addr + yyVAL.addr2.to = nullgen + } + case 56: + //line a.y:296 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 57: + //line a.y:303 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + yyVAL.addr2.to.Offset = yyS[yypt-0].lval + } + case 58: + //line a.y:311 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + if yyS[yypt-4].addr.Type != obj.TYPE_CONST { + yyerror("illegal constant") + } + yyVAL.addr2.to.Offset = yyS[yypt-4].addr.Offset + } + case 59: + //line a.y:321 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = nullgen + } + case 60: + //line a.y:326 + { + yyVAL.addr2.from = yyS[yypt-0].addr + yyVAL.addr2.to = nullgen + } + case 61: + //line a.y:333 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { + yyerror("arguments to asm.PCDATA must be integer constants") + } + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 62: + //line a.y:343 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if yyS[yypt-0].addr.Type != obj.TYPE_MEM || (yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC) { + yyerror("value for FUNCDATA must be symbol reference") + } + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 63: + yyVAL.addr = yyS[yypt-0].addr + case 64: + yyVAL.addr = yyS[yypt-0].addr + case 65: + yyVAL.addr = yyS[yypt-0].addr + case 66: + yyVAL.addr = yyS[yypt-0].addr + case 67: + //line a.y:362 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 68: + //line a.y:366 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 69: + yyVAL.addr = yyS[yypt-0].addr + case 70: + yyVAL.addr = yyS[yypt-0].addr + case 71: + yyVAL.addr = yyS[yypt-0].addr + case 72: + yyVAL.addr = yyS[yypt-0].addr + case 73: + //line a.y:378 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyS[yypt-3].lval + int64(asm.PC) + } + case 74: + //line a.y:384 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + yyVAL.addr = nullgen + if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { + yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) + } + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyS[yypt-1].sym.Value + yyS[yypt-0].lval + } + case 75: + //line a.y:396 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 76: + //line a.y:402 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 77: + //line a.y:408 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 78: + //line a.y:414 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 79: + //line a.y:420 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = x86.REG_SP + } + case 80: + //line a.y:426 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 81: + //line a.y:432 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 82: + //line a.y:440 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + yyVAL.addr.Offset = yyS[yypt-0].lval + } + case 83: + //line a.y:446 + { + yyVAL.addr = yyS[yypt-0].addr + yyVAL.addr.Type = obj.TYPE_ADDR + /* + if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM) + yyerror("constant cannot be automatic: %s", + $2.sym.Name); + */ + } + case 84: + //line a.y:455 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SCONST + yyVAL.addr.U.Sval = (yyS[yypt-0].sval + "\x00\x00\x00\x00\x00\x00\x00\x00")[:8] + } + case 85: + //line a.y:461 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyS[yypt-0].dval + } + case 86: + //line a.y:467 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyS[yypt-1].dval + } + case 87: + //line a.y:473 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyS[yypt-1].dval + } + case 88: + //line a.y:479 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyS[yypt-0].dval + } + case 89: + yyVAL.addr = yyS[yypt-0].addr + case 90: + yyVAL.addr = yyS[yypt-0].addr + case 91: + //line a.y:491 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Offset = yyS[yypt-0].lval + } + case 92: + //line a.y:497 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 93: + //line a.y:504 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = x86.REG_SP + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 94: + //line a.y:511 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 95: + //line a.y:518 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Offset = yyS[yypt-5].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 96: + //line a.y:527 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Offset = yyS[yypt-8].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 97: + //line a.y:537 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Offset = yyS[yypt-8].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 98: + //line a.y:547 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + } + case 99: + //line a.y:553 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = x86.REG_SP + } + case 100: + //line a.y:559 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 101: + //line a.y:567 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 102: + //line a.y:578 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 103: + //line a.y:582 + { + yyVAL.addr = yyS[yypt-5].addr + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 104: + //line a.y:591 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyS[yypt-1].lval) + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 105: + //line a.y:599 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = obj.NAME_STATIC + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 106: + //line a.y:608 + { + yyVAL.lval = 0 + } + case 107: + //line a.y:612 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 108: + //line a.y:616 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 109: + yyVAL.lval = yyS[yypt-0].lval + case 110: + //line a.y:623 + { + yyVAL.lval = obj.NAME_AUTO + } + case 111: + yyVAL.lval = yyS[yypt-0].lval + case 112: + yyVAL.lval = yyS[yypt-0].lval + case 113: + //line a.y:631 + { + yyVAL.lval = yyS[yypt-0].sym.Value + } + case 114: + //line a.y:635 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 115: + //line a.y:639 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 116: + //line a.y:643 + { + yyVAL.lval = ^yyS[yypt-0].lval + } + case 117: + //line a.y:647 + { + yyVAL.lval = yyS[yypt-1].lval + } + case 118: + //line a.y:653 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = yyS[yypt-0].lval + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 119: + //line a.y:660 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -yyS[yypt-0].lval + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 120: + //line a.y:667 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = yyS[yypt-2].lval + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 121: + //line a.y:674 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -yyS[yypt-2].lval + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 122: + yyVAL.lval = yyS[yypt-0].lval + case 123: + //line a.y:684 + { + yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval + } + case 124: + //line a.y:688 + { + yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval + } + case 125: + //line a.y:692 + { + yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval + } + case 126: + //line a.y:696 + { + yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval + } + case 127: + //line a.y:700 + { + yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval + } + case 128: + //line a.y:704 + { + yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) + } + case 129: + //line a.y:708 + { + yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) + } + case 130: + //line a.y:712 + { + yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval + } + case 131: + //line a.y:716 + { + yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval + } + case 132: + //line a.y:720 + { + yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval + } + } + goto yystack /* stack new state and value */ +} diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c deleted file mode 100644 index a3ee581d69..0000000000 --- a/src/cmd/6a/y.tab.c +++ /dev/null @@ -1,2800 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.3" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE0 = 258, - LTYPE1 = 259, - LTYPE2 = 260, - LTYPE3 = 261, - LTYPE4 = 262, - LTYPEC = 263, - LTYPED = 264, - LTYPEN = 265, - LTYPER = 266, - LTYPET = 267, - LTYPEG = 268, - LTYPEPC = 269, - LTYPES = 270, - LTYPEM = 271, - LTYPEI = 272, - LTYPEXC = 273, - LTYPEX = 274, - LTYPERT = 275, - LTYPEF = 276, - LCONST = 277, - LFP = 278, - LPC = 279, - LSB = 280, - LBREG = 281, - LLREG = 282, - LSREG = 283, - LFREG = 284, - LMREG = 285, - LXREG = 286, - LFCONST = 287, - LSCONST = 288, - LSP = 289, - LNAME = 290, - LLAB = 291, - LVAR = 292 - }; -#endif -/* Tokens. */ -#define LTYPE0 258 -#define LTYPE1 259 -#define LTYPE2 260 -#define LTYPE3 261 -#define LTYPE4 262 -#define LTYPEC 263 -#define LTYPED 264 -#define LTYPEN 265 -#define LTYPER 266 -#define LTYPET 267 -#define LTYPEG 268 -#define LTYPEPC 269 -#define LTYPES 270 -#define LTYPEM 271 -#define LTYPEI 272 -#define LTYPEXC 273 -#define LTYPEX 274 -#define LTYPERT 275 -#define LTYPEF 276 -#define LCONST 277 -#define LFP 278 -#define LPC 279 -#define LSB 280 -#define LBREG 281 -#define LLREG 282 -#define LSREG 283 -#define LFREG 284 -#define LMREG 285 -#define LXREG 286 -#define LFCONST 287 -#define LSCONST 288 -#define LSP 289 -#define LNAME 290 -#define LLAB 291 -#define LVAR 292 - - - - -/* Copy the first part of user declarations. */ -#line 31 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; -} -/* Line 193 of yacc.c. */ -#line 187 "y.tab.c" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 216 of yacc.c. */ -#line 200 "y.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int i) -#else -static int -YYID (i) - int i; -#endif -{ - return i; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 2 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 524 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 56 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 40 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 133 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 271 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 292 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 52, 12, 5, 2, - 53, 54, 10, 8, 51, 9, 2, 11, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, - 6, 50, 7, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 55, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 4, 5, 9, 10, 15, 17, 20, - 23, 27, 31, 34, 37, 40, 43, 46, 49, 51, - 53, 56, 59, 62, 65, 68, 71, 74, 77, 79, - 82, 85, 86, 88, 92, 96, 99, 101, 104, 106, - 109, 111, 115, 122, 128, 136, 141, 148, 151, 153, - 155, 157, 161, 167, 171, 177, 180, 182, 186, 192, - 198, 199, 201, 205, 209, 211, 213, 215, 217, 220, - 223, 225, 227, 229, 231, 236, 239, 241, 243, 245, - 247, 249, 251, 253, 256, 259, 262, 265, 270, 276, - 280, 282, 284, 286, 291, 296, 301, 308, 318, 328, - 332, 336, 342, 351, 353, 360, 366, 374, 375, 378, - 381, 383, 385, 387, 389, 391, 394, 397, 400, 404, - 406, 409, 413, 418, 420, 424, 428, 432, 436, 440, - 445, 450, 454, 458 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 57, 0, -1, -1, -1, 57, 58, 59, -1, -1, - 45, 48, 60, 59, -1, 49, -1, 61, 49, -1, - 1, 49, -1, 45, 50, 95, -1, 47, 50, 95, - -1, 13, 62, -1, 14, 66, -1, 15, 65, -1, - 16, 63, -1, 17, 64, -1, 21, 67, -1, 68, - -1, 69, -1, 18, 71, -1, 20, 72, -1, 25, - 73, -1, 26, 74, -1, 27, 75, -1, 28, 76, - -1, 29, 77, -1, 30, 78, -1, 70, -1, 24, - 79, -1, 31, 80, -1, -1, 51, -1, 83, 51, - 81, -1, 81, 51, 83, -1, 83, 51, -1, 83, - -1, 51, 81, -1, 81, -1, 51, 84, -1, 84, - -1, 86, 51, 84, -1, 19, 90, 11, 93, 51, - 86, -1, 22, 87, 51, 52, 94, -1, 22, 87, - 51, 93, 51, 52, 94, -1, 23, 87, 51, 86, - -1, 23, 87, 51, 93, 51, 86, -1, 51, 82, - -1, 82, -1, 62, -1, 66, -1, 83, 51, 81, - -1, 83, 51, 81, 48, 37, -1, 83, 51, 81, - -1, 83, 51, 81, 48, 38, -1, 83, 51, -1, - 83, -1, 83, 51, 81, -1, 85, 51, 81, 51, - 93, -1, 86, 51, 81, 51, 85, -1, -1, 86, - -1, 83, 51, 83, -1, 83, 51, 83, -1, 85, - -1, 87, -1, 84, -1, 89, -1, 10, 85, -1, - 10, 88, -1, 85, -1, 88, -1, 81, -1, 86, - -1, 93, 53, 34, 54, -1, 45, 91, -1, 36, - -1, 39, -1, 37, -1, 40, -1, 44, -1, 38, - -1, 41, -1, 52, 93, -1, 52, 90, -1, 52, - 43, -1, 52, 42, -1, 52, 53, 42, 54, -1, - 52, 53, 9, 42, 54, -1, 52, 9, 42, -1, - 88, -1, 89, -1, 93, -1, 93, 53, 37, 54, - -1, 93, 53, 44, 54, -1, 93, 53, 38, 54, - -1, 93, 53, 37, 10, 93, 54, -1, 93, 53, - 37, 54, 53, 37, 10, 93, 54, -1, 93, 53, - 37, 54, 53, 38, 10, 93, 54, -1, 53, 37, - 54, -1, 53, 44, 54, -1, 53, 37, 10, 93, - 54, -1, 53, 37, 54, 53, 37, 10, 93, 54, - -1, 90, -1, 90, 53, 37, 10, 93, 54, -1, - 45, 91, 53, 92, 54, -1, 45, 6, 7, 91, - 53, 35, 54, -1, -1, 8, 93, -1, 9, 93, - -1, 35, -1, 44, -1, 33, -1, 32, -1, 47, - -1, 9, 93, -1, 8, 93, -1, 55, 93, -1, - 53, 95, 54, -1, 32, -1, 9, 32, -1, 32, - 9, 32, -1, 9, 32, 9, 32, -1, 93, -1, - 95, 8, 95, -1, 95, 9, 95, -1, 95, 10, - 95, -1, 95, 11, 95, -1, 95, 12, 95, -1, - 95, 6, 6, 95, -1, 95, 7, 7, 95, -1, - 95, 5, 95, -1, 95, 4, 95, -1, 95, 3, - 95, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 66, 66, 68, 67, 75, 74, 83, 84, 85, - 88, 93, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 120, 124, 131, 138, 145, 150, 157, 162, 169, - 174, 179, 186, 199, 207, 221, 229, 243, 248, 255, - 256, 259, 264, 274, 279, 289, 294, 299, 306, 314, - 324, 328, 335, 344, 355, 356, 359, 360, 361, 365, - 369, 370, 373, 374, 377, 383, 394, 400, 406, 412, - 418, 424, 430, 438, 444, 454, 460, 466, 472, 478, - 486, 487, 490, 496, 503, 510, 517, 526, 536, 546, - 552, 558, 566, 577, 581, 590, 598, 608, 611, 615, - 621, 622, 626, 629, 630, 634, 638, 642, 646, 652, - 659, 666, 673, 682, 683, 687, 691, 695, 699, 703, - 707, 711, 715, 719 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'", - "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3", - "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPEG", - "LTYPEPC", "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT", - "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", - "LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", - "LVAR", "':'", "';'", "'='", "','", "'$'", "'('", "')'", "'~'", - "$accept", "prog", "@1", "line", "@2", "inst", "nonnon", "rimrem", - "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec11", - "spec3", "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", - "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm", "mem", - "omem", "nmem", "nam", "offset", "pointer", "con", "textsize", "expr", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 124, 94, 38, 60, 62, 43, 45, - 42, 47, 37, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 58, 59, - 61, 44, 36, 40, 41, 126 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 56, 57, 58, 57, 60, 59, 59, 59, 59, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 62, 62, 63, 64, 65, 65, 66, 66, 67, - 67, 67, 68, 69, 69, 70, 70, 71, 71, 72, - 72, 73, 73, 74, 74, 75, 75, 75, 76, 77, - 78, 78, 79, 80, 81, 81, 82, 82, 82, 82, - 82, 82, 83, 83, 84, 84, 85, 85, 85, 85, - 85, 85, 85, 86, 86, 86, 86, 86, 86, 86, - 87, 87, 88, 88, 88, 88, 88, 88, 88, 88, - 88, 88, 88, 89, 89, 90, 90, 91, 91, 91, - 92, 92, 92, 93, 93, 93, 93, 93, 93, 94, - 94, 94, 94, 95, 95, 95, 95, 95, 95, 95, - 95, 95, 95, 95 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 0, 0, 3, 0, 4, 1, 2, 2, - 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, - 2, 0, 1, 3, 3, 2, 1, 2, 1, 2, - 1, 3, 6, 5, 7, 4, 6, 2, 1, 1, - 1, 3, 5, 3, 5, 2, 1, 3, 5, 5, - 0, 1, 3, 3, 1, 1, 1, 1, 2, 2, - 1, 1, 1, 1, 4, 2, 1, 1, 1, 1, - 1, 1, 1, 2, 2, 2, 2, 4, 5, 3, - 1, 1, 1, 4, 4, 4, 6, 9, 9, 3, - 3, 5, 8, 1, 6, 5, 7, 0, 2, 2, - 1, 1, 1, 1, 1, 2, 2, 2, 3, 1, - 2, 3, 4, 1, 3, 3, 3, 3, 3, 4, - 4, 3, 3, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 2, 3, 1, 0, 0, 31, 0, 0, 0, 0, - 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 60, 0, 0, 0, 7, 4, 0, 18, - 19, 28, 9, 32, 12, 0, 0, 113, 76, 78, - 81, 77, 79, 82, 80, 107, 114, 0, 0, 0, - 13, 38, 64, 65, 90, 91, 103, 92, 0, 14, - 72, 36, 73, 15, 0, 16, 0, 0, 107, 0, - 20, 48, 66, 70, 71, 67, 92, 0, 32, 49, - 50, 21, 107, 0, 0, 17, 40, 0, 0, 0, - 0, 29, 0, 22, 0, 23, 0, 24, 56, 25, - 0, 26, 0, 27, 61, 30, 0, 5, 0, 0, - 8, 116, 115, 0, 0, 0, 0, 37, 0, 0, - 123, 0, 117, 0, 0, 0, 86, 85, 0, 84, - 83, 35, 0, 0, 68, 69, 75, 47, 0, 0, - 75, 39, 0, 0, 0, 0, 0, 0, 0, 55, - 0, 0, 0, 0, 10, 11, 107, 108, 109, 0, - 0, 99, 100, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 118, 0, 0, 0, 0, 89, 0, - 0, 33, 34, 0, 0, 41, 0, 0, 45, 0, - 62, 51, 53, 57, 0, 0, 63, 6, 0, 112, - 110, 111, 0, 0, 0, 133, 132, 131, 0, 0, - 124, 125, 126, 127, 128, 0, 0, 93, 95, 94, - 0, 87, 74, 0, 0, 119, 43, 0, 0, 0, - 0, 0, 0, 0, 105, 101, 0, 129, 130, 0, - 0, 0, 88, 42, 120, 0, 0, 46, 52, 54, - 58, 59, 0, 0, 104, 96, 0, 0, 0, 121, - 44, 106, 0, 0, 0, 122, 102, 0, 0, 97, - 98 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 3, 27, 153, 28, 34, 63, 65, 59, - 50, 85, 29, 30, 31, 70, 81, 93, 95, 97, - 99, 101, 103, 91, 105, 60, 71, 61, 72, 52, - 62, 53, 54, 55, 56, 116, 202, 57, 226, 121 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -87 -static const yytype_int16 yypact[] = -{ - -87, 24, -87, 211, 20, -5, 236, 256, 256, 330, - 156, 25, 290, 55, 364, 364, 256, 256, 256, 256, - 145, 29, 29, 256, 17, 46, -87, -87, 26, -87, - -87, -87, -87, -87, -87, 451, 451, -87, -87, -87, - -87, -87, -87, -87, -87, 27, -87, 330, 270, 451, - -87, -87, -87, -87, -87, -87, 39, 44, 48, -87, - -87, 65, -87, -87, 66, -87, 68, 350, 27, 310, - -87, -87, -87, -87, -87, -87, 71, 110, 330, -87, - -87, -87, 23, 384, 451, -87, -87, 75, 72, 77, - 82, -87, 85, -87, 87, -87, 88, -87, 89, -87, - 90, -87, 91, -87, -87, -87, 92, -87, 451, 451, - -87, -87, -87, 120, 451, 451, 98, -87, 7, 113, - -87, 168, -87, 115, 5, 391, -87, -87, 398, -87, - -87, -87, 330, 256, -87, -87, 98, -87, 3, 451, - -87, -87, 384, 122, 416, 426, 256, 330, 330, 330, - 330, 330, 256, 211, 504, 504, 23, -87, -87, 76, - 451, 117, -87, 451, 451, 451, 162, 180, 451, 451, - 451, 451, 451, -87, 181, 8, 136, 148, -87, 433, - 150, -87, -87, 154, 159, -87, 12, 163, -87, 165, - -87, 169, 170, -87, 204, 206, -87, -87, 160, -87, - -87, -87, 205, 207, 182, 485, 512, 240, 451, 451, - 102, 102, -87, -87, -87, 451, 451, 209, -87, -87, - 212, -87, -87, 29, 231, 258, -87, 217, 29, 233, - 244, 451, 145, 249, -87, -87, 261, 42, 42, 232, - 250, -22, -87, -87, 276, 273, 12, -87, -87, -87, - -87, -87, 252, 451, -87, -87, 280, 300, 281, -87, - -87, -87, 262, 451, 451, -87, -87, 267, 278, -87, - -87 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -87, -87, -87, 171, -87, -87, 303, -87, -87, -87, - 321, -87, -87, -87, -87, -87, -87, -87, -87, -87, - -87, -87, -87, -87, -87, -2, 243, 11, -11, -9, - -8, 74, -1, 2, -3, -62, -87, -10, 94, -86 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 -static const yytype_uint16 yytable[] = -{ - 76, 73, 86, 88, 51, 87, 136, 66, 77, 74, - 51, 100, 75, 102, 104, 256, 257, 160, 216, 64, - 140, 224, 154, 155, 2, 111, 112, 92, 94, 96, - 98, 114, 115, 113, 106, 114, 115, 183, 120, 122, - 175, 176, 175, 176, 225, 117, 33, 177, 130, 177, - 168, 169, 170, 171, 172, 129, 35, 125, 134, 76, - 73, 161, 217, 35, 36, 107, 135, 108, 74, 32, - 45, 75, 141, 88, 120, 110, 117, 205, 206, 207, - 37, 58, 210, 211, 212, 213, 214, 37, 89, 90, - 126, 127, 123, 45, 198, 46, 109, 124, 120, 120, - 82, 128, 46, 49, 157, 158, 83, 58, 84, 199, - 49, 200, 170, 171, 172, 112, 131, 132, 120, 133, - 201, 139, 237, 238, 138, 143, 142, 156, 144, 184, - 181, 185, 88, 145, 187, 189, 146, 188, 147, 148, - 149, 150, 151, 152, 182, 191, 192, 193, 194, 195, - 203, 159, 174, 120, 120, 120, 183, 190, 120, 120, - 120, 120, 120, 196, 35, 36, 67, 162, 208, 112, - 204, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 38, 39, 40, 41, 42, 43, 209, 37, 44, - 218, 215, 38, 39, 40, 41, 42, 43, 120, 120, - 44, 68, 219, 46, 221, 239, 240, 69, 222, 48, - 223, 49, 4, 233, 227, 243, 228, 229, 230, 236, - 247, 250, 173, 251, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 262, 35, 36, 166, 167, 168, 169, - 170, 171, 172, 267, 268, 231, 24, 232, 25, 234, - 26, 235, 241, 244, 35, 36, 242, 245, 37, 246, - 248, 253, 38, 39, 40, 41, 42, 43, 35, 36, - 44, 45, 249, 46, 252, 258, 254, 47, 37, 48, - 263, 49, 38, 39, 40, 41, 42, 43, 35, 36, - 44, 45, 37, 46, 255, 259, 261, 118, 58, 48, - 264, 49, 137, 265, 119, 79, 266, 46, 35, 36, - 67, 269, 37, 84, 197, 49, 38, 39, 40, 41, - 42, 43, 270, 80, 44, 45, 0, 46, 35, 36, - 260, 78, 37, 48, 0, 49, 38, 39, 40, 41, - 42, 43, 0, 0, 44, 68, 0, 46, 35, 36, - 0, 0, 37, 48, 0, 49, 38, 39, 40, 41, - 42, 43, 35, 36, 44, 45, 0, 46, 0, 0, - 0, 0, 37, 48, 0, 49, 38, 39, 40, 41, - 42, 43, 35, 36, 44, 0, 37, 46, 0, 35, - 36, 0, 0, 48, 0, 49, 35, 179, 0, 45, - 0, 46, 0, 0, 0, 0, 37, 48, 0, 49, - 0, 0, 0, 37, 35, 36, 0, 0, 0, 82, - 37, 46, 0, 178, 35, 36, 0, 84, 46, 49, - 180, 35, 36, 0, 84, 46, 49, 0, 37, 0, - 0, 84, 0, 49, 0, 0, 0, 0, 37, 35, - 36, 0, 0, 46, 0, 37, 0, 0, 186, 84, - 0, 49, 0, 46, 0, 220, 0, 0, 58, 84, - 46, 49, 0, 37, 0, 0, 84, 0, 49, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 46, 0, - 0, 0, 0, 0, 84, 0, 49, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 165, 166, 167, - 168, 169, 170, 171, 172 -}; - -static const yytype_int16 yycheck[] = -{ - 10, 10, 13, 13, 6, 13, 68, 9, 11, 10, - 12, 20, 10, 21, 22, 37, 38, 10, 10, 8, - 82, 9, 108, 109, 0, 35, 36, 16, 17, 18, - 19, 8, 9, 6, 23, 8, 9, 34, 48, 49, - 37, 38, 37, 38, 32, 47, 51, 44, 58, 44, - 8, 9, 10, 11, 12, 58, 8, 9, 67, 69, - 69, 54, 54, 8, 9, 48, 67, 50, 69, 49, - 45, 69, 83, 83, 84, 49, 78, 163, 164, 165, - 32, 52, 168, 169, 170, 171, 172, 32, 14, 15, - 42, 43, 53, 45, 156, 47, 50, 53, 108, 109, - 45, 53, 47, 55, 114, 115, 51, 52, 53, 33, - 55, 35, 10, 11, 12, 125, 51, 51, 128, 51, - 44, 11, 208, 209, 53, 53, 51, 7, 51, 139, - 132, 142, 142, 51, 144, 145, 51, 145, 51, 51, - 51, 51, 51, 51, 133, 147, 148, 149, 150, 151, - 160, 53, 37, 163, 164, 165, 34, 146, 168, 169, - 170, 171, 172, 152, 8, 9, 10, 54, 6, 179, - 53, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 36, 37, 38, 39, 40, 41, 7, 32, 44, - 54, 10, 36, 37, 38, 39, 40, 41, 208, 209, - 44, 45, 54, 47, 54, 215, 216, 51, 54, 53, - 51, 55, 1, 53, 51, 223, 51, 48, 48, 37, - 228, 231, 54, 232, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 253, 8, 9, 6, 7, 8, 9, - 10, 11, 12, 263, 264, 51, 45, 51, 47, 54, - 49, 54, 53, 32, 8, 9, 54, 9, 32, 52, - 37, 10, 36, 37, 38, 39, 40, 41, 8, 9, - 44, 45, 38, 47, 35, 9, 54, 51, 32, 53, - 10, 55, 36, 37, 38, 39, 40, 41, 8, 9, - 44, 45, 32, 47, 54, 32, 54, 37, 52, 53, - 10, 55, 69, 32, 44, 12, 54, 47, 8, 9, - 10, 54, 32, 53, 153, 55, 36, 37, 38, 39, - 40, 41, 54, 12, 44, 45, -1, 47, 8, 9, - 246, 51, 32, 53, -1, 55, 36, 37, 38, 39, - 40, 41, -1, -1, 44, 45, -1, 47, 8, 9, - -1, -1, 32, 53, -1, 55, 36, 37, 38, 39, - 40, 41, 8, 9, 44, 45, -1, 47, -1, -1, - -1, -1, 32, 53, -1, 55, 36, 37, 38, 39, - 40, 41, 8, 9, 44, -1, 32, 47, -1, 8, - 9, -1, -1, 53, -1, 55, 8, 9, -1, 45, - -1, 47, -1, -1, -1, -1, 32, 53, -1, 55, - -1, -1, -1, 32, 8, 9, -1, -1, -1, 45, - 32, 47, -1, 42, 8, 9, -1, 53, 47, 55, - 42, 8, 9, -1, 53, 47, 55, -1, 32, -1, - -1, 53, -1, 55, -1, -1, -1, -1, 32, 8, - 9, -1, -1, 47, -1, 32, -1, -1, 52, 53, - -1, 55, -1, 47, -1, 42, -1, -1, 52, 53, - 47, 55, -1, 32, -1, -1, 53, -1, 55, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 47, -1, - -1, -1, -1, -1, 53, -1, 55, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, - 8, 9, 10, 11, 12 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 57, 0, 58, 1, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 45, 47, 49, 59, 61, 68, - 69, 70, 49, 51, 62, 8, 9, 32, 36, 37, - 38, 39, 40, 41, 44, 45, 47, 51, 53, 55, - 66, 81, 85, 87, 88, 89, 90, 93, 52, 65, - 81, 83, 86, 63, 83, 64, 81, 10, 45, 51, - 71, 82, 84, 85, 88, 89, 93, 90, 51, 62, - 66, 72, 45, 51, 53, 67, 84, 86, 93, 87, - 87, 79, 83, 73, 83, 74, 83, 75, 83, 76, - 85, 77, 86, 78, 86, 80, 83, 48, 50, 50, - 49, 93, 93, 6, 8, 9, 91, 81, 37, 44, - 93, 95, 93, 53, 53, 9, 42, 43, 53, 90, - 93, 51, 51, 51, 85, 88, 91, 82, 53, 11, - 91, 84, 51, 53, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 60, 95, 95, 7, 93, 93, 53, - 10, 54, 54, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 54, 37, 37, 38, 44, 42, 9, - 42, 81, 83, 34, 93, 84, 52, 93, 86, 93, - 83, 81, 81, 81, 81, 81, 83, 59, 91, 33, - 35, 44, 92, 93, 53, 95, 95, 95, 6, 7, - 95, 95, 95, 95, 95, 10, 10, 54, 54, 54, - 42, 54, 54, 51, 9, 32, 94, 51, 51, 48, - 48, 51, 51, 53, 54, 54, 37, 95, 95, 93, - 93, 53, 54, 86, 32, 9, 52, 86, 37, 38, - 93, 85, 35, 10, 54, 54, 37, 38, 9, 32, - 94, 54, 93, 10, 10, 32, 54, 93, 93, 54, - 54 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) -#else -static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - fprintf (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - fprintf (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The look-ahead symbol. */ -int yychar; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to look-ahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a look-ahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the look-ahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: -#line 68 "a.y" - { - stmtline = lineno; - } - break; - - case 5: -#line 75 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc) - yyerror("redeclaration of %s (%s)", (yyvsp[(1) - (2)].sym)->labelname, (yyvsp[(1) - (2)].sym)->name); - (yyvsp[(1) - (2)].sym)->type = LLAB; - (yyvsp[(1) - (2)].sym)->value = pc; - } - break; - - case 10: -#line 89 "a.y" - { - (yyvsp[(1) - (3)].sym)->type = LVAR; - (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval); - } - break; - - case 11: -#line 94 "a.y" - { - if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval)) - yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name); - (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval); - } - break; - - case 12: -#line 99 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 13: -#line 100 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 14: -#line 101 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 15: -#line 102 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 16: -#line 103 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 17: -#line 104 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 20: -#line 107 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 21: -#line 108 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 22: -#line 109 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 23: -#line 110 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 24: -#line 111 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 25: -#line 112 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 26: -#line 113 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 27: -#line 114 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 29: -#line 116 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 30: -#line 117 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 31: -#line 120 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = nullgen; - } - break; - - case 32: -#line 125 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = nullgen; - } - break; - - case 33: -#line 132 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 34: -#line 139 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 35: -#line 146 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (2)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 36: -#line 151 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (1)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 37: -#line 158 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 38: -#line 163 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 39: -#line 170 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 40: -#line 175 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 41: -#line 180 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 42: -#line 187 "a.y" - { - Addr2 a; - a.from = (yyvsp[(2) - (6)].addr); - a.to = (yyvsp[(6) - (6)].addr); - outcode(ADATA, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 43: -#line 200 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (5)].addr).sym); - a.from = (yyvsp[(2) - (5)].addr); - a.to = (yyvsp[(5) - (5)].addr); - outcode(ATEXT, &a); - } - break; - - case 44: -#line 208 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (7)].addr).sym); - a.from = (yyvsp[(2) - (7)].addr); - a.to = (yyvsp[(7) - (7)].addr); - outcode(ATEXT, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (7)].lval); - } - } - break; - - case 45: -#line 222 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (4)].addr).sym); - a.from = (yyvsp[(2) - (4)].addr); - a.to = (yyvsp[(4) - (4)].addr); - outcode(AGLOBL, &a); - } - break; - - case 46: -#line 230 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (6)].addr).sym); - a.from = (yyvsp[(2) - (6)].addr); - a.to = (yyvsp[(6) - (6)].addr); - outcode(AGLOBL, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 47: -#line 244 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 48: -#line 249 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 51: -#line 260 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 52: -#line 265 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - if((yyval.addr2).from.index != TYPE_NONE) - yyerror("dp shift with lhs index"); - (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval); - } - break; - - case 53: -#line 275 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 54: -#line 280 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - if((yyval.addr2).to.index != TYPE_NONE) - yyerror("dp move with lhs index"); - (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval); - } - break; - - case 55: -#line 290 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (2)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 56: -#line 295 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (1)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 57: -#line 300 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 58: -#line 307 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval); - } - break; - - case 59: -#line 315 "a.y" - { - (yyval.addr2).from = (yyvsp[(3) - (5)].addr); - (yyval.addr2).to = (yyvsp[(5) - (5)].addr); - if((yyvsp[(1) - (5)].addr).type != TYPE_CONST) - yyerror("illegal constant"); - (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset; - } - break; - - case 60: -#line 324 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = nullgen; - } - break; - - case 61: -#line 329 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (1)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 62: -#line 336 "a.y" - { - if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 63: -#line 345 "a.y" - { - if((yyvsp[(1) - (3)].addr).type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC)) - yyerror("value for FUNCDATA must be symbol reference"); - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 68: -#line 362 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - } - break; - - case 69: -#line 366 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - } - break; - - case 74: -#line 378 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; - } - break; - - case 75: -#line 384 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - (yyval.addr) = nullgen; - if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB) - yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); - } - break; - - case 76: -#line 395 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 77: -#line 401 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 78: -#line 407 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 79: -#line 413 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 80: -#line 419 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = REG_SP; - } - break; - - case 81: -#line 425 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 82: -#line 431 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 83: -#line 439 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - (yyval.addr).offset = (yyvsp[(2) - (2)].lval); - } - break; - - case 84: -#line 445 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - (yyval.addr).type = TYPE_ADDR; - /* - if($2.type == D_AUTO || $2.type == D_PARAM) - yyerror("constant cannot be automatic: %s", - $2.sym->name); - */ - } - break; - - case 85: -#line 455 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SCONST; - memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); - } - break; - - case 86: -#line 461 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); - } - break; - - case 87: -#line 467 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval); - } - break; - - case 88: -#line 473 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval); - } - break; - - case 89: -#line 479 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); - } - break; - - case 92: -#line 491 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - } - break; - - case 93: -#line 497 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 94: -#line 504 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_SP; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 95: -#line 511 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 96: -#line 518 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).offset = (yyvsp[(1) - (6)].lval); - (yyval.addr).index = (yyvsp[(3) - (6)].lval); - (yyval.addr).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 97: -#line 527 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (9)].lval); - (yyval.addr).offset = (yyvsp[(1) - (9)].lval); - (yyval.addr).index = (yyvsp[(6) - (9)].lval); - (yyval.addr).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 98: -#line 537 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (9)].lval); - (yyval.addr).offset = (yyvsp[(1) - (9)].lval); - (yyval.addr).index = (yyvsp[(6) - (9)].lval); - (yyval.addr).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 99: -#line 547 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (3)].lval); - } - break; - - case 100: -#line 553 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_SP; - } - break; - - case 101: -#line 559 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).index = (yyvsp[(2) - (5)].lval); - (yyval.addr).scale = (yyvsp[(4) - (5)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 102: -#line 567 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (8)].lval); - (yyval.addr).index = (yyvsp[(5) - (8)].lval); - (yyval.addr).scale = (yyvsp[(7) - (8)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 103: -#line 578 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (1)].addr); - } - break; - - case 104: -#line 582 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (6)].addr); - (yyval.addr).index = (yyvsp[(3) - (6)].lval); - (yyval.addr).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 105: -#line 591 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(4) - (5)].lval); - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); - (yyval.addr).offset = (yyvsp[(2) - (5)].lval); - } - break; - - case 106: -#line 599 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = NAME_STATIC; - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); - (yyval.addr).offset = (yyvsp[(4) - (7)].lval); - } - break; - - case 107: -#line 608 "a.y" - { - (yyval.lval) = 0; - } - break; - - case 108: -#line 612 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 109: -#line 616 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 111: -#line 623 "a.y" - { - (yyval.lval) = NAME_AUTO; - } - break; - - case 114: -#line 631 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; - } - break; - - case 115: -#line 635 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 116: -#line 639 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 117: -#line 643 "a.y" - { - (yyval.lval) = ~(yyvsp[(2) - (2)].lval); - } - break; - - case 118: -#line 647 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (3)].lval); - } - break; - - case 119: -#line 653 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 120: -#line 660 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (2)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 121: -#line 667 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (3)].lval); - (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval); - } - break; - - case 122: -#line 674 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (4)].lval); - (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval); - } - break; - - case 124: -#line 684 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); - } - break; - - case 125: -#line 688 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); - } - break; - - case 126: -#line 692 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); - } - break; - - case 127: -#line 696 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); - } - break; - - case 128: -#line 700 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); - } - break; - - case 129: -#line 704 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); - } - break; - - case 130: -#line 708 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); - } - break; - - case 131: -#line 712 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); - } - break; - - case 132: -#line 716 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); - } - break; - - case 133: -#line 720 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); - } - break; - - -/* Line 1267 of yacc.c. */ -#line 2587 "y.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse look-ahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse look-ahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h deleted file mode 100644 index e0eb5e12cf..0000000000 --- a/src/cmd/6a/y.tab.h +++ /dev/null @@ -1,139 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE0 = 258, - LTYPE1 = 259, - LTYPE2 = 260, - LTYPE3 = 261, - LTYPE4 = 262, - LTYPEC = 263, - LTYPED = 264, - LTYPEN = 265, - LTYPER = 266, - LTYPET = 267, - LTYPEG = 268, - LTYPEPC = 269, - LTYPES = 270, - LTYPEM = 271, - LTYPEI = 272, - LTYPEXC = 273, - LTYPEX = 274, - LTYPERT = 275, - LTYPEF = 276, - LCONST = 277, - LFP = 278, - LPC = 279, - LSB = 280, - LBREG = 281, - LLREG = 282, - LSREG = 283, - LFREG = 284, - LMREG = 285, - LXREG = 286, - LFCONST = 287, - LSCONST = 288, - LSP = 289, - LNAME = 290, - LLAB = 291, - LVAR = 292 - }; -#endif -/* Tokens. */ -#define LTYPE0 258 -#define LTYPE1 259 -#define LTYPE2 260 -#define LTYPE3 261 -#define LTYPE4 262 -#define LTYPEC 263 -#define LTYPED 264 -#define LTYPEN 265 -#define LTYPER 266 -#define LTYPET 267 -#define LTYPEG 268 -#define LTYPEPC 269 -#define LTYPES 270 -#define LTYPEM 271 -#define LTYPEI 272 -#define LTYPEXC 273 -#define LTYPEX 274 -#define LTYPERT 275 -#define LTYPEF 276 -#define LCONST 277 -#define LFP 278 -#define LPC 279 -#define LSB 280 -#define LBREG 281 -#define LLREG 282 -#define LSREG 283 -#define LFREG 284 -#define LMREG 285 -#define LXREG 286 -#define LFCONST 287 -#define LSCONST 288 -#define LSP 289 -#define LNAME 290 -#define LLAB 291 -#define LVAR 292 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; -} -/* Line 1529 of yacc.c. */ -#line 132 "y.tab.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/6g/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c deleted file mode 100644 index 77ab2d2167..0000000000 --- a/src/cmd/6g/cgen.c +++ /dev/null @@ -1,1745 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -void -cgen(Node *n, Node *res) -{ - Node *nl, *nr, *r; - Node n1, n2; - int a, f; - Prog *p1, *p2, *p3; - Addr addr; - - if(debug['g']) { - dump("\ncgen-n", n); - dump("cgen-res", res); - } - if(n == N || n->type == T) - goto ret; - - if(res == N || res->type == T) - fatal("cgen: res nil"); - - while(n->op == OCONVNOP) - n = n->left; - - switch(n->op) { - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_slice(n, &n1); - cgen(&n1, res); - } else - cgen_slice(n, res); - goto ret; - case OEFACE: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_eface(n, &n1); - cgen(&n1, res); - } else - cgen_eface(n, res); - goto ret; - } - - if(n->ullman >= UINF) { - if(n->op == OINDREG) - fatal("cgen: this is going to misscompile"); - if(res->ullman >= UINF) { - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - goto ret; - } - } - - if(isfat(n->type)) { - if(n->type->width < 0) - fatal("forgot to compute width for %T", n->type); - sgen(n, res, n->type->width); - goto ret; - } - - if(!res->addable) { - if(n->ullman > res->ullman) { - regalloc(&n1, n->type, res); - cgen(n, &n1); - if(n1.ullman > res->ullman) { - dump("n1", &n1); - dump("res", res); - fatal("loop in cgen"); - } - cgen(&n1, res); - regfree(&n1); - goto ret; - } - - if(res->ullman >= UINF) - goto gen; - - if(complexop(n, res)) { - complexgen(n, res); - goto ret; - } - - f = 1; // gen thru register - switch(n->op) { - case OLITERAL: - if(smallintconst(n)) - f = 0; - break; - case OREGISTER: - f = 0; - break; - } - - if(!iscomplex[n->type->etype]) { - a = optoas(OAS, res->type); - if(sudoaddable(a, res, &addr)) { - if(f) { - regalloc(&n2, res->type, N); - cgen(n, &n2); - p1 = gins(a, &n2, N); - regfree(&n2); - } else - p1 = gins(a, n, N); - p1->to = addr; - if(debug['g']) - print("%P [ignore previous line]\n", p1); - sudoclean(); - goto ret; - } - } - - gen: - igen(res, &n1, N); - cgen(n, &n1); - regfree(&n1); - goto ret; - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch(n->op) { - case OSPTR: - case OLEN: - if(isslice(n->left->type) || istype(n->left->type, TSTRING)) - n->addable = n->left->addable; - break; - case OCAP: - if(isslice(n->left->type)) - n->addable = n->left->addable; - break; - case OITAB: - n->addable = n->left->addable; - break; - } - - if(complexop(n, res)) { - complexgen(n, res); - goto ret; - } - - if(n->addable) { - gmove(n, res); - goto ret; - } - - nl = n->left; - nr = n->right; - - if(nl != N && nl->ullman >= UINF) - if(nr != N && nr->ullman >= UINF) { - tempname(&n1, nl->type); - cgen(nl, &n1); - n2 = *n; - n2.left = &n1; - cgen(&n2, res); - goto ret; - } - - if(!iscomplex[n->type->etype]) { - a = optoas(OAS, n->type); - if(sudoaddable(a, n, &addr)) { - if(res->op == OREGISTER) { - p1 = gins(a, N, res); - p1->from = addr; - } else { - regalloc(&n2, n->type, N); - p1 = gins(a, N, &n2); - p1->from = addr; - gins(a, &n2, res); - regfree(&n2); - } - sudoclean(); - goto ret; - } - } - - switch(n->op) { - default: - dump("cgen", n); - fatal("cgen: unknown op %+hN", n); - break; - - // these call bgen to get a bool value - case OOROR: - case OANDAND: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case ONOT: - p1 = gbranch(AJMP, T, 0); - p2 = pc; - gmove(nodbool(1), res); - p3 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n, 1, 0, p2); - gmove(nodbool(0), res); - patch(p3, pc); - goto ret; - - case OPLUS: - cgen(nl, res); - goto ret; - - // unary - case OCOM: - a = optoas(OXOR, nl->type); - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - nodconst(&n2, nl->type, -1); - gins(a, &n2, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - - case OMINUS: - if(isfloat[nl->type->etype]) { - nr = nodintconst(-1); - convlit(&nr, n->type); - a = optoas(OMUL, nl->type); - goto sbop; - } - a = optoas(n->op, nl->type); - goto uop; - - // symmetric binary - case OAND: - case OOR: - case OXOR: - case OADD: - case OMUL: - a = optoas(n->op, nl->type); - if(a == AIMULB) { - cgen_bmul(n->op, nl, nr, res); - break; - } - goto sbop; - - // asymmetric binary - case OSUB: - a = optoas(n->op, nl->type); - goto abop; - - case OHMUL: - cgen_hmul(nl, nr, res); - break; - - case OCONV: - if(n->type->width > nl->type->width) { - // If loading from memory, do conversion during load, - // so as to avoid use of 8-bit register in, say, int(*byteptr). - switch(nl->op) { - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: - igen(nl, &n1, res); - regalloc(&n2, n->type, res); - gmove(&n1, &n2); - gmove(&n2, res); - regfree(&n2); - regfree(&n1); - goto ret; - } - } - - regalloc(&n1, nl->type, res); - regalloc(&n2, n->type, &n1); - cgen(nl, &n1); - - // if we do the conversion n1 -> n2 here - // reusing the register, then gmove won't - // have to allocate its own register. - gmove(&n1, &n2); - gmove(&n2, res); - regfree(&n2); - regfree(&n1); - break; - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case OITAB: - // interface table is first word of interface value - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OSPTR: - // pointer is the first word of string or slice. - if(isconst(nl, CTSTR)) { - regalloc(&n1, types[tptr], res); - p1 = gins(ALEAQ, N, &n1); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - gmove(&n1, res); - regfree(&n1); - break; - } - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OLEN: - if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { - // map and chan have len in the first int-sized word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); - - n2 = n1; - n2.op = OINDREG; - n2.type = types[simtype[TINT]]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(istype(nl->type, TSTRING) || isslice(nl->type)) { - // both slice and string have len one pointer into the struct. - // a zero pointer means zero length - igen(nl, &n1, res); - n1.type = types[simtype[TUINT]]; - n1.xoffset += Array_nel; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OLEN: unknown type %lT", nl->type); - break; - - case OCAP: - if(istype(nl->type, TCHAN)) { - // chan has cap in the second int-sized word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); - - n2 = n1; - n2.op = OINDREG; - n2.xoffset = widthint; - n2.type = types[simtype[TINT]]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(isslice(nl->type)) { - igen(nl, &n1, res); - n1.type = types[simtype[TUINT]]; - n1.xoffset += Array_cap; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OCAP: unknown type %lT", nl->type); - break; - - case OADDR: - if(n->bounded) // let race detector avoid nil checks - disable_checknil++; - agen(nl, res); - if(n->bounded) - disable_checknil--; - break; - - case OCALLMETH: - cgen_callmeth(n, 0); - cgen_callret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_callret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_callret(n, res); - break; - - case OMOD: - case ODIV: - if(isfloat[n->type->etype]) { - a = optoas(n->op, nl->type); - goto abop; - } - - if(nl->ullman >= nr->ullman) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - cgen_div(n->op, &n1, nr, res); - regfree(&n1); - } else { - if(!smallintconst(nr)) { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - } else { - n2 = *nr; - } - cgen_div(n->op, nl, &n2, res); - if(n2.op != OLITERAL) - regfree(&n2); - } - break; - - case OLSH: - case ORSH: - case OLROT: - cgen_shift(n->op, n->bounded, nl, nr, res); - break; - } - goto ret; - -sbop: // symmetric binary - /* - * put simplest on right - we'll generate into left - * and then adjust it using the computation of right. - * constants and variables have the same ullman - * count, so look for constants specially. - * - * an integer constant we can use as an immediate - * is simpler than a variable - we can use the immediate - * in the adjustment instruction directly - so it goes - * on the right. - * - * other constants, like big integers or floating point - * constants, require a mov into a register, so those - * might as well go on the left, so we can reuse that - * register for the computation. - */ - if(nl->ullman < nr->ullman || - (nl->ullman == nr->ullman && - (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) { - r = nl; - nl = nr; - nr = r; - } - -abop: // asymmetric binary - if(nl->ullman >= nr->ullman) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - /* - * This generates smaller code - it avoids a MOV - but it's - * easily 10% slower due to not being able to - * optimize/manipulate the move. - * To see, run: go test -bench . crypto/md5 - * with and without. - * - if(sudoaddable(a, nr, &addr)) { - p1 = gins(a, N, &n1); - p1->from = addr; - gmove(&n1, res); - sudoclean(); - regfree(&n1); - goto ret; - } - * - */ - - if(smallintconst(nr)) - n2 = *nr; - else { - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - } - } else { - if(smallintconst(nr)) - n2 = *nr; - else { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - } - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - } - gins(a, &n2, &n1); - gmove(&n1, res); - regfree(&n1); - if(n2.op != OLITERAL) - regfree(&n2); - goto ret; - -uop: // unary - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - gins(a, N, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - -ret: - ; -} - -/* - * allocate a register (reusing res if possible) and generate - * a = n - * The caller must call regfree(a). - */ -void -cgenr(Node *n, Node *a, Node *res) -{ - Node n1; - - if(debug['g']) - dump("cgenr-n", n); - - if(isfat(n->type)) - fatal("cgenr on fat node"); - - if(n->addable) { - regalloc(a, n->type, res); - gmove(n, a); - return; - } - - switch(n->op) { - case ONAME: - case ODOT: - case ODOTPTR: - case OINDEX: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - gmove(&n1, a); - regfree(&n1); - break; - default: - regalloc(a, n->type, res); - cgen(n, a); - break; - } -} - -/* - * allocate a register (reusing res if possible) and generate - * a = &n - * The caller must call regfree(a). - * The generated code checks that the result is not nil. - */ -void -agenr(Node *n, Node *a, Node *res) -{ - Node *nl, *nr; - Node n1, n2, n3, n5, tmp, tmp2, nlen; - Prog *p1; - Type *t; - uint64 w; - uint64 v; - int freelen; - - if(debug['g']) { - dump("\nagenr-n", n); - } - - nl = n->left; - nr = n->right; - - switch(n->op) { - case ODOT: - case ODOTPTR: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - agen(&n1, a); - regfree(&n1); - break; - - case OIND: - cgenr(n->left, a, res); - cgen_checknil(a); - break; - - case OINDEX: - freelen = 0; - w = n->type->width; - // Generate the non-addressable child first. - if(nr->addable) - goto irad; - if(nl->addable) { - cgenr(nr, &n1, N); - if(!isconst(nl, CTSTR)) { - if(isfixedarray(nl->type)) { - agenr(nl, &n3, res); - } else { - igen(nl, &nlen, res); - freelen = 1; - nlen.type = types[tptr]; - nlen.xoffset += Array_array; - regalloc(&n3, types[tptr], res); - gmove(&nlen, &n3); - nlen.type = types[simtype[TUINT]]; - nlen.xoffset += Array_nel-Array_array; - } - } - goto index; - } - tempname(&tmp, nr->type); - cgen(nr, &tmp); - nr = &tmp; - irad: - if(!isconst(nl, CTSTR)) { - if(isfixedarray(nl->type)) { - agenr(nl, &n3, res); - } else { - if(!nl->addable) { - // igen will need an addressable node. - tempname(&tmp2, nl->type); - cgen(nl, &tmp2); - nl = &tmp2; - } - igen(nl, &nlen, res); - freelen = 1; - nlen.type = types[tptr]; - nlen.xoffset += Array_array; - regalloc(&n3, types[tptr], res); - gmove(&nlen, &n3); - nlen.type = types[simtype[TUINT]]; - nlen.xoffset += Array_nel-Array_array; - } - } - if(!isconst(nr, CTINT)) { - cgenr(nr, &n1, N); - } - goto index; - - index: - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // len(a) is in nlen (if needed) - // w is width - - // constant index - if(isconst(nr, CTINT)) { - if(isconst(nl, CTSTR)) - fatal("constant string constant index"); // front end should handle - v = mpgetfix(nr->val.u.xval); - if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(!debug['B'] && !n->bounded) { - nodconst(&n2, types[simtype[TUINT]], v); - if(smallintconst(nr)) { - gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2); - } else { - regalloc(&tmp, types[simtype[TUINT]], N); - gmove(&n2, &tmp); - gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp); - regfree(&tmp); - } - p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1); - ginscall(panicindex, -1); - patch(p1, pc); - } - regfree(&nlen); - } - - if (v*w != 0) - ginscon(optoas(OADD, types[tptr]), v*w, &n3); - *a = n3; - break; - } - - // type of the index - t = types[TUINT64]; - if(issigned[n1.type->etype]) - t = types[TINT64]; - - regalloc(&n2, t, &n1); // i - gmove(&n1, &n2); - regfree(&n1); - - if(!debug['B'] && !n->bounded) { - // check bounds - t = types[simtype[TUINT]]; - if(is64(nr->type)) - t = types[TUINT64]; - if(isconst(nl, CTSTR)) { - nodconst(&nlen, t, nl->val.u.sval->len); - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(is64(nr->type)) { - regalloc(&n5, t, N); - gmove(&nlen, &n5); - regfree(&nlen); - nlen = n5; - } - } else { - nodconst(&nlen, t, nl->type->bound); - if(!smallintconst(&nlen)) { - regalloc(&n5, t, N); - gmove(&nlen, &n5); - nlen = n5; - freelen = 1; - } - } - gins(optoas(OCMP, t), &n2, &nlen); - p1 = gbranch(optoas(OLT, t), T, +1); - ginscall(panicindex, -1); - patch(p1, pc); - } - - if(isconst(nl, CTSTR)) { - regalloc(&n3, types[tptr], res); - p1 = gins(ALEAQ, N, &n3); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - gins(AADDQ, &n2, &n3); - goto indexdone; - } - - if(w == 0) { - // nothing to do - } else if(w == 1 || w == 2 || w == 4 || w == 8) { - p1 = gins(ALEAQ, &n2, &n3); - p1->from.type = TYPE_MEM; - p1->from.scale = w; - p1->from.index = p1->from.reg; - p1->from.reg = p1->to.reg; - } else { - ginscon(optoas(OMUL, t), w, &n2); - gins(optoas(OADD, types[tptr]), &n2, &n3); - } - - indexdone: - *a = n3; - regfree(&n2); - if(freelen) - regfree(&nlen); - break; - - default: - regalloc(a, types[tptr], res); - agen(n, a); - break; - } -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -void -agen(Node *n, Node *res) -{ - Node *nl; - Node n1, n2; - - if(debug['g']) { - dump("\nagen-res", res); - dump("agen-r", n); - } - if(n == N || n->type == T) - return; - - while(n->op == OCONVNOP) - n = n->left; - - if(isconst(n, CTNIL) && n->type->width > widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - tempname(&n1, n->type); - gvardef(&n1); - clearfat(&n1); - regalloc(&n2, types[tptr], res); - gins(ALEAQ, &n1, &n2); - gmove(&n2, res); - regfree(&n2); - goto ret; - } - - if(n->addable) { - regalloc(&n1, types[tptr], res); - gins(ALEAQ, n, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - } - - nl = n->left; - - switch(n->op) { - default: - fatal("agen: unknown op %+hN", n); - break; - - case OCALLMETH: - cgen_callmeth(n, 0); - cgen_aret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_aret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_aret(n, res); - break; - - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - tempname(&n1, n->type); - cgen_slice(n, &n1); - agen(&n1, res); - break; - - case OEFACE: - tempname(&n1, n->type); - cgen_eface(n, &n1); - agen(&n1, res); - break; - - case OINDEX: - agenr(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case ONAME: - // should only get here with names in this func. - if(n->funcdepth > 0 && n->funcdepth != funcdepth) { - dump("bad agen", n); - fatal("agen: bad ONAME funcdepth %d != %d", - n->funcdepth, funcdepth); - } - - // should only get here for heap vars or paramref - if(!(n->class & PHEAP) && n->class != PPARAMREF) { - dump("bad agen", n); - fatal("agen: bad ONAME class %#x", n->class); - } - cgen(n->heapaddr, res); - if(n->xoffset != 0) - ginscon(optoas(OADD, types[tptr]), n->xoffset, res); - break; - - case OIND: - cgen(nl, res); - cgen_checknil(res); - break; - - case ODOT: - agen(nl, res); - if(n->xoffset != 0) - ginscon(optoas(OADD, types[tptr]), n->xoffset, res); - break; - - case ODOTPTR: - cgen(nl, res); - cgen_checknil(res); - if(n->xoffset != 0) - ginscon(optoas(OADD, types[tptr]), n->xoffset, res); - break; - } - -ret: - ; -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -void -igen(Node *n, Node *a, Node *res) -{ - Type *fp; - Iter flist; - Node n1; - - if(debug['g']) { - dump("\nigen-n", n); - } - switch(n->op) { - case ONAME: - if((n->class&PHEAP) || n->class == PPARAMREF) - break; - *a = *n; - return; - - case OINDREG: - // Increase the refcount of the register so that igen's caller - // has to call regfree. - if(n->val.u.reg != REG_SP) - reg[n->val.u.reg]++; - *a = *n; - return; - - case ODOT: - igen(n->left, a, res); - a->xoffset += n->xoffset; - a->type = n->type; - fixlargeoffset(a); - return; - - case ODOTPTR: - cgenr(n->left, a, res); - cgen_checknil(a); - a->op = OINDREG; - a->xoffset += n->xoffset; - a->type = n->type; - fixlargeoffset(a); - return; - - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - switch(n->op) { - case OCALLFUNC: - cgen_call(n, 0); - break; - case OCALLMETH: - cgen_callmeth(n, 0); - break; - case OCALLINTER: - cgen_callinter(n, N, 0); - break; - } - fp = structfirst(&flist, getoutarg(n->left->type)); - memset(a, 0, sizeof *a); - a->op = OINDREG; - a->val.u.reg = REG_SP; - a->addable = 1; - a->xoffset = fp->width; - a->type = n->type; - return; - - case OINDEX: - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - if(isfixedarray(n->left->type) || - (isptr[n->left->type->etype] && isfixedarray(n->left->left->type))) - if(isconst(n->right, CTINT)) { - // Compute &a. - if(!isptr[n->left->type->etype]) - igen(n->left, a, res); - else { - igen(n->left, &n1, res); - cgen_checknil(&n1); - regalloc(a, types[tptr], res); - gmove(&n1, a); - regfree(&n1); - a->op = OINDREG; - } - - // Compute &a[i] as &a + i*width. - a->type = n->type; - a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width; - fixlargeoffset(a); - return; - } - break; - } - - agenr(n, a, res); - a->op = OINDREG; - a->type = n->type; -} - -/* - * generate: - * if(n == true) goto to; - */ -void -bgen(Node *n, int true, int likely, Prog *to) -{ - int et, a; - Node *nl, *nr, *l, *r; - Node n1, n2, tmp; - NodeList *ll; - Prog *p1, *p2; - - if(debug['g']) { - dump("\nbgen", n); - } - - if(n == N) - n = nodbool(1); - - if(n->ninit != nil) - genlist(n->ninit); - - if(n->type == T) { - convlit(&n, types[TBOOL]); - if(n->type == T) - goto ret; - } - - et = n->type->etype; - if(et != TBOOL) { - yyerror("cgen: bad type %T for %O", n->type, n->op); - patch(gins(AEND, N, N), to); - goto ret; - } - nr = N; - - while(n->op == OCONVNOP) { - n = n->left; - if(n->ninit != nil) - genlist(n->ninit); - } - - switch(n->op) { - default: - goto def; - - case OLITERAL: - // need to ask if it is bool? - if(!true == !n->val.u.bval) - patch(gbranch(AJMP, T, likely), to); - goto ret; - - case ONAME: - if(n->addable == 0) - goto def; - nodconst(&n1, n->type, 0); - gins(optoas(OCMP, n->type), n, &n1); - a = AJNE; - if(!true) - a = AJEQ; - patch(gbranch(a, n->type, likely), to); - goto ret; - - case OANDAND: - case OOROR: - if((n->op == OANDAND) == true) { - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n->left, !true, -likely, p2); - bgen(n->right, !true, -likely, p2); - p1 = gbranch(AJMP, T, 0); - patch(p1, to); - patch(p2, pc); - } else { - bgen(n->left, true, likely, to); - bgen(n->right, true, likely, to); - } - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - nr = n->right; - if(nr == N || nr->type == T) - goto ret; - - case ONOT: // unary - nl = n->left; - if(nl == N || nl->type == T) - goto ret; - break; - } - - switch(n->op) { - - case ONOT: - bgen(nl, !true, likely, to); - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - a = n->op; - if(!true) { - if(isfloat[nr->type->etype]) { - // brcom is not valid on floats when NaN is involved. - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - ll = n->ninit; // avoid re-genning ninit - n->ninit = nil; - bgen(n, 1, -likely, p2); - n->ninit = ll; - patch(gbranch(AJMP, T, 0), to); - patch(p2, pc); - goto ret; - } - a = brcom(a); - true = !true; - } - - // make simplest on right - if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) { - a = brrev(a); - r = nl; - nl = nr; - nr = r; - } - - if(isslice(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal slice comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.xoffset += Array_array; - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &tmp); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - - if(isinter(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal interface comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &tmp); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - if(iscomplex[nl->type->etype]) { - complexbool(a, nl, nr, true, likely, to); - break; - } - - if(nr->ullman >= UINF) { - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - - tempname(&tmp, nl->type); - gmove(&n1, &tmp); - regfree(&n1); - - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - - regalloc(&n1, nl->type, N); - cgen(&tmp, &n1); - - goto cmp; - } - - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - - if(smallintconst(nr)) { - gins(optoas(OCMP, nr->type), &n1, nr); - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - regfree(&n1); - break; - } - - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - cmp: - // only < and <= work right with NaN; reverse if needed - l = &n1; - r = &n2; - if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) { - l = &n2; - r = &n1; - a = brrev(a); - } - - gins(optoas(OCMP, nr->type), l, r); - - if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) { - if(n->op == OEQ) { - // neither NE nor P - p1 = gbranch(AJNE, T, -likely); - p2 = gbranch(AJPS, T, -likely); - patch(gbranch(AJMP, T, 0), to); - patch(p1, pc); - patch(p2, pc); - } else { - // either NE or P - patch(gbranch(AJNE, T, likely), to); - patch(gbranch(AJPS, T, likely), to); - } - } else - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - regfree(&n1); - regfree(&n2); - break; - } - goto ret; - -def: - regalloc(&n1, n->type, N); - cgen(n, &n1); - nodconst(&n2, n->type, 0); - gins(optoas(OCMP, n->type), &n1, &n2); - a = AJNE; - if(!true) - a = AJEQ; - patch(gbranch(a, n->type, likely), to); - regfree(&n1); - goto ret; - -ret: - ; -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -int64 -stkof(Node *n) -{ - Type *t; - Iter flist; - int64 off; - - switch(n->op) { - case OINDREG: - return n->xoffset; - - case ODOT: - t = n->left->type; - if(isptr[t->etype]) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - return off + n->xoffset; - - case OINDEX: - t = n->left->type; - if(!isfixedarray(t)) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - if(isconst(n->right, CTINT)) - return off + t->type->width * mpgetfix(n->right->val.u.xval); - return 1000; - - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - t = structfirst(&flist, getoutarg(t)); - if(t != T) - return t->width; - break; - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000; -} - -/* - * block copy: - * memmove(&ns, &n, w); - */ -void -sgen(Node *n, Node *ns, int64 w) -{ - Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp; - vlong c, q, odst, osrc; - NodeList *l; - Prog *p; - - if(debug['g']) { - print("\nsgen w=%lld\n", w); - dump("r", n); - dump("res", ns); - } - - if(n->ullman >= UINF && ns->ullman >= UINF) - fatal("sgen UINF"); - - if(w < 0) - fatal("sgen copy %lld", w); - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0) - for(l = curfn->dcl; l != nil; l = l->next) - if(l->n->class == PPARAMOUT) - gvardef(l->n); - - // Avoid taking the address for simple enough types. - if(componentgen(n, ns)) - return; - - if(w == 0) { - // evaluate side effects only - regalloc(&nodr, types[tptr], N); - agen(ns, &nodr); - agen(n, &nodr); - regfree(&nodr); - return; - } - - // offset on the stack - osrc = stkof(n); - odst = stkof(ns); - - if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - tempname(&tmp, n->type); - sgen(n, &tmp, w); - sgen(&tmp, ns, w); - return; - } - - nodreg(&noddi, types[tptr], REG_DI); - nodreg(&nodsi, types[tptr], REG_SI); - - if(n->ullman >= ns->ullman) { - agenr(n, &nodr, &nodsi); - if(ns->op == ONAME) - gvardef(ns); - agenr(ns, &nodl, &noddi); - } else { - if(ns->op == ONAME) - gvardef(ns); - agenr(ns, &nodl, &noddi); - agenr(n, &nodr, &nodsi); - } - - if(nodl.val.u.reg != REG_DI) - gmove(&nodl, &noddi); - if(nodr.val.u.reg != REG_SI) - gmove(&nodr, &nodsi); - regfree(&nodl); - regfree(&nodr); - - c = w % 8; // bytes - q = w / 8; // quads - - savex(REG_CX, &cx, &oldcx, N, types[TINT64]); - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - if(osrc < odst && odst < osrc+w) { - // reverse direction - gins(ASTD, N, N); // set direction flag - if(c > 0) { - gconreg(addptr, w-1, REG_SI); - gconreg(addptr, w-1, REG_DI); - - gconreg(movptr, c, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- - } - - if(q > 0) { - if(c > 0) { - gconreg(addptr, -7, REG_SI); - gconreg(addptr, -7, REG_DI); - } else { - gconreg(addptr, w-8, REG_SI); - gconreg(addptr, w-8, REG_DI); - } - gconreg(movptr, q, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSQ, N, N); // MOVQ *(SI)-,*(DI)- - } - // we leave with the flag clear - gins(ACLD, N, N); - } else { - // normal direction - if(q > 128 || (nacl && q >= 4)) { - gconreg(movptr, q, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ - } else if (q >= 4) { - p = gins(ADUFFCOPY, N, N); - p->to.type = TYPE_ADDR; - p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); - // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s - p->to.offset = 14*(128-q); - } else if(!nacl && c == 0) { - // We don't need the MOVSQ side-effect of updating SI and DI, - // and issuing a sequence of MOVQs directly is faster. - nodsi.op = OINDREG; - noddi.op = OINDREG; - while(q > 0) { - gmove(&nodsi, &cx); // MOVQ x+(SI),CX - gmove(&cx, &noddi); // MOVQ CX,x+(DI) - nodsi.xoffset += 8; - noddi.xoffset += 8; - q--; - } - } else - while(q > 0) { - gins(AMOVSQ, N, N); // MOVQ *(SI)+,*(DI)+ - q--; - } - // copy the remaining c bytes - if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) { - while(c > 0) { - gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ - c--; - } - } else if(w < 8 || c <= 4) { - nodsi.op = OINDREG; - noddi.op = OINDREG; - cx.type = types[TINT32]; - nodsi.type = types[TINT32]; - noddi.type = types[TINT32]; - if(c > 4) { - nodsi.xoffset = 0; - noddi.xoffset = 0; - gmove(&nodsi, &cx); - gmove(&cx, &noddi); - } - nodsi.xoffset = c-4; - noddi.xoffset = c-4; - gmove(&nodsi, &cx); - gmove(&cx, &noddi); - } else { - nodsi.op = OINDREG; - noddi.op = OINDREG; - cx.type = types[TINT64]; - nodsi.type = types[TINT64]; - noddi.type = types[TINT64]; - nodsi.xoffset = c-8; - noddi.xoffset = c-8; - gmove(&nodsi, &cx); - gmove(&cx, &noddi); - } - } - - restx(&cx, &oldcx); -} - -static int -cadable(Node *n) -{ - if(!n->addable) { - // dont know how it happens, - // but it does - return 0; - } - - switch(n->op) { - case ONAME: - return 1; - } - return 0; -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -int -componentgen(Node *nr, Node *nl) -{ - Node nodl, nodr, tmp; - Type *t; - int freel, freer; - vlong fldcount; - vlong loffset, roffset; - - freel = 0; - freer = 0; - - switch(nl->type->etype) { - default: - goto no; - - case TARRAY: - t = nl->type; - - // Slices are ok. - if(isslice(t)) - break; - // Small arrays are ok. - if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) - break; - - goto no; - - case TSTRUCT: - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - fldcount = 0; - for(t=nl->type->type; t; t=t->down) { - if(isfat(t->type)) - goto no; - if(t->etype != TFIELD) - fatal("componentgen: not a TFIELD: %lT", t); - fldcount++; - } - if(fldcount == 0 || fldcount > 4) - goto no; - - break; - - case TSTRING: - case TINTER: - break; - } - - nodl = *nl; - if(!cadable(nl)) { - if(nr != N && !cadable(nr)) - goto no; - igen(nl, &nodl, N); - freel = 1; - } - - if(nr != N) { - nodr = *nr; - if(!cadable(nr)) { - igen(nr, &nodr, N); - freer = 1; - } - } else { - // When zeroing, prepare a register containing zero. - nodconst(&tmp, nl->type, 0); - regalloc(&nodr, types[TUINT], N); - gmove(&tmp, &nodr); - freer = 1; - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) - goto yes; - - switch(nl->type->etype) { - case TARRAY: - // componentgen for arrays. - if(nl->op == ONAME) - gvardef(nl); - t = nl->type; - if(!isslice(t)) { - nodl.type = t->type; - nodr.type = nodl.type; - for(fldcount=0; fldcount < t->bound; fldcount++) { - if(nr == N) - clearslim(&nodl); - else - gmove(&nodr, &nodl); - nodl.xoffset += t->type->width; - nodr.xoffset += t->type->width; - } - goto yes; - } - - // componentgen for slices. - nodl.xoffset += Array_array; - nodl.type = ptrto(nl->type->type); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_cap-Array_nel; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_cap-Array_nel; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRING: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TINTER: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRUCT: - if(nl->op == ONAME) - gvardef(nl); - loffset = nodl.xoffset; - roffset = nodr.xoffset; - // funarg structs may not begin at offset zero. - if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) - loffset -= nl->type->type->width; - if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) - roffset -= nr->type->type->width; - - for(t=nl->type->type; t; t=t->down) { - nodl.xoffset = loffset + t->width; - nodl.type = t->type; - - if(nr == N) - clearslim(&nodl); - else { - nodr.xoffset = roffset + t->width; - nodr.type = nodl.type; - gmove(&nodr, &nodl); - } - } - goto yes; - } - -no: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 0; - -yes: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 1; -} diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go new file mode 100644 index 0000000000..36fa62c469 --- /dev/null +++ b/src/cmd/6g/cgen.go @@ -0,0 +1,1889 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" + "fmt" +) +import "cmd/internal/gc" + +/* + * reg.c + */ + +/* + * peep.c + */ +/* + * generate: + * res = n; + * simplifies and calls gmove. + */ +func cgen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var a int + var f int + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var addr obj.Addr + + if gc.Debug['g'] != 0 { + gc.Dump("\ncgen-n", n) + gc.Dump("cgen-res", res) + } + + if n == nil || n.Type == nil { + goto ret + } + + if res == nil || res.Type == nil { + gc.Fatal("cgen: res nil") + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + switch n.Op { + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_slice(n, res) + } + goto ret + + case gc.OEFACE: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_eface(n, res) + } + goto ret + } + + if n.Ullman >= gc.UINF { + if n.Op == gc.OINDREG { + gc.Fatal("cgen: this is going to misscompile") + } + if res.Ullman >= gc.UINF { + gc.Tempname(&n1, n.Type) + cgen(n, &n1) + cgen(&n1, res) + goto ret + } + } + + if gc.Isfat(n.Type) { + if n.Type.Width < 0 { + gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) + } + sgen(n, res, n.Type.Width) + goto ret + } + + if res.Addable == 0 { + if n.Ullman > res.Ullman { + regalloc(&n1, n.Type, res) + cgen(n, &n1) + if n1.Ullman > res.Ullman { + gc.Dump("n1", &n1) + gc.Dump("res", res) + gc.Fatal("loop in cgen") + } + + cgen(&n1, res) + regfree(&n1) + goto ret + } + + if res.Ullman >= gc.UINF { + goto gen + } + + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + goto ret + } + + f = 1 // gen thru register + switch n.Op { + case gc.OLITERAL: + if gc.Smallintconst(n) { + f = 0 + } + + case gc.OREGISTER: + f = 0 + } + + if gc.Iscomplex[n.Type.Etype] == 0 { + a = optoas(gc.OAS, res.Type) + if sudoaddable(a, res, &addr) { + if f != 0 { + regalloc(&n2, res.Type, nil) + cgen(n, &n2) + p1 = gins(a, &n2, nil) + regfree(&n2) + } else { + p1 = gins(a, n, nil) + } + p1.To = addr + if gc.Debug['g'] != 0 { + fmt.Printf("%v [ignore previous line]\n", p1) + } + sudoclean() + goto ret + } + } + + gen: + igen(res, &n1, nil) + cgen(n, &n1) + regfree(&n1) + goto ret + } + + // update addressability for string, slice + // can't do in walk because n->left->addable + // changes if n->left is an escaping local variable. + switch n.Op { + case gc.OSPTR, + gc.OLEN: + if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { + n.Addable = n.Left.Addable + } + + case gc.OCAP: + if gc.Isslice(n.Left.Type) { + n.Addable = n.Left.Addable + } + + case gc.OITAB: + n.Addable = n.Left.Addable + } + + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + goto ret + } + + if n.Addable != 0 { + gmove(n, res) + goto ret + } + + nl = n.Left + nr = n.Right + + if nl != nil && nl.Ullman >= gc.UINF { + if nr != nil && nr.Ullman >= gc.UINF { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + n2 = *n + n2.Left = &n1 + cgen(&n2, res) + goto ret + } + } + + if gc.Iscomplex[n.Type.Etype] == 0 { + a = optoas(gc.OAS, n.Type) + if sudoaddable(a, n, &addr) { + if res.Op == gc.OREGISTER { + p1 = gins(a, nil, res) + p1.From = addr + } else { + regalloc(&n2, n.Type, nil) + p1 = gins(a, nil, &n2) + p1.From = addr + gins(a, &n2, res) + regfree(&n2) + } + + sudoclean() + goto ret + } + } + + switch n.Op { + default: + gc.Dump("cgen", n) + gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + // these call bgen to get a bool value + case gc.OOROR, + gc.OANDAND, + gc.OEQ, + gc.ONE, + gc.OLT, + gc.OLE, + gc.OGE, + gc.OGT, + gc.ONOT: + p1 = gc.Gbranch(obj.AJMP, nil, 0) + + p2 = gc.Pc + gmove(gc.Nodbool(true), res) + p3 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n, true, 0, p2) + gmove(gc.Nodbool(false), res) + gc.Patch(p3, gc.Pc) + goto ret + + case gc.OPLUS: + cgen(nl, res) + goto ret + + // unary + case gc.OCOM: + a = optoas(gc.OXOR, nl.Type) + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gc.Nodconst(&n2, nl.Type, -1) + gins(a, &n2, &n1) + gmove(&n1, res) + regfree(&n1) + goto ret + + case gc.OMINUS: + if gc.Isfloat[nl.Type.Etype] != 0 { + nr = gc.Nodintconst(-1) + gc.Convlit(&nr, n.Type) + a = optoas(gc.OMUL, nl.Type) + goto sbop + } + + a = optoas(int(n.Op), nl.Type) + goto uop + + // symmetric binary + case gc.OAND, + gc.OOR, + gc.OXOR, + gc.OADD, + gc.OMUL: + a = optoas(int(n.Op), nl.Type) + + if a == x86.AIMULB { + cgen_bmul(int(n.Op), nl, nr, res) + break + } + + goto sbop + + // asymmetric binary + case gc.OSUB: + a = optoas(int(n.Op), nl.Type) + + goto abop + + case gc.OHMUL: + cgen_hmul(nl, nr, res) + + case gc.OCONV: + if n.Type.Width > nl.Type.Width { + // If loading from memory, do conversion during load, + // so as to avoid use of 8-bit register in, say, int(*byteptr). + switch nl.Op { + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: + igen(nl, &n1, res) + regalloc(&n2, n.Type, res) + gmove(&n1, &n2) + gmove(&n2, res) + regfree(&n2) + regfree(&n1) + goto ret + } + } + + regalloc(&n1, nl.Type, res) + regalloc(&n2, n.Type, &n1) + cgen(nl, &n1) + + // if we do the conversion n1 -> n2 here + // reusing the register, then gmove won't + // have to allocate its own register. + gmove(&n1, &n2) + + gmove(&n2, res) + regfree(&n2) + regfree(&n1) + + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: // PHEAP or PPARAMREF var + igen(n, &n1, res) + + gmove(&n1, res) + regfree(&n1) + + // interface table is first word of interface value + case gc.OITAB: + igen(nl, &n1, res) + + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + // pointer is the first word of string or slice. + case gc.OSPTR: + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n1, gc.Types[gc.Tptr], res) + p1 = gins(x86.ALEAQ, nil, &n1) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + gmove(&n1, res) + regfree(&n1) + break + } + + igen(nl, &n1, res) + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + case gc.OLEN: + if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { + // map and chan have len in the first int-sized word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.Simtype[gc.TINT]] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { + // both slice and string have len one pointer into the struct. + // a zero pointer means zero length + igen(nl, &n1, res) + + n1.Type = gc.Types[gc.Simtype[gc.TUINT]] + n1.Xoffset += int64(gc.Array_nel) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OCAP: + if gc.Istype(nl.Type, gc.TCHAN) { + // chan has cap in the second int-sized word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Xoffset = int64(gc.Widthint) + n2.Type = gc.Types[gc.Simtype[gc.TINT]] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Isslice(nl.Type) { + igen(nl, &n1, res) + n1.Type = gc.Types[gc.Simtype[gc.TUINT]] + n1.Xoffset += int64(gc.Array_cap) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OADDR: + if n.Bounded { // let race detector avoid nil checks + gc.Disable_checknil++ + } + agen(nl, res) + if n.Bounded { + gc.Disable_checknil-- + } + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + cgen_callret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_callret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_callret(n, res) + + case gc.OMOD, + gc.ODIV: + if gc.Isfloat[n.Type.Etype] != 0 { + a = optoas(int(n.Op), nl.Type) + goto abop + } + + if nl.Ullman >= nr.Ullman { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + cgen_div(int(n.Op), &n1, nr, res) + regfree(&n1) + } else { + if !gc.Smallintconst(nr) { + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + } else { + n2 = *nr + } + + cgen_div(int(n.Op), nl, &n2, res) + if n2.Op != gc.OLITERAL { + regfree(&n2) + } + } + + case gc.OLSH, + gc.ORSH, + gc.OLROT: + cgen_shift(int(n.Op), n.Bounded, nl, nr, res) + } + + goto ret + + /* + * put simplest on right - we'll generate into left + * and then adjust it using the computation of right. + * constants and variables have the same ullman + * count, so look for constants specially. + * + * an integer constant we can use as an immediate + * is simpler than a variable - we can use the immediate + * in the adjustment instruction directly - so it goes + * on the right. + * + * other constants, like big integers or floating point + * constants, require a mov into a register, so those + * might as well go on the left, so we can reuse that + * register for the computation. + */ +sbop: // symmetric binary + if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) { + r = nl + nl = nr + nr = r + } + +abop: // asymmetric binary + if nl.Ullman >= nr.Ullman { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + + /* + * This generates smaller code - it avoids a MOV - but it's + * easily 10% slower due to not being able to + * optimize/manipulate the move. + * To see, run: go test -bench . crypto/md5 + * with and without. + * + if(sudoaddable(a, nr, &addr)) { + p1 = gins(a, N, &n1); + p1->from = addr; + gmove(&n1, res); + sudoclean(); + regfree(&n1); + goto ret; + } + * + */ + if gc.Smallintconst(nr) { + n2 = *nr + } else { + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + } + } else { + if gc.Smallintconst(nr) { + n2 = *nr + } else { + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + } + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + } + + gins(a, &n2, &n1) + gmove(&n1, res) + regfree(&n1) + if n2.Op != gc.OLITERAL { + regfree(&n2) + } + goto ret + +uop: // unary + regalloc(&n1, nl.Type, res) + + cgen(nl, &n1) + gins(a, nil, &n1) + gmove(&n1, res) + regfree(&n1) + goto ret + +ret: +} + +/* + * allocate a register (reusing res if possible) and generate + * a = n + * The caller must call regfree(a). + */ +func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("cgenr-n", n) + } + + if gc.Isfat(n.Type) { + gc.Fatal("cgenr on fat node") + } + + if n.Addable != 0 { + regalloc(a, n.Type, res) + gmove(n, a) + return + } + + switch n.Op { + case gc.ONAME, + gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + gmove(&n1, a) + regfree(&n1) + + default: + regalloc(a, n.Type, res) + cgen(n, a) + } +} + +/* + * allocate a register (reusing res if possible) and generate + * a = &n + * The caller must call regfree(a). + * The generated code checks that the result is not nil. + */ +func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n5 gc.Node + var tmp gc.Node + var tmp2 gc.Node + var nlen gc.Node + var p1 *obj.Prog + var t *gc.Type + var w uint64 + var v uint64 + var freelen int + + if gc.Debug['g'] != 0 { + gc.Dump("\nagenr-n", n) + } + + nl = n.Left + nr = n.Right + + switch n.Op { + case gc.ODOT, + gc.ODOTPTR, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + agen(&n1, a) + regfree(&n1) + + case gc.OIND: + cgenr(n.Left, a, res) + gc.Cgen_checknil(a) + + case gc.OINDEX: + freelen = 0 + w = uint64(n.Type.Width) + + // Generate the non-addressable child first. + if nr.Addable != 0 { + goto irad + } + if nl.Addable != 0 { + cgenr(nr, &n1, nil) + if !gc.Isconst(nl, gc.CTSTR) { + if gc.Isfixedarray(nl.Type) { + agenr(nl, &n3, res) + } else { + igen(nl, &nlen, res) + freelen = 1 + nlen.Type = gc.Types[gc.Tptr] + nlen.Xoffset += int64(gc.Array_array) + regalloc(&n3, gc.Types[gc.Tptr], res) + gmove(&nlen, &n3) + nlen.Type = gc.Types[gc.Simtype[gc.TUINT]] + nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + } + } + + goto index + } + + gc.Tempname(&tmp, nr.Type) + cgen(nr, &tmp) + nr = &tmp + + irad: + if !gc.Isconst(nl, gc.CTSTR) { + if gc.Isfixedarray(nl.Type) { + agenr(nl, &n3, res) + } else { + if nl.Addable == 0 { + // igen will need an addressable node. + gc.Tempname(&tmp2, nl.Type) + + cgen(nl, &tmp2) + nl = &tmp2 + } + + igen(nl, &nlen, res) + freelen = 1 + nlen.Type = gc.Types[gc.Tptr] + nlen.Xoffset += int64(gc.Array_array) + regalloc(&n3, gc.Types[gc.Tptr], res) + gmove(&nlen, &n3) + nlen.Type = gc.Types[gc.Simtype[gc.TUINT]] + nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + } + } + + if !gc.Isconst(nr, gc.CTINT) { + cgenr(nr, &n1, nil) + } + + goto index + + // &a is in &n3 (allocated in res) + // i is in &n1 (if not constant) + // len(a) is in nlen (if needed) + // w is width + + // constant index + index: + if gc.Isconst(nr, gc.CTINT) { + if gc.Isconst(nl, gc.CTSTR) { + gc.Fatal("constant string constant index") // front end should handle + } + v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + if gc.Debug['B'] == 0 && !n.Bounded { + gc.Nodconst(&n2, gc.Types[gc.Simtype[gc.TUINT]], int64(v)) + if gc.Smallintconst(nr) { + gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &n2) + } else { + regalloc(&tmp, gc.Types[gc.Simtype[gc.TUINT]], nil) + gmove(&n2, &tmp) + gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &tmp) + regfree(&tmp) + } + + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + + regfree(&nlen) + } + + if v*w != 0 { + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*w), &n3) + } + *a = n3 + break + } + + // type of the index + t = gc.Types[gc.TUINT64] + + if gc.Issigned[n1.Type.Etype] != 0 { + t = gc.Types[gc.TINT64] + } + + regalloc(&n2, t, &n1) // i + gmove(&n1, &n2) + regfree(&n1) + + if gc.Debug['B'] == 0 && !n.Bounded { + // check bounds + t = gc.Types[gc.Simtype[gc.TUINT]] + + if gc.Is64(nr.Type) { + t = gc.Types[gc.TUINT64] + } + if gc.Isconst(nl, gc.CTSTR) { + gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval.S))) + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + if gc.Is64(nr.Type) { + regalloc(&n5, t, nil) + gmove(&nlen, &n5) + regfree(&nlen) + nlen = n5 + } + } else { + gc.Nodconst(&nlen, t, nl.Type.Bound) + if !gc.Smallintconst(&nlen) { + regalloc(&n5, t, nil) + gmove(&nlen, &n5) + nlen = n5 + freelen = 1 + } + } + + gins(optoas(gc.OCMP, t), &n2, &nlen) + p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n3, gc.Types[gc.Tptr], res) + p1 = gins(x86.ALEAQ, nil, &n3) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + gins(x86.AADDQ, &n2, &n3) + goto indexdone + } + + if w == 0 { + } else // nothing to do + if w == 1 || w == 2 || w == 4 || w == 8 { + p1 = gins(x86.ALEAQ, &n2, &n3) + p1.From.Type = obj.TYPE_MEM + p1.From.Scale = int8(w) + p1.From.Index = p1.From.Reg + p1.From.Reg = p1.To.Reg + } else { + ginscon(optoas(gc.OMUL, t), int64(w), &n2) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + } + + indexdone: + *a = n3 + regfree(&n2) + if freelen != 0 { + regfree(&nlen) + } + + default: + regalloc(a, gc.Types[gc.Tptr], res) + agen(n, a) + } +} + +/* + * generate: + * res = &n; + * The generated code checks that the result is not nil. + */ +func agen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var n1 gc.Node + var n2 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("\nagen-res", res) + gc.Dump("agen-r", n) + } + + if n == nil || n.Type == nil { + return + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { + // Use of a nil interface or nil slice. + // Create a temporary we can take the address of and read. + // The generated code is just going to panic, so it need not + // be terribly efficient. See issue 3670. + gc.Tempname(&n1, n.Type) + + gc.Gvardef(&n1) + clearfat(&n1) + regalloc(&n2, gc.Types[gc.Tptr], res) + gins(x86.ALEAQ, &n1, &n2) + gmove(&n2, res) + regfree(&n2) + goto ret + } + + if n.Addable != 0 { + regalloc(&n1, gc.Types[gc.Tptr], res) + gins(x86.ALEAQ, n, &n1) + gmove(&n1, res) + regfree(&n1) + goto ret + } + + nl = n.Left + + switch n.Op { + default: + gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + cgen_aret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_aret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_aret(n, res) + + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + agen(&n1, res) + + case gc.OEFACE: + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + agen(&n1, res) + + case gc.OINDEX: + agenr(n, &n1, res) + gmove(&n1, res) + regfree(&n1) + + // should only get here with names in this func. + case gc.ONAME: + if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) + } + + // should only get here for heap vars or paramref + if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME class %#x", n.Class) + } + + cgen(n.Heapaddr, res) + if n.Xoffset != 0 { + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + + case gc.OIND: + cgen(nl, res) + gc.Cgen_checknil(res) + + case gc.ODOT: + agen(nl, res) + if n.Xoffset != 0 { + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + + case gc.ODOTPTR: + cgen(nl, res) + gc.Cgen_checknil(res) + if n.Xoffset != 0 { + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + } + +ret: +} + +/* + * generate: + * newreg = &n; + * res = newreg + * + * on exit, a has been changed to be *newreg. + * caller must regfree(a). + * The generated code checks that the result is not *nil. + */ +func igen(n *gc.Node, a *gc.Node, res *gc.Node) { + var fp *gc.Type + var flist gc.Iter + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("\nigen-n", n) + } + + switch n.Op { + case gc.ONAME: + if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { + break + } + *a = *n + return + + // Increase the refcount of the register so that igen's caller + // has to call regfree. + case gc.OINDREG: + if n.Val.U.Reg != x86.REG_SP { + reg[n.Val.U.Reg]++ + } + *a = *n + return + + case gc.ODOT: + igen(n.Left, a, res) + a.Xoffset += n.Xoffset + a.Type = n.Type + fixlargeoffset(a) + return + + case gc.ODOTPTR: + cgenr(n.Left, a, res) + gc.Cgen_checknil(a) + a.Op = gc.OINDREG + a.Xoffset += n.Xoffset + a.Type = n.Type + fixlargeoffset(a) + return + + case gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + switch n.Op { + case gc.OCALLFUNC: + cgen_call(n, 0) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + + case gc.OCALLINTER: + cgen_callinter(n, nil, 0) + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) + *a = gc.Node{} + a.Op = gc.OINDREG + a.Val.U.Reg = x86.REG_SP + a.Addable = 1 + a.Xoffset = fp.Width + a.Type = n.Type + return + + // Index of fixed-size array by constant can + // put the offset in the addressing. + // Could do the same for slice except that we need + // to use the real index for the bounds checking. + case gc.OINDEX: + if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { + if gc.Isconst(n.Right, gc.CTINT) { + // Compute &a. + if gc.Isptr[n.Left.Type.Etype] == 0 { + igen(n.Left, a, res) + } else { + igen(n.Left, &n1, res) + gc.Cgen_checknil(&n1) + regalloc(a, gc.Types[gc.Tptr], res) + gmove(&n1, a) + regfree(&n1) + a.Op = gc.OINDREG + } + + // Compute &a[i] as &a + i*width. + a.Type = n.Type + + a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width + fixlargeoffset(a) + return + } + } + } + + agenr(n, a, res) + a.Op = gc.OINDREG + a.Type = n.Type +} + +/* + * generate: + * if(n == true) goto to; + */ +func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { + var et int + var a int + var nl *gc.Node + var nr *gc.Node + var l *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var tmp gc.Node + var ll *gc.NodeList + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['g'] != 0 { + gc.Dump("\nbgen", n) + } + + if n == nil { + n = gc.Nodbool(true) + } + + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + + if n.Type == nil { + gc.Convlit(&n, gc.Types[gc.TBOOL]) + if n.Type == nil { + goto ret + } + } + + et = int(n.Type.Etype) + if et != gc.TBOOL { + gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) + gc.Patch(gins(obj.AEND, nil, nil), to) + goto ret + } + + nr = nil + + for n.Op == gc.OCONVNOP { + n = n.Left + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + } + + switch n.Op { + default: + goto def + + // need to ask if it is bool? + case gc.OLITERAL: + if !true_ == (n.Val.U.Bval == 0) { + gc.Patch(gc.Gbranch(obj.AJMP, nil, likely), to) + } + goto ret + + case gc.ONAME: + if n.Addable == 0 { + goto def + } + gc.Nodconst(&n1, n.Type, 0) + gins(optoas(gc.OCMP, n.Type), n, &n1) + a = x86.AJNE + if !true_ { + a = x86.AJEQ + } + gc.Patch(gc.Gbranch(a, n.Type, likely), to) + goto ret + + case gc.OANDAND, + gc.OOROR: + if (n.Op == gc.OANDAND) == true_ { + p1 = gc.Gbranch(obj.AJMP, nil, 0) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n.Left, !true_, -likely, p2) + bgen(n.Right, !true_, -likely, p2) + p1 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, to) + gc.Patch(p2, gc.Pc) + } else { + bgen(n.Left, true_, likely, to) + bgen(n.Right, true_, likely, to) + } + + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + nr = n.Right + if nr == nil || nr.Type == nil { + goto ret + } + fallthrough + + case gc.ONOT: // unary + nl = n.Left + + if nl == nil || nl.Type == nil { + goto ret + } + } + + switch n.Op { + case gc.ONOT: + bgen(nl, !true_, likely, to) + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + a = int(n.Op) + if !true_ { + if gc.Isfloat[nr.Type.Etype] != 0 { + // brcom is not valid on floats when NaN is involved. + p1 = gc.Gbranch(obj.AJMP, nil, 0) + + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + ll = n.Ninit // avoid re-genning ninit + n.Ninit = nil + bgen(n, true, -likely, p2) + n.Ninit = ll + gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) + gc.Patch(p2, gc.Pc) + goto ret + } + + a = gc.Brcom(a) + true_ = !true_ + } + + // make simplest on right + if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { + a = gc.Brrev(a) + r = nl + nl = nr + nr = r + } + + if gc.Isslice(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal slice comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Xoffset += int64(gc.Array_array) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Isinter(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal interface comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Iscomplex[nl.Type.Etype] != 0 { + gc.Complexbool(a, nl, nr, true_, likely, to) + break + } + + if nr.Ullman >= gc.UINF { + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + + gc.Tempname(&tmp, nl.Type) + gmove(&n1, &tmp) + regfree(&n1) + + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + + regalloc(&n1, nl.Type, nil) + cgen(&tmp, &n1) + + goto cmp + } + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + + if gc.Smallintconst(nr) { + gins(optoas(gc.OCMP, nr.Type), &n1, nr) + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + regfree(&n1) + break + } + + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + + // only < and <= work right with NaN; reverse if needed + cmp: + l = &n1 + + r = &n2 + if gc.Isfloat[nl.Type.Etype] != 0 && (a == gc.OGT || a == gc.OGE) { + l = &n2 + r = &n1 + a = gc.Brrev(a) + } + + gins(optoas(gc.OCMP, nr.Type), l, r) + + if gc.Isfloat[nr.Type.Etype] != 0 && (n.Op == gc.OEQ || n.Op == gc.ONE) { + if n.Op == gc.OEQ { + // neither NE nor P + p1 = gc.Gbranch(x86.AJNE, nil, -likely) + + p2 = gc.Gbranch(x86.AJPS, nil, -likely) + gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) + gc.Patch(p1, gc.Pc) + gc.Patch(p2, gc.Pc) + } else { + // either NE or P + gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to) + + gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to) + } + } else { + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + } + regfree(&n1) + regfree(&n2) + } + + goto ret + +def: + regalloc(&n1, n.Type, nil) + cgen(n, &n1) + gc.Nodconst(&n2, n.Type, 0) + gins(optoas(gc.OCMP, n.Type), &n1, &n2) + a = x86.AJNE + if !true_ { + a = x86.AJEQ + } + gc.Patch(gc.Gbranch(a, n.Type, likely), to) + regfree(&n1) + goto ret + +ret: +} + +/* + * n is on stack, either local variable + * or return value from function call. + * return n's offset from SP. + */ +func stkof(n *gc.Node) int64 { + var t *gc.Type + var flist gc.Iter + var off int64 + + switch n.Op { + case gc.OINDREG: + return n.Xoffset + + case gc.ODOT: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + return off + n.Xoffset + + case gc.OINDEX: + t = n.Left.Type + if !gc.Isfixedarray(t) { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + if gc.Isconst(n.Right, gc.CTINT) { + return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval) + } + return 1000 + + case gc.OCALLMETH, + gc.OCALLINTER, + gc.OCALLFUNC: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + t = gc.Structfirst(&flist, gc.Getoutarg(t)) + if t != nil { + return t.Width + } + } + + // botch - probably failing to recognize address + // arithmetic on the above. eg INDEX and DOT + return -1000 +} + +/* + * block copy: + * memmove(&ns, &n, w); + */ +func sgen(n *gc.Node, ns *gc.Node, w int64) { + var nodl gc.Node + var nodr gc.Node + var nodsi gc.Node + var noddi gc.Node + var cx gc.Node + var oldcx gc.Node + var tmp gc.Node + var c int64 + var q int64 + var odst int64 + var osrc int64 + var l *gc.NodeList + var p *obj.Prog + + if gc.Debug['g'] != 0 { + fmt.Printf("\nsgen w=%d\n", w) + gc.Dump("r", n) + gc.Dump("res", ns) + } + + if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF { + gc.Fatal("sgen UINF") + } + + if w < 0 { + gc.Fatal("sgen copy %d", w) + } + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if ns.Op == gc.ONAME && ns.Sym.Name == ".args" { + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + if l.N.Class == gc.PPARAMOUT { + gc.Gvardef(l.N) + } + } + } + + // Avoid taking the address for simple enough types. + if componentgen(n, ns) { + return + } + + if w == 0 { + // evaluate side effects only + regalloc(&nodr, gc.Types[gc.Tptr], nil) + + agen(ns, &nodr) + agen(n, &nodr) + regfree(&nodr) + return + } + + // offset on the stack + osrc = stkof(n) + + odst = stkof(ns) + + if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + gc.Tempname(&tmp, n.Type) + + sgen(n, &tmp, w) + sgen(&tmp, ns, w) + return + } + + gc.Nodreg(&noddi, gc.Types[gc.Tptr], x86.REG_DI) + gc.Nodreg(&nodsi, gc.Types[gc.Tptr], x86.REG_SI) + + if n.Ullman >= ns.Ullman { + agenr(n, &nodr, &nodsi) + if ns.Op == gc.ONAME { + gc.Gvardef(ns) + } + agenr(ns, &nodl, &noddi) + } else { + if ns.Op == gc.ONAME { + gc.Gvardef(ns) + } + agenr(ns, &nodl, &noddi) + agenr(n, &nodr, &nodsi) + } + + if nodl.Val.U.Reg != x86.REG_DI { + gmove(&nodl, &noddi) + } + if nodr.Val.U.Reg != x86.REG_SI { + gmove(&nodr, &nodsi) + } + regfree(&nodl) + regfree(&nodr) + + c = w % 8 // bytes + q = w / 8 // quads + + savex(x86.REG_CX, &cx, &oldcx, nil, gc.Types[gc.TINT64]) + + // if we are copying forward on the stack and + // the src and dst overlap, then reverse direction + if osrc < odst && odst < osrc+w { + // reverse direction + gins(x86.ASTD, nil, nil) // set direction flag + if c > 0 { + gconreg(addptr, w-1, x86.REG_SI) + gconreg(addptr, w-1, x86.REG_DI) + + gconreg(movptr, c, x86.REG_CX) + gins(x86.AREP, nil, nil) // repeat + gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)- + } + + if q > 0 { + if c > 0 { + gconreg(addptr, -7, x86.REG_SI) + gconreg(addptr, -7, x86.REG_DI) + } else { + gconreg(addptr, w-8, x86.REG_SI) + gconreg(addptr, w-8, x86.REG_DI) + } + + gconreg(movptr, q, x86.REG_CX) + gins(x86.AREP, nil, nil) // repeat + gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)-,*(DI)- + } + + // we leave with the flag clear + gins(x86.ACLD, nil, nil) + } else { + // normal direction + if q > 128 || (gc.Nacl && q >= 4) { + gconreg(movptr, q, x86.REG_CX) + gins(x86.AREP, nil, nil) // repeat + gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+ + } else if q >= 4 { + p = gins(obj.ADUFFCOPY, nil, nil) + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg)) + + // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s + p.To.Offset = 14 * (128 - q) + } else if !gc.Nacl && c == 0 { + // We don't need the MOVSQ side-effect of updating SI and DI, + // and issuing a sequence of MOVQs directly is faster. + nodsi.Op = gc.OINDREG + + noddi.Op = gc.OINDREG + for q > 0 { + gmove(&nodsi, &cx) // MOVQ x+(SI),CX + gmove(&cx, &noddi) // MOVQ CX,x+(DI) + nodsi.Xoffset += 8 + noddi.Xoffset += 8 + q-- + } + } else { + for q > 0 { + gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+ + q-- + } + } + + // copy the remaining c bytes + if w < 4 || c <= 1 || (odst < osrc && osrc < odst+w) { + for c > 0 { + gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+ + c-- + } + } else if w < 8 || c <= 4 { + nodsi.Op = gc.OINDREG + noddi.Op = gc.OINDREG + cx.Type = gc.Types[gc.TINT32] + nodsi.Type = gc.Types[gc.TINT32] + noddi.Type = gc.Types[gc.TINT32] + if c > 4 { + nodsi.Xoffset = 0 + noddi.Xoffset = 0 + gmove(&nodsi, &cx) + gmove(&cx, &noddi) + } + + nodsi.Xoffset = c - 4 + noddi.Xoffset = c - 4 + gmove(&nodsi, &cx) + gmove(&cx, &noddi) + } else { + nodsi.Op = gc.OINDREG + noddi.Op = gc.OINDREG + cx.Type = gc.Types[gc.TINT64] + nodsi.Type = gc.Types[gc.TINT64] + noddi.Type = gc.Types[gc.TINT64] + nodsi.Xoffset = c - 8 + noddi.Xoffset = c - 8 + gmove(&nodsi, &cx) + gmove(&cx, &noddi) + } + } + + restx(&cx, &oldcx) +} + +func cadable(n *gc.Node) bool { + if n.Addable == 0 { + // dont know how it happens, + // but it does + return false + } + + switch n.Op { + case gc.ONAME: + return true + } + + return false +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * Small structs or arrays with elements of basic type are + * also supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if can't. + */ +func componentgen(nr *gc.Node, nl *gc.Node) bool { + var nodl gc.Node + var nodr gc.Node + var tmp gc.Node + var t *gc.Type + var freel int + var freer int + var fldcount int64 + var loffset int64 + var roffset int64 + + freel = 0 + freer = 0 + + switch nl.Type.Etype { + default: + goto no + + case gc.TARRAY: + t = nl.Type + + // Slices are ok. + if gc.Isslice(t) { + break + } + + // Small arrays are ok. + if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { + break + } + + goto no + + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + case gc.TSTRUCT: + fldcount = 0 + + for t = nl.Type.Type; t != nil; t = t.Down { + if gc.Isfat(t.Type) { + goto no + } + if t.Etype != gc.TFIELD { + gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) + } + fldcount++ + } + + if fldcount == 0 || fldcount > 4 { + goto no + } + + case gc.TSTRING, + gc.TINTER: + break + } + + nodl = *nl + if !cadable(nl) { + if nr != nil && !cadable(nr) { + goto no + } + igen(nl, &nodl, nil) + freel = 1 + } + + if nr != nil { + nodr = *nr + if !cadable(nr) { + igen(nr, &nodr, nil) + freer = 1 + } + } else { + // When zeroing, prepare a register containing zero. + gc.Nodconst(&tmp, nl.Type, 0) + + regalloc(&nodr, gc.Types[gc.TUINT], nil) + gmove(&tmp, &nodr) + freer = 1 + } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { + goto yes + } + + switch nl.Type.Etype { + // componentgen for arrays. + case gc.TARRAY: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + t = nl.Type + if !gc.Isslice(t) { + nodl.Type = t.Type + nodr.Type = nodl.Type + for fldcount = 0; fldcount < t.Bound; fldcount++ { + if nr == nil { + gc.Clearslim(&nodl) + } else { + gmove(&nodr, &nodl) + } + nodl.Xoffset += t.Type.Width + nodr.Xoffset += t.Type.Width + } + + goto yes + } + + // componentgen for slices. + nodl.Xoffset += int64(gc.Array_array) + + nodl.Type = gc.Ptrto(nl.Type.Type) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRING: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TINTER: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRUCT: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + loffset = nodl.Xoffset + roffset = nodr.Xoffset + + // funarg structs may not begin at offset zero. + if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { + loffset -= nl.Type.Type.Width + } + if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { + roffset -= nr.Type.Type.Width + } + + for t = nl.Type.Type; t != nil; t = t.Down { + nodl.Xoffset = loffset + t.Width + nodl.Type = t.Type + + if nr == nil { + gc.Clearslim(&nodl) + } else { + nodr.Xoffset = roffset + t.Width + nodr.Type = nodl.Type + gmove(&nodr, &nodl) + } + } + + goto yes + } + +no: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return false + +yes: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return true +} diff --git a/src/cmd/6g/doc.go b/src/cmd/6g/doc.go deleted file mode 100644 index 07b2818da4..0000000000 --- a/src/cmd/6g/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -6g is the version of the gc compiler for the x86-64. -The $GOARCH for these tools is amd64. - -It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go. - -*/ -package main diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c deleted file mode 100644 index fa9998b0ee..0000000000 --- a/src/cmd/6g/galign.c +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -int thechar = '6'; -char* thestring = "amd64"; -LinkArch* thelinkarch = &linkamd64; - -void -linkarchinit(void) -{ - if(strcmp(getgoarch(), "amd64p32") == 0) { - thelinkarch = &linkamd64p32; - thearch.thelinkarch = thelinkarch; - thestring = "amd64p32"; - thearch.thestring = "amd64p32"; - } -} - -vlong MAXWIDTH = 1LL<<50; - -int addptr = AADDQ; -int movptr = AMOVQ; -int leaptr = ALEAQ; -int cmpptr = ACMPQ; - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -Typedef typedefs[] = -{ - {"int", TINT, TINT64}, - {"uint", TUINT, TUINT64}, - {"uintptr", TUINTPTR, TUINT64}, - {0} -}; - -void -betypeinit(void) -{ - widthptr = 8; - widthint = 8; - widthreg = 8; - if(strcmp(getgoarch(), "amd64p32") == 0) { - widthptr = 4; - widthint = 4; - addptr = AADDL; - movptr = AMOVL; - leaptr = ALEAL; - cmpptr = ACMPL; - typedefs[0].sameas = TINT32; - typedefs[1].sameas = TUINT32; - typedefs[2].sameas = TUINT32; - - } - - listinit6(); -} - -void -main(int argc, char **argv) -{ - thearch.thechar = thechar; - thearch.thestring = thestring; - thearch.thelinkarch = thelinkarch; - thearch.typedefs = typedefs; - thearch.REGSP = REGSP; - thearch.REGCTXT = REGCTXT; - thearch.MAXWIDTH = MAXWIDTH; - thearch.anyregalloc = anyregalloc; - thearch.betypeinit = betypeinit; - thearch.bgen = bgen; - thearch.cgen = cgen; - thearch.cgen_call = cgen_call; - thearch.cgen_callinter = cgen_callinter; - thearch.cgen_ret = cgen_ret; - thearch.clearfat = clearfat; - thearch.defframe = defframe; - thearch.excise = excise; - thearch.expandchecks = expandchecks; - thearch.gclean = gclean; - thearch.ginit = ginit; - thearch.gins = gins; - thearch.ginscall = ginscall; - thearch.igen = igen; - thearch.linkarchinit = linkarchinit; - thearch.peep = peep; - thearch.proginfo = proginfo; - thearch.regalloc = regalloc; - thearch.regfree = regfree; - thearch.regtyp = regtyp; - thearch.sameaddr = sameaddr; - thearch.smallindir = smallindir; - thearch.stackaddr = stackaddr; - thearch.excludedregs = excludedregs; - thearch.RtoB = RtoB; - thearch.FtoB = FtoB; - thearch.BtoR = BtoR; - thearch.BtoF = BtoF; - thearch.optoas = optoas; - thearch.doregbits = doregbits; - thearch.regnames = regnames; - - gcmain(argc, argv); -} diff --git a/src/cmd/6g/galign.go b/src/cmd/6g/galign.go new file mode 100644 index 0000000000..bdd8a3c226 --- /dev/null +++ b/src/cmd/6g/galign.go @@ -0,0 +1,110 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" +) +import "cmd/internal/gc" + +var thechar int = '6' + +var thestring string = "amd64" + +var thelinkarch *obj.LinkArch = &x86.Linkamd64 + +func linkarchinit() { + if obj.Getgoarch() == "amd64p32" { + thelinkarch = &x86.Linkamd64p32 + gc.Thearch.Thelinkarch = thelinkarch + thestring = "amd64p32" + gc.Thearch.Thestring = "amd64p32" + } +} + +var MAXWIDTH int64 = 1 << 50 + +var addptr int = x86.AADDQ + +var movptr int = x86.AMOVQ + +var leaptr int = x86.ALEAQ + +var cmpptr int = x86.ACMPQ + +/* + * go declares several platform-specific type aliases: + * int, uint, float, and uintptr + */ +var typedefs = []gc.Typedef{ + gc.Typedef{"int", gc.TINT, gc.TINT64}, + gc.Typedef{"uint", gc.TUINT, gc.TUINT64}, + gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64}, +} + +func betypeinit() { + gc.Widthptr = 8 + gc.Widthint = 8 + gc.Widthreg = 8 + if obj.Getgoarch() == "amd64p32" { + gc.Widthptr = 4 + gc.Widthint = 4 + addptr = x86.AADDL + movptr = x86.AMOVL + leaptr = x86.ALEAL + cmpptr = x86.ACMPL + typedefs[0].Sameas = gc.TINT32 + typedefs[1].Sameas = gc.TUINT32 + typedefs[2].Sameas = gc.TUINT32 + } + +} + +func main() { + gc.Thearch.Thechar = thechar + gc.Thearch.Thestring = thestring + gc.Thearch.Thelinkarch = thelinkarch + gc.Thearch.Typedefs = typedefs + gc.Thearch.REGSP = x86.REGSP + gc.Thearch.REGCTXT = x86.REGCTXT + gc.Thearch.MAXWIDTH = MAXWIDTH + gc.Thearch.Anyregalloc = anyregalloc + gc.Thearch.Betypeinit = betypeinit + gc.Thearch.Bgen = bgen + gc.Thearch.Cgen = cgen + gc.Thearch.Cgen_call = cgen_call + gc.Thearch.Cgen_callinter = cgen_callinter + gc.Thearch.Cgen_ret = cgen_ret + gc.Thearch.Clearfat = clearfat + gc.Thearch.Defframe = defframe + gc.Thearch.Excise = excise + gc.Thearch.Expandchecks = expandchecks + gc.Thearch.Gclean = gclean + gc.Thearch.Ginit = ginit + gc.Thearch.Gins = gins + gc.Thearch.Ginscall = ginscall + gc.Thearch.Igen = igen + gc.Thearch.Linkarchinit = linkarchinit + gc.Thearch.Peep = peep + gc.Thearch.Proginfo = proginfo + gc.Thearch.Regalloc = regalloc + gc.Thearch.Regfree = regfree + gc.Thearch.Regtyp = regtyp + gc.Thearch.Sameaddr = sameaddr + gc.Thearch.Smallindir = smallindir + gc.Thearch.Stackaddr = stackaddr + gc.Thearch.Excludedregs = excludedregs + gc.Thearch.RtoB = RtoB + gc.Thearch.FtoB = FtoB + gc.Thearch.BtoR = BtoR + gc.Thearch.BtoF = BtoF + gc.Thearch.Optoas = optoas + gc.Thearch.Doregbits = doregbits + gc.Thearch.Regnames = regnames + + gc.Main() + gc.Exit(0) +} diff --git a/src/cmd/6g/gg.go b/src/cmd/6g/gg.go new file mode 100644 index 0000000000..2deed5deb9 --- /dev/null +++ b/src/cmd/6g/gg.go @@ -0,0 +1,24 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "cmd/internal/obj/x86" +import "cmd/internal/gc" + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +var reg [x86.MAXREG]uint8 + +var panicdiv *gc.Node + +/* + * cgen.c + */ + +/* + * list.c + */ diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h deleted file mode 100644 index a6dfad9c8e..0000000000 --- a/src/cmd/6g/gg.h +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef EXTERN -#define EXTERN extern -#endif - -#include "../gc/go.h" -#include "../6l/6.out.h" - -EXTERN uchar reg[MAXREG]; -EXTERN Node* panicdiv; -extern vlong unmappedzero; -extern int addptr; -extern int cmpptr; -extern int movptr; -extern int leaptr; - -/* - * ggen.c - */ -void compile(Node*); -void gen(Node*); -Node* lookdot(Node*, Node*, int); -void cgen_as(Node*, Node*); -void cgen_callmeth(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_proc(Node*, int); -void cgen_callret(Node*, Node*); -void cgen_div(int, Node*, Node*, Node*); -void cgen_bmul(int, Node*, Node*, Node*); -void cgen_hmul(Node*, Node*, Node*); -void cgen_shift(int, int, Node*, Node*, Node*); -void cgen_dcl(Node*); -int needconvert(Type*, Type*); -void genconv(Type*, Type*); -void allocparams(void); -void checklabels(void); -void ginscall(Node*, int); -int gen_as_init(Node*); - -/* - * cgen.c - */ -void agen(Node*, Node*); -void agenr(Node*, Node*, Node*); -void cgenr(Node*, Node*, Node*); -void igen(Node*, Node*, Node*); -vlong fieldoffset(Type*, Node*); -void sgen(Node*, Node*, int64); -void gmove(Node*, Node*); -Prog* gins(int, Node*, Node*); -int samaddr(Node*, Node*); -void naddr(Node*, Addr*, int); -void cgen_aret(Node*, Node*); -void restx(Node*, Node*); -void savex(int, Node*, Node*, Node*, Type*); -int componentgen(Node*, Node*); - -/* - * gsubr.c - */ -void clearp(Prog*); -Prog* gbranch(int, Type*, int); -Prog* prog(int); -void gconv(int, int); -int conv2pt(Type*); -vlong convvtox(vlong, int); -void fnparam(Type*, int, int); -Prog* gop(int, Node*, Node*, Node*); -int optoas(int, Type*); -void ginit(void); -void gclean(void); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -Node* nodarg(Type*, int); -void nodreg(Node*, Type*, int); -void nodindreg(Node*, Type*, int); -void gconreg(int, vlong, int); -void ginscon(int, vlong, Node*); -void buildtxt(void); -Plist* newplist(void); -int isfat(Type*); -void sudoclean(void); -int sudoaddable(int, Node*, Addr*); -void afunclit(Addr*, Node*); -void nodfconst(Node*, Type*, Mpflt*); -void gtrack(Sym*); -void fixlargeoffset(Node *n); - -/* - * cplx.c - */ -int complexop(Node*, Node*); -void complexmove(Node*, Node*); -void complexgen(Node*, Node*); - -/* - * gobj.c - */ -void datastring(char*, int, Addr*); -void datagostring(Strlit*, Addr*); - -/* - * list.c - */ -void listinit(void); - -void zaddr(Biobuf*, Addr*, int, int); - -void afunclit(Addr*, Node*); -int anyregalloc(void); -void betypeinit(void); -void bgen(Node*, int, int, Prog*); -void cgen(Node*, Node*); -void cgen_call(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_ret(Node*); -void clearfat(Node*); -void clearp(Prog*); -void defframe(Prog*); -int dgostringptr(Sym*, int, char*); -int dgostrlitptr(Sym*, int, Strlit*); -int dsname(Sym*, int, char*, int); -int dsymptr(Sym*, int, Sym*, int); -void dumpdata(void); -void dumpit(char*, Flow*, int); -void excise(Flow*); -void expandchecks(Prog*); -void fixautoused(Prog*); -void gclean(void); -void gdata(Node*, Node*, int); -void gdatacomplex(Node*, Mpcplx*); -void gdatastring(Node*, Strlit*); -void ggloblnod(Node *nam); -void ggloblsym(Sym *s, int32 width, int8 flags); -void ginit(void); -Prog* gins(int, Node*, Node*); -void ginscall(Node*, int); -Prog* gjmp(Prog*); -void gtrack(Sym*); -void gused(Node*); -void igen(Node*, Node*, Node*); -int isfat(Type*); -void linkarchinit(void); -void markautoused(Prog*); -void naddr(Node*, Addr*, int); -Plist* newplist(void); -Node* nodarg(Type*, int); -void patch(Prog*, Prog*); -void proginfo(ProgInfo*, Prog*); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -void regopt(Prog*); -int regtyp(Addr*); -int sameaddr(Addr*, Addr*); -int smallindir(Addr*, Addr*); -int stackaddr(Addr*); -Prog* unpatch(Prog*); - -/* - * reg.c - */ -uint64 excludedregs(void); -uint64 RtoB(int); -uint64 FtoB(int); -int BtoR(uint64); -int BtoF(uint64); -uint64 doregbits(int); -char** regnames(int*); - -/* - * peep.c - */ -void peep(Prog*); diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c deleted file mode 100644 index 72104589a3..0000000000 --- a/src/cmd/6g/ggen.c +++ /dev/null @@ -1,1046 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#undef EXTERN -#define EXTERN -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong); -static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax); - -void -defframe(Prog *ptxt) -{ - uint32 frame, ax; - Prog *p; - vlong hi, lo; - NodeList *l; - Node *n; - - // fill in argument size, stack size - ptxt->to.type = TYPE_TEXTSIZE; - ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr); - frame = rnd(stksize+maxarg, widthreg); - ptxt->to.offset = frame; - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt; - lo = hi = 0; - ax = 0; - // iterate through declarations - they are sorted in decreasing xoffset order. - for(l=curfn->dcl; l != nil; l = l->next) { - n = l->n; - if(!n->needzero) - continue; - if(n->class != PAUTO) - fatal("needzero class %d", n->class); - if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) - fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); - - if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) { - // merge with range we already have - lo = n->xoffset; - continue; - } - // zero old range - p = zerorange(p, frame, lo, hi, &ax); - - // set new range - hi = n->xoffset + n->type->width; - lo = n->xoffset; - } - // zero final range - zerorange(p, frame, lo, hi, &ax); -} - -static Prog* -zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax) -{ - vlong cnt, i; - - cnt = hi - lo; - if(cnt == 0) - return p; - if(*ax == 0) { - p = appendpp(p, AMOVQ, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0); - *ax = 1; - } - if(cnt % widthreg != 0) { - // should only happen with nacl - if(cnt % widthptr != 0) - fatal("zerorange count not a multiple of widthptr %d", cnt); - p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo); - lo += widthptr; - cnt -= widthptr; - } - if(cnt <= 4*widthreg) { - for(i = 0; i < cnt; i += widthreg) { - p = appendpp(p, AMOVQ, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i); - } - } else if(!nacl && (cnt <= 128*widthreg)) { - p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0); - p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 2*(128-cnt/widthreg)); - p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - } else { - p = appendpp(p, AMOVQ, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0); - p = appendpp(p, leaptr, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0); - p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0); - p = appendpp(p, ASTOSQ, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0); - } - return p; -} - -static Prog* -appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset) -{ - Prog *q; - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) - */ -void -ginscall(Node *f, int proc) -{ - Prog *p; - Node reg, stk; - Node r1; - int32 extra; - - if(f->type != T) { - extra = 0; - if(proc == 1 || proc == 2) - extra = 2 * widthptr; - setmaxarg(f->type, extra); - } - - switch(proc) { - default: - fatal("ginscall: bad proc %d", proc); - break; - - case 0: // normal call - case -1: // normal call but no return - if(f->op == ONAME && f->class == PFUNC) { - if(f == deferreturn) { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an x86 NOP that we will have the right line number. - // x86 NOP 0x90 is really XCHG AX, AX; use that description - // because the NOP pseudo-instruction would be removed by - // the linker. - nodreg(®, types[TINT], REG_AX); - gins(AXCHGL, ®, ®); - } - p = gins(ACALL, N, f); - afunclit(&p->to, f); - if(proc == -1 || noreturn(p)) - gins(AUNDEF, N, N); - break; - } - nodreg(®, types[tptr], REG_DX); - nodreg(&r1, types[tptr], REG_BX); - gmove(f, ®); - reg.op = OINDREG; - gmove(®, &r1); - reg.op = OREGISTER; - gins(ACALL, ®, &r1); - break; - - case 3: // normal call of c function pointer - gins(ACALL, N, f); - break; - - case 1: // call in new proc (go) - case 2: // deferred call (defer) - memset(&stk, 0, sizeof(stk)); - stk.op = OINDREG; - stk.val.u.reg = REG_SP; - stk.xoffset = 0; - - if(widthptr == 8) { - // size of arguments at 0(SP) - ginscon(AMOVQ, argsize(f->type), &stk); - - // FuncVal* at 8(SP) - stk.xoffset = widthptr; - nodreg(®, types[TINT64], REG_AX); - gmove(f, ®); - gins(AMOVQ, ®, &stk); - } else { - // size of arguments at 0(SP) - ginscon(AMOVL, argsize(f->type), &stk); - - // FuncVal* at 4(SP) - stk.xoffset = widthptr; - nodreg(®, types[TINT32], REG_AX); - gmove(f, ®); - gins(AMOVL, ®, &stk); - } - - if(proc == 1) - ginscall(newproc, 0); - else { - if(!hasdefer) - fatal("hasdefer=0 but has defer"); - ginscall(deferproc, 0); - } - if(proc == 2) { - nodreg(®, types[TINT32], REG_AX); - gins(ATESTL, ®, ®); - p = gbranch(AJEQ, T, +1); - cgen_ret(N); - patch(p, pc); - } - break; - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -void -cgen_callinter(Node *n, Node *res, int proc) -{ - Node *i, *f; - Node tmpi, nodi, nodo, nodr, nodsp; - - i = n->left; - if(i->op != ODOTINTER) - fatal("cgen_callinter: not ODOTINTER %O", i->op); - - f = i->right; // field - if(f->op != ONAME) - fatal("cgen_callinter: not ONAME %O", f->op); - - i = i->left; // interface - - if(!i->addable) { - tempname(&tmpi, i->type); - cgen(i, &tmpi); - i = &tmpi; - } - - genlist(n->list); // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res); // REG = &inter - - nodindreg(&nodsp, types[tptr], REG_SP); - nodsp.xoffset = 0; - if(proc != 0) - nodsp.xoffset += 2 * widthptr; // leave room for size & fn - nodi.type = types[tptr]; - nodi.xoffset += widthptr; - cgen(&nodi, &nodsp); // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data - - regalloc(&nodo, types[tptr], res); - nodi.type = types[tptr]; - nodi.xoffset -= widthptr; - cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab - regfree(&nodi); - - regalloc(&nodr, types[tptr], &nodo); - if(n->left->xoffset == BADWIDTH) - fatal("cgen_callinter: badwidth"); - cgen_checknil(&nodo); // in case offset is huge - nodo.op = OINDREG; - nodo.xoffset = n->left->xoffset + 3*widthptr + 8; - if(proc == 0) { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f] - proc = 3; - } else { - // go/defer. generate go func value. - gins(ALEAQ, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.tab->fun[f] - } - - nodr.type = n->left->type; - ginscall(&nodr, proc); - - regfree(&nodr); - regfree(&nodo); -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -void -cgen_call(Node *n, int proc) -{ - Type *t; - Node nod, afun; - - if(n == N) - return; - - if(n->left->ullman >= UINF) { - // if name involves a fn call - // precompute the address of the fn - tempname(&afun, types[tptr]); - cgen(n->left, &afun); - } - - genlist(n->list); // assign the args - t = n->left->type; - - // call tempname pointer - if(n->left->ullman >= UINF) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, &afun); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call pointer - if(n->left->op != ONAME || n->left->class != PFUNC) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, n->left); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call direct - n->left->method = 1; - ginscall(n->left, proc); -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -void -cgen_callret(Node *n, Node *res) -{ - Node nod; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(t->etype == TPTR32 || t->etype == TPTR64) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_callret: nil"); - - memset(&nod, 0, sizeof(nod)); - nod.op = OINDREG; - nod.val.u.reg = REG_SP; - nod.addable = 1; - - nod.xoffset = fp->width; - nod.type = fp->type; - cgen_as(res, &nod); -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -void -cgen_aret(Node *n, Node *res) -{ - Node nod1, nod2; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_aret: nil"); - - memset(&nod1, 0, sizeof(nod1)); - nod1.op = OINDREG; - nod1.val.u.reg = REG_SP; - nod1.addable = 1; - - nod1.xoffset = fp->width; - nod1.type = fp->type; - - if(res->op != OREGISTER) { - regalloc(&nod2, types[tptr], res); - gins(leaptr, &nod1, &nod2); - gins(movptr, &nod2, res); - regfree(&nod2); - } else - gins(leaptr, &nod1, res); -} - -/* - * generate return. - * n->left is assignments to return values. - */ -void -cgen_ret(Node *n) -{ - Prog *p; - - if(n != N) - genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - genlist(curfn->exit); - p = gins(ARET, N, N); - if(n != N && n->op == ORETJMP) { - p->to.type = TYPE_MEM; - p->to.name = NAME_EXTERN; - p->to.sym = linksym(n->left->sym); - } -} - -/* - * generate division. - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -void -dodiv(int op, Node *nl, Node *nr, Node *res) -{ - int a, check; - Node n3, n4; - Type *t, *t0; - Node ax, dx, ax1, n31, oldax, olddx; - Prog *p1, *p2; - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will trap. - // Also the byte divide instruction needs AH, - // which we otherwise don't have to deal with. - // Easiest way to avoid for int8, int16: use int32. - // For int32 and int64, use explicit test. - // Could use int64 hw for int32. - t = nl->type; - t0 = t; - check = 0; - if(issigned[t->etype]) { - check = 1; - if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1))) - check = 0; - else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1) - check = 0; - } - if(t->width < 4) { - if(issigned[t->etype]) - t = types[TINT32]; - else - t = types[TUINT32]; - check = 0; - } - a = optoas(op, t); - - regalloc(&n3, t0, N); - if(nl->ullman >= nr->ullman) { - savex(REG_AX, &ax, &oldax, res, t0); - cgen(nl, &ax); - regalloc(&ax, t0, &ax); // mark ax live during cgen - cgen(nr, &n3); - regfree(&ax); - } else { - cgen(nr, &n3); - savex(REG_AX, &ax, &oldax, res, t0); - cgen(nl, &ax); - } - if(t != t0) { - // Convert - ax1 = ax; - n31 = n3; - ax.type = t; - n3.type = t; - gmove(&ax1, &ax); - gmove(&n31, &n3); - } - - p2 = P; - if(nacl) { - // Native Client does not relay the divide-by-zero trap - // to the executing program, so we must insert a check - // for ourselves. - nodconst(&n4, t, 0); - gins(optoas(OCMP, t), &n3, &n4); - p1 = gbranch(optoas(ONE, t), T, +1); - if(panicdiv == N) - panicdiv = sysfunc("panicdivide"); - ginscall(panicdiv, -1); - patch(p1, pc); - } - if(check) { - nodconst(&n4, t, -1); - gins(optoas(OCMP, t), &n3, &n4); - p1 = gbranch(optoas(ONE, t), T, +1); - if(op == ODIV) { - // a / (-1) is -a. - gins(optoas(OMINUS, t), N, &ax); - gmove(&ax, res); - } else { - // a % (-1) is 0. - nodconst(&n4, t, 0); - gmove(&n4, res); - } - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - } - savex(REG_DX, &dx, &olddx, res, t); - if(!issigned[t->etype]) { - nodconst(&n4, t, 0); - gmove(&n4, &dx); - } else - gins(optoas(OEXTEND, t), N, N); - gins(a, &n3, N); - regfree(&n3); - if(op == ODIV) - gmove(&ax, res); - else - gmove(&dx, res); - restx(&dx, &olddx); - if(check) - patch(p2, pc); - restx(&ax, &oldax); -} - -/* - * register dr is one of the special ones (AX, CX, DI, SI, etc.). - * we need to use it. if it is already allocated as a temporary - * (r > 1; can only happen if a routine like sgen passed a - * special as cgen's res and then cgen used regalloc to reuse - * it as its own temporary), then move it for now to another - * register. caller must call restx to move it back. - * the move is not necessary if dr == res, because res is - * known to be dead. - */ -void -savex(int dr, Node *x, Node *oldx, Node *res, Type *t) -{ - int r; - - r = reg[dr]; - - // save current ax and dx if they are live - // and not the destination - memset(oldx, 0, sizeof *oldx); - nodreg(x, t, dr); - if(r > 1 && !samereg(x, res)) { - regalloc(oldx, types[TINT64], N); - x->type = types[TINT64]; - gmove(x, oldx); - x->type = t; - oldx->ostk = r; // squirrel away old r value - reg[dr] = 1; - } -} - -void -restx(Node *x, Node *oldx) -{ - if(oldx->op != 0) { - x->type = types[TINT64]; - reg[x->val.u.reg] = oldx->ostk; - gmove(oldx, x); - regfree(oldx); - } -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -void -cgen_div(int op, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3; - int w, a; - Magic m; - - if(nr->op != OLITERAL) - goto longdiv; - w = nl->type->width*8; - - // Front end handled 32-bit division. We only need to handle 64-bit. - // try to do division by multiply by (2^w)/d - // see hacker's delight chapter 10 - switch(simtype[nl->type->etype]) { - default: - goto longdiv; - - case TUINT64: - m.w = w; - m.ud = mpgetfix(nr->val.u.xval); - umagic(&m); - if(m.bad) - break; - if(op == OMOD) - goto longmod; - - cgenr(nl, &n1, N); - nodconst(&n2, nl->type, m.um); - regalloc(&n3, nl->type, res); - cgen_hmul(&n1, &n2, &n3); - - if(m.ua) { - // need to add numerator accounting for overflow - gins(optoas(OADD, nl->type), &n1, &n3); - nodconst(&n2, nl->type, 1); - gins(optoas(ORROTC, nl->type), &n2, &n3); - nodconst(&n2, nl->type, m.s-1); - gins(optoas(ORSH, nl->type), &n2, &n3); - } else { - nodconst(&n2, nl->type, m.s); - gins(optoas(ORSH, nl->type), &n2, &n3); // shift dx - } - - gmove(&n3, res); - regfree(&n1); - regfree(&n3); - return; - - case TINT64: - m.w = w; - m.sd = mpgetfix(nr->val.u.xval); - smagic(&m); - if(m.bad) - break; - if(op == OMOD) - goto longmod; - - cgenr(nl, &n1, res); - nodconst(&n2, nl->type, m.sm); - regalloc(&n3, nl->type, N); - cgen_hmul(&n1, &n2, &n3); - - if(m.sm < 0) { - // need to add numerator - gins(optoas(OADD, nl->type), &n1, &n3); - } - - nodconst(&n2, nl->type, m.s); - gins(optoas(ORSH, nl->type), &n2, &n3); // shift n3 - - nodconst(&n2, nl->type, w-1); - gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg - gins(optoas(OSUB, nl->type), &n1, &n3); // added - - if(m.sd < 0) { - // this could probably be removed - // by factoring it into the multiplier - gins(optoas(OMINUS, nl->type), N, &n3); - } - - gmove(&n3, res); - regfree(&n1); - regfree(&n3); - return; - } - goto longdiv; - -longdiv: - // division and mod using (slow) hardware instruction - dodiv(op, nl, nr, res); - return; - -longmod: - // mod using formula A%B = A-(A/B*B) but - // we know that there is a fast algorithm for A/B - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - regalloc(&n2, nl->type, N); - cgen_div(ODIV, &n1, nr, &n2); - a = optoas(OMUL, nl->type); - if(w == 8) { - // use 2-operand 16-bit multiply - // because there is no 2-operand 8-bit multiply - a = AIMULW; - } - if(!smallintconst(nr)) { - regalloc(&n3, nl->type, N); - cgen(nr, &n3); - gins(a, &n3, &n2); - regfree(&n3); - } else - gins(a, nr, &n2); - gins(optoas(OSUB, nl->type), &n2, &n1); - gmove(&n1, res); - regfree(&n1); - regfree(&n2); -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -void -cgen_hmul(Node *nl, Node *nr, Node *res) -{ - Type *t; - int a; - Node n1, n2, ax, dx, *tmp; - - t = nl->type; - a = optoas(OHMUL, t); - if(nl->ullman < nr->ullman) { - tmp = nl; - nl = nr; - nr = tmp; - } - cgenr(nl, &n1, res); - cgenr(nr, &n2, N); - nodreg(&ax, t, REG_AX); - gmove(&n1, &ax); - gins(a, &n2, N); - regfree(&n2); - regfree(&n1); - - if(t->width == 1) { - // byte multiply behaves differently. - nodreg(&ax, t, REG_AH); - nodreg(&dx, t, REG_DX); - gmove(&ax, &dx); - } - nodreg(&dx, t, REG_DX); - gmove(&dx, res); -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -void -cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3, n4, n5, cx, oldcx; - int a, rcx; - Prog *p1; - uvlong sc; - Type *tcount; - - a = optoas(op, nl->type); - - if(nr->op == OLITERAL) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - sc = mpgetfix(nr->val.u.xval); - if(sc >= nl->type->width*8) { - // large shift gets 2 shifts by width-1 - nodconst(&n3, types[TUINT32], nl->type->width*8-1); - gins(a, &n3, &n1); - gins(a, &n3, &n1); - } else - gins(a, nr, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - } - - if(nl->ullman >= UINF) { - tempname(&n4, nl->type); - cgen(nl, &n4); - nl = &n4; - } - if(nr->ullman >= UINF) { - tempname(&n5, nr->type); - cgen(nr, &n5); - nr = &n5; - } - - rcx = reg[REG_CX]; - nodreg(&n1, types[TUINT32], REG_CX); - - // Allow either uint32 or uint64 as shift type, - // to avoid unnecessary conversion from uint32 to uint64 - // just to do the comparison. - tcount = types[simtype[nr->type->etype]]; - if(tcount->etype < TUINT32) - tcount = types[TUINT32]; - - regalloc(&n1, nr->type, &n1); // to hold the shift type in CX - regalloc(&n3, tcount, &n1); // to clear high bits of CX - - nodreg(&cx, types[TUINT64], REG_CX); - memset(&oldcx, 0, sizeof oldcx); - if(rcx > 0 && !samereg(&cx, res)) { - regalloc(&oldcx, types[TUINT64], N); - gmove(&cx, &oldcx); - } - cx.type = tcount; - - if(samereg(&cx, res)) - regalloc(&n2, nl->type, N); - else - regalloc(&n2, nl->type, res); - if(nl->ullman >= nr->ullman) { - cgen(nl, &n2); - cgen(nr, &n1); - gmove(&n1, &n3); - } else { - cgen(nr, &n1); - gmove(&n1, &n3); - cgen(nl, &n2); - } - regfree(&n3); - - // test and fix up large shifts - if(!bounded) { - nodconst(&n3, tcount, nl->type->width*8); - gins(optoas(OCMP, tcount), &n1, &n3); - p1 = gbranch(optoas(OLT, tcount), T, +1); - if(op == ORSH && issigned[nl->type->etype]) { - nodconst(&n3, types[TUINT32], nl->type->width*8-1); - gins(a, &n3, &n2); - } else { - nodconst(&n3, nl->type, 0); - gmove(&n3, &n2); - } - patch(p1, pc); - } - - gins(a, &n1, &n2); - - if(oldcx.op != 0) { - cx.type = types[TUINT64]; - gmove(&oldcx, &cx); - regfree(&oldcx); - } - - gmove(&n2, res); - - regfree(&n1); - regfree(&n2); - -ret: - ; -} - -/* - * generate byte multiply: - * res = nl * nr - * there is no 2-operand byte multiply instruction so - * we do a full-width multiplication and truncate afterwards. - */ -void -cgen_bmul(int op, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n1b, n2b, *tmp; - Type *t; - int a; - - // largest ullman on left. - if(nl->ullman < nr->ullman) { - tmp = nl; - nl = nr; - nr = tmp; - } - - // generate operands in "8-bit" registers. - regalloc(&n1b, nl->type, res); - cgen(nl, &n1b); - regalloc(&n2b, nr->type, N); - cgen(nr, &n2b); - - // perform full-width multiplication. - t = types[TUINT64]; - if(issigned[nl->type->etype]) - t = types[TINT64]; - nodreg(&n1, t, n1b.val.u.reg); - nodreg(&n2, t, n2b.val.u.reg); - a = optoas(op, t); - gins(a, &n2, &n1); - - // truncate. - gmove(&n1, res); - regfree(&n1b); - regfree(&n2b); -} - -void -clearfat(Node *nl) -{ - int64 w, c, q; - Node n1, oldn1, ax, oldax, di, z; - Prog *p; - - /* clear a fat object */ - if(debug['g']) - dump("\nclearfat", nl); - - w = nl->type->width; - // Avoid taking the address for simple enough types. - if(componentgen(N, nl)) - return; - - c = w % 8; // bytes - q = w / 8; // quads - - if(q < 4) { - // Write sequence of MOV 0, off(base) instead of using STOSQ. - // The hope is that although the code will be slightly longer, - // the MOVs will have no dependencies and pipeline better - // than the unrolled STOSQ loop. - // NOTE: Must use agen, not igen, so that optimizer sees address - // being taken. We are not writing on field boundaries. - agenr(nl, &n1, N); - n1.op = OINDREG; - nodconst(&z, types[TUINT64], 0); - while(q-- > 0) { - n1.type = z.type; - gins(AMOVQ, &z, &n1); - n1.xoffset += 8; - } - if(c >= 4) { - nodconst(&z, types[TUINT32], 0); - n1.type = z.type; - gins(AMOVL, &z, &n1); - n1.xoffset += 4; - c -= 4; - } - nodconst(&z, types[TUINT8], 0); - while(c-- > 0) { - n1.type = z.type; - gins(AMOVB, &z, &n1); - n1.xoffset++; - } - regfree(&n1); - return; - } - - savex(REG_DI, &n1, &oldn1, N, types[tptr]); - agen(nl, &n1); - - savex(REG_AX, &ax, &oldax, N, types[tptr]); - gconreg(AMOVL, 0, REG_AX); - - if(q > 128 || nacl) { - gconreg(movptr, q, REG_CX); - gins(AREP, N, N); // repeat - gins(ASTOSQ, N, N); // STOQ AL,*(DI)+ - } else { - p = gins(ADUFFZERO, N, N); - p->to.type = TYPE_ADDR; - p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s - p->to.offset = 2*(128-q); - } - - z = ax; - di = n1; - if(w >= 8 && c >= 4) { - di.op = OINDREG; - di.type = z.type = types[TINT64]; - p = gins(AMOVQ, &z, &di); - p->to.scale = 1; - p->to.offset = c-8; - } else if(c >= 4) { - di.op = OINDREG; - di.type = z.type = types[TINT32]; - p = gins(AMOVL, &z, &di); - if(c > 4) { - p = gins(AMOVL, &z, &di); - p->to.scale = 1; - p->to.offset = c-4; - } - } else - while(c > 0) { - gins(ASTOSB, N, N); // STOB AL,*(DI)+ - c--; - } - - restx(&n1, &oldn1); - restx(&ax, &oldax); -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -void -expandchecks(Prog *firstp) -{ - Prog *p, *p1, *p2; - - for(p = firstp; p != P; p = p->link) { - if(p->as != ACHECKNIL) - continue; - if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers - warnl(p->lineno, "generated nil check"); - // check is - // CMP arg, $0 - // JNE 2(PC) (likely) - // MOV AX, 0 - p1 = mal(sizeof *p1); - p2 = mal(sizeof *p2); - clearp(p1); - clearp(p2); - p1->link = p2; - p2->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - p2->lineno = p->lineno; - p1->pc = 9999; - p2->pc = 9999; - p->as = cmpptr; - p->to.type = TYPE_CONST; - p->to.offset = 0; - p1->as = AJNE; - p1->from.type = TYPE_CONST; - p1->from.offset = 1; // likely - p1->to.type = TYPE_BRANCH; - p1->to.u.branch = p2->link; - // crash by write to memory address 0. - // if possible, since we know arg is 0, use 0(arg), - // which will be shorter to encode than plain 0. - p2->as = AMOVL; - p2->from.type = TYPE_REG; - p2->from.reg = REG_AX; - if(regtyp(&p->from)) { - p2->to.type = TYPE_MEM; - p2->to.reg = p->from.reg; - } else { - p2->to.type = TYPE_MEM; - p2->to.reg = REG_NONE; - } - p2->to.offset = 0; - } -} diff --git a/src/cmd/6g/ggen.go b/src/cmd/6g/ggen.go new file mode 100644 index 0000000000..be6ff2152e --- /dev/null +++ b/src/cmd/6g/ggen.go @@ -0,0 +1,1169 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" +) +import "cmd/internal/gc" + +func defframe(ptxt *obj.Prog) { + var frame uint32 + var ax uint32 + var p *obj.Prog + var hi int64 + var lo int64 + var l *gc.NodeList + var n *gc.Node + + // fill in argument size, stack size + ptxt.To.Type = obj.TYPE_TEXTSIZE + + ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) + frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) + ptxt.To.Offset = int64(frame) + + // insert code to zero ambiguously live variables + // so that the garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt + + hi = 0 + lo = hi + ax = 0 + + // iterate through declarations - they are sorted in decreasing xoffset order. + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + n = l.N + if n.Needzero == 0 { + continue + } + if n.Class != gc.PAUTO { + gc.Fatal("needzero class %d", n.Class) + } + if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { + gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) + } + + if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) { + // merge with range we already have + lo = n.Xoffset + + continue + } + + // zero old range + p = zerorange(p, int64(frame), lo, hi, &ax) + + // set new range + hi = n.Xoffset + n.Type.Width + + lo = n.Xoffset + } + + // zero final range + zerorange(p, int64(frame), lo, hi, &ax) +} + +func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog { + var cnt int64 + var i int64 + + cnt = hi - lo + if cnt == 0 { + return p + } + if *ax == 0 { + p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0) + *ax = 1 + } + + if cnt%int64(gc.Widthreg) != 0 { + // should only happen with nacl + if cnt%int64(gc.Widthptr) != 0 { + gc.Fatal("zerorange count not a multiple of widthptr %d", cnt) + } + p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo) + lo += int64(gc.Widthptr) + cnt -= int64(gc.Widthptr) + } + + if cnt <= int64(4*gc.Widthreg) { + for i = 0; i < cnt; i += int64(gc.Widthreg) { + p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i) + } + } else if !gc.Nacl && (cnt <= int64(128*gc.Widthreg)) { + p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0) + p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 2*(128-cnt/int64(gc.Widthreg))) + p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) + } else { + p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0) + p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0) + p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) + p = appendpp(p, x86.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) + } + + return p +} + +func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { + var q *obj.Prog + q = gc.Ctxt.NewProg() + gc.Clearp(q) + q.As = int16(as) + q.Lineno = p.Lineno + q.From.Type = int16(ftype) + q.From.Reg = int16(freg) + q.From.Offset = foffset + q.To.Type = int16(ttype) + q.To.Reg = int16(treg) + q.To.Offset = toffset + q.Link = p.Link + p.Link = q + return q +} + +/* + * generate: + * call f + * proc=-1 normal call but no return + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + * proc=3 normal call to C pointer (not Go func value) +*/ +func ginscall(f *gc.Node, proc int) { + var p *obj.Prog + var reg gc.Node + var stk gc.Node + var r1 gc.Node + var extra int32 + + if f.Type != nil { + extra = 0 + if proc == 1 || proc == 2 { + extra = 2 * int32(gc.Widthptr) + } + gc.Setmaxarg(f.Type, extra) + } + + switch proc { + default: + gc.Fatal("ginscall: bad proc %d", proc) + + case 0, // normal call + -1: // normal call but no return + if f.Op == gc.ONAME && f.Class == gc.PFUNC { + if f == gc.Deferreturn { + // Deferred calls will appear to be returning to + // the CALL deferreturn(SB) that we are about to emit. + // However, the stack trace code will show the line + // of the instruction byte before the return PC. + // To avoid that being an unrelated instruction, + // insert an x86 NOP that we will have the right line number. + // x86 NOP 0x90 is really XCHG AX, AX; use that description + // because the NOP pseudo-instruction would be removed by + // the linker. + gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX) + + gins(x86.AXCHGL, ®, ®) + } + + p = gins(obj.ACALL, nil, f) + gc.Afunclit(&p.To, f) + if proc == -1 || gc.Noreturn(p) { + gins(obj.AUNDEF, nil, nil) + } + break + } + + gc.Nodreg(®, gc.Types[gc.Tptr], x86.REG_DX) + gc.Nodreg(&r1, gc.Types[gc.Tptr], x86.REG_BX) + gmove(f, ®) + reg.Op = gc.OINDREG + gmove(®, &r1) + reg.Op = gc.OREGISTER + gins(obj.ACALL, ®, &r1) + + case 3: // normal call of c function pointer + gins(obj.ACALL, nil, f) + + case 1, // call in new proc (go) + 2: // deferred call (defer) + stk = gc.Node{} + + stk.Op = gc.OINDREG + stk.Val.U.Reg = x86.REG_SP + stk.Xoffset = 0 + + if gc.Widthptr == 8 { + // size of arguments at 0(SP) + ginscon(x86.AMOVQ, int64(gc.Argsize(f.Type)), &stk) + + // FuncVal* at 8(SP) + stk.Xoffset = int64(gc.Widthptr) + + gc.Nodreg(®, gc.Types[gc.TINT64], x86.REG_AX) + gmove(f, ®) + gins(x86.AMOVQ, ®, &stk) + } else { + // size of arguments at 0(SP) + ginscon(x86.AMOVL, int64(gc.Argsize(f.Type)), &stk) + + // FuncVal* at 4(SP) + stk.Xoffset = int64(gc.Widthptr) + + gc.Nodreg(®, gc.Types[gc.TINT32], x86.REG_AX) + gmove(f, ®) + gins(x86.AMOVL, ®, &stk) + } + + if proc == 1 { + ginscall(gc.Newproc, 0) + } else { + if gc.Hasdefer == 0 { + gc.Fatal("hasdefer=0 but has defer") + } + ginscall(gc.Deferproc, 0) + } + + if proc == 2 { + gc.Nodreg(®, gc.Types[gc.TINT32], x86.REG_AX) + gins(x86.ATESTL, ®, ®) + p = gc.Gbranch(x86.AJEQ, nil, +1) + cgen_ret(nil) + gc.Patch(p, gc.Pc) + } + } +} + +/* + * n is call to interface method. + * generate res = n. + */ +func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { + var i *gc.Node + var f *gc.Node + var tmpi gc.Node + var nodi gc.Node + var nodo gc.Node + var nodr gc.Node + var nodsp gc.Node + + i = n.Left + if i.Op != gc.ODOTINTER { + gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) + } + + f = i.Right // field + if f.Op != gc.ONAME { + gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) + } + + i = i.Left // interface + + if i.Addable == 0 { + gc.Tempname(&tmpi, i.Type) + cgen(i, &tmpi) + i = &tmpi + } + + gc.Genlist(n.List) // assign the args + + // i is now addable, prepare an indirected + // register to hold its address. + igen(i, &nodi, res) // REG = &inter + + gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP) + + nodsp.Xoffset = 0 + if proc != 0 { + nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn + } + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset += int64(gc.Widthptr) + cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data + + regalloc(&nodo, gc.Types[gc.Tptr], res) + + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset -= int64(gc.Widthptr) + cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab + regfree(&nodi) + + regalloc(&nodr, gc.Types[gc.Tptr], &nodo) + if n.Left.Xoffset == gc.BADWIDTH { + gc.Fatal("cgen_callinter: badwidth") + } + gc.Cgen_checknil(&nodo) // in case offset is huge + nodo.Op = gc.OINDREG + nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 + if proc == 0 { + // plain call: use direct c function pointer - more efficient + cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] + proc = 3 + } else { + // go/defer. generate go func value. + gins(x86.ALEAQ, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] + } + + nodr.Type = n.Left.Type + ginscall(&nodr, proc) + + regfree(&nodr) + regfree(&nodo) +} + +/* + * generate function call; + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + */ +func cgen_call(n *gc.Node, proc int) { + var t *gc.Type + var nod gc.Node + var afun gc.Node + + if n == nil { + return + } + + if n.Left.Ullman >= gc.UINF { + // if name involves a fn call + // precompute the address of the fn + gc.Tempname(&afun, gc.Types[gc.Tptr]) + + cgen(n.Left, &afun) + } + + gc.Genlist(n.List) // assign the args + t = n.Left.Type + + // call tempname pointer + if n.Left.Ullman >= gc.UINF { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, &afun) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call pointer + if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, n.Left) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call direct + n.Left.Method = 1 + + ginscall(n.Left, proc) +} + +/* + * call to n has already been generated. + * generate: + * res = return value from call. + */ +func cgen_callret(n *gc.Node, res *gc.Node) { + var nod gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_callret: nil") + } + + nod = gc.Node{} + nod.Op = gc.OINDREG + nod.Val.U.Reg = x86.REG_SP + nod.Addable = 1 + + nod.Xoffset = fp.Width + nod.Type = fp.Type + gc.Cgen_as(res, &nod) +} + +/* + * call to n has already been generated. + * generate: + * res = &return value from call. + */ +func cgen_aret(n *gc.Node, res *gc.Node) { + var nod1 gc.Node + var nod2 gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_aret: nil") + } + + nod1 = gc.Node{} + nod1.Op = gc.OINDREG + nod1.Val.U.Reg = x86.REG_SP + nod1.Addable = 1 + + nod1.Xoffset = fp.Width + nod1.Type = fp.Type + + if res.Op != gc.OREGISTER { + regalloc(&nod2, gc.Types[gc.Tptr], res) + gins(leaptr, &nod1, &nod2) + gins(movptr, &nod2, res) + regfree(&nod2) + } else { + gins(leaptr, &nod1, res) + } +} + +/* + * generate return. + * n->left is assignments to return values. + */ +func cgen_ret(n *gc.Node) { + var p *obj.Prog + + if n != nil { + gc.Genlist(n.List) // copy out args + } + if gc.Hasdefer != 0 { + ginscall(gc.Deferreturn, 0) + } + gc.Genlist(gc.Curfn.Exit) + p = gins(obj.ARET, nil, nil) + if n != nil && n.Op == gc.ORETJMP { + p.To.Type = obj.TYPE_MEM + p.To.Name = obj.NAME_EXTERN + p.To.Sym = gc.Linksym(n.Left.Sym) + } +} + +/* + * generate division. + * generates one of: + * res = nl / nr + * res = nl % nr + * according to op. + */ +func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var a int + var check int + var n3 gc.Node + var n4 gc.Node + var t *gc.Type + var t0 *gc.Type + var ax gc.Node + var dx gc.Node + var ax1 gc.Node + var n31 gc.Node + var oldax gc.Node + var olddx gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + // Have to be careful about handling + // most negative int divided by -1 correctly. + // The hardware will trap. + // Also the byte divide instruction needs AH, + // which we otherwise don't have to deal with. + // Easiest way to avoid for int8, int16: use int32. + // For int32 and int64, use explicit test. + // Could use int64 hw for int32. + t = nl.Type + + t0 = t + check = 0 + if gc.Issigned[t.Etype] != 0 { + check = 1 + if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= nr.Ullman { + savex(x86.REG_AX, &ax, &oldax, res, t0) + cgen(nl, &ax) + regalloc(&ax, t0, &ax) // mark ax live during cgen + cgen(nr, &n3) + regfree(&ax) + } else { + cgen(nr, &n3) + savex(x86.REG_AX, &ax, &oldax, res, t0) + cgen(nl, &ax) + } + + if t != t0 { + // Convert + ax1 = ax + + n31 = n3 + ax.Type = t + n3.Type = t + gmove(&ax1, &ax) + gmove(&n31, &n3) + } + + p2 = nil + if gc.Nacl { + // Native Client does not relay the divide-by-zero trap + // to the executing program, so we must insert a check + // for ourselves. + gc.Nodconst(&n4, t, 0) + + gins(optoas(gc.OCMP, t), &n3, &n4) + p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) + if panicdiv == nil { + panicdiv = gc.Sysfunc("panicdivide") + } + ginscall(panicdiv, -1) + gc.Patch(p1, gc.Pc) + } + + if check != 0 { + gc.Nodconst(&n4, t, -1) + gins(optoas(gc.OCMP, t), &n3, &n4) + p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) + if op == gc.ODIV { + // a / (-1) is -a. + gins(optoas(gc.OMINUS, t), nil, &ax) + + gmove(&ax, res) + } else { + // a % (-1) is 0. + gc.Nodconst(&n4, t, 0) + + gmove(&n4, res) + } + + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + } + + savex(x86.REG_DX, &dx, &olddx, res, t) + if gc.Issigned[t.Etype] == 0 { + gc.Nodconst(&n4, t, 0) + gmove(&n4, &dx) + } else { + gins(optoas(gc.OEXTEND, t), nil, nil) + } + gins(a, &n3, nil) + regfree(&n3) + if op == gc.ODIV { + gmove(&ax, res) + } else { + gmove(&dx, res) + } + restx(&dx, &olddx) + if check != 0 { + gc.Patch(p2, gc.Pc) + } + restx(&ax, &oldax) +} + +/* + * register dr is one of the special ones (AX, CX, DI, SI, etc.). + * we need to use it. if it is already allocated as a temporary + * (r > 1; can only happen if a routine like sgen passed a + * special as cgen's res and then cgen used regalloc to reuse + * it as its own temporary), then move it for now to another + * register. caller must call restx to move it back. + * the move is not necessary if dr == res, because res is + * known to be dead. + */ +func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { + var r int + + r = int(reg[dr]) + + // save current ax and dx if they are live + // and not the destination + *oldx = gc.Node{} + + gc.Nodreg(x, t, dr) + if r > 1 && !gc.Samereg(x, res) { + regalloc(oldx, gc.Types[gc.TINT64], nil) + x.Type = gc.Types[gc.TINT64] + gmove(x, oldx) + x.Type = t + oldx.Ostk = int32(r) // squirrel away old r value + reg[dr] = 1 + } +} + +func restx(x *gc.Node, oldx *gc.Node) { + if oldx.Op != 0 { + x.Type = gc.Types[gc.TINT64] + reg[x.Val.U.Reg] = uint8(oldx.Ostk) + gmove(oldx, x) + regfree(oldx) + } +} + +/* + * generate division according to op, one of: + * res = nl / nr + * res = nl % nr + */ +func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var w int + var a int + var m gc.Magic + + if nr.Op != gc.OLITERAL { + goto longdiv + } + w = int(nl.Type.Width * 8) + + // Front end handled 32-bit division. We only need to handle 64-bit. + // try to do division by multiply by (2^w)/d + // see hacker's delight chapter 10 + switch gc.Simtype[nl.Type.Etype] { + default: + goto longdiv + + case gc.TUINT64: + m.W = w + m.Ud = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + gc.Umagic(&m) + if m.Bad != 0 { + break + } + if op == gc.OMOD { + goto longmod + } + + cgenr(nl, &n1, nil) + gc.Nodconst(&n2, nl.Type, int64(m.Um)) + regalloc(&n3, nl.Type, res) + cgen_hmul(&n1, &n2, &n3) + + if m.Ua != 0 { + // need to add numerator accounting for overflow + gins(optoas(gc.OADD, nl.Type), &n1, &n3) + + gc.Nodconst(&n2, nl.Type, 1) + gins(optoas(gc.ORROTC, nl.Type), &n2, &n3) + gc.Nodconst(&n2, nl.Type, int64(m.S)-1) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) + } else { + gc.Nodconst(&n2, nl.Type, int64(m.S)) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift dx + } + + gmove(&n3, res) + regfree(&n1) + regfree(&n3) + return + + case gc.TINT64: + m.W = w + m.Sd = gc.Mpgetfix(nr.Val.U.Xval) + gc.Smagic(&m) + if m.Bad != 0 { + break + } + if op == gc.OMOD { + goto longmod + } + + cgenr(nl, &n1, res) + gc.Nodconst(&n2, nl.Type, m.Sm) + regalloc(&n3, nl.Type, nil) + cgen_hmul(&n1, &n2, &n3) + + if m.Sm < 0 { + // need to add numerator + gins(optoas(gc.OADD, nl.Type), &n1, &n3) + } + + gc.Nodconst(&n2, nl.Type, int64(m.S)) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift n3 + + gc.Nodconst(&n2, nl.Type, int64(w)-1) + + gins(optoas(gc.ORSH, nl.Type), &n2, &n1) // -1 iff num is neg + gins(optoas(gc.OSUB, nl.Type), &n1, &n3) // added + + if m.Sd < 0 { + // this could probably be removed + // by factoring it into the multiplier + gins(optoas(gc.OMINUS, nl.Type), nil, &n3) + } + + gmove(&n3, res) + regfree(&n1) + regfree(&n3) + return + } + + goto longdiv + + // division and mod using (slow) hardware instruction +longdiv: + dodiv(op, nl, nr, res) + + return + + // mod using formula A%B = A-(A/B*B) but + // we know that there is a fast algorithm for A/B +longmod: + regalloc(&n1, nl.Type, res) + + cgen(nl, &n1) + regalloc(&n2, nl.Type, nil) + cgen_div(gc.ODIV, &n1, nr, &n2) + a = optoas(gc.OMUL, nl.Type) + if w == 8 { + // use 2-operand 16-bit multiply + // because there is no 2-operand 8-bit multiply + a = x86.AIMULW + } + + if !gc.Smallintconst(nr) { + regalloc(&n3, nl.Type, nil) + cgen(nr, &n3) + gins(a, &n3, &n2) + regfree(&n3) + } else { + gins(a, nr, &n2) + } + gins(optoas(gc.OSUB, nl.Type), &n2, &n1) + gmove(&n1, res) + regfree(&n1) + regfree(&n2) +} + +/* + * generate high multiply: + * res = (nl*nr) >> width + */ +func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { + var t *gc.Type + var a int + var n1 gc.Node + var n2 gc.Node + var ax gc.Node + var dx gc.Node + var tmp *gc.Node + + t = nl.Type + a = optoas(gc.OHMUL, t) + if nl.Ullman < nr.Ullman { + tmp = nl + nl = nr + nr = tmp + } + + cgenr(nl, &n1, res) + cgenr(nr, &n2, nil) + gc.Nodreg(&ax, t, x86.REG_AX) + gmove(&n1, &ax) + gins(a, &n2, nil) + regfree(&n2) + regfree(&n1) + + if t.Width == 1 { + // byte multiply behaves differently. + gc.Nodreg(&ax, t, x86.REG_AH) + + gc.Nodreg(&dx, t, x86.REG_DX) + gmove(&ax, &dx) + } + + gc.Nodreg(&dx, t, x86.REG_DX) + gmove(&dx, res) +} + +/* + * generate shift according to op, one of: + * res = nl << nr + * res = nl >> nr + */ +func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var n5 gc.Node + var cx gc.Node + var oldcx gc.Node + var a int + var rcx int + var p1 *obj.Prog + var sc uint64 + var tcount *gc.Type + + a = optoas(op, nl.Type) + + if nr.Op == gc.OLITERAL { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if sc >= uint64(nl.Type.Width*8) { + // large shift gets 2 shifts by width-1 + gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) + + gins(a, &n3, &n1) + gins(a, &n3, &n1) + } else { + gins(a, nr, &n1) + } + gmove(&n1, res) + regfree(&n1) + goto ret + } + + if nl.Ullman >= gc.UINF { + gc.Tempname(&n4, nl.Type) + cgen(nl, &n4) + nl = &n4 + } + + if nr.Ullman >= gc.UINF { + gc.Tempname(&n5, nr.Type) + cgen(nr, &n5) + nr = &n5 + } + + rcx = int(reg[x86.REG_CX]) + gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX) + + // Allow either uint32 or uint64 as shift type, + // to avoid unnecessary conversion from uint32 to uint64 + // just to do the comparison. + tcount = gc.Types[gc.Simtype[nr.Type.Etype]] + + if tcount.Etype < gc.TUINT32 { + tcount = gc.Types[gc.TUINT32] + } + + regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX + regalloc(&n3, tcount, &n1) // to clear high bits of CX + + gc.Nodreg(&cx, gc.Types[gc.TUINT64], x86.REG_CX) + + oldcx = gc.Node{} + if rcx > 0 && !gc.Samereg(&cx, res) { + regalloc(&oldcx, gc.Types[gc.TUINT64], nil) + gmove(&cx, &oldcx) + } + + cx.Type = tcount + + if gc.Samereg(&cx, res) { + regalloc(&n2, nl.Type, nil) + } else { + regalloc(&n2, nl.Type, res) + } + if nl.Ullman >= nr.Ullman { + cgen(nl, &n2) + cgen(nr, &n1) + gmove(&n1, &n3) + } else { + cgen(nr, &n1) + gmove(&n1, &n3) + cgen(nl, &n2) + } + + regfree(&n3) + + // test and fix up large shifts + if !bounded { + gc.Nodconst(&n3, tcount, nl.Type.Width*8) + gins(optoas(gc.OCMP, tcount), &n1, &n3) + p1 = gc.Gbranch(optoas(gc.OLT, tcount), nil, +1) + if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { + gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) + gins(a, &n3, &n2) + } else { + gc.Nodconst(&n3, nl.Type, 0) + gmove(&n3, &n2) + } + + gc.Patch(p1, gc.Pc) + } + + gins(a, &n1, &n2) + + if oldcx.Op != 0 { + cx.Type = gc.Types[gc.TUINT64] + gmove(&oldcx, &cx) + regfree(&oldcx) + } + + gmove(&n2, res) + + regfree(&n1) + regfree(&n2) + +ret: +} + +/* + * generate byte multiply: + * res = nl * nr + * there is no 2-operand byte multiply instruction so + * we do a full-width multiplication and truncate afterwards. + */ +func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n1b gc.Node + var n2b gc.Node + var tmp *gc.Node + var t *gc.Type + var a int + + // largest ullman on left. + if nl.Ullman < nr.Ullman { + tmp = nl + nl = nr + nr = tmp + } + + // generate operands in "8-bit" registers. + regalloc(&n1b, nl.Type, res) + + cgen(nl, &n1b) + regalloc(&n2b, nr.Type, nil) + cgen(nr, &n2b) + + // perform full-width multiplication. + t = gc.Types[gc.TUINT64] + + if gc.Issigned[nl.Type.Etype] != 0 { + t = gc.Types[gc.TINT64] + } + gc.Nodreg(&n1, t, int(n1b.Val.U.Reg)) + gc.Nodreg(&n2, t, int(n2b.Val.U.Reg)) + a = optoas(op, t) + gins(a, &n2, &n1) + + // truncate. + gmove(&n1, res) + + regfree(&n1b) + regfree(&n2b) +} + +func clearfat(nl *gc.Node) { + var w int64 + var c int64 + var q int64 + var n1 gc.Node + var oldn1 gc.Node + var ax gc.Node + var oldax gc.Node + var di gc.Node + var z gc.Node + var p *obj.Prog + + /* clear a fat object */ + if gc.Debug['g'] != 0 { + gc.Dump("\nclearfat", nl) + } + + w = nl.Type.Width + + // Avoid taking the address for simple enough types. + if componentgen(nil, nl) { + return + } + + c = w % 8 // bytes + q = w / 8 // quads + + if q < 4 { + // Write sequence of MOV 0, off(base) instead of using STOSQ. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSQ loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + agenr(nl, &n1, nil) + + n1.Op = gc.OINDREG + gc.Nodconst(&z, gc.Types[gc.TUINT64], 0) + for { + tmp14 := q + q-- + if tmp14 <= 0 { + break + } + n1.Type = z.Type + gins(x86.AMOVQ, &z, &n1) + n1.Xoffset += 8 + } + + if c >= 4 { + gc.Nodconst(&z, gc.Types[gc.TUINT32], 0) + n1.Type = z.Type + gins(x86.AMOVL, &z, &n1) + n1.Xoffset += 4 + c -= 4 + } + + gc.Nodconst(&z, gc.Types[gc.TUINT8], 0) + for { + tmp15 := c + c-- + if tmp15 <= 0 { + break + } + n1.Type = z.Type + gins(x86.AMOVB, &z, &n1) + n1.Xoffset++ + } + + regfree(&n1) + return + } + + savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr]) + agen(nl, &n1) + + savex(x86.REG_AX, &ax, &oldax, nil, gc.Types[gc.Tptr]) + gconreg(x86.AMOVL, 0, x86.REG_AX) + + if q > 128 || gc.Nacl { + gconreg(movptr, q, x86.REG_CX) + gins(x86.AREP, nil, nil) // repeat + gins(x86.ASTOSQ, nil, nil) // STOQ AL,*(DI)+ + } else { + p = gins(obj.ADUFFZERO, nil, nil) + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) + + // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s + p.To.Offset = 2 * (128 - q) + } + + z = ax + di = n1 + if w >= 8 && c >= 4 { + di.Op = gc.OINDREG + z.Type = gc.Types[gc.TINT64] + di.Type = z.Type + p = gins(x86.AMOVQ, &z, &di) + p.To.Scale = 1 + p.To.Offset = c - 8 + } else if c >= 4 { + di.Op = gc.OINDREG + z.Type = gc.Types[gc.TINT32] + di.Type = z.Type + p = gins(x86.AMOVL, &z, &di) + if c > 4 { + p = gins(x86.AMOVL, &z, &di) + p.To.Scale = 1 + p.To.Offset = c - 4 + } + } else { + for c > 0 { + gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+ + c-- + } + } + + restx(&n1, &oldn1) + restx(&ax, &oldax) +} + +// Called after regopt and peep have run. +// Expand CHECKNIL pseudo-op into actual nil pointer check. +func expandchecks(firstp *obj.Prog) { + var p *obj.Prog + var p1 *obj.Prog + var p2 *obj.Prog + + for p = firstp; p != nil; p = p.Link { + if p.As != obj.ACHECKNIL { + continue + } + if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers + gc.Warnl(int(p.Lineno), "generated nil check") + } + + // check is + // CMP arg, $0 + // JNE 2(PC) (likely) + // MOV AX, 0 + p1 = gc.Ctxt.NewProg() + + p2 = gc.Ctxt.NewProg() + gc.Clearp(p1) + gc.Clearp(p2) + p1.Link = p2 + p2.Link = p.Link + p.Link = p1 + p1.Lineno = p.Lineno + p2.Lineno = p.Lineno + p1.Pc = 9999 + p2.Pc = 9999 + p.As = int16(cmpptr) + p.To.Type = obj.TYPE_CONST + p.To.Offset = 0 + p1.As = x86.AJNE + p1.From.Type = obj.TYPE_CONST + p1.From.Offset = 1 // likely + p1.To.Type = obj.TYPE_BRANCH + p1.To.U.Branch = p2.Link + + // crash by write to memory address 0. + // if possible, since we know arg is 0, use 0(arg), + // which will be shorter to encode than plain 0. + p2.As = x86.AMOVL + + p2.From.Type = obj.TYPE_REG + p2.From.Reg = x86.REG_AX + if regtyp(&p.From) { + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = p.From.Reg + } else { + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = x86.REG_NONE + } + + p2.To.Offset = 0 + } +} diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c deleted file mode 100644 index 55d3425081..0000000000 --- a/src/cmd/6g/gsubr.c +++ /dev/null @@ -1,1737 +0,0 @@ -// Derived from Inferno utils/6c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../../runtime/funcdata.h" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 6l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -vlong unmappedzero = 4096; -static int resvd[] = -{ - REG_DI, // for movstring - REG_SI, // for movstring - - REG_AX, // for divide - REG_CX, // for shift - REG_DX, // for divide - REG_SP, // for stack -}; - -void -ginit(void) -{ - int i; - - for(i=0; ietype]; - - switch(et) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TPTR32: - case TPTR64: - case TBOOL: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REG_AX && i <= REG_R15) - goto out; - } - for(i=REG_AX; i<=REG_R15; i++) - if(reg[i] == 0) { - regpc[i-REG_AX] = (uintptr)getcallerpc(&n); - goto out; - } - - flusherrors(); - for(i=0; i+REG_AX<=REG_R15; i++) - print("%d %p\n", i, regpc[i]); - fatal("out of fixed registers"); - - case TFLOAT32: - case TFLOAT64: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REG_X0 && i <= REG_X15) - goto out; - } - for(i=REG_X0; i<=REG_X15; i++) - if(reg[i] == 0) - goto out; - fatal("out of floating registers"); - - case TCOMPLEX64: - case TCOMPLEX128: - tempname(n, t); - return; - } - fatal("regalloc: unknown type %T", t); - return; - -out: - reg[i]++; - nodreg(n, t, i); -} - -void -regfree(Node *n) -{ - int i; - - if(n->op == ONAME) - return; - if(n->op != OREGISTER && n->op != OINDREG) - fatal("regfree: not a register"); - i = n->val.u.reg; - if(i == REG_SP) - return; - if(i < 0 || i >= nelem(reg)) - fatal("regfree: reg out of range"); - if(reg[i] <= 0) - fatal("regfree: reg not allocated"); - reg[i]--; - if(reg[i] == 0 && REG_AX <= i && i <= REG_R15) - regpc[i - REG_AX] = 0; -} - -/* - * generate - * as $c, reg - */ -void -gconreg(int as, vlong c, int reg) -{ - Node nr; - - switch(as) { - case AADDL: - case AMOVL: - case ALEAL: - nodreg(&nr, types[TINT32], reg); - break; - default: - nodreg(&nr, types[TINT64], reg); - } - - ginscon(as, c, &nr); -} - -/* - * generate - * as $c, n - */ -void -ginscon(int as, vlong c, Node *n2) -{ - Node n1, ntmp; - - switch(as) { - case AADDL: - case AMOVL: - case ALEAL: - nodconst(&n1, types[TINT32], c); - break; - default: - nodconst(&n1, types[TINT64], c); - } - - if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) { - // cannot have 64-bit immediate in ADD, etc. - // instead, MOV into register first. - regalloc(&ntmp, types[TINT64], N); - gins(AMOVQ, &n1, &ntmp); - gins(as, &ntmp, n2); - regfree(&ntmp); - return; - } - gins(as, &n1, n2); -} - -#define CASE(a,b) (((a)<<16)|((b)<<0)) -/*c2go int CASE(int, int); */ - -/* - * set up nodes representing 2^63 - */ -Node bigi; -Node bigf; - -void -bignodes(void) -{ - static int did; - - if(did) - return; - did = 1; - - nodconst(&bigi, types[TUINT64], 1); - mpshiftfix(bigi.val.u.xval, 63); - - bigf = bigi; - bigf.type = types[TFLOAT64]; - bigf.val.ctype = CTFLT; - bigf.val.u.fval = mal(sizeof *bigf.val.u.fval); - mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval); -} - -/* - * generate move: - * t = f - * hard part is conversions. - */ -void -gmove(Node *f, Node *t) -{ - int a, ft, tt; - Type *cvt; - Node r1, r2, r3, r4, zero, one, con; - Prog *p1, *p2; - - if(debug['M']) - print("gmove %lN -> %lN\n", f, t); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); - return; - } - - // cannot have two memory operands - if(ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - convconst(&con, t->type, &f->val); - f = &con; - ft = tt; // so big switch will choose a simple mov - - // some constants can't move directly to memory. - if(ismem(t)) { - // float constants come from memory. - if(isfloat[tt]) - goto hard; - - // 64-bit immediates are really 32-bit sign-extended - // unless moving into a register. - if(isint[tt]) { - if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) - goto hard; - if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) - goto hard; - } - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - fatal("gmove %lT -> %lT", f->type, t->type); - - /* - * integer copy and truncate - */ - case CASE(TINT8, TINT8): // same size - case CASE(TINT8, TUINT8): - case CASE(TUINT8, TINT8): - case CASE(TUINT8, TUINT8): - case CASE(TINT16, TINT8): // truncate - case CASE(TUINT16, TINT8): - case CASE(TINT32, TINT8): - case CASE(TUINT32, TINT8): - case CASE(TINT64, TINT8): - case CASE(TUINT64, TINT8): - case CASE(TINT16, TUINT8): - case CASE(TUINT16, TUINT8): - case CASE(TINT32, TUINT8): - case CASE(TUINT32, TUINT8): - case CASE(TINT64, TUINT8): - case CASE(TUINT64, TUINT8): - a = AMOVB; - break; - - case CASE(TINT16, TINT16): // same size - case CASE(TINT16, TUINT16): - case CASE(TUINT16, TINT16): - case CASE(TUINT16, TUINT16): - case CASE(TINT32, TINT16): // truncate - case CASE(TUINT32, TINT16): - case CASE(TINT64, TINT16): - case CASE(TUINT64, TINT16): - case CASE(TINT32, TUINT16): - case CASE(TUINT32, TUINT16): - case CASE(TINT64, TUINT16): - case CASE(TUINT64, TUINT16): - a = AMOVW; - break; - - case CASE(TINT32, TINT32): // same size - case CASE(TINT32, TUINT32): - case CASE(TUINT32, TINT32): - case CASE(TUINT32, TUINT32): - a = AMOVL; - break; - - case CASE(TINT64, TINT32): // truncate - case CASE(TUINT64, TINT32): - case CASE(TINT64, TUINT32): - case CASE(TUINT64, TUINT32): - a = AMOVQL; - break; - - case CASE(TINT64, TINT64): // same size - case CASE(TINT64, TUINT64): - case CASE(TUINT64, TINT64): - case CASE(TUINT64, TUINT64): - a = AMOVQ; - break; - - /* - * integer up-conversions - */ - case CASE(TINT8, TINT16): // sign extend int8 - case CASE(TINT8, TUINT16): - a = AMOVBWSX; - goto rdst; - case CASE(TINT8, TINT32): - case CASE(TINT8, TUINT32): - a = AMOVBLSX; - goto rdst; - case CASE(TINT8, TINT64): - case CASE(TINT8, TUINT64): - a = AMOVBQSX; - goto rdst; - - case CASE(TUINT8, TINT16): // zero extend uint8 - case CASE(TUINT8, TUINT16): - a = AMOVBWZX; - goto rdst; - case CASE(TUINT8, TINT32): - case CASE(TUINT8, TUINT32): - a = AMOVBLZX; - goto rdst; - case CASE(TUINT8, TINT64): - case CASE(TUINT8, TUINT64): - a = AMOVBQZX; - goto rdst; - - case CASE(TINT16, TINT32): // sign extend int16 - case CASE(TINT16, TUINT32): - a = AMOVWLSX; - goto rdst; - case CASE(TINT16, TINT64): - case CASE(TINT16, TUINT64): - a = AMOVWQSX; - goto rdst; - - case CASE(TUINT16, TINT32): // zero extend uint16 - case CASE(TUINT16, TUINT32): - a = AMOVWLZX; - goto rdst; - case CASE(TUINT16, TINT64): - case CASE(TUINT16, TUINT64): - a = AMOVWQZX; - goto rdst; - - case CASE(TINT32, TINT64): // sign extend int32 - case CASE(TINT32, TUINT64): - a = AMOVLQSX; - goto rdst; - - case CASE(TUINT32, TINT64): // zero extend uint32 - case CASE(TUINT32, TUINT64): - // AMOVL into a register zeros the top of the register, - // so this is not always necessary, but if we rely on AMOVL - // the optimizer is almost certain to screw with us. - a = AMOVLQZX; - goto rdst; - - /* - * float to integer - */ - case CASE(TFLOAT32, TINT32): - a = ACVTTSS2SL; - goto rdst; - - case CASE(TFLOAT64, TINT32): - a = ACVTTSD2SL; - goto rdst; - - case CASE(TFLOAT32, TINT64): - a = ACVTTSS2SQ; - goto rdst; - - case CASE(TFLOAT64, TINT64): - a = ACVTTSD2SQ; - goto rdst; - - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TUINT8): - // convert via int32. - cvt = types[TINT32]; - goto hard; - - case CASE(TFLOAT32, TUINT32): - case CASE(TFLOAT64, TUINT32): - // convert via int64. - cvt = types[TINT64]; - goto hard; - - case CASE(TFLOAT32, TUINT64): - case CASE(TFLOAT64, TUINT64): - // algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - a = ACVTTSS2SQ; - if(ft == TFLOAT64) - a = ACVTTSD2SQ; - bignodes(); - regalloc(&r1, types[ft], N); - regalloc(&r2, types[tt], t); - regalloc(&r3, types[ft], N); - regalloc(&r4, types[tt], N); - gins(optoas(OAS, f->type), f, &r1); - gins(optoas(OCMP, f->type), &bigf, &r1); - p1 = gbranch(optoas(OLE, f->type), T, +1); - gins(a, &r1, &r2); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - gins(optoas(OAS, f->type), &bigf, &r3); - gins(optoas(OSUB, f->type), &r3, &r1); - gins(a, &r1, &r2); - gins(AMOVQ, &bigi, &r4); - gins(AXORQ, &r4, &r2); - patch(p2, pc); - gmove(&r2, t); - regfree(&r4); - regfree(&r3); - regfree(&r2); - regfree(&r1); - return; - - /* - * integer to float - */ - case CASE(TINT32, TFLOAT32): - a = ACVTSL2SS; - goto rdst; - - - case CASE(TINT32, TFLOAT64): - a = ACVTSL2SD; - goto rdst; - - case CASE(TINT64, TFLOAT32): - a = ACVTSQ2SS; - goto rdst; - - case CASE(TINT64, TFLOAT64): - a = ACVTSQ2SD; - goto rdst; - - case CASE(TINT16, TFLOAT32): - case CASE(TINT16, TFLOAT64): - case CASE(TINT8, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT64): - case CASE(TUINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT64): - // convert via int32 - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT64): - // convert via int64. - cvt = types[TINT64]; - goto hard; - - case CASE(TUINT64, TFLOAT32): - case CASE(TUINT64, TFLOAT64): - // algorithm is: - // if small enough, use native int64 -> uint64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - a = ACVTSQ2SS; - if(tt == TFLOAT64) - a = ACVTSQ2SD; - nodconst(&zero, types[TUINT64], 0); - nodconst(&one, types[TUINT64], 1); - regalloc(&r1, f->type, f); - regalloc(&r2, t->type, t); - regalloc(&r3, f->type, N); - regalloc(&r4, f->type, N); - gmove(f, &r1); - gins(ACMPQ, &r1, &zero); - p1 = gbranch(AJLT, T, +1); - gins(a, &r1, &r2); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - gmove(&r1, &r3); - gins(ASHRQ, &one, &r3); - gmove(&r1, &r4); - gins(AANDL, &one, &r4); - gins(AORQ, &r4, &r3); - gins(a, &r3, &r2); - gins(optoas(OADD, t->type), &r2, &r2); - patch(p2, pc); - gmove(&r2, t); - regfree(&r4); - regfree(&r3); - regfree(&r2); - regfree(&r1); - return; - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - a = AMOVSS; - break; - - case CASE(TFLOAT64, TFLOAT64): - a = AMOVSD; - break; - - case CASE(TFLOAT32, TFLOAT64): - a = ACVTSS2SD; - goto rdst; - - case CASE(TFLOAT64, TFLOAT32): - a = ACVTSD2SS; - goto rdst; - } - - gins(a, f, t); - return; - -rdst: - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; -} - -int -samaddr(Node *f, Node *t) -{ - - if(f->op != t->op) - return 0; - - switch(f->op) { - case OREGISTER: - if(f->val.u.reg != t->val.u.reg) - break; - return 1; - } - return 0; -} - -/* - * generate one instruction: - * as f, t - */ -Prog* -gins(int as, Node *f, Node *t) -{ -// Node nod; - int32 w; - Prog *p; - Addr af, at; - -// if(f != N && f->op == OINDEX) { -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(f->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); -// } -// if(t != N && t->op == OINDEX) { -// regalloc(&nod, ®node, Z); -// v = constnode.vconst; -// cgen(t->right, &nod); -// constnode.vconst = v; -// idx.reg = nod.reg; -// regfree(&nod); -// } - - switch(as) { - case AMOVB: - case AMOVW: - case AMOVL: - case AMOVQ: - case AMOVSS: - case AMOVSD: - if(f != N && t != N && samaddr(f, t)) - return nil; - break; - - case ALEAQ: - if(f != N && isconst(f, CTNIL)) { - fatal("gins LEAQ nil %T", f->type); - } - break; - } - - memset(&af, 0, sizeof af); - memset(&at, 0, sizeof at); - if(f != N) - naddr(f, &af, 1); - if(t != N) - naddr(t, &at, 1); - p = prog(as); - if(f != N) - p->from = af; - if(t != N) - p->to = at; - if(debug['g']) - print("%P\n", p); - - w = 0; - switch(as) { - case AMOVB: - w = 1; - break; - case AMOVW: - w = 2; - break; - case AMOVL: - w = 4; - break; - case AMOVQ: - w = 8; - break; - } - if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) { - dump("f", f); - dump("t", t); - fatal("bad width: %P (%d, %d)\n", p, af.width, at.width); - } - if(p->to.type == TYPE_ADDR && w > 0) - fatal("bad use of addr: %P", p); - - return p; -} - -void -fixlargeoffset(Node *n) -{ - Node a; - - if(n == N) - return; - if(n->op != OINDREG) - return; - if(n->val.u.reg == REG_SP) // stack offset cannot be large - return; - if(n->xoffset != (int32)n->xoffset) { - // offset too large, add to register instead. - a = *n; - a.op = OREGISTER; - a.type = types[tptr]; - a.xoffset = 0; - cgen_checknil(&a); - ginscon(optoas(OADD, types[tptr]), n->xoffset, &a); - n->xoffset = 0; - } -} - -/* - * return Axxx for Oxxx on type t. - */ -int -optoas(int op, Type *t) -{ - int a; - - if(t == T) - fatal("optoas: t is nil"); - - a = AXXX; - switch(CASE(op, simtype[t->etype])) { - default: - fatal("optoas: no entry %O-%T", op, t); - break; - - case CASE(OADDR, TPTR32): - a = ALEAL; - break; - - case CASE(OADDR, TPTR64): - a = ALEAQ; - break; - - case CASE(OEQ, TBOOL): - case CASE(OEQ, TINT8): - case CASE(OEQ, TUINT8): - case CASE(OEQ, TINT16): - case CASE(OEQ, TUINT16): - case CASE(OEQ, TINT32): - case CASE(OEQ, TUINT32): - case CASE(OEQ, TINT64): - case CASE(OEQ, TUINT64): - case CASE(OEQ, TPTR32): - case CASE(OEQ, TPTR64): - case CASE(OEQ, TFLOAT32): - case CASE(OEQ, TFLOAT64): - a = AJEQ; - break; - - case CASE(ONE, TBOOL): - case CASE(ONE, TINT8): - case CASE(ONE, TUINT8): - case CASE(ONE, TINT16): - case CASE(ONE, TUINT16): - case CASE(ONE, TINT32): - case CASE(ONE, TUINT32): - case CASE(ONE, TINT64): - case CASE(ONE, TUINT64): - case CASE(ONE, TPTR32): - case CASE(ONE, TPTR64): - case CASE(ONE, TFLOAT32): - case CASE(ONE, TFLOAT64): - a = AJNE; - break; - - case CASE(OLT, TINT8): - case CASE(OLT, TINT16): - case CASE(OLT, TINT32): - case CASE(OLT, TINT64): - a = AJLT; - break; - - case CASE(OLT, TUINT8): - case CASE(OLT, TUINT16): - case CASE(OLT, TUINT32): - case CASE(OLT, TUINT64): - a = AJCS; - break; - - case CASE(OLE, TINT8): - case CASE(OLE, TINT16): - case CASE(OLE, TINT32): - case CASE(OLE, TINT64): - a = AJLE; - break; - - case CASE(OLE, TUINT8): - case CASE(OLE, TUINT16): - case CASE(OLE, TUINT32): - case CASE(OLE, TUINT64): - a = AJLS; - break; - - case CASE(OGT, TINT8): - case CASE(OGT, TINT16): - case CASE(OGT, TINT32): - case CASE(OGT, TINT64): - a = AJGT; - break; - - case CASE(OGT, TUINT8): - case CASE(OGT, TUINT16): - case CASE(OGT, TUINT32): - case CASE(OGT, TUINT64): - case CASE(OLT, TFLOAT32): - case CASE(OLT, TFLOAT64): - a = AJHI; - break; - - case CASE(OGE, TINT8): - case CASE(OGE, TINT16): - case CASE(OGE, TINT32): - case CASE(OGE, TINT64): - a = AJGE; - break; - - case CASE(OGE, TUINT8): - case CASE(OGE, TUINT16): - case CASE(OGE, TUINT32): - case CASE(OGE, TUINT64): - case CASE(OLE, TFLOAT32): - case CASE(OLE, TFLOAT64): - a = AJCC; - break; - - case CASE(OCMP, TBOOL): - case CASE(OCMP, TINT8): - case CASE(OCMP, TUINT8): - a = ACMPB; - break; - - case CASE(OCMP, TINT16): - case CASE(OCMP, TUINT16): - a = ACMPW; - break; - - case CASE(OCMP, TINT32): - case CASE(OCMP, TUINT32): - case CASE(OCMP, TPTR32): - a = ACMPL; - break; - - case CASE(OCMP, TINT64): - case CASE(OCMP, TUINT64): - case CASE(OCMP, TPTR64): - a = ACMPQ; - break; - - case CASE(OCMP, TFLOAT32): - a = AUCOMISS; - break; - - case CASE(OCMP, TFLOAT64): - a = AUCOMISD; - break; - - case CASE(OAS, TBOOL): - case CASE(OAS, TINT8): - case CASE(OAS, TUINT8): - a = AMOVB; - break; - - case CASE(OAS, TINT16): - case CASE(OAS, TUINT16): - a = AMOVW; - break; - - case CASE(OAS, TINT32): - case CASE(OAS, TUINT32): - case CASE(OAS, TPTR32): - a = AMOVL; - break; - - case CASE(OAS, TINT64): - case CASE(OAS, TUINT64): - case CASE(OAS, TPTR64): - a = AMOVQ; - break; - - case CASE(OAS, TFLOAT32): - a = AMOVSS; - break; - - case CASE(OAS, TFLOAT64): - a = AMOVSD; - break; - - case CASE(OADD, TINT8): - case CASE(OADD, TUINT8): - a = AADDB; - break; - - case CASE(OADD, TINT16): - case CASE(OADD, TUINT16): - a = AADDW; - break; - - case CASE(OADD, TINT32): - case CASE(OADD, TUINT32): - case CASE(OADD, TPTR32): - a = AADDL; - break; - - case CASE(OADD, TINT64): - case CASE(OADD, TUINT64): - case CASE(OADD, TPTR64): - a = AADDQ; - break; - - case CASE(OADD, TFLOAT32): - a = AADDSS; - break; - - case CASE(OADD, TFLOAT64): - a = AADDSD; - break; - - case CASE(OSUB, TINT8): - case CASE(OSUB, TUINT8): - a = ASUBB; - break; - - case CASE(OSUB, TINT16): - case CASE(OSUB, TUINT16): - a = ASUBW; - break; - - case CASE(OSUB, TINT32): - case CASE(OSUB, TUINT32): - case CASE(OSUB, TPTR32): - a = ASUBL; - break; - - case CASE(OSUB, TINT64): - case CASE(OSUB, TUINT64): - case CASE(OSUB, TPTR64): - a = ASUBQ; - break; - - case CASE(OSUB, TFLOAT32): - a = ASUBSS; - break; - - case CASE(OSUB, TFLOAT64): - a = ASUBSD; - break; - - case CASE(OINC, TINT8): - case CASE(OINC, TUINT8): - a = AINCB; - break; - - case CASE(OINC, TINT16): - case CASE(OINC, TUINT16): - a = AINCW; - break; - - case CASE(OINC, TINT32): - case CASE(OINC, TUINT32): - case CASE(OINC, TPTR32): - a = AINCL; - break; - - case CASE(OINC, TINT64): - case CASE(OINC, TUINT64): - case CASE(OINC, TPTR64): - a = AINCQ; - break; - - case CASE(ODEC, TINT8): - case CASE(ODEC, TUINT8): - a = ADECB; - break; - - case CASE(ODEC, TINT16): - case CASE(ODEC, TUINT16): - a = ADECW; - break; - - case CASE(ODEC, TINT32): - case CASE(ODEC, TUINT32): - case CASE(ODEC, TPTR32): - a = ADECL; - break; - - case CASE(ODEC, TINT64): - case CASE(ODEC, TUINT64): - case CASE(ODEC, TPTR64): - a = ADECQ; - break; - - case CASE(OMINUS, TINT8): - case CASE(OMINUS, TUINT8): - a = ANEGB; - break; - - case CASE(OMINUS, TINT16): - case CASE(OMINUS, TUINT16): - a = ANEGW; - break; - - case CASE(OMINUS, TINT32): - case CASE(OMINUS, TUINT32): - case CASE(OMINUS, TPTR32): - a = ANEGL; - break; - - case CASE(OMINUS, TINT64): - case CASE(OMINUS, TUINT64): - case CASE(OMINUS, TPTR64): - a = ANEGQ; - break; - - case CASE(OAND, TINT8): - case CASE(OAND, TUINT8): - a = AANDB; - break; - - case CASE(OAND, TINT16): - case CASE(OAND, TUINT16): - a = AANDW; - break; - - case CASE(OAND, TINT32): - case CASE(OAND, TUINT32): - case CASE(OAND, TPTR32): - a = AANDL; - break; - - case CASE(OAND, TINT64): - case CASE(OAND, TUINT64): - case CASE(OAND, TPTR64): - a = AANDQ; - break; - - case CASE(OOR, TINT8): - case CASE(OOR, TUINT8): - a = AORB; - break; - - case CASE(OOR, TINT16): - case CASE(OOR, TUINT16): - a = AORW; - break; - - case CASE(OOR, TINT32): - case CASE(OOR, TUINT32): - case CASE(OOR, TPTR32): - a = AORL; - break; - - case CASE(OOR, TINT64): - case CASE(OOR, TUINT64): - case CASE(OOR, TPTR64): - a = AORQ; - break; - - case CASE(OXOR, TINT8): - case CASE(OXOR, TUINT8): - a = AXORB; - break; - - case CASE(OXOR, TINT16): - case CASE(OXOR, TUINT16): - a = AXORW; - break; - - case CASE(OXOR, TINT32): - case CASE(OXOR, TUINT32): - case CASE(OXOR, TPTR32): - a = AXORL; - break; - - case CASE(OXOR, TINT64): - case CASE(OXOR, TUINT64): - case CASE(OXOR, TPTR64): - a = AXORQ; - break; - - case CASE(OLROT, TINT8): - case CASE(OLROT, TUINT8): - a = AROLB; - break; - - case CASE(OLROT, TINT16): - case CASE(OLROT, TUINT16): - a = AROLW; - break; - - case CASE(OLROT, TINT32): - case CASE(OLROT, TUINT32): - case CASE(OLROT, TPTR32): - a = AROLL; - break; - - case CASE(OLROT, TINT64): - case CASE(OLROT, TUINT64): - case CASE(OLROT, TPTR64): - a = AROLQ; - break; - - case CASE(OLSH, TINT8): - case CASE(OLSH, TUINT8): - a = ASHLB; - break; - - case CASE(OLSH, TINT16): - case CASE(OLSH, TUINT16): - a = ASHLW; - break; - - case CASE(OLSH, TINT32): - case CASE(OLSH, TUINT32): - case CASE(OLSH, TPTR32): - a = ASHLL; - break; - - case CASE(OLSH, TINT64): - case CASE(OLSH, TUINT64): - case CASE(OLSH, TPTR64): - a = ASHLQ; - break; - - case CASE(ORSH, TUINT8): - a = ASHRB; - break; - - case CASE(ORSH, TUINT16): - a = ASHRW; - break; - - case CASE(ORSH, TUINT32): - case CASE(ORSH, TPTR32): - a = ASHRL; - break; - - case CASE(ORSH, TUINT64): - case CASE(ORSH, TPTR64): - a = ASHRQ; - break; - - case CASE(ORSH, TINT8): - a = ASARB; - break; - - case CASE(ORSH, TINT16): - a = ASARW; - break; - - case CASE(ORSH, TINT32): - a = ASARL; - break; - - case CASE(ORSH, TINT64): - a = ASARQ; - break; - - case CASE(ORROTC, TINT8): - case CASE(ORROTC, TUINT8): - a = ARCRB; - break; - - case CASE(ORROTC, TINT16): - case CASE(ORROTC, TUINT16): - a = ARCRW; - break; - - case CASE(ORROTC, TINT32): - case CASE(ORROTC, TUINT32): - a = ARCRL; - break; - - case CASE(ORROTC, TINT64): - case CASE(ORROTC, TUINT64): - a = ARCRQ; - break; - - case CASE(OHMUL, TINT8): - case CASE(OMUL, TINT8): - case CASE(OMUL, TUINT8): - a = AIMULB; - break; - - case CASE(OHMUL, TINT16): - case CASE(OMUL, TINT16): - case CASE(OMUL, TUINT16): - a = AIMULW; - break; - - case CASE(OHMUL, TINT32): - case CASE(OMUL, TINT32): - case CASE(OMUL, TUINT32): - case CASE(OMUL, TPTR32): - a = AIMULL; - break; - - case CASE(OHMUL, TINT64): - case CASE(OMUL, TINT64): - case CASE(OMUL, TUINT64): - case CASE(OMUL, TPTR64): - a = AIMULQ; - break; - - case CASE(OHMUL, TUINT8): - a = AMULB; - break; - - case CASE(OHMUL, TUINT16): - a = AMULW; - break; - - case CASE(OHMUL, TUINT32): - case CASE(OHMUL, TPTR32): - a = AMULL; - break; - - case CASE(OHMUL, TUINT64): - case CASE(OHMUL, TPTR64): - a = AMULQ; - break; - - case CASE(OMUL, TFLOAT32): - a = AMULSS; - break; - - case CASE(OMUL, TFLOAT64): - a = AMULSD; - break; - - case CASE(ODIV, TINT8): - case CASE(OMOD, TINT8): - a = AIDIVB; - break; - - case CASE(ODIV, TUINT8): - case CASE(OMOD, TUINT8): - a = ADIVB; - break; - - case CASE(ODIV, TINT16): - case CASE(OMOD, TINT16): - a = AIDIVW; - break; - - case CASE(ODIV, TUINT16): - case CASE(OMOD, TUINT16): - a = ADIVW; - break; - - case CASE(ODIV, TINT32): - case CASE(OMOD, TINT32): - a = AIDIVL; - break; - - case CASE(ODIV, TUINT32): - case CASE(ODIV, TPTR32): - case CASE(OMOD, TUINT32): - case CASE(OMOD, TPTR32): - a = ADIVL; - break; - - case CASE(ODIV, TINT64): - case CASE(OMOD, TINT64): - a = AIDIVQ; - break; - - case CASE(ODIV, TUINT64): - case CASE(ODIV, TPTR64): - case CASE(OMOD, TUINT64): - case CASE(OMOD, TPTR64): - a = ADIVQ; - break; - - case CASE(OEXTEND, TINT16): - a = ACWD; - break; - - case CASE(OEXTEND, TINT32): - a = ACDQ; - break; - - case CASE(OEXTEND, TINT64): - a = ACQO; - break; - - case CASE(ODIV, TFLOAT32): - a = ADIVSS; - break; - - case CASE(ODIV, TFLOAT64): - a = ADIVSD; - break; - - } - return a; -} - -enum -{ - ODynam = 1<<0, - OAddable = 1<<1, -}; - -static Node clean[20]; -static int cleani = 0; - -int -xgen(Node *n, Node *a, int o) -{ - regalloc(a, types[tptr], N); - - if(o & ODynam) - if(n->addable) - if(n->op != OINDREG) - if(n->op != OREGISTER) - return 1; - - agen(n, a); - return 0; -} - -void -sudoclean(void) -{ - if(clean[cleani-1].op != OEMPTY) - regfree(&clean[cleani-1]); - if(clean[cleani-2].op != OEMPTY) - regfree(&clean[cleani-2]); - cleani -= 2; -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -int -sudoaddable(int as, Node *n, Addr *a) -{ - int o, i; - int64 oary[10]; - int64 v, w; - Node n1, n2, n3, n4, *nn, *l, *r; - Node *reg, *reg1; - Prog *p1; - Type *t; - - if(n->type == T) - return 0; - - memset(a, 0, sizeof *a); - - switch(n->op) { - case OLITERAL: - if(!isconst(n, CTINT)) - break; - v = mpgetfix(n->val.u.xval); - if(v >= 32000 || v <= -32000) - break; - goto lit; - - case ODOT: - case ODOTPTR: - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - goto odot; - - case OINDEX: - return 0; - // disabled: OINDEX case is now covered by agenr - // for a more suitable register allocation pattern. - if(n->left->type->etype == TSTRING) - return 0; - goto oindex; - } - return 0; - -lit: - switch(as) { - default: - return 0; - case AADDB: case AADDW: case AADDL: case AADDQ: - case ASUBB: case ASUBW: case ASUBL: case ASUBQ: - case AANDB: case AANDW: case AANDL: case AANDQ: - case AORB: case AORW: case AORL: case AORQ: - case AXORB: case AXORW: case AXORL: case AXORQ: - case AINCB: case AINCW: case AINCL: case AINCQ: - case ADECB: case ADECW: case ADECL: case ADECQ: - case AMOVB: case AMOVW: case AMOVL: case AMOVQ: - break; - } - - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - naddr(n, a, 1); - goto yes; - -odot: - o = dotoffset(n, oary, &nn); - if(nn == N) - goto no; - - if(nn->addable && o == 1 && oary[0] >= 0) { - // directly addressable set of DOTs - n1 = *nn; - n1.type = n->type; - n1.xoffset += oary[0]; - naddr(&n1, a, 1); - goto yes; - } - - regalloc(reg, types[tptr], N); - n1 = *reg; - n1.op = OINDREG; - if(oary[0] >= 0) { - agen(nn, reg); - n1.xoffset = oary[0]; - } else { - cgen(nn, reg); - cgen_checknil(reg); - n1.xoffset = -(oary[0]+1); - } - - for(i=1; i= 0) - fatal("can't happen"); - gins(movptr, &n1, reg); - cgen_checknil(reg); - n1.xoffset = -(oary[i]+1); - } - - a->type = TYPE_NONE; - a->index = TYPE_NONE; - fixlargeoffset(&n1); - naddr(&n1, a, 1); - goto yes; - -oindex: - l = n->left; - r = n->right; - if(l->ullman >= UINF && r->ullman >= UINF) - return 0; - - // set o to type of array - o = 0; - if(isptr[l->type->etype]) - fatal("ptr ary"); - if(l->type->etype != TARRAY) - fatal("not ary"); - if(l->type->bound < 0) - o |= ODynam; - - w = n->type->width; - if(isconst(r, CTINT)) - goto oindex_const; - - switch(w) { - default: - return 0; - case 1: - case 2: - case 4: - case 8: - break; - } - - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - - // load the array (reg) - if(l->ullman > r->ullman) { - if(xgen(l, reg, o)) - o |= OAddable; - } - - // load the index (reg1) - t = types[TUINT64]; - if(issigned[r->type->etype]) - t = types[TINT64]; - regalloc(reg1, t, N); - regalloc(&n3, r->type, reg1); - cgen(r, &n3); - gmove(&n3, reg1); - regfree(&n3); - - // load the array (reg) - if(l->ullman <= r->ullman) { - if(xgen(l, reg, o)) - o |= OAddable; - } - - // check bounds - if(!debug['B'] && !n->bounded) { - // check bounds - n4.op = OXXX; - t = types[simtype[TUINT]]; - if(o & ODynam) { - if(o & OAddable) { - n2 = *l; - n2.xoffset += Array_nel; - n2.type = types[simtype[TUINT]]; - } else { - n2 = *reg; - n2.xoffset = Array_nel; - n2.op = OINDREG; - n2.type = types[simtype[TUINT]]; - } - } else { - if(is64(r->type)) - t = types[TUINT64]; - nodconst(&n2, types[TUINT64], l->type->bound); - } - gins(optoas(OCMP, t), reg1, &n2); - p1 = gbranch(optoas(OLT, t), T, +1); - if(n4.op != OXXX) - regfree(&n4); - ginscall(panicindex, -1); - patch(p1, pc); - } - - if(o & ODynam) { - if(o & OAddable) { - n2 = *l; - n2.xoffset += Array_array; - n2.type = types[tptr]; - gmove(&n2, reg); - } else { - n2 = *reg; - n2.op = OINDREG; - n2.xoffset = Array_array; - n2.type = types[tptr]; - gmove(&n2, reg); - } - } - - if(o & OAddable) { - naddr(reg1, a, 1); - a->offset = 0; - a->scale = w; - a->index = a->reg; - a->type = TYPE_MEM; - a->reg = reg->val.u.reg; - } else { - naddr(reg1, a, 1); - a->offset = 0; - a->scale = w; - a->index = a->reg; - a->type = TYPE_MEM; - a->reg = reg->val.u.reg; - } - - goto yes; - -oindex_const: - // index is constant - // can check statically and - // can multiply by width statically - - v = mpgetfix(r->val.u.xval); - - if(sudoaddable(as, l, a)) - goto oindex_const_sudo; - - cleani += 2; - reg = &clean[cleani-1]; - reg1 = &clean[cleani-2]; - reg->op = OEMPTY; - reg1->op = OEMPTY; - - if(o & ODynam) { - regalloc(reg, types[tptr], N); - agen(l, reg); - - if(!debug['B'] && !n->bounded) { - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - nodconst(&n2, types[TUINT64], v); - gins(optoas(OCMP, types[simtype[TUINT]]), &n1, &n2); - p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1); - ginscall(panicindex, -1); - patch(p1, pc); - } - - n1 = *reg; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, reg); - - n2 = *reg; - n2.op = OINDREG; - n2.xoffset = v*w; - fixlargeoffset(&n2); - a->type = TYPE_NONE; - a->index = TYPE_NONE; - naddr(&n2, a, 1); - goto yes; - } - - igen(l, &n1, N); - if(n1.op == OINDREG) { - *reg = n1; - reg->op = OREGISTER; - } - n1.xoffset += v*w; - fixlargeoffset(&n1); - a->type = TYPE_NONE; - a->index= TYPE_NONE; - naddr(&n1, a, 1); - goto yes; - -oindex_const_sudo: - if((o & ODynam) == 0) { - // array indexed by a constant - a->offset += v*w; - goto yes; - } - - // slice indexed by a constant - if(!debug['B'] && !n->bounded) { - a->offset += Array_nel; - nodconst(&n2, types[TUINT64], v); - p1 = gins(optoas(OCMP, types[simtype[TUINT]]), N, &n2); - p1->from = *a; - p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1); - ginscall(panicindex, -1); - patch(p1, pc); - a->offset -= Array_nel; - } - - a->offset += Array_array; - reg = &clean[cleani-1]; - if(reg->op == OEMPTY) - regalloc(reg, types[tptr], N); - - p1 = gins(movptr, N, reg); - p1->from = *a; - - n2 = *reg; - n2.op = OINDREG; - n2.xoffset = v*w; - fixlargeoffset(&n2); - a->type = TYPE_NONE; - a->index = TYPE_NONE; - naddr(&n2, a, 1); - goto yes; - -yes: - return 1; - -no: - sudoclean(); - return 0; -} diff --git a/src/cmd/6g/gsubr.go b/src/cmd/6g/gsubr.go new file mode 100644 index 0000000000..c440f8c5f7 --- /dev/null +++ b/src/cmd/6g/gsubr.go @@ -0,0 +1,1752 @@ +// Derived from Inferno utils/6c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" + "fmt" +) +import "cmd/internal/gc" + +// TODO(rsc): Can make this bigger if we move +// the text segment up higher in 6l for all GOOS. +// At the same time, can raise StackBig in ../../runtime/stack.h. +var unmappedzero int64 = 4096 + +var resvd = []int{ + x86.REG_DI, // for movstring + x86.REG_SI, // for movstring + + x86.REG_AX, // for divide + x86.REG_CX, // for shift + x86.REG_DX, // for divide + x86.REG_SP, // for stack +} + +func ginit() { + var i int + + for i = 0; i < len(reg); i++ { + reg[i] = 1 + } + for i = x86.REG_AX; i <= x86.REG_R15; i++ { + reg[i] = 0 + } + for i = x86.REG_X0; i <= x86.REG_X15; i++ { + reg[i] = 0 + } + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]++ + } + + if gc.Nacl { + reg[x86.REG_BP]++ + reg[x86.REG_R15]++ + } else if obj.Framepointer_enabled != 0 { + // BP is part of the calling convention of framepointer_enabled. + reg[x86.REG_BP]++ + } +} + +func gclean() { + var i int + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]-- + } + if gc.Nacl { + reg[x86.REG_BP]-- + reg[x86.REG_R15]-- + } else if obj.Framepointer_enabled != 0 { + reg[x86.REG_BP]-- + } + + for i = x86.REG_AX; i <= x86.REG_R15; i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) + } + } + for i = x86.REG_X0; i <= x86.REG_X15; i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) + } + } +} + +func anyregalloc() bool { + var i int + var j int + + for i = x86.REG_AX; i <= x86.REG_R15; i++ { + if reg[i] == 0 { + goto ok + } + for j = 0; j < len(resvd); j++ { + if resvd[j] == i { + goto ok + } + } + return true + ok: + } + + return false +} + +var regpc [x86.REG_R15 + 1 - x86.REG_AX]uint32 + +/* + * allocate register of type t, leave in n. + * if o != N, o is desired fixed register. + * caller must regfree(n). + */ +func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { + var i int + var et int + + if t == nil { + gc.Fatal("regalloc: t nil") + } + et = int(gc.Simtype[t.Etype]) + + switch et { + case gc.TINT8, + gc.TUINT8, + gc.TINT16, + gc.TUINT16, + gc.TINT32, + gc.TUINT32, + gc.TINT64, + gc.TUINT64, + gc.TPTR32, + gc.TPTR64, + gc.TBOOL: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= x86.REG_AX && i <= x86.REG_R15 { + goto out + } + } + + for i = x86.REG_AX; i <= x86.REG_R15; i++ { + if reg[i] == 0 { + regpc[i-x86.REG_AX] = uint32(obj.Getcallerpc(&n)) + goto out + } + } + + gc.Flusherrors() + for i = 0; i+x86.REG_AX <= x86.REG_R15; i++ { + fmt.Printf("%d %p\n", i, regpc[i]) + } + gc.Fatal("out of fixed registers") + + case gc.TFLOAT32, + gc.TFLOAT64: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= x86.REG_X0 && i <= x86.REG_X15 { + goto out + } + } + + for i = x86.REG_X0; i <= x86.REG_X15; i++ { + if reg[i] == 0 { + goto out + } + } + gc.Fatal("out of floating registers") + + case gc.TCOMPLEX64, + gc.TCOMPLEX128: + gc.Tempname(n, t) + return + } + + gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0)) + return + +out: + reg[i]++ + gc.Nodreg(n, t, i) +} + +func regfree(n *gc.Node) { + var i int + + if n.Op == gc.ONAME { + return + } + if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { + gc.Fatal("regfree: not a register") + } + i = int(n.Val.U.Reg) + if i == x86.REG_SP { + return + } + if i < 0 || i >= len(reg) { + gc.Fatal("regfree: reg out of range") + } + if reg[i] <= 0 { + gc.Fatal("regfree: reg not allocated") + } + reg[i]-- + if reg[i] == 0 && x86.REG_AX <= i && i <= x86.REG_R15 { + regpc[i-x86.REG_AX] = 0 + } +} + +/* + * generate + * as $c, reg + */ +func gconreg(as int, c int64, reg int) { + var nr gc.Node + + switch as { + case x86.AADDL, + x86.AMOVL, + x86.ALEAL: + gc.Nodreg(&nr, gc.Types[gc.TINT32], reg) + + default: + gc.Nodreg(&nr, gc.Types[gc.TINT64], reg) + } + + ginscon(as, c, &nr) +} + +/* + * generate + * as $c, n + */ +func ginscon(as int, c int64, n2 *gc.Node) { + var n1 gc.Node + var ntmp gc.Node + + switch as { + case x86.AADDL, + x86.AMOVL, + x86.ALEAL: + gc.Nodconst(&n1, gc.Types[gc.TINT32], c) + + default: + gc.Nodconst(&n1, gc.Types[gc.TINT64], c) + } + + if as != x86.AMOVQ && (c < -(1<<31) || c >= 1<<31) { + // cannot have 64-bit immediate in ADD, etc. + // instead, MOV into register first. + regalloc(&ntmp, gc.Types[gc.TINT64], nil) + + gins(x86.AMOVQ, &n1, &ntmp) + gins(as, &ntmp, n2) + regfree(&ntmp) + return + } + + gins(as, &n1, n2) +} + +/* + * set up nodes representing 2^63 + */ +var bigi gc.Node + +var bigf gc.Node + +var bignodes_did int + +func bignodes() { + if bignodes_did != 0 { + return + } + bignodes_did = 1 + + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) + gc.Mpshiftfix(bigi.Val.U.Xval, 63) + + bigf = bigi + bigf.Type = gc.Types[gc.TFLOAT64] + bigf.Val.Ctype = gc.CTFLT + bigf.Val.U.Fval = new(gc.Mpflt) + gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) +} + +/* + * generate move: + * t = f + * hard part is conversions. + */ +func gmove(f *gc.Node, t *gc.Node) { + var a int + var ft int + var tt int + var cvt *gc.Type + var r1 gc.Node + var r2 gc.Node + var r3 gc.Node + var r4 gc.Node + var zero gc.Node + var one gc.Node + var con gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['M'] != 0 { + fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) + } + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { + gc.Complexmove(f, t) + return + } + + // cannot have two memory operands + if gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + + // convert constant to desired type + if f.Op == gc.OLITERAL { + gc.Convconst(&con, t.Type, &f.Val) + f = &con + ft = tt // so big switch will choose a simple mov + + // some constants can't move directly to memory. + if gc.Ismem(t) { + // float constants come from memory. + if gc.Isfloat[tt] != 0 { + goto hard + } + + // 64-bit immediates are really 32-bit sign-extended + // unless moving into a register. + if gc.Isint[tt] != 0 { + if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 { + goto hard + } + if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 { + goto hard + } + } + } + } + + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + + switch uint32(ft)<<16 | uint32(tt) { + default: + gc.Fatal("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong)) + + /* + * integer copy and truncate + */ + case gc.TINT8<<16 | gc.TINT8, // same size + gc.TINT8<<16 | gc.TUINT8, + gc.TUINT8<<16 | gc.TINT8, + gc.TUINT8<<16 | gc.TUINT8, + gc.TINT16<<16 | gc.TINT8, + // truncate + gc.TUINT16<<16 | gc.TINT8, + gc.TINT32<<16 | gc.TINT8, + gc.TUINT32<<16 | gc.TINT8, + gc.TINT64<<16 | gc.TINT8, + gc.TUINT64<<16 | gc.TINT8, + gc.TINT16<<16 | gc.TUINT8, + gc.TUINT16<<16 | gc.TUINT8, + gc.TINT32<<16 | gc.TUINT8, + gc.TUINT32<<16 | gc.TUINT8, + gc.TINT64<<16 | gc.TUINT8, + gc.TUINT64<<16 | gc.TUINT8: + a = x86.AMOVB + + case gc.TINT16<<16 | gc.TINT16, // same size + gc.TINT16<<16 | gc.TUINT16, + gc.TUINT16<<16 | gc.TINT16, + gc.TUINT16<<16 | gc.TUINT16, + gc.TINT32<<16 | gc.TINT16, + // truncate + gc.TUINT32<<16 | gc.TINT16, + gc.TINT64<<16 | gc.TINT16, + gc.TUINT64<<16 | gc.TINT16, + gc.TINT32<<16 | gc.TUINT16, + gc.TUINT32<<16 | gc.TUINT16, + gc.TINT64<<16 | gc.TUINT16, + gc.TUINT64<<16 | gc.TUINT16: + a = x86.AMOVW + + case gc.TINT32<<16 | gc.TINT32, // same size + gc.TINT32<<16 | gc.TUINT32, + gc.TUINT32<<16 | gc.TINT32, + gc.TUINT32<<16 | gc.TUINT32: + a = x86.AMOVL + + case gc.TINT64<<16 | gc.TINT32, // truncate + gc.TUINT64<<16 | gc.TINT32, + gc.TINT64<<16 | gc.TUINT32, + gc.TUINT64<<16 | gc.TUINT32: + a = x86.AMOVQL + + case gc.TINT64<<16 | gc.TINT64, // same size + gc.TINT64<<16 | gc.TUINT64, + gc.TUINT64<<16 | gc.TINT64, + gc.TUINT64<<16 | gc.TUINT64: + a = x86.AMOVQ + + /* + * integer up-conversions + */ + case gc.TINT8<<16 | gc.TINT16, // sign extend int8 + gc.TINT8<<16 | gc.TUINT16: + a = x86.AMOVBWSX + + goto rdst + + case gc.TINT8<<16 | gc.TINT32, + gc.TINT8<<16 | gc.TUINT32: + a = x86.AMOVBLSX + goto rdst + + case gc.TINT8<<16 | gc.TINT64, + gc.TINT8<<16 | gc.TUINT64: + a = x86.AMOVBQSX + goto rdst + + case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 + gc.TUINT8<<16 | gc.TUINT16: + a = x86.AMOVBWZX + + goto rdst + + case gc.TUINT8<<16 | gc.TINT32, + gc.TUINT8<<16 | gc.TUINT32: + a = x86.AMOVBLZX + goto rdst + + case gc.TUINT8<<16 | gc.TINT64, + gc.TUINT8<<16 | gc.TUINT64: + a = x86.AMOVBQZX + goto rdst + + case gc.TINT16<<16 | gc.TINT32, // sign extend int16 + gc.TINT16<<16 | gc.TUINT32: + a = x86.AMOVWLSX + + goto rdst + + case gc.TINT16<<16 | gc.TINT64, + gc.TINT16<<16 | gc.TUINT64: + a = x86.AMOVWQSX + goto rdst + + case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 + gc.TUINT16<<16 | gc.TUINT32: + a = x86.AMOVWLZX + + goto rdst + + case gc.TUINT16<<16 | gc.TINT64, + gc.TUINT16<<16 | gc.TUINT64: + a = x86.AMOVWQZX + goto rdst + + case gc.TINT32<<16 | gc.TINT64, // sign extend int32 + gc.TINT32<<16 | gc.TUINT64: + a = x86.AMOVLQSX + + goto rdst + + // AMOVL into a register zeros the top of the register, + // so this is not always necessary, but if we rely on AMOVL + // the optimizer is almost certain to screw with us. + case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 + gc.TUINT32<<16 | gc.TUINT64: + a = x86.AMOVLQZX + + goto rdst + + /* + * float to integer + */ + case gc.TFLOAT32<<16 | gc.TINT32: + a = x86.ACVTTSS2SL + + goto rdst + + case gc.TFLOAT64<<16 | gc.TINT32: + a = x86.ACVTTSD2SL + goto rdst + + case gc.TFLOAT32<<16 | gc.TINT64: + a = x86.ACVTTSS2SQ + goto rdst + + case gc.TFLOAT64<<16 | gc.TINT64: + a = x86.ACVTTSD2SQ + goto rdst + + // convert via int32. + case gc.TFLOAT32<<16 | gc.TINT16, + gc.TFLOAT32<<16 | gc.TINT8, + gc.TFLOAT32<<16 | gc.TUINT16, + gc.TFLOAT32<<16 | gc.TUINT8, + gc.TFLOAT64<<16 | gc.TINT16, + gc.TFLOAT64<<16 | gc.TINT8, + gc.TFLOAT64<<16 | gc.TUINT16, + gc.TFLOAT64<<16 | gc.TUINT8: + cvt = gc.Types[gc.TINT32] + + goto hard + + // convert via int64. + case gc.TFLOAT32<<16 | gc.TUINT32, + gc.TFLOAT64<<16 | gc.TUINT32: + cvt = gc.Types[gc.TINT64] + + goto hard + + // algorithm is: + // if small enough, use native float64 -> int64 conversion. + // otherwise, subtract 2^63, convert, and add it back. + case gc.TFLOAT32<<16 | gc.TUINT64, + gc.TFLOAT64<<16 | gc.TUINT64: + a = x86.ACVTTSS2SQ + + if ft == gc.TFLOAT64 { + a = x86.ACVTTSD2SQ + } + bignodes() + regalloc(&r1, gc.Types[ft], nil) + regalloc(&r2, gc.Types[tt], t) + regalloc(&r3, gc.Types[ft], nil) + regalloc(&r4, gc.Types[tt], nil) + gins(optoas(gc.OAS, f.Type), f, &r1) + gins(optoas(gc.OCMP, f.Type), &bigf, &r1) + p1 = gc.Gbranch(optoas(gc.OLE, f.Type), nil, +1) + gins(a, &r1, &r2) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + gins(optoas(gc.OAS, f.Type), &bigf, &r3) + gins(optoas(gc.OSUB, f.Type), &r3, &r1) + gins(a, &r1, &r2) + gins(x86.AMOVQ, &bigi, &r4) + gins(x86.AXORQ, &r4, &r2) + gc.Patch(p2, gc.Pc) + gmove(&r2, t) + regfree(&r4) + regfree(&r3) + regfree(&r2) + regfree(&r1) + return + + /* + * integer to float + */ + case gc.TINT32<<16 | gc.TFLOAT32: + a = x86.ACVTSL2SS + + goto rdst + + case gc.TINT32<<16 | gc.TFLOAT64: + a = x86.ACVTSL2SD + goto rdst + + case gc.TINT64<<16 | gc.TFLOAT32: + a = x86.ACVTSQ2SS + goto rdst + + case gc.TINT64<<16 | gc.TFLOAT64: + a = x86.ACVTSQ2SD + goto rdst + + // convert via int32 + case gc.TINT16<<16 | gc.TFLOAT32, + gc.TINT16<<16 | gc.TFLOAT64, + gc.TINT8<<16 | gc.TFLOAT32, + gc.TINT8<<16 | gc.TFLOAT64, + gc.TUINT16<<16 | gc.TFLOAT32, + gc.TUINT16<<16 | gc.TFLOAT64, + gc.TUINT8<<16 | gc.TFLOAT32, + gc.TUINT8<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + // convert via int64. + case gc.TUINT32<<16 | gc.TFLOAT32, + gc.TUINT32<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT64] + + goto hard + + // algorithm is: + // if small enough, use native int64 -> uint64 conversion. + // otherwise, halve (rounding to odd?), convert, and double. + case gc.TUINT64<<16 | gc.TFLOAT32, + gc.TUINT64<<16 | gc.TFLOAT64: + a = x86.ACVTSQ2SS + + if tt == gc.TFLOAT64 { + a = x86.ACVTSQ2SD + } + gc.Nodconst(&zero, gc.Types[gc.TUINT64], 0) + gc.Nodconst(&one, gc.Types[gc.TUINT64], 1) + regalloc(&r1, f.Type, f) + regalloc(&r2, t.Type, t) + regalloc(&r3, f.Type, nil) + regalloc(&r4, f.Type, nil) + gmove(f, &r1) + gins(x86.ACMPQ, &r1, &zero) + p1 = gc.Gbranch(x86.AJLT, nil, +1) + gins(a, &r1, &r2) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + gmove(&r1, &r3) + gins(x86.ASHRQ, &one, &r3) + gmove(&r1, &r4) + gins(x86.AANDL, &one, &r4) + gins(x86.AORQ, &r4, &r3) + gins(a, &r3, &r2) + gins(optoas(gc.OADD, t.Type), &r2, &r2) + gc.Patch(p2, gc.Pc) + gmove(&r2, t) + regfree(&r4) + regfree(&r3) + regfree(&r2) + regfree(&r1) + return + + /* + * float to float + */ + case gc.TFLOAT32<<16 | gc.TFLOAT32: + a = x86.AMOVSS + + case gc.TFLOAT64<<16 | gc.TFLOAT64: + a = x86.AMOVSD + + case gc.TFLOAT32<<16 | gc.TFLOAT64: + a = x86.ACVTSS2SD + goto rdst + + case gc.TFLOAT64<<16 | gc.TFLOAT32: + a = x86.ACVTSD2SS + goto rdst + } + + gins(a, f, t) + return + + // requires register destination +rdst: + regalloc(&r1, t.Type, t) + + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return +} + +func samaddr(f *gc.Node, t *gc.Node) bool { + if f.Op != t.Op { + return false + } + + switch f.Op { + case gc.OREGISTER: + if f.Val.U.Reg != t.Val.U.Reg { + break + } + return true + } + + return false +} + +/* + * generate one instruction: + * as f, t + */ +func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { + var w int32 + var p *obj.Prog + // Node nod; + + var af obj.Addr + var at obj.Addr + + // if(f != N && f->op == OINDEX) { + // regalloc(&nod, ®node, Z); + // v = constnode.vconst; + // cgen(f->right, &nod); + // constnode.vconst = v; + // idx.reg = nod.reg; + // regfree(&nod); + // } + // if(t != N && t->op == OINDEX) { + // regalloc(&nod, ®node, Z); + // v = constnode.vconst; + // cgen(t->right, &nod); + // constnode.vconst = v; + // idx.reg = nod.reg; + // regfree(&nod); + // } + + switch as { + case x86.AMOVB, + x86.AMOVW, + x86.AMOVL, + x86.AMOVQ, + x86.AMOVSS, + x86.AMOVSD: + if f != nil && t != nil && samaddr(f, t) { + return nil + } + + case x86.ALEAQ: + if f != nil && gc.Isconst(f, gc.CTNIL) { + gc.Fatal("gins LEAQ nil %v", gc.Tconv(f.Type, 0)) + } + } + + af = obj.Addr{} + at = obj.Addr{} + if f != nil { + gc.Naddr(f, &af, 1) + } + if t != nil { + gc.Naddr(t, &at, 1) + } + p = gc.Prog(as) + if f != nil { + p.From = af + } + if t != nil { + p.To = at + } + if gc.Debug['g'] != 0 { + fmt.Printf("%v\n", p) + } + + w = 0 + switch as { + case x86.AMOVB: + w = 1 + + case x86.AMOVW: + w = 2 + + case x86.AMOVL: + w = 4 + + case x86.AMOVQ: + w = 8 + } + + if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Width > int64(w))) { + gc.Dump("f", f) + gc.Dump("t", t) + gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) + } + + if p.To.Type == obj.TYPE_ADDR && w > 0 { + gc.Fatal("bad use of addr: %v", p) + } + + return p +} + +func fixlargeoffset(n *gc.Node) { + var a gc.Node + + if n == nil { + return + } + if n.Op != gc.OINDREG { + return + } + if n.Val.U.Reg == x86.REG_SP { // stack offset cannot be large + return + } + if n.Xoffset != int64(int32(n.Xoffset)) { + // offset too large, add to register instead. + a = *n + + a.Op = gc.OREGISTER + a.Type = gc.Types[gc.Tptr] + a.Xoffset = 0 + gc.Cgen_checknil(&a) + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a) + n.Xoffset = 0 + } +} + +/* + * return Axxx for Oxxx on type t. + */ +func optoas(op int, t *gc.Type) int { + var a int + + if t == nil { + gc.Fatal("optoas: t is nil") + } + + a = obj.AXXX + switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { + default: + gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + case gc.OADDR<<16 | gc.TPTR32: + a = x86.ALEAL + + case gc.OADDR<<16 | gc.TPTR64: + a = x86.ALEAQ + + case gc.OEQ<<16 | gc.TBOOL, + gc.OEQ<<16 | gc.TINT8, + gc.OEQ<<16 | gc.TUINT8, + gc.OEQ<<16 | gc.TINT16, + gc.OEQ<<16 | gc.TUINT16, + gc.OEQ<<16 | gc.TINT32, + gc.OEQ<<16 | gc.TUINT32, + gc.OEQ<<16 | gc.TINT64, + gc.OEQ<<16 | gc.TUINT64, + gc.OEQ<<16 | gc.TPTR32, + gc.OEQ<<16 | gc.TPTR64, + gc.OEQ<<16 | gc.TFLOAT32, + gc.OEQ<<16 | gc.TFLOAT64: + a = x86.AJEQ + + case gc.ONE<<16 | gc.TBOOL, + gc.ONE<<16 | gc.TINT8, + gc.ONE<<16 | gc.TUINT8, + gc.ONE<<16 | gc.TINT16, + gc.ONE<<16 | gc.TUINT16, + gc.ONE<<16 | gc.TINT32, + gc.ONE<<16 | gc.TUINT32, + gc.ONE<<16 | gc.TINT64, + gc.ONE<<16 | gc.TUINT64, + gc.ONE<<16 | gc.TPTR32, + gc.ONE<<16 | gc.TPTR64, + gc.ONE<<16 | gc.TFLOAT32, + gc.ONE<<16 | gc.TFLOAT64: + a = x86.AJNE + + case gc.OLT<<16 | gc.TINT8, + gc.OLT<<16 | gc.TINT16, + gc.OLT<<16 | gc.TINT32, + gc.OLT<<16 | gc.TINT64: + a = x86.AJLT + + case gc.OLT<<16 | gc.TUINT8, + gc.OLT<<16 | gc.TUINT16, + gc.OLT<<16 | gc.TUINT32, + gc.OLT<<16 | gc.TUINT64: + a = x86.AJCS + + case gc.OLE<<16 | gc.TINT8, + gc.OLE<<16 | gc.TINT16, + gc.OLE<<16 | gc.TINT32, + gc.OLE<<16 | gc.TINT64: + a = x86.AJLE + + case gc.OLE<<16 | gc.TUINT8, + gc.OLE<<16 | gc.TUINT16, + gc.OLE<<16 | gc.TUINT32, + gc.OLE<<16 | gc.TUINT64: + a = x86.AJLS + + case gc.OGT<<16 | gc.TINT8, + gc.OGT<<16 | gc.TINT16, + gc.OGT<<16 | gc.TINT32, + gc.OGT<<16 | gc.TINT64: + a = x86.AJGT + + case gc.OGT<<16 | gc.TUINT8, + gc.OGT<<16 | gc.TUINT16, + gc.OGT<<16 | gc.TUINT32, + gc.OGT<<16 | gc.TUINT64, + gc.OLT<<16 | gc.TFLOAT32, + gc.OLT<<16 | gc.TFLOAT64: + a = x86.AJHI + + case gc.OGE<<16 | gc.TINT8, + gc.OGE<<16 | gc.TINT16, + gc.OGE<<16 | gc.TINT32, + gc.OGE<<16 | gc.TINT64: + a = x86.AJGE + + case gc.OGE<<16 | gc.TUINT8, + gc.OGE<<16 | gc.TUINT16, + gc.OGE<<16 | gc.TUINT32, + gc.OGE<<16 | gc.TUINT64, + gc.OLE<<16 | gc.TFLOAT32, + gc.OLE<<16 | gc.TFLOAT64: + a = x86.AJCC + + case gc.OCMP<<16 | gc.TBOOL, + gc.OCMP<<16 | gc.TINT8, + gc.OCMP<<16 | gc.TUINT8: + a = x86.ACMPB + + case gc.OCMP<<16 | gc.TINT16, + gc.OCMP<<16 | gc.TUINT16: + a = x86.ACMPW + + case gc.OCMP<<16 | gc.TINT32, + gc.OCMP<<16 | gc.TUINT32, + gc.OCMP<<16 | gc.TPTR32: + a = x86.ACMPL + + case gc.OCMP<<16 | gc.TINT64, + gc.OCMP<<16 | gc.TUINT64, + gc.OCMP<<16 | gc.TPTR64: + a = x86.ACMPQ + + case gc.OCMP<<16 | gc.TFLOAT32: + a = x86.AUCOMISS + + case gc.OCMP<<16 | gc.TFLOAT64: + a = x86.AUCOMISD + + case gc.OAS<<16 | gc.TBOOL, + gc.OAS<<16 | gc.TINT8, + gc.OAS<<16 | gc.TUINT8: + a = x86.AMOVB + + case gc.OAS<<16 | gc.TINT16, + gc.OAS<<16 | gc.TUINT16: + a = x86.AMOVW + + case gc.OAS<<16 | gc.TINT32, + gc.OAS<<16 | gc.TUINT32, + gc.OAS<<16 | gc.TPTR32: + a = x86.AMOVL + + case gc.OAS<<16 | gc.TINT64, + gc.OAS<<16 | gc.TUINT64, + gc.OAS<<16 | gc.TPTR64: + a = x86.AMOVQ + + case gc.OAS<<16 | gc.TFLOAT32: + a = x86.AMOVSS + + case gc.OAS<<16 | gc.TFLOAT64: + a = x86.AMOVSD + + case gc.OADD<<16 | gc.TINT8, + gc.OADD<<16 | gc.TUINT8: + a = x86.AADDB + + case gc.OADD<<16 | gc.TINT16, + gc.OADD<<16 | gc.TUINT16: + a = x86.AADDW + + case gc.OADD<<16 | gc.TINT32, + gc.OADD<<16 | gc.TUINT32, + gc.OADD<<16 | gc.TPTR32: + a = x86.AADDL + + case gc.OADD<<16 | gc.TINT64, + gc.OADD<<16 | gc.TUINT64, + gc.OADD<<16 | gc.TPTR64: + a = x86.AADDQ + + case gc.OADD<<16 | gc.TFLOAT32: + a = x86.AADDSS + + case gc.OADD<<16 | gc.TFLOAT64: + a = x86.AADDSD + + case gc.OSUB<<16 | gc.TINT8, + gc.OSUB<<16 | gc.TUINT8: + a = x86.ASUBB + + case gc.OSUB<<16 | gc.TINT16, + gc.OSUB<<16 | gc.TUINT16: + a = x86.ASUBW + + case gc.OSUB<<16 | gc.TINT32, + gc.OSUB<<16 | gc.TUINT32, + gc.OSUB<<16 | gc.TPTR32: + a = x86.ASUBL + + case gc.OSUB<<16 | gc.TINT64, + gc.OSUB<<16 | gc.TUINT64, + gc.OSUB<<16 | gc.TPTR64: + a = x86.ASUBQ + + case gc.OSUB<<16 | gc.TFLOAT32: + a = x86.ASUBSS + + case gc.OSUB<<16 | gc.TFLOAT64: + a = x86.ASUBSD + + case gc.OINC<<16 | gc.TINT8, + gc.OINC<<16 | gc.TUINT8: + a = x86.AINCB + + case gc.OINC<<16 | gc.TINT16, + gc.OINC<<16 | gc.TUINT16: + a = x86.AINCW + + case gc.OINC<<16 | gc.TINT32, + gc.OINC<<16 | gc.TUINT32, + gc.OINC<<16 | gc.TPTR32: + a = x86.AINCL + + case gc.OINC<<16 | gc.TINT64, + gc.OINC<<16 | gc.TUINT64, + gc.OINC<<16 | gc.TPTR64: + a = x86.AINCQ + + case gc.ODEC<<16 | gc.TINT8, + gc.ODEC<<16 | gc.TUINT8: + a = x86.ADECB + + case gc.ODEC<<16 | gc.TINT16, + gc.ODEC<<16 | gc.TUINT16: + a = x86.ADECW + + case gc.ODEC<<16 | gc.TINT32, + gc.ODEC<<16 | gc.TUINT32, + gc.ODEC<<16 | gc.TPTR32: + a = x86.ADECL + + case gc.ODEC<<16 | gc.TINT64, + gc.ODEC<<16 | gc.TUINT64, + gc.ODEC<<16 | gc.TPTR64: + a = x86.ADECQ + + case gc.OMINUS<<16 | gc.TINT8, + gc.OMINUS<<16 | gc.TUINT8: + a = x86.ANEGB + + case gc.OMINUS<<16 | gc.TINT16, + gc.OMINUS<<16 | gc.TUINT16: + a = x86.ANEGW + + case gc.OMINUS<<16 | gc.TINT32, + gc.OMINUS<<16 | gc.TUINT32, + gc.OMINUS<<16 | gc.TPTR32: + a = x86.ANEGL + + case gc.OMINUS<<16 | gc.TINT64, + gc.OMINUS<<16 | gc.TUINT64, + gc.OMINUS<<16 | gc.TPTR64: + a = x86.ANEGQ + + case gc.OAND<<16 | gc.TINT8, + gc.OAND<<16 | gc.TUINT8: + a = x86.AANDB + + case gc.OAND<<16 | gc.TINT16, + gc.OAND<<16 | gc.TUINT16: + a = x86.AANDW + + case gc.OAND<<16 | gc.TINT32, + gc.OAND<<16 | gc.TUINT32, + gc.OAND<<16 | gc.TPTR32: + a = x86.AANDL + + case gc.OAND<<16 | gc.TINT64, + gc.OAND<<16 | gc.TUINT64, + gc.OAND<<16 | gc.TPTR64: + a = x86.AANDQ + + case gc.OOR<<16 | gc.TINT8, + gc.OOR<<16 | gc.TUINT8: + a = x86.AORB + + case gc.OOR<<16 | gc.TINT16, + gc.OOR<<16 | gc.TUINT16: + a = x86.AORW + + case gc.OOR<<16 | gc.TINT32, + gc.OOR<<16 | gc.TUINT32, + gc.OOR<<16 | gc.TPTR32: + a = x86.AORL + + case gc.OOR<<16 | gc.TINT64, + gc.OOR<<16 | gc.TUINT64, + gc.OOR<<16 | gc.TPTR64: + a = x86.AORQ + + case gc.OXOR<<16 | gc.TINT8, + gc.OXOR<<16 | gc.TUINT8: + a = x86.AXORB + + case gc.OXOR<<16 | gc.TINT16, + gc.OXOR<<16 | gc.TUINT16: + a = x86.AXORW + + case gc.OXOR<<16 | gc.TINT32, + gc.OXOR<<16 | gc.TUINT32, + gc.OXOR<<16 | gc.TPTR32: + a = x86.AXORL + + case gc.OXOR<<16 | gc.TINT64, + gc.OXOR<<16 | gc.TUINT64, + gc.OXOR<<16 | gc.TPTR64: + a = x86.AXORQ + + case gc.OLROT<<16 | gc.TINT8, + gc.OLROT<<16 | gc.TUINT8: + a = x86.AROLB + + case gc.OLROT<<16 | gc.TINT16, + gc.OLROT<<16 | gc.TUINT16: + a = x86.AROLW + + case gc.OLROT<<16 | gc.TINT32, + gc.OLROT<<16 | gc.TUINT32, + gc.OLROT<<16 | gc.TPTR32: + a = x86.AROLL + + case gc.OLROT<<16 | gc.TINT64, + gc.OLROT<<16 | gc.TUINT64, + gc.OLROT<<16 | gc.TPTR64: + a = x86.AROLQ + + case gc.OLSH<<16 | gc.TINT8, + gc.OLSH<<16 | gc.TUINT8: + a = x86.ASHLB + + case gc.OLSH<<16 | gc.TINT16, + gc.OLSH<<16 | gc.TUINT16: + a = x86.ASHLW + + case gc.OLSH<<16 | gc.TINT32, + gc.OLSH<<16 | gc.TUINT32, + gc.OLSH<<16 | gc.TPTR32: + a = x86.ASHLL + + case gc.OLSH<<16 | gc.TINT64, + gc.OLSH<<16 | gc.TUINT64, + gc.OLSH<<16 | gc.TPTR64: + a = x86.ASHLQ + + case gc.ORSH<<16 | gc.TUINT8: + a = x86.ASHRB + + case gc.ORSH<<16 | gc.TUINT16: + a = x86.ASHRW + + case gc.ORSH<<16 | gc.TUINT32, + gc.ORSH<<16 | gc.TPTR32: + a = x86.ASHRL + + case gc.ORSH<<16 | gc.TUINT64, + gc.ORSH<<16 | gc.TPTR64: + a = x86.ASHRQ + + case gc.ORSH<<16 | gc.TINT8: + a = x86.ASARB + + case gc.ORSH<<16 | gc.TINT16: + a = x86.ASARW + + case gc.ORSH<<16 | gc.TINT32: + a = x86.ASARL + + case gc.ORSH<<16 | gc.TINT64: + a = x86.ASARQ + + case gc.ORROTC<<16 | gc.TINT8, + gc.ORROTC<<16 | gc.TUINT8: + a = x86.ARCRB + + case gc.ORROTC<<16 | gc.TINT16, + gc.ORROTC<<16 | gc.TUINT16: + a = x86.ARCRW + + case gc.ORROTC<<16 | gc.TINT32, + gc.ORROTC<<16 | gc.TUINT32: + a = x86.ARCRL + + case gc.ORROTC<<16 | gc.TINT64, + gc.ORROTC<<16 | gc.TUINT64: + a = x86.ARCRQ + + case gc.OHMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TUINT8: + a = x86.AIMULB + + case gc.OHMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TUINT16: + a = x86.AIMULW + + case gc.OHMUL<<16 | gc.TINT32, + gc.OMUL<<16 | gc.TINT32, + gc.OMUL<<16 | gc.TUINT32, + gc.OMUL<<16 | gc.TPTR32: + a = x86.AIMULL + + case gc.OHMUL<<16 | gc.TINT64, + gc.OMUL<<16 | gc.TINT64, + gc.OMUL<<16 | gc.TUINT64, + gc.OMUL<<16 | gc.TPTR64: + a = x86.AIMULQ + + case gc.OHMUL<<16 | gc.TUINT8: + a = x86.AMULB + + case gc.OHMUL<<16 | gc.TUINT16: + a = x86.AMULW + + case gc.OHMUL<<16 | gc.TUINT32, + gc.OHMUL<<16 | gc.TPTR32: + a = x86.AMULL + + case gc.OHMUL<<16 | gc.TUINT64, + gc.OHMUL<<16 | gc.TPTR64: + a = x86.AMULQ + + case gc.OMUL<<16 | gc.TFLOAT32: + a = x86.AMULSS + + case gc.OMUL<<16 | gc.TFLOAT64: + a = x86.AMULSD + + case gc.ODIV<<16 | gc.TINT8, + gc.OMOD<<16 | gc.TINT8: + a = x86.AIDIVB + + case gc.ODIV<<16 | gc.TUINT8, + gc.OMOD<<16 | gc.TUINT8: + a = x86.ADIVB + + case gc.ODIV<<16 | gc.TINT16, + gc.OMOD<<16 | gc.TINT16: + a = x86.AIDIVW + + case gc.ODIV<<16 | gc.TUINT16, + gc.OMOD<<16 | gc.TUINT16: + a = x86.ADIVW + + case gc.ODIV<<16 | gc.TINT32, + gc.OMOD<<16 | gc.TINT32: + a = x86.AIDIVL + + case gc.ODIV<<16 | gc.TUINT32, + gc.ODIV<<16 | gc.TPTR32, + gc.OMOD<<16 | gc.TUINT32, + gc.OMOD<<16 | gc.TPTR32: + a = x86.ADIVL + + case gc.ODIV<<16 | gc.TINT64, + gc.OMOD<<16 | gc.TINT64: + a = x86.AIDIVQ + + case gc.ODIV<<16 | gc.TUINT64, + gc.ODIV<<16 | gc.TPTR64, + gc.OMOD<<16 | gc.TUINT64, + gc.OMOD<<16 | gc.TPTR64: + a = x86.ADIVQ + + case gc.OEXTEND<<16 | gc.TINT16: + a = x86.ACWD + + case gc.OEXTEND<<16 | gc.TINT32: + a = x86.ACDQ + + case gc.OEXTEND<<16 | gc.TINT64: + a = x86.ACQO + + case gc.ODIV<<16 | gc.TFLOAT32: + a = x86.ADIVSS + + case gc.ODIV<<16 | gc.TFLOAT64: + a = x86.ADIVSD + } + + return a +} + +const ( + ODynam = 1 << 0 + OAddable = 1 << 1 +) + +var clean [20]gc.Node + +var cleani int = 0 + +func xgen(n *gc.Node, a *gc.Node, o int) bool { + regalloc(a, gc.Types[gc.Tptr], nil) + + if o&ODynam != 0 { + if n.Addable != 0 { + if n.Op != gc.OINDREG { + if n.Op != gc.OREGISTER { + return true + } + } + } + } + + agen(n, a) + return false +} + +func sudoclean() { + if clean[cleani-1].Op != gc.OEMPTY { + regfree(&clean[cleani-1]) + } + if clean[cleani-2].Op != gc.OEMPTY { + regfree(&clean[cleani-2]) + } + cleani -= 2 +} + +/* + * generate code to compute address of n, + * a reference to a (perhaps nested) field inside + * an array or struct. + * return 0 on failure, 1 on success. + * on success, leaves usable address in a. + * + * caller is responsible for calling sudoclean + * after successful sudoaddable, + * to release the register used for a. + */ +func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { + var o int + var i int + var oary [10]int64 + var v int64 + var w int64 + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var nn *gc.Node + var l *gc.Node + var r *gc.Node + var reg *gc.Node + var reg1 *gc.Node + var p1 *obj.Prog + var t *gc.Type + + if n.Type == nil { + return false + } + + *a = obj.Addr{} + + switch n.Op { + case gc.OLITERAL: + if !gc.Isconst(n, gc.CTINT) { + break + } + v = gc.Mpgetfix(n.Val.U.Xval) + if v >= 32000 || v <= -32000 { + break + } + goto lit + + case gc.ODOT, + gc.ODOTPTR: + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + goto odot + + case gc.OINDEX: + return false + + // disabled: OINDEX case is now covered by agenr + // for a more suitable register allocation pattern. + if n.Left.Type.Etype == gc.TSTRING { + return false + } + goto oindex + } + + return false + +lit: + switch as { + default: + return false + + case x86.AADDB, + x86.AADDW, + x86.AADDL, + x86.AADDQ, + x86.ASUBB, + x86.ASUBW, + x86.ASUBL, + x86.ASUBQ, + x86.AANDB, + x86.AANDW, + x86.AANDL, + x86.AANDQ, + x86.AORB, + x86.AORW, + x86.AORL, + x86.AORQ, + x86.AXORB, + x86.AXORW, + x86.AXORL, + x86.AXORQ, + x86.AINCB, + x86.AINCW, + x86.AINCL, + x86.AINCQ, + x86.ADECB, + x86.ADECW, + x86.ADECL, + x86.ADECQ, + x86.AMOVB, + x86.AMOVW, + x86.AMOVL, + x86.AMOVQ: + break + } + + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + gc.Naddr(n, a, 1) + goto yes + +odot: + o = gc.Dotoffset(n, oary[:], &nn) + if nn == nil { + goto no + } + + if nn.Addable != 0 && o == 1 && oary[0] >= 0 { + // directly addressable set of DOTs + n1 = *nn + + n1.Type = n.Type + n1.Xoffset += oary[0] + gc.Naddr(&n1, a, 1) + goto yes + } + + regalloc(reg, gc.Types[gc.Tptr], nil) + n1 = *reg + n1.Op = gc.OINDREG + if oary[0] >= 0 { + agen(nn, reg) + n1.Xoffset = oary[0] + } else { + cgen(nn, reg) + gc.Cgen_checknil(reg) + n1.Xoffset = -(oary[0] + 1) + } + + for i = 1; i < o; i++ { + if oary[i] >= 0 { + gc.Fatal("can't happen") + } + gins(movptr, &n1, reg) + gc.Cgen_checknil(reg) + n1.Xoffset = -(oary[i] + 1) + } + + a.Type = obj.TYPE_NONE + a.Index = obj.TYPE_NONE + fixlargeoffset(&n1) + gc.Naddr(&n1, a, 1) + goto yes + +oindex: + l = n.Left + r = n.Right + if l.Ullman >= gc.UINF && r.Ullman >= gc.UINF { + return false + } + + // set o to type of array + o = 0 + + if gc.Isptr[l.Type.Etype] != 0 { + gc.Fatal("ptr ary") + } + if l.Type.Etype != gc.TARRAY { + gc.Fatal("not ary") + } + if l.Type.Bound < 0 { + o |= ODynam + } + + w = n.Type.Width + if gc.Isconst(r, gc.CTINT) { + goto oindex_const + } + + switch w { + default: + return false + + case 1, + 2, + 4, + 8: + break + } + + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + + // load the array (reg) + if l.Ullman > r.Ullman { + if xgen(l, reg, o) { + o |= OAddable + } + } + + // load the index (reg1) + t = gc.Types[gc.TUINT64] + + if gc.Issigned[r.Type.Etype] != 0 { + t = gc.Types[gc.TINT64] + } + regalloc(reg1, t, nil) + regalloc(&n3, r.Type, reg1) + cgen(r, &n3) + gmove(&n3, reg1) + regfree(&n3) + + // load the array (reg) + if l.Ullman <= r.Ullman { + if xgen(l, reg, o) { + o |= OAddable + } + } + + // check bounds + if gc.Debug['B'] == 0 && !n.Bounded { + // check bounds + n4.Op = gc.OXXX + + t = gc.Types[gc.Simtype[gc.TUINT]] + if o&ODynam != 0 { + if o&OAddable != 0 { + n2 = *l + n2.Xoffset += int64(gc.Array_nel) + n2.Type = gc.Types[gc.Simtype[gc.TUINT]] + } else { + n2 = *reg + n2.Xoffset = int64(gc.Array_nel) + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.Simtype[gc.TUINT]] + } + } else { + if gc.Is64(r.Type) { + t = gc.Types[gc.TUINT64] + } + gc.Nodconst(&n2, gc.Types[gc.TUINT64], l.Type.Bound) + } + + gins(optoas(gc.OCMP, t), reg1, &n2) + p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) + if n4.Op != gc.OXXX { + regfree(&n4) + } + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + + if o&ODynam != 0 { + if o&OAddable != 0 { + n2 = *l + n2.Xoffset += int64(gc.Array_array) + n2.Type = gc.Types[gc.Tptr] + gmove(&n2, reg) + } else { + n2 = *reg + n2.Op = gc.OINDREG + n2.Xoffset = int64(gc.Array_array) + n2.Type = gc.Types[gc.Tptr] + gmove(&n2, reg) + } + } + + if o&OAddable != 0 { + gc.Naddr(reg1, a, 1) + a.Offset = 0 + a.Scale = int8(w) + a.Index = a.Reg + a.Type = obj.TYPE_MEM + a.Reg = reg.Val.U.Reg + } else { + gc.Naddr(reg1, a, 1) + a.Offset = 0 + a.Scale = int8(w) + a.Index = a.Reg + a.Type = obj.TYPE_MEM + a.Reg = reg.Val.U.Reg + } + + goto yes + + // index is constant + // can check statically and + // can multiply by width statically + +oindex_const: + v = gc.Mpgetfix(r.Val.U.Xval) + + if sudoaddable(as, l, a) { + goto oindex_const_sudo + } + + cleani += 2 + reg = &clean[cleani-1] + reg1 = &clean[cleani-2] + reg.Op = gc.OEMPTY + reg1.Op = gc.OEMPTY + + if o&ODynam != 0 { + regalloc(reg, gc.Types[gc.Tptr], nil) + agen(l, reg) + + if gc.Debug['B'] == 0 && !n.Bounded { + n1 = *reg + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + gc.Nodconst(&n2, gc.Types[gc.TUINT64], v) + gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + + n1 = *reg + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, reg) + + n2 = *reg + n2.Op = gc.OINDREG + n2.Xoffset = v * w + fixlargeoffset(&n2) + a.Type = obj.TYPE_NONE + a.Index = obj.TYPE_NONE + gc.Naddr(&n2, a, 1) + goto yes + } + + igen(l, &n1, nil) + if n1.Op == gc.OINDREG { + *reg = n1 + reg.Op = gc.OREGISTER + } + + n1.Xoffset += v * w + fixlargeoffset(&n1) + a.Type = obj.TYPE_NONE + a.Index = obj.TYPE_NONE + gc.Naddr(&n1, a, 1) + goto yes + +oindex_const_sudo: + if o&ODynam == 0 { + // array indexed by a constant + a.Offset += v * w + + goto yes + } + + // slice indexed by a constant + if gc.Debug['B'] == 0 && !n.Bounded { + a.Offset += int64(gc.Array_nel) + gc.Nodconst(&n2, gc.Types[gc.TUINT64], v) + p1 = gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), nil, &n2) + p1.From = *a + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + a.Offset -= int64(gc.Array_nel) + } + + a.Offset += int64(gc.Array_array) + reg = &clean[cleani-1] + if reg.Op == gc.OEMPTY { + regalloc(reg, gc.Types[gc.Tptr], nil) + } + + p1 = gins(movptr, nil, reg) + p1.From = *a + + n2 = *reg + n2.Op = gc.OINDREG + n2.Xoffset = v * w + fixlargeoffset(&n2) + a.Type = obj.TYPE_NONE + a.Index = obj.TYPE_NONE + gc.Naddr(&n2, a, 1) + goto yes + +yes: + return true + +no: + sudoclean() + return false +} diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c deleted file mode 100644 index 261cb6e0a1..0000000000 --- a/src/cmd/6g/peep.c +++ /dev/null @@ -1,988 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static void conprop(Flow *r); -static void elimshortmov(Graph *g); -static int prevl(Flow *r, int reg); -static void pushback(Flow *r); -static int regconsttyp(Adr*); -static int subprop(Flow*); -static int copyprop(Graph*, Flow*); -static int copy1(Adr*, Adr*, Flow*, int); -static int copyas(Adr*, Adr*); -static int copyau(Adr*, Adr*); -static int copysub(Adr*, Adr*, Adr*, int); -static int copyu(Prog*, Adr*, Adr*); - -static uint32 gactive; - -enum -{ - exregoffset = REG_R15, -}; - -// do we need the carry bit -static int -needc(Prog *p) -{ - ProgInfo info; - - while(p != P) { - proginfo(&info, p); - if(info.flags & UseCarry) - return 1; - if(info.flags & (SetCarry|KillCarry)) - return 0; - p = p->link; - } - return 0; -} - -static Flow* -rnops(Flow *r) -{ - Prog *p; - Flow *r1; - - if(r != nil) - for(;;) { - p = r->prog; - if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE) - break; - r1 = uniqs(r); - if(r1 == nil) - break; - r = r1; - } - return r; -} - -void -peep(Prog *firstp) -{ - Flow *r, *r1; - Graph *g; - Prog *p, *p1; - int t; - - g = flowstart(firstp, 0); - if(g == nil) - return; - gactive = 0; - - // byte, word arithmetic elimination. - elimshortmov(g); - - // constant propagation - // find MOV $con,R followed by - // another MOV $con,R without - // setting R in the interim - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case ALEAL: - case ALEAQ: - if(regtyp(&p->to)) - if(p->from.sym != nil) - if(p->from.index == REG_NONE) - conprop(r); - break; - - case AMOVB: - case AMOVW: - case AMOVL: - case AMOVQ: - case AMOVSS: - case AMOVSD: - if(regtyp(&p->to)) - if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST) - conprop(r); - break; - } - } - -loop1: - if(debug['P'] && debug['v']) - dumpit("loop1", g->start, 0); - - t = 0; - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case AMOVL: - case AMOVQ: - case AMOVSS: - case AMOVSD: - if(regtyp(&p->to)) - if(regtyp(&p->from)) { - if(copyprop(g, r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(g, r)) { - excise(r); - t++; - } - } - break; - - case AMOVBLZX: - case AMOVWLZX: - case AMOVBLSX: - case AMOVWLSX: - if(regtyp(&p->to)) { - r1 = rnops(uniqs(r)); - if(r1 != nil) { - p1 = r1->prog; - if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){ - p1->as = AMOVL; - t++; - } - } - } - break; - - case AMOVBQSX: - case AMOVBQZX: - case AMOVWQSX: - case AMOVWQZX: - case AMOVLQSX: - case AMOVLQZX: - case AMOVQL: - if(regtyp(&p->to)) { - r1 = rnops(uniqs(r)); - if(r1 != nil) { - p1 = r1->prog; - if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){ - p1->as = AMOVQ; - t++; - } - } - } - break; - - case AADDL: - case AADDQ: - case AADDW: - if(p->from.type != TYPE_CONST || needc(p->link)) - break; - if(p->from.offset == -1){ - if(p->as == AADDQ) - p->as = ADECQ; - else - if(p->as == AADDL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - break; - } - if(p->from.offset == 1){ - if(p->as == AADDQ) - p->as = AINCQ; - else if(p->as == AADDL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - break; - } - break; - - case ASUBL: - case ASUBQ: - case ASUBW: - if(p->from.type != TYPE_CONST || needc(p->link)) - break; - if(p->from.offset == -1) { - if(p->as == ASUBQ) - p->as = AINCQ; - else - if(p->as == ASUBL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - break; - } - if(p->from.offset == 1){ - if(p->as == ASUBQ) - p->as = ADECQ; - else - if(p->as == ASUBL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - break; - } - break; - } - } - if(t) - goto loop1; - - // MOVLQZX removal. - // The MOVLQZX exists to avoid being confused for a - // MOVL that is just copying 32-bit data around during - // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 - // if it is dominated by an earlier ADDL/MOVL/etc into R1 that - // will have already cleared the high bits. - // - // MOVSD removal. - // We never use packed registers, so a MOVSD between registers - // can be replaced by MOVAPD, which moves the pair of float64s - // instead of just the lower one. We only use the lower one, but - // the processor can do better if we do moves using both. - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - if(p->as == AMOVLQZX) - if(regtyp(&p->from)) - if(p->from.type == p->to.type && p->from.reg == p->to.reg) - if(prevl(r, p->from.reg)) - excise(r); - - if(p->as == AMOVSD) - if(regtyp(&p->from)) - if(regtyp(&p->to)) - p->as = AMOVAPD; - } - - // load pipelining - // push any load from memory as early as possible - // to give it time to complete before use. - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case AMOVB: - case AMOVW: - case AMOVL: - case AMOVQ: - case AMOVLQZX: - if(regtyp(&p->to) && !regconsttyp(&p->from)) - pushback(r); - } - } - - flowend(g); -} - -static void -pushback(Flow *r0) -{ - Flow *r, *b; - Prog *p0, *p, t; - - b = nil; - p0 = r0->prog; - for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) { - p = r->prog; - if(p->as != ANOP) { - if(!regconsttyp(&p->from) || !regtyp(&p->to)) - break; - if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil)) - break; - } - if(p->as == ACALL) - break; - b = r; - } - - if(b == nil) { - if(debug['v']) { - print("no pushback: %P\n", r0->prog); - if(r) - print("\t%P [%d]\n", r->prog, uniqs(r)!=nil); - } - return; - } - - if(debug['v']) { - print("pushback\n"); - for(r=b;; r=r->link) { - print("\t%P\n", r->prog); - if(r == r0) - break; - } - } - - t = *r0->prog; - for(r=uniqp(r0);; r=uniqp(r)) { - p0 = r->link->prog; - p = r->prog; - p0->as = p->as; - p0->lineno = p->lineno; - p0->from = p->from; - p0->to = p->to; - - if(r == b) - break; - } - p0 = r->prog; - p0->as = t.as; - p0->lineno = t.lineno; - p0->from = t.from; - p0->to = t.to; - - if(debug['v']) { - print("\tafter\n"); - for(r=b;; r=r->link) { - print("\t%P\n", r->prog); - if(r == r0) - break; - } - } -} - -void -excise(Flow *r) -{ - Prog *p; - - p = r->prog; - if(debug['P'] && debug['v']) - print("%P ===delete===\n", p); - - nopout(p); - - ostats.ndelmov++; -} - -int -regtyp(Adr *a) -{ - return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_R15 || REG_X0 <= a->reg && a->reg <= REG_X15); -} - -// movb elimination. -// movb is simulated by the linker -// when a register other than ax, bx, cx, dx -// is used, so rewrite to other instructions -// when possible. a movb into a register -// can smash the entire 32-bit register without -// causing any trouble. -// -// TODO: Using the Q forms here instead of the L forms -// seems unnecessary, and it makes the instructions longer. -static void -elimshortmov(Graph *g) -{ - Prog *p; - Flow *r; - - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - if(regtyp(&p->to)) { - switch(p->as) { - case AINCB: - case AINCW: - p->as = AINCQ; - break; - case ADECB: - case ADECW: - p->as = ADECQ; - break; - case ANEGB: - case ANEGW: - p->as = ANEGQ; - break; - case ANOTB: - case ANOTW: - p->as = ANOTQ; - break; - } - if(regtyp(&p->from) || p->from.type == TYPE_CONST) { - // move or artihmetic into partial register. - // from another register or constant can be movl. - // we don't switch to 64-bit arithmetic if it can - // change how the carry bit is set (and the carry bit is needed). - switch(p->as) { - case AMOVB: - case AMOVW: - p->as = AMOVQ; - break; - case AADDB: - case AADDW: - if(!needc(p->link)) - p->as = AADDQ; - break; - case ASUBB: - case ASUBW: - if(!needc(p->link)) - p->as = ASUBQ; - break; - case AMULB: - case AMULW: - p->as = AMULQ; - break; - case AIMULB: - case AIMULW: - p->as = AIMULQ; - break; - case AANDB: - case AANDW: - p->as = AANDQ; - break; - case AORB: - case AORW: - p->as = AORQ; - break; - case AXORB: - case AXORW: - p->as = AXORQ; - break; - case ASHLB: - case ASHLW: - p->as = ASHLQ; - break; - } - } else if(p->from.type != TYPE_REG) { - // explicit zero extension, but don't - // do that if source is a byte register - // (only AH can occur and it's forbidden). - switch(p->as) { - case AMOVB: - p->as = AMOVBQZX; - break; - case AMOVW: - p->as = AMOVWQZX; - break; - } - } - } - } -} - -// is 'a' a register or constant? -static int -regconsttyp(Adr *a) -{ - if(regtyp(a)) - return 1; - switch(a->type) { - case TYPE_CONST: - case TYPE_FCONST: - case TYPE_SCONST: - case TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants. - return 1; - } - return 0; -} - -// is reg guaranteed to be truncated by a previous L instruction? -static int -prevl(Flow *r0, int reg) -{ - Prog *p; - Flow *r; - ProgInfo info; - - for(r=uniqp(r0); r!=nil; r=uniqp(r)) { - p = r->prog; - if(p->to.type == TYPE_REG && p->to.reg == reg) { - proginfo(&info, p); - if(info.flags & RightWrite) { - if(info.flags & SizeL) - return 1; - return 0; - } - } - } - return 0; -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -static int -subprop(Flow *r0) -{ - Prog *p; - ProgInfo info; - Adr *v1, *v2; - Flow *r; - int t; - - if(debug['P'] && debug['v']) - print("subprop %P\n", r0->prog); - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) { - if(debug['P'] && debug['v']) - print("\tnot regtype %D; return 0\n", v1); - return 0; - } - v2 = &p->to; - if(!regtyp(v2)) { - if(debug['P'] && debug['v']) - print("\tnot regtype %D; return 0\n", v2); - return 0; - } - for(r=uniqp(r0); r!=nil; r=uniqp(r)) { - if(debug['P'] && debug['v']) - print("\t? %P\n", r->prog); - if(uniqs(r) == nil) { - if(debug['P'] && debug['v']) - print("\tno unique successor\n"); - break; - } - p = r->prog; - if(p->as == AVARDEF || p->as == AVARKILL) - continue; - proginfo(&info, p); - if(info.flags & Call) { - if(debug['P'] && debug['v']) - print("\tfound %P; return 0\n", p); - return 0; - } - - if(info.reguse | info.regset) { - if(debug['P'] && debug['v']) - print("\tfound %P; return 0\n", p); - return 0; - } - - if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg) - goto gotit; - - if(copyau(&p->from, v2) || - copyau(&p->to, v2)) { - if(debug['P'] && debug['v']) - print("\tcopyau %D failed\n", v2); - break; - } - if(copysub(&p->from, v1, v2, 0) || - copysub(&p->to, v1, v2, 0)) { - if(debug['P'] && debug['v']) - print("\tcopysub failed\n"); - break; - } - } - if(debug['P'] && debug['v']) - print("\tran off end; return 0\n"); - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type && p->from.reg == v2->reg) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -static int -copyprop(Graph *g, Flow *r0) -{ - Prog *p; - Adr *v1, *v2; - - USED(g); - if(debug['P'] && debug['v']) - print("copyprop %P\n", r0->prog); - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) - return 1; - gactive++; - return copy1(v1, v2, r0->s1, 0); -} - -static int -copy1(Adr *v1, Adr *v2, Flow *r, int f) -{ - int t; - Prog *p; - - if(r->active == gactive) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = gactive; - if(debug['P']) - print("copy %D->%D f=%d\n", v1, v2, f); - for(; r != nil; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == nil) { - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, can't split */ - if(debug['P']) - print("; %D rar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %D set; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %D used+set and f=%d; return 0\n", v2, f); - else - print("; %D used and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub %D/%D", v2, v1); - if(t == 4) { - if(debug['P']) - print("; %D used+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %D set and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -static int -copyu(Prog *p, Adr *v, Adr *s) -{ - ProgInfo info; - - switch(p->as) { - case AJMP: - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARET: - if(s != nil) - return 1; - return 3; - - case ACALL: - if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset) - return 2; - if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG) - return 2; - if(v->type == p->from.type && v->reg == p->from.reg) - return 2; - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - - case ATEXT: - if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG) - return 3; - return 0; - } - - if(p->as == AVARDEF || p->as == AVARKILL) - return 0; - proginfo(&info, p); - - if((info.reguse|info.regset) & RtoB(v->reg)) - return 2; - - if(info.flags & LeftAddr) - if(copyas(&p->from, v)) - return 2; - - if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite)) - if(copyas(&p->to, v)) - return 2; - - if(info.flags & RightWrite) { - if(copyas(&p->to, v)) { - if(s != nil) - return copysub(&p->from, v, s, 1); - if(copyau(&p->from, v)) - return 4; - return 3; - } - } - - if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - } - - return 0; -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -static int -copyas(Adr *a, Adr *v) -{ - if(REG_AL <= a->reg && a->reg <= REG_R15B) - fatal("use of byte register"); - if(REG_AL <= v->reg && v->reg <= REG_R15B) - fatal("use of byte register"); - - if(a->type != v->type || a->name != v->name || a->reg != v->reg) - return 0; - if(regtyp(v)) - return 1; - if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM)) - if(v->offset == a->offset) - return 1; - return 0; -} - -int -sameaddr(Addr *a, Addr *v) -{ - if(a->type != v->type || a->name != v->name || a->reg != v->reg) - return 0; - if(regtyp(v)) - return 1; - if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM)) - if(v->offset == a->offset) - return 1; - return 0; -} - -/* - * either direct or indirect - */ -static int -copyau(Adr *a, Adr *v) -{ - - if(copyas(a, v)) { - if(debug['P'] && debug['v']) - print("\tcopyau: copyas returned 1\n"); - return 1; - } - if(regtyp(v)) { - if(a->type == TYPE_MEM && a->reg == v->reg) { - if(debug['P'] && debug['v']) - print("\tcopyau: found indir use - return 1\n"); - return 1; - } - if(a->index == v->reg) { - if(debug['P'] && debug['v']) - print("\tcopyau: found index use - return 1\n"); - return 1; - } - } - return 0; -} - -/* - * substitute s for v in a - * return failure to substitute - */ -static int -copysub(Adr *a, Adr *v, Adr *s, int f) -{ - int reg; - - if(copyas(a, v)) { - reg = s->reg; - if(reg >= REG_AX && reg <= REG_R15 || reg >= REG_X0 && reg <= REG_X0+15) { - if(f) - a->reg = reg; - } - return 0; - } - if(regtyp(v)) { - reg = v->reg; - if(a->type == TYPE_MEM && a->reg == reg) { - if((s->reg == REG_BP || s->reg == REG_R13) && a->index != REG_NONE) - return 1; /* can't use BP-base with index */ - if(f) - a->reg = s->reg; -// return 0; - } - if(a->index == reg) { - if(f) - a->index = s->reg; - return 0; - } - return 0; - } - return 0; -} - -static void -conprop(Flow *r0) -{ - Flow *r; - Prog *p, *p0; - int t; - Adr *v0; - - p0 = r0->prog; - v0 = &p0->to; - r = r0; - -loop: - r = uniqs(r); - if(r == nil || r == r0) - return; - if(uniqp(r) == nil) - return; - - p = r->prog; - t = copyu(p, v0, nil); - switch(t) { - case 0: // miss - case 1: // use - goto loop; - - case 2: // rar - case 4: // use and set - break; - - case 3: // set - if(p->as == p0->as) - if(p->from.type == p0->from.type) - if(p->from.reg == p0->from.reg) - if(p->from.node == p0->from.node) - if(p->from.offset == p0->from.offset) - if(p->from.scale == p0->from.scale) - if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval) - if(p->from.index == p0->from.index) { - excise(r); - goto loop; - } - break; - } -} - -int -smallindir(Addr *a, Addr *reg) -{ - return regtyp(reg) && - a->type == TYPE_MEM && a->reg == reg->reg && - a->index == REG_NONE && - 0 <= a->offset && a->offset < 4096; -} - -int -stackaddr(Addr *a) -{ - return a->type == TYPE_REG && a->reg == REG_SP; -} diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go new file mode 100644 index 0000000000..9870ca5e4e --- /dev/null +++ b/src/cmd/6g/peep.go @@ -0,0 +1,1077 @@ +// Derived from Inferno utils/6c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" + "fmt" +) +import "cmd/internal/gc" + +var gactive uint32 + +const ( + exregoffset = x86.REG_R15 +) + +// do we need the carry bit +func needc(p *obj.Prog) bool { + var info gc.ProgInfo + + for p != nil { + proginfo(&info, p) + if info.Flags&gc.UseCarry != 0 { + return true + } + if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 { + return false + } + p = p.Link + } + + return false +} + +func rnops(r *gc.Flow) *gc.Flow { + var p *obj.Prog + var r1 *gc.Flow + + if r != nil { + for { + p = r.Prog + if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE { + break + } + r1 = gc.Uniqs(r) + if r1 == nil { + break + } + r = r1 + } + } + + return r +} + +func peep(firstp *obj.Prog) { + var r *gc.Flow + var r1 *gc.Flow + var g *gc.Graph + var p *obj.Prog + var p1 *obj.Prog + var t int + + g = gc.Flowstart(firstp, nil) + if g == nil { + return + } + gactive = 0 + + // byte, word arithmetic elimination. + elimshortmov(g) + + // constant propagation + // find MOV $con,R followed by + // another MOV $con,R without + // setting R in the interim + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case x86.ALEAL, + x86.ALEAQ: + if regtyp(&p.To) { + if p.From.Sym != nil { + if p.From.Index == x86.REG_NONE { + conprop(r) + } + } + } + + case x86.AMOVB, + x86.AMOVW, + x86.AMOVL, + x86.AMOVQ, + x86.AMOVSS, + x86.AMOVSD: + if regtyp(&p.To) { + if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST { + conprop(r) + } + } + } + } + +loop1: + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + gc.Dumpit("loop1", g.Start, 0) + } + + t = 0 + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case x86.AMOVL, + x86.AMOVQ, + x86.AMOVSS, + x86.AMOVSD: + if regtyp(&p.To) { + if regtyp(&p.From) { + if copyprop(g, r) { + excise(r) + t++ + } else if subprop(r) && copyprop(g, r) { + excise(r) + t++ + } + } + } + + case x86.AMOVBLZX, + x86.AMOVWLZX, + x86.AMOVBLSX, + x86.AMOVWLSX: + if regtyp(&p.To) { + r1 = rnops(gc.Uniqs(r)) + if r1 != nil { + p1 = r1.Prog + if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { + p1.As = x86.AMOVL + t++ + } + } + } + + case x86.AMOVBQSX, + x86.AMOVBQZX, + x86.AMOVWQSX, + x86.AMOVWQZX, + x86.AMOVLQSX, + x86.AMOVLQZX, + x86.AMOVQL: + if regtyp(&p.To) { + r1 = rnops(gc.Uniqs(r)) + if r1 != nil { + p1 = r1.Prog + if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { + p1.As = x86.AMOVQ + t++ + } + } + } + + case x86.AADDL, + x86.AADDQ, + x86.AADDW: + if p.From.Type != obj.TYPE_CONST || needc(p.Link) { + break + } + if p.From.Offset == -1 { + if p.As == x86.AADDQ { + p.As = x86.ADECQ + } else if p.As == x86.AADDL { + p.As = x86.ADECL + } else { + p.As = x86.ADECW + } + p.From = obj.Addr{} + break + } + + if p.From.Offset == 1 { + if p.As == x86.AADDQ { + p.As = x86.AINCQ + } else if p.As == x86.AADDL { + p.As = x86.AINCL + } else { + p.As = x86.AINCW + } + p.From = obj.Addr{} + break + } + + case x86.ASUBL, + x86.ASUBQ, + x86.ASUBW: + if p.From.Type != obj.TYPE_CONST || needc(p.Link) { + break + } + if p.From.Offset == -1 { + if p.As == x86.ASUBQ { + p.As = x86.AINCQ + } else if p.As == x86.ASUBL { + p.As = x86.AINCL + } else { + p.As = x86.AINCW + } + p.From = obj.Addr{} + break + } + + if p.From.Offset == 1 { + if p.As == x86.ASUBQ { + p.As = x86.ADECQ + } else if p.As == x86.ASUBL { + p.As = x86.ADECL + } else { + p.As = x86.ADECW + } + p.From = obj.Addr{} + break + } + } + } + + if t != 0 { + goto loop1 + } + + // MOVLQZX removal. + // The MOVLQZX exists to avoid being confused for a + // MOVL that is just copying 32-bit data around during + // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 + // if it is dominated by an earlier ADDL/MOVL/etc into R1 that + // will have already cleared the high bits. + // + // MOVSD removal. + // We never use packed registers, so a MOVSD between registers + // can be replaced by MOVAPD, which moves the pair of float64s + // instead of just the lower one. We only use the lower one, but + // the processor can do better if we do moves using both. + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + if p.As == x86.AMOVLQZX { + if regtyp(&p.From) { + if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg { + if prevl(r, int(p.From.Reg)) { + excise(r) + } + } + } + } + + if p.As == x86.AMOVSD { + if regtyp(&p.From) { + if regtyp(&p.To) { + p.As = x86.AMOVAPD + } + } + } + } + + // load pipelining + // push any load from memory as early as possible + // to give it time to complete before use. + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case x86.AMOVB, + x86.AMOVW, + x86.AMOVL, + x86.AMOVQ, + x86.AMOVLQZX: + if regtyp(&p.To) && !regconsttyp(&p.From) { + pushback(r) + } + } + } + + gc.Flowend(g) +} + +func pushback(r0 *gc.Flow) { + var r *gc.Flow + var b *gc.Flow + var p0 *obj.Prog + var p *obj.Prog + var t obj.Prog + + b = nil + p0 = r0.Prog + for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) { + p = r.Prog + if p.As != obj.ANOP { + if !regconsttyp(&p.From) || !regtyp(&p.To) { + break + } + if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 { + break + } + } + + if p.As == obj.ACALL { + break + } + b = r + } + + if b == nil { + if gc.Debug['v'] != 0 { + fmt.Printf("no pushback: %v\n", r0.Prog) + if r != nil { + fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil) + } + } + + return + } + + if gc.Debug['v'] != 0 { + fmt.Printf("pushback\n") + for r = b; ; r = r.Link { + fmt.Printf("\t%v\n", r.Prog) + if r == r0 { + break + } + } + } + + t = *r0.Prog + for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) { + p0 = r.Link.Prog + p = r.Prog + p0.As = p.As + p0.Lineno = p.Lineno + p0.From = p.From + p0.To = p.To + + if r == b { + break + } + } + + p0 = r.Prog + p0.As = t.As + p0.Lineno = t.Lineno + p0.From = t.From + p0.To = t.To + + if gc.Debug['v'] != 0 { + fmt.Printf("\tafter\n") + for r = b; ; r = r.Link { + fmt.Printf("\t%v\n", r.Prog) + if r == r0 { + break + } + } + } +} + +func excise(r *gc.Flow) { + var p *obj.Prog + + p = r.Prog + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("%v ===delete===\n", p) + } + + obj.Nopout(p) + + gc.Ostats.Ndelmov++ +} + +func regtyp(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_R15 || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X15) +} + +// movb elimination. +// movb is simulated by the linker +// when a register other than ax, bx, cx, dx +// is used, so rewrite to other instructions +// when possible. a movb into a register +// can smash the entire 32-bit register without +// causing any trouble. +// +// TODO: Using the Q forms here instead of the L forms +// seems unnecessary, and it makes the instructions longer. +func elimshortmov(g *gc.Graph) { + var p *obj.Prog + var r *gc.Flow + + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + if regtyp(&p.To) { + switch p.As { + case x86.AINCB, + x86.AINCW: + p.As = x86.AINCQ + + case x86.ADECB, + x86.ADECW: + p.As = x86.ADECQ + + case x86.ANEGB, + x86.ANEGW: + p.As = x86.ANEGQ + + case x86.ANOTB, + x86.ANOTW: + p.As = x86.ANOTQ + } + + if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST { + // move or artihmetic into partial register. + // from another register or constant can be movl. + // we don't switch to 64-bit arithmetic if it can + // change how the carry bit is set (and the carry bit is needed). + switch p.As { + case x86.AMOVB, + x86.AMOVW: + p.As = x86.AMOVQ + + case x86.AADDB, + x86.AADDW: + if !needc(p.Link) { + p.As = x86.AADDQ + } + + case x86.ASUBB, + x86.ASUBW: + if !needc(p.Link) { + p.As = x86.ASUBQ + } + + case x86.AMULB, + x86.AMULW: + p.As = x86.AMULQ + + case x86.AIMULB, + x86.AIMULW: + p.As = x86.AIMULQ + + case x86.AANDB, + x86.AANDW: + p.As = x86.AANDQ + + case x86.AORB, + x86.AORW: + p.As = x86.AORQ + + case x86.AXORB, + x86.AXORW: + p.As = x86.AXORQ + + case x86.ASHLB, + x86.ASHLW: + p.As = x86.ASHLQ + } + } else if p.From.Type != obj.TYPE_REG { + // explicit zero extension, but don't + // do that if source is a byte register + // (only AH can occur and it's forbidden). + switch p.As { + case x86.AMOVB: + p.As = x86.AMOVBQZX + + case x86.AMOVW: + p.As = x86.AMOVWQZX + } + } + } + } +} + +// is 'a' a register or constant? +func regconsttyp(a *obj.Addr) bool { + if regtyp(a) { + return true + } + switch a.Type { + case obj.TYPE_CONST, + obj.TYPE_FCONST, + obj.TYPE_SCONST, + obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants. + return true + } + + return false +} + +// is reg guaranteed to be truncated by a previous L instruction? +func prevl(r0 *gc.Flow, reg int) bool { + var p *obj.Prog + var r *gc.Flow + var info gc.ProgInfo + + for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { + p = r.Prog + if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg { + proginfo(&info, p) + if info.Flags&gc.RightWrite != 0 { + if info.Flags&gc.SizeL != 0 { + return true + } + return false + } + } + } + + return false +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +func subprop(r0 *gc.Flow) bool { + var p *obj.Prog + var info gc.ProgInfo + var v1 *obj.Addr + var v2 *obj.Addr + var r *gc.Flow + var t int + + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("subprop %v\n", r0.Prog) + } + p = r0.Prog + v1 = &p.From + if !regtyp(v1) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1)) + } + return false + } + + v2 = &p.To + if !regtyp(v2) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2)) + } + return false + } + + for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\t? %v\n", r.Prog) + } + if gc.Uniqs(r) == nil { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tno unique successor\n") + } + break + } + + p = r.Prog + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + continue + } + proginfo(&info, p) + if info.Flags&gc.Call != 0 { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tfound %v; return 0\n", p) + } + return false + } + + if info.Reguse|info.Regset != 0 { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tfound %v; return 0\n", p) + } + return false + } + + if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg { + goto gotit + } + + if copyau(&p.From, v2) || copyau(&p.To, v2) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2)) + } + break + } + + if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tcopysub failed\n") + } + break + } + } + + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tran off end; return 0\n") + } + return false + +gotit: + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) + if p.From.Type == v2.Type && p.From.Reg == v2.Reg { + fmt.Printf(" excise") + } + fmt.Printf("\n") + } + + for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { + p = r.Prog + copysub(&p.From, v1, v2, 1) + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("%v\n", r.Prog) + } + } + + t = int(v1.Reg) + v1.Reg = v2.Reg + v2.Reg = int16(t) + if gc.Debug['P'] != 0 { + fmt.Printf("%v last\n", r.Prog) + } + return true +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +func copyprop(g *gc.Graph, r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("copyprop %v\n", r0.Prog) + } + p = r0.Prog + v1 = &p.From + v2 = &p.To + if copyas(v1, v2) { + return true + } + gactive++ + return copy1(v1, v2, r0.S1, 0) +} + +func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { + var t int + var p *obj.Prog + + if uint32(r.Active) == gactive { + if gc.Debug['P'] != 0 { + fmt.Printf("act set; return 1\n") + } + return true + } + + r.Active = int32(gactive) + if gc.Debug['P'] != 0 { + fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) + } + for ; r != nil; r = r.S1 { + p = r.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("%v", p) + } + if f == 0 && gc.Uniqp(r) == nil { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; merge; f=%d", f) + } + } + + t = copyu(p, v2, nil) + switch t { + case 2: /* rar, can't split */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) + } + return false + + case 3: /* set */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + + case 1, /* used, substitute */ + 4: /* use and set */ + if f != 0 { + if gc.Debug['P'] == 0 { + return false + } + if t == 4 { + fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } else { + fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } + return false + } + + if copyu(p, v2, v1) != 0 { + if gc.Debug['P'] != 0 { + fmt.Printf("; sub fail; return 0\n") + } + return false + } + + if gc.Debug['P'] != 0 { + fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) + } + if t == 4 { + if gc.Debug['P'] != 0 { + fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + } + } + + if f == 0 { + t = copyu(p, v1, nil) + if f == 0 && (t == 2 || t == 3 || t == 4) { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) + } + } + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\n") + } + if r.S2 != nil { + if !copy1(v1, v2, r.S2, f) { + return false + } + } + } + + return true +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { + var info gc.ProgInfo + + switch p.As { + case obj.AJMP: + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 1 + } + return 0 + + case obj.ARET: + if s != nil { + return 1 + } + return 3 + + case obj.ACALL: + if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset { + return 2 + } + if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { + return 2 + } + if v.Type == p.From.Type && v.Reg == p.From.Reg { + return 2 + } + + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 4 + } + return 3 + + case obj.ATEXT: + if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { + return 3 + } + return 0 + } + + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + return 0 + } + proginfo(&info, p) + + if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 { + return 2 + } + + if info.Flags&gc.LeftAddr != 0 { + if copyas(&p.From, v) { + return 2 + } + } + + if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite { + if copyas(&p.To, v) { + return 2 + } + } + + if info.Flags&gc.RightWrite != 0 { + if copyas(&p.To, v) { + if s != nil { + return copysub(&p.From, v, s, 1) + } + if copyau(&p.From, v) { + return 4 + } + return 3 + } + } + + if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 { + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + return copysub(&p.To, v, s, 1) + } + + if copyau(&p.From, v) { + return 1 + } + if copyau(&p.To, v) { + return 1 + } + } + + return 0 +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +func copyas(a *obj.Addr, v *obj.Addr) bool { + if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B { + gc.Fatal("use of byte register") + } + if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B { + gc.Fatal("use of byte register") + } + + if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { + return false + } + if regtyp(v) { + return true + } + if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { + if v.Offset == a.Offset { + return true + } + } + return false +} + +func sameaddr(a *obj.Addr, v *obj.Addr) bool { + if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { + return false + } + if regtyp(v) { + return true + } + if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { + if v.Offset == a.Offset { + return true + } + } + return false +} + +/* + * either direct or indirect + */ +func copyau(a *obj.Addr, v *obj.Addr) bool { + if copyas(a, v) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tcopyau: copyas returned 1\n") + } + return true + } + + if regtyp(v) { + if a.Type == obj.TYPE_MEM && a.Reg == v.Reg { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tcopyau: found indir use - return 1\n") + } + return true + } + + if a.Index == v.Reg { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\tcopyau: found index use - return 1\n") + } + return true + } + } + + return false +} + +/* + * substitute s for v in a + * return failure to substitute + */ +func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { + var reg int + + if copyas(a, v) { + reg = int(s.Reg) + if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 { + if f != 0 { + a.Reg = int16(reg) + } + } + + return 0 + } + + if regtyp(v) { + reg = int(v.Reg) + if a.Type == obj.TYPE_MEM && int(a.Reg) == reg { + if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE { + return 1 /* can't use BP-base with index */ + } + if f != 0 { + a.Reg = s.Reg + } + } + + // return 0; + if int(a.Index) == reg { + if f != 0 { + a.Index = s.Reg + } + return 0 + } + + return 0 + } + + return 0 +} + +func conprop(r0 *gc.Flow) { + var r *gc.Flow + var p *obj.Prog + var p0 *obj.Prog + var t int + var v0 *obj.Addr + + p0 = r0.Prog + v0 = &p0.To + r = r0 + +loop: + r = gc.Uniqs(r) + if r == nil || r == r0 { + return + } + if gc.Uniqp(r) == nil { + return + } + + p = r.Prog + t = copyu(p, v0, nil) + switch t { + case 0, // miss + 1: // use + goto loop + + case 2, // rar + 4: // use and set + break + + case 3: // set + if p.As == p0.As { + if p.From.Type == p0.From.Type { + if p.From.Reg == p0.From.Reg { + if p.From.Node == p0.From.Node { + if p.From.Offset == p0.From.Offset { + if p.From.Scale == p0.From.Scale { + if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval { + if p.From.Index == p0.From.Index { + excise(r) + goto loop + } + } + } + } + } + } + } + } + } +} + +func smallindir(a *obj.Addr, reg *obj.Addr) bool { + return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096 +} + +func stackaddr(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP +} diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c deleted file mode 100644 index 79b7911e5b..0000000000 --- a/src/cmd/6g/prog.c +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -// Matches real RtoB but can be used in global initializer. -#define RtoB(r) (1<<((r)-REG_AX)) - -enum { - AX = RtoB(REG_AX), - BX = RtoB(REG_BX), - CX = RtoB(REG_CX), - DX = RtoB(REG_DX), - DI = RtoB(REG_DI), - SI = RtoB(REG_SI), - - LeftRdwr = LeftRead | LeftWrite, - RightRdwr = RightRead | RightWrite, -}; - -#undef RtoB - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -static ProgInfo progtable[ALAST] = { - [ATYPE]= {Pseudo | Skip}, - [ATEXT]= {Pseudo}, - [AFUNCDATA]= {Pseudo}, - [APCDATA]= {Pseudo}, - [AUNDEF]= {Break}, - [AUSEFIELD]= {OK}, - [ACHECKNIL]= {LeftRead}, - [AVARDEF]= {Pseudo | RightWrite}, - [AVARKILL]= {Pseudo | RightWrite}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - [ANOP]= {LeftRead | RightWrite}, - - [AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry}, - [AADCQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry}, - [AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry}, - - [AADDB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AADDL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AADDW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - [AADDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry}, - - [AADDSD]= {SizeD | LeftRead | RightRdwr}, - [AADDSS]= {SizeF | LeftRead | RightRdwr}, - - [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AANDQ]= {SizeQ | LeftRead | RightRdwr | SetCarry}, - [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [ACALL]= {RightAddr | Call | KillCarry}, - - [ACDQ]= {OK, AX, AX | DX}, - [ACQO]= {OK, AX, AX | DX}, - [ACWD]= {OK, AX, AX | DX}, - - [ACLD]= {OK}, - [ASTD]= {OK}, - - [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry}, - [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry}, - [ACMPQ]= {SizeQ | LeftRead | RightRead | SetCarry}, - [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry}, - - [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry}, - [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry}, - - [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv}, - [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv}, - [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv}, - [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv}, - [ACVTSQ2SD]= {SizeD | LeftRead | RightWrite | Conv}, - [ACVTSQ2SS]= {SizeF | LeftRead | RightWrite | Conv}, - [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv}, - [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv}, - [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTTSD2SQ]= {SizeQ | LeftRead | RightWrite | Conv}, - [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTTSS2SQ]= {SizeQ | LeftRead | RightWrite | Conv}, - - [ADECB]= {SizeB | RightRdwr}, - [ADECL]= {SizeL | RightRdwr}, - [ADECQ]= {SizeQ | RightRdwr}, - [ADECW]= {SizeW | RightRdwr}, - - [ADIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [ADIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, - [ADIVQ]= {SizeQ | LeftRead | SetCarry, AX|DX, AX|DX}, - [ADIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, - - [ADIVSD]= {SizeD | LeftRead | RightRdwr}, - [ADIVSS]= {SizeF | LeftRead | RightRdwr}, - - [AIDIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AIDIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, - [AIDIVQ]= {SizeQ | LeftRead | SetCarry, AX|DX, AX|DX}, - [AIDIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, - - [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry}, - [AIMULQ]= {SizeQ | LeftRead | ImulAXDX | SetCarry}, - [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry}, - - [AINCB]= {SizeB | RightRdwr}, - [AINCL]= {SizeL | RightRdwr}, - [AINCQ]= {SizeQ | RightRdwr}, - [AINCW]= {SizeW | RightRdwr}, - - [AJCC]= {Cjmp | UseCarry}, - [AJCS]= {Cjmp | UseCarry}, - [AJEQ]= {Cjmp | UseCarry}, - [AJGE]= {Cjmp | UseCarry}, - [AJGT]= {Cjmp | UseCarry}, - [AJHI]= {Cjmp | UseCarry}, - [AJLE]= {Cjmp | UseCarry}, - [AJLS]= {Cjmp | UseCarry}, - [AJLT]= {Cjmp | UseCarry}, - [AJMI]= {Cjmp | UseCarry}, - [AJNE]= {Cjmp | UseCarry}, - [AJOC]= {Cjmp | UseCarry}, - [AJOS]= {Cjmp | UseCarry}, - [AJPC]= {Cjmp | UseCarry}, - [AJPL]= {Cjmp | UseCarry}, - [AJPS]= {Cjmp | UseCarry}, - - [AJMP]= {Jump | Break | KillCarry}, - - [ALEAL]= {LeftAddr | RightWrite}, - [ALEAQ]= {LeftAddr | RightWrite}, - - [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVBQSX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVBQZX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv}, - [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv}, - [AMOVLQSX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVLQZX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVWQSX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVWQZX]= {SizeQ | LeftRead | RightWrite | Conv}, - [AMOVQL]= {SizeL | LeftRead | RightWrite | Conv}, - - [AMOVB]= {SizeB | LeftRead | RightWrite | Move}, - [AMOVL]= {SizeL | LeftRead | RightWrite | Move}, - [AMOVQ]= {SizeQ | LeftRead | RightWrite | Move}, - [AMOVW]= {SizeW | LeftRead | RightWrite | Move}, - - [AMOVSB]= {OK, DI|SI, DI|SI}, - [AMOVSL]= {OK, DI|SI, DI|SI}, - [AMOVSQ]= {OK, DI|SI, DI|SI}, - [AMOVSW]= {OK, DI|SI, DI|SI}, - [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, - - [AMOVSD]= {SizeD | LeftRead | RightWrite | Move}, - [AMOVSS]= {SizeF | LeftRead | RightWrite | Move}, - - // We use MOVAPD as a faster synonym for MOVSD. - [AMOVAPD]= {SizeD | LeftRead | RightWrite | Move}, - - [AMULB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AMULL]= {SizeL | LeftRead | SetCarry, AX, AX|DX}, - [AMULQ]= {SizeQ | LeftRead | SetCarry, AX, AX|DX}, - [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX}, - - [AMULSD]= {SizeD | LeftRead | RightRdwr}, - [AMULSS]= {SizeF | LeftRead | RightRdwr}, - - [ANEGB]= {SizeB | RightRdwr | SetCarry}, - [ANEGL]= {SizeL | RightRdwr | SetCarry}, - [ANEGQ]= {SizeQ | RightRdwr | SetCarry}, - [ANEGW]= {SizeW | RightRdwr | SetCarry}, - - [ANOTB]= {SizeB | RightRdwr}, - [ANOTL]= {SizeL | RightRdwr}, - [ANOTQ]= {SizeQ | RightRdwr}, - [ANOTW]= {SizeW | RightRdwr}, - - [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry}, - [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [APOPQ]= {SizeQ | RightWrite}, - [APUSHQ]= {SizeQ | LeftRead}, - - [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - - [ARCRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - - [AREP]= {OK, CX, CX}, - [AREPN]= {OK, CX, CX}, - - [ARET]= {Break | KillCarry}, - - [AROLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [AROLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [AROLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ARORQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASALQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASARQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry}, - [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry}, - [ASBBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry}, - [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry}, - - [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHLQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHRQ]= {SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASTOSB]= {OK, AX|DI, DI}, - [ASTOSL]= {OK, AX|DI, DI}, - [ASTOSQ]= {OK, AX|DI, DI}, - [ASTOSW]= {OK, AX|DI, DI}, - [ADUFFZERO]= {OK, AX|DI, DI}, - - [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [ASUBQ]= {SizeQ | LeftRead | RightRdwr | SetCarry}, - [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [ASUBSD]= {SizeD | LeftRead | RightRdwr}, - [ASUBSS]= {SizeF | LeftRead | RightRdwr}, - - [ATESTB]= {SizeB | LeftRead | RightRead | SetCarry}, - [ATESTL]= {SizeL | LeftRead | RightRead | SetCarry}, - [ATESTQ]= {SizeQ | LeftRead | RightRead | SetCarry}, - [ATESTW]= {SizeW | LeftRead | RightRead | SetCarry}, - - [AUCOMISD]= {SizeD | LeftRead | RightRead}, - [AUCOMISS]= {SizeF | LeftRead | RightRead}, - - [AXCHGB]= {SizeB | LeftRdwr | RightRdwr}, - [AXCHGL]= {SizeL | LeftRdwr | RightRdwr}, - [AXCHGQ]= {SizeQ | LeftRdwr | RightRdwr}, - [AXCHGW]= {SizeW | LeftRdwr | RightRdwr}, - - [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AXORL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AXORQ]= {SizeQ | LeftRead | RightRdwr | SetCarry}, - [AXORW]= {SizeW | LeftRead | RightRdwr | SetCarry}, -}; - -void -proginfo(ProgInfo *info, Prog *p) -{ - *info = progtable[p->as]; - if(info->flags == 0) - fatal("unknown instruction %P", p); - - if((info->flags & ShiftCX) && p->from.type != TYPE_CONST) - info->reguse |= CX; - - if(info->flags & ImulAXDX) { - if(p->to.type == TYPE_NONE) { - info->reguse |= AX; - info->regset |= AX | DX; - } else { - info->flags |= RightRdwr; - } - } - - // Addressing makes some registers used. - if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE) - info->regindex |= RtoB(p->from.reg); - if(p->from.index != REG_NONE) - info->regindex |= RtoB(p->from.index); - if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE) - info->regindex |= RtoB(p->to.reg); - if(p->to.index != REG_NONE) - info->regindex |= RtoB(p->to.index); -} diff --git a/src/cmd/6g/prog.go b/src/cmd/6g/prog.go new file mode 100644 index 0000000000..3f4c19567c --- /dev/null +++ b/src/cmd/6g/prog.go @@ -0,0 +1,272 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" +) +import "cmd/internal/gc" + +var ( + AX = RtoB(x86.REG_AX) + BX = RtoB(x86.REG_BX) + CX = RtoB(x86.REG_CX) + DX = RtoB(x86.REG_DX) + DI = RtoB(x86.REG_DI) + SI = RtoB(x86.REG_SI) + LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite + RightRdwr uint32 = gc.RightRead | gc.RightWrite +) + +// This table gives the basic information about instruction +// generated by the compiler and processed in the optimizer. +// See opt.h for bit definitions. +// +// Instructions not generated need not be listed. +// As an exception to that rule, we typically write down all the +// size variants of an operation even if we just use a subset. +// +// The table is formatted for 8-space tabs. +var progtable = [x86.ALAST]gc.ProgInfo{ + obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, + obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, + obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, + obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, + obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + + // NOP is an internal no-op that also stands + // for USED and SET annotations, not the Intel opcode. + obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, + x86.AADCL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.AADCQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.AADCW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.AADDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AADDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AADDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AADDQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AADDSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.AADDSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.AANDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AANDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AANDQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AANDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + obj.ACALL: gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0}, + x86.ACDQ: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, + x86.ACQO: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, + x86.ACWD: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, + x86.ACLD: gc.ProgInfo{gc.OK, 0, 0, 0}, + x86.ASTD: gc.ProgInfo{gc.OK, 0, 0, 0}, + x86.ACMPB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACMPL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACMPQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACMPW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ACVTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSD2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSD2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSL2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSL2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSQ2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSQ2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSS2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTSS2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTTSD2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ACVTTSS2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.ADECB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + x86.ADECL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + x86.ADECQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, + x86.ADECW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + x86.ADIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + x86.ADIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.ADIVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.ADIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.ADIVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.ADIVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.AIDIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + x86.AIDIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.AIDIVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.AIDIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + x86.AIMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + x86.AIMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, + x86.AIMULQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, + x86.AIMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, + x86.AINCB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + x86.AINCL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + x86.AINCQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, + x86.AINCW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + x86.AJCC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJCS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJEQ: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJGE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJGT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJHI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJLE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJLS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJLT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJMI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJNE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJOC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJOS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJPC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJPL: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + x86.AJPS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + obj.AJMP: gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0}, + x86.ALEAL: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + x86.ALEAQ: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + x86.AMOVBLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVBLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVBQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVBQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVBWSX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVBWZX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVLQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVLQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVWLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVWLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVWQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVWQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVQL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + x86.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMOVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMOVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMOVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMOVSB: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + x86.AMOVSL: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + x86.AMOVSQ: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + x86.AMOVSW: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + obj.ADUFFCOPY: gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0}, + x86.AMOVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMOVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + + // We use MOVAPD as a faster synonym for MOVSD. + x86.AMOVAPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + x86.AMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + x86.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, + x86.AMULQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, + x86.AMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, + x86.AMULSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.AMULSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.ANEGB: gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ANEGL: gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ANEGQ: gc.ProgInfo{gc.SizeQ | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ANEGW: gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ANOTB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + x86.ANOTL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + x86.ANOTQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, + x86.ANOTW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + x86.AORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.APOPQ: gc.ProgInfo{gc.SizeQ | gc.RightWrite, 0, 0, 0}, + x86.APUSHQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead, 0, 0, 0}, + x86.ARCLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCRQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ARCRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.AREP: gc.ProgInfo{gc.OK, CX, CX, 0}, + x86.AREPN: gc.ProgInfo{gc.OK, CX, CX, 0}, + obj.ARET: gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0}, + x86.AROLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.AROLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.AROLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.AROLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ARORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ARORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ARORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ARORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASALB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASALL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASALQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASALW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASARB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASARL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASARQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASARW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASBBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ASBBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ASBBQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ASBBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + x86.ASHLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHRQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASHRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + x86.ASTOSB: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + x86.ASTOSL: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + x86.ASTOSQ: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + x86.ASTOSW: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + x86.ASUBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ASUBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ASUBQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ASUBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.ASUBSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.ASUBSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + x86.ATESTB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ATESTL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ATESTQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.ATESTW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + x86.AUCOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, + x86.AUCOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, + x86.AXCHGB: gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0}, + x86.AXCHGL: gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0}, + x86.AXCHGQ: gc.ProgInfo{gc.SizeQ | LeftRdwr | RightRdwr, 0, 0, 0}, + x86.AXCHGW: gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0}, + x86.AXORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AXORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AXORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + x86.AXORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, +} + +func proginfo(info *gc.ProgInfo, p *obj.Prog) { + *info = progtable[p.As] + if info.Flags == 0 { + gc.Fatal("unknown instruction %v", p) + } + + if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST { + info.Reguse |= CX + } + + if info.Flags&gc.ImulAXDX != 0 { + if p.To.Type == obj.TYPE_NONE { + info.Reguse |= AX + info.Regset |= AX | DX + } else { + info.Flags |= RightRdwr + } + } + + // Addressing makes some registers used. + if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE { + info.Regindex |= RtoB(int(p.From.Reg)) + } + if p.From.Index != x86.REG_NONE { + info.Regindex |= RtoB(int(p.From.Index)) + } + if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE { + info.Regindex |= RtoB(int(p.To.Reg)) + } + if p.To.Index != x86.REG_NONE { + info.Regindex |= RtoB(int(p.To.Index)) + } +} diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c deleted file mode 100644 index e01f265a13..0000000000 --- a/src/cmd/6g/reg.c +++ /dev/null @@ -1,153 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -enum { - NREGVAR = 32, -}; - -static char* regname[] = { - ".AX", - ".CX", - ".DX", - ".BX", - ".SP", - ".BP", - ".SI", - ".DI", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".X0", - ".X1", - ".X2", - ".X3", - ".X4", - ".X5", - ".X6", - ".X7", - ".X8", - ".X9", - ".X10", - ".X11", - ".X12", - ".X13", - ".X14", - ".X15", -}; - -char** -regnames(int *n) -{ - *n = NREGVAR; - return regname; -} - -uint64 -excludedregs(void) -{ - return RtoB(REG_SP); -} - -uint64 -doregbits(int r) -{ - uint64 b; - - b = 0; - if(r >= REG_AX && r <= REG_R15) - b |= RtoB(r); - else - if(r >= REG_AL && r <= REG_R15B) - b |= RtoB(r-REG_AL+REG_AX); - else - if(r >= REG_AH && r <= REG_BH) - b |= RtoB(r-REG_AH+REG_AX); - else - if(r >= REG_X0 && r <= REG_X0+15) - b |= FtoB(r); - return b; -} - -uint64 -RtoB(int r) -{ - - if(r < REG_AX || r > REG_R15) - return 0; - return 1ULL << (r-REG_AX); -} - -int -BtoR(uint64 b) -{ - b &= 0xffffULL; - if(nacl) - b &= ~((1<<(REG_BP-REG_AX)) | (1<<(REG_R15-REG_AX))); - else if(framepointer_enabled) - // BP is part of the calling convention if framepointer_enabled. - b &= ~(1<<(REG_BP-REG_AX)); - if(b == 0) - return 0; - return bitno(b) + REG_AX; -} - -/* - * bit reg - * 16 X0 - * ... - * 31 X15 - */ -uint64 -FtoB(int f) -{ - if(f < REG_X0 || f > REG_X15) - return 0; - return 1ULL << (f - REG_X0 + 16); -} - -int -BtoF(uint64 b) -{ - - b &= 0xFFFF0000L; - if(b == 0) - return 0; - return bitno(b) - 16 + REG_X0; -} diff --git a/src/cmd/6g/reg.go b/src/cmd/6g/reg.go new file mode 100644 index 0000000000..0629a6248d --- /dev/null +++ b/src/cmd/6g/reg.go @@ -0,0 +1,144 @@ +// Derived from Inferno utils/6c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/x86" +) +import "cmd/internal/gc" + +const ( + NREGVAR = 32 +) + +var regname = []string{ + ".AX", + ".CX", + ".DX", + ".BX", + ".SP", + ".BP", + ".SI", + ".DI", + ".R8", + ".R9", + ".R10", + ".R11", + ".R12", + ".R13", + ".R14", + ".R15", + ".X0", + ".X1", + ".X2", + ".X3", + ".X4", + ".X5", + ".X6", + ".X7", + ".X8", + ".X9", + ".X10", + ".X11", + ".X12", + ".X13", + ".X14", + ".X15", +} + +func regnames(n *int) []string { + *n = NREGVAR + return regname +} + +func excludedregs() uint64 { + return RtoB(x86.REG_SP) +} + +func doregbits(r int) uint64 { + var b uint64 + + b = 0 + if r >= x86.REG_AX && r <= x86.REG_R15 { + b |= RtoB(r) + } else if r >= x86.REG_AL && r <= x86.REG_R15B { + b |= RtoB(r - x86.REG_AL + x86.REG_AX) + } else if r >= x86.REG_AH && r <= x86.REG_BH { + b |= RtoB(r - x86.REG_AH + x86.REG_AX) + } else if r >= x86.REG_X0 && r <= x86.REG_X0+15 { + b |= FtoB(r) + } + return b +} + +func RtoB(r int) uint64 { + if r < x86.REG_AX || r > x86.REG_R15 { + return 0 + } + return 1 << uint(r-x86.REG_AX) +} + +func BtoR(b uint64) int { + b &= 0xffff + if gc.Nacl { + b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX)) + } else if obj.Framepointer_enabled != 0 { + // BP is part of the calling convention if framepointer_enabled. + b &^= (1 << (x86.REG_BP - x86.REG_AX)) + } + + if b == 0 { + return 0 + } + return gc.Bitno(b) + x86.REG_AX +} + +/* + * bit reg + * 16 X0 + * ... + * 31 X15 + */ +func FtoB(f int) uint64 { + if f < x86.REG_X0 || f > x86.REG_X15 { + return 0 + } + return 1 << uint(f-x86.REG_X0+16) +} + +func BtoF(b uint64) int { + b &= 0xFFFF0000 + if b == 0 { + return 0 + } + return gc.Bitno(b) - 16 + x86.REG_X0 +} diff --git a/src/cmd/6g/util.go b/src/cmd/6g/util.go new file mode 100644 index 0000000000..bb5eedb15a --- /dev/null +++ b/src/cmd/6g/util.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func bool2int(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile deleted file mode 100644 index 27290ddd71..0000000000 --- a/src/cmd/8a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist - -install: y.tab.h - -y.tab.h: a.y - LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h deleted file mode 100644 index 24654b0ab8..0000000000 --- a/src/cmd/8a/a.h +++ /dev/null @@ -1,186 +0,0 @@ -// Inferno utils/8a/a.h -// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "../8l/8.out.h" - -#ifndef EXTERN -#define EXTERN extern -#endif - -#undef getc -#undef ungetc -#undef BUFSIZ - -#define getc ccgetc -#define ungetc ccungetc - -typedef struct Sym Sym; -typedef struct Ref Ref; -typedef struct Io Io; -typedef struct Addr2 Addr2; - -#define MAXALIGN 7 -#define FPCHIP 1 -#define NSYMB 500 -#define BUFSIZ 8192 -#define HISTSZ 20 -#ifndef EOF -#define EOF (-1) -#endif -#define IGN (-2) -#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) -#define NHASH 503 -#define STRINGSZ 200 -#define NMACRO 10 - -struct Sym -{ - Sym* link; - Ref* ref; - char* macro; - int32 value; - ushort type; - char *name; - char* labelname; - char sym; -}; -#define S ((Sym*)0) - -struct Ref -{ - int class; -}; - -EXTERN struct -{ - char* p; - int c; -} fi; - -struct Io -{ - Io* link; - char b[BUFSIZ]; - char* p; - short c; - short f; -}; -#define I ((Io*)0) - -struct Addr2 -{ - Addr from; - Addr to; -}; - -enum -{ - CLAST, - CMACARG, - CMACRO, - CPREPROC, -}; - -EXTERN int debug[256]; -EXTERN Sym* hash[NHASH]; -EXTERN char** Dlist; -EXTERN int nDlist; -EXTERN int newflag; -EXTERN char* hunk; -EXTERN char** include; -EXTERN Io* iofree; -EXTERN Io* ionext; -EXTERN Io* iostack; -EXTERN int32 lineno; -EXTERN int nerrors; -EXTERN int32 nhunk; -EXTERN int ninclude; -EXTERN int32 nsymb; -EXTERN Addr nullgen; -EXTERN char* outfile; -EXTERN int pass; -EXTERN int32 pc; -EXTERN int peekc; -EXTERN int32 stmtline; -EXTERN int sym; -EXTERN char* symb; -EXTERN int thechar; -EXTERN char* thestring; -EXTERN int32 thunk; -EXTERN Biobuf obuf; -EXTERN Link* ctxt; -EXTERN Biobuf bstdout; -EXTERN Prog* lastpc; - -void* alloc(int32); -void* allocn(void*, int32, int32); -void ensuresymb(int32); -void errorexit(void); -void pushio(void); -void newio(void); -void newfile(char*, int); -Sym* slookup(char*); -Sym* lookup(void); -Sym* labellookup(Sym*); -void settext(LSym*); -void syminit(Sym*); -int32 yylex(void); -int getc(void); -int getnsc(void); -void unget(int); -int escchar(int); -void cinit(void); -void checkscale(int); -void pinit(char*); -void cclean(void); -int isreg(Addr*); -void outcode(int, Addr2*); -void outhist(void); -int filbuf(void); -Sym* getsym(void); -void domacro(void); -void macund(void); -void macdef(void); -void macexpand(Sym*, char*); -void macinc(void); -void macprag(void); -void maclin(void); -void macif(int); -void macend(void); -void dodefine(char*); -void prfile(int32); -void linehist(char*, int); -void gethunk(void); -void yyerror(char*, ...); -int yyparse(void); -void setinclude(char*); -int assemble(char*); diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y index 1a3ab72ff2..906ad331df 100644 --- a/src/cmd/8a/a.y +++ b/src/cmd/8a/a.y @@ -29,20 +29,28 @@ // THE SOFTWARE. %{ -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/i386" +) %} -%union { - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; + +%union { + sym *asm.Sym + lval int64 + con2 struct { + v1 int32 + v2 int32 + } + dval float64 + sval string + addr obj.Addr + addr2 Addr2 } + %left '|' %left '^' %left '&' @@ -64,18 +72,19 @@ prog: | prog { - stmtline = lineno; + stmtline = asm.Lineno; } line line: LNAME ':' { - $1 = labellookup($1); - if($1->type == LLAB && $1->value != pc) - yyerror("redeclaration of %s", $1->labelname); - $1->type = LLAB; - $1->value = pc; + $1 = asm.LabelLookup($1); + if $1.Type == LLAB && $1.Value != int64(asm.PC) { + yyerror("redeclaration of %s", $1.Labelname) + } + $1.Type = LLAB; + $1.Value = int64(asm.PC) } line | ';' @@ -85,33 +94,34 @@ line: inst: LNAME '=' expr { - $1->type = LVAR; - $1->value = $3; + $1.Type = LVAR; + $1.Value = $3; } | LVAR '=' expr { - if($1->value != $3) - yyerror("redeclaration of %s", $1->name); - $1->value = $3; - } -| LTYPE0 nonnon { outcode($1, &$2); } -| LTYPE1 nonrem { outcode($1, &$2); } -| LTYPE2 rimnon { outcode($1, &$2); } -| LTYPE3 rimrem { outcode($1, &$2); } -| LTYPE4 remrim { outcode($1, &$2); } -| LTYPER nonrel { outcode($1, &$2); } + if $1.Value != int64($3) { + yyerror("redeclaration of %s", $1.Name); + } + $1.Value = $3; + } +| LTYPE0 nonnon { outcode(int($1), &$2); } +| LTYPE1 nonrem { outcode(int($1), &$2); } +| LTYPE2 rimnon { outcode(int($1), &$2); } +| LTYPE3 rimrem { outcode(int($1), &$2); } +| LTYPE4 remrim { outcode(int($1), &$2); } +| LTYPER nonrel { outcode(int($1), &$2); } | spec1 | spec2 -| LTYPEC spec3 { outcode($1, &$2); } -| LTYPEN spec4 { outcode($1, &$2); } -| LTYPES spec5 { outcode($1, &$2); } -| LTYPEM spec6 { outcode($1, &$2); } -| LTYPEI spec7 { outcode($1, &$2); } +| LTYPEC spec3 { outcode(int($1), &$2); } +| LTYPEN spec4 { outcode(int($1), &$2); } +| LTYPES spec5 { outcode(int($1), &$2); } +| LTYPEM spec6 { outcode(int($1), &$2); } +| LTYPEI spec7 { outcode(int($1), &$2); } | spec8 -| LTYPEXC spec9 { outcode($1, &$2); } -| LTYPEX spec10 { outcode($1, &$2); } -| LTYPEPC spec11 { outcode($1, &$2); } -| LTYPEF spec12 { outcode($1, &$2); } +| LTYPEXC spec9 { outcode(int($1), &$2); } +| LTYPEX spec10 { outcode(int($1), &$2); } +| LTYPEPC spec11 { outcode(int($1), &$2); } +| LTYPEF spec12 { outcode(int($1), &$2); } nonnon: { @@ -182,60 +192,46 @@ nonrel: spec1: /* DATA */ LTYPED nam '/' con ',' imm { - Addr2 a; - a.from = $2; - a.to = $6; - outcode(ADATA, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + outcode(obj.ADATA, &Addr2{$2, $6}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } spec2: /* TEXT */ LTYPET mem ',' '$' textsize { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $5; - outcode(ATEXT, &a); + asm.Settext($2.Sym); + outcode(obj.ATEXT, &Addr2{$2, $5}) } | LTYPET mem ',' con ',' '$' textsize { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $7; - outcode(ATEXT, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym); + outcode(obj.ATEXT, &Addr2{$2, $7}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } spec8: /* GLOBL */ LTYPEG mem ',' imm { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $4; - outcode(AGLOBL, &a); + asm.Settext($2.Sym); + outcode(obj.AGLOBL, &Addr2{$2, $4}) } | LTYPEG mem ',' con ',' imm { - Addr2 a; - settext($2.sym); - a.from = $2; - a.to = $6; - outcode(AGLOBL, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym); + outcode(obj.AGLOBL, &Addr2{$2, $6}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } + spec3: /* JMP/CALL */ ',' rom { @@ -251,7 +247,7 @@ spec3: /* JMP/CALL */ { $$.from = nullgen; $$.to = $2; - $$.to.type = TYPE_INDIR; + $$.to.Type = obj.TYPE_INDIR } spec4: /* NOP */ @@ -268,9 +264,10 @@ spec5: /* SHL/SHR */ { $$.from = $1; $$.to = $3; - if($$.from.index != TYPE_NONE) + if $$.from.Index != obj.TYPE_NONE { yyerror("dp shift with lhs index"); - $$.from.index = $5; + } + $$.from.Index = int16($5); } spec6: /* MOVW/MOVL */ @@ -283,9 +280,10 @@ spec6: /* MOVW/MOVL */ { $$.from = $1; $$.to = $3; - if($$.to.index != TYPE_NONE) + if $$.to.Index != obj.TYPE_NONE { yyerror("dp move with lhs index"); - $$.to.index = $5; + } + $$.to.Index = int16($5); } spec7: @@ -310,7 +308,7 @@ spec9: /* CMPPS/CMPPD */ { $$.from = $1; $$.to = $3; - $$.to.offset = $5; + $$.to.Offset = $5; } spec10: /* PINSRD */ @@ -318,16 +316,18 @@ spec10: /* PINSRD */ { $$.from = $3; $$.to = $5; - if($1.type != TYPE_CONST) - yyerror("illegal constant"); - $$.to.offset = $1.offset; + if $1.Type != obj.TYPE_CONST { + yyerror("illegal constant") + } + $$.to.Offset = $1.Offset; } spec11: /* PCDATA */ rim ',' rim { - if($1.type != TYPE_CONST || $3.type != TYPE_CONST) + if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST { yyerror("arguments to PCDATA must be integer constants"); + } $$.from = $1; $$.to = $3; } @@ -335,10 +335,12 @@ spec11: /* PCDATA */ spec12: /* FUNCDATA */ rim ',' rim { - if($1.type != TYPE_CONST) + if $1.Type != obj.TYPE_CONST { yyerror("index for FUNCDATA must be integer constant"); - if($3.type != TYPE_MEM || ($3.name != NAME_EXTERN && $3.name != NAME_STATIC)) + } + if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) { yyerror("value for FUNCDATA must be symbol reference"); + } $$.from = $1; $$.to = $3; } @@ -370,135 +372,137 @@ rel: con '(' LPC ')' { $$ = nullgen; - $$.type = TYPE_BRANCH; - $$.offset = $1 + pc; + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1 + int64(asm.PC); } | LNAME offset { - $1 = labellookup($1); + $1 = asm.LabelLookup($1); $$ = nullgen; - if(pass == 2 && $1->type != LLAB) - yyerror("undefined label: %s", $1->labelname); - $$.type = TYPE_BRANCH; - $$.offset = $1->value + $2; + if asm.Pass == 2 && $1.Type != LLAB { + yyerror("undefined label: %s", $1.Labelname); + } + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1.Value + $2; } reg: LBREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LFREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LLREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LXREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } | LSP { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = REG_SP; + $$.Type = obj.TYPE_REG + $$.Reg = REG_SP; } | LSREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1); } imm: '$' con { $$ = nullgen; - $$.type = TYPE_CONST; - $$.offset = $2; + $$.Type = obj.TYPE_CONST; + $$.Offset = $2; } | '$' nam { $$ = $2; - $$.type = TYPE_ADDR; + $$.Type = obj.TYPE_ADDR /* - if($2.name == NAME_AUTO || $2.name == NAME_PARAM) + if($2.Type == D_AUTO || $2.Type == D_PARAM) yyerror("constant cannot be automatic: %s", - $2.sym->name); + $2.Sym.name); */ } | '$' LSCONST { $$ = nullgen; - $$.type = TYPE_SCONST; - memcpy($$.u.sval, $2, sizeof($$.u.sval)); + $$.Type = obj.TYPE_SCONST; + $$.U.Sval = $2 } | '$' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $2; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $2; } | '$' '(' LFCONST ')' { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $3; } | '$' '(' '-' LFCONST ')' { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$4; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$4; } | '$' '-' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$3; } textsize: LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = $1; + $$.U.Argsize = obj.ArgsSizeUnknown; } | '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -$2; + $$.U.Argsize = obj.ArgsSizeUnknown; } | LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = $3; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = $1; + $$.U.Argsize = int32($3); } | '-' LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = $4; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -$2; + $$.U.Argsize = int32($4); } + mem: omem | nmem @@ -507,90 +511,87 @@ omem: con { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_NONE; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Offset = $1; } | con '(' LLREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; } | con '(' LSP ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_SP; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = REG_SP + $$.Offset = $1; } | con '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_NONE; - $$.offset = $1; - $$.index = $3; - $$.scale = $5; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Offset = $1; + $$.Index = int16($3); + $$.Scale = int8($5); + checkscale($$.Scale); } | con '(' LLREG ')' '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; - $$.index = $6; - $$.scale = $8; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; + $$.Index = int16($6); + $$.Scale = int8($8); + checkscale($$.Scale); } | con '(' LLREG ')' '(' LSREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; - $$.index = $6; - $$.scale = $8; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; + $$.Index = int16($6); + $$.Scale = int8($8); + checkscale($$.Scale); } | '(' LLREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($2); } | '(' LSP ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_SP; + $$.Type = obj.TYPE_MEM + $$.Reg = REG_SP } | con '(' LSREG ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; + $$.Type = obj.TYPE_MEM + $$.Reg = int16($3) + $$.Offset = $1; } | '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = REG_NONE; - $$.index = $2; - $$.scale = $4; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Index = int16($2); + $$.Scale = int8($4); + checkscale($$.Scale); } | '(' LLREG ')' '(' LLREG '*' con ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; - $$.index = $5; - $$.scale = $7; - checkscale($$.scale); + $$.Type = obj.TYPE_MEM + $$.Reg = int16($2) + $$.Index = int16($5); + $$.Scale = int8($7); + checkscale($$.Scale); } nmem: @@ -601,27 +602,27 @@ nmem: | nam '(' LLREG '*' con ')' { $$ = $1; - $$.index = $3; - $$.scale = $5; - checkscale($$.scale); + $$.Index = int16($3); + $$.Scale = int8($5); + checkscale($$.Scale); } nam: LNAME offset '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $4; - $$.sym = linklookup(ctxt, $1->name, 0); - $$.offset = $2; + $$.Type = obj.TYPE_MEM + $$.Name = int8($4); + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); + $$.Offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = NAME_STATIC; - $$.sym = linklookup(ctxt, $1->name, 1); - $$.offset = $4; + $$.Type = obj.TYPE_MEM + $$.Name = obj.NAME_STATIC + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); + $$.Offset = $4; } offset: @@ -641,7 +642,7 @@ pointer: LSB | LSP { - $$ = NAME_AUTO; + $$ = obj.NAME_AUTO; } | LFP @@ -649,7 +650,7 @@ con: LCONST | LVAR { - $$ = $1->value; + $$ = $1.Value; } | '-' con { @@ -661,7 +662,7 @@ con: } | '~' con { - $$ = ~$2; + $$ = ^$2; } | '(' expr ')' { @@ -692,11 +693,11 @@ expr: } | expr '<' '<' expr { - $$ = $1 << $4; + $$ = $1 << uint($4); } | expr '>' '>' expr { - $$ = $1 >> $4; + $$ = $1 >> uint($4); } | expr '&' expr { diff --git a/src/cmd/8a/doc.go b/src/cmd/8a/doc.go deleted file mode 100644 index 84c7254c80..0000000000 --- a/src/cmd/8a/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -8a is a version of the Plan 9 assembler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8a - -Go-specific considerations are documented at - - http://golang.org/doc/asm - -I -Its target architecture is the x86, referred to by these tools for historical reasons as 386. - -*/ -package main diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c deleted file mode 100644 index 846f6c6daf..0000000000 --- a/src/cmd/8a/lex.c +++ /dev/null @@ -1,914 +0,0 @@ -// Inferno utils/8a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include -#include -#include "a.h" -#include "y.tab.h" - -enum -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; - -int -systemtype(int sys) -{ -#ifdef _WIN32 - return sys&Windows; -#else - return sys&Plan9; -#endif -} - -int -pathchar(void) -{ - return '/'; -} - -int -Lconv(Fmt *fp) -{ - return linklinefmt(ctxt, fp); -} - -void -dodef(char *p) -{ - if(nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; -} - -void -usage(void) -{ - print("usage: %ca [options] file.c...\n", thechar); - flagprint(1); - errorexit(); -} -void -main(int argc, char *argv[]) -{ - char *p; - - thechar = '8'; - thestring = "386"; - - ctxt = linknew(&link386); - ctxt->diag = yyerror; - ctxt->bso = &bstdout; - ctxt->enforce_data_order = 1; - Binit(&bstdout, 1, OWRITE); - listinit8(); - fmtinstall('L', Lconv); - - // Allow GOARCH=thestring or GOARCH=thestringsuffix, - // but not other values. - p = getgoarch(); - if(strncmp(p, thestring, strlen(thestring)) != 0) - sysfatal("cannot use %cc with GOARCH=%s", thechar, p); - - ensuresymb(NSYMB); - memset(debug, 0, sizeof(debug)); - cinit(); - outfile = 0; - setinclude("."); - - flagfn1("D", "name[=value]: add #define", dodef); - flagfn1("I", "dir: add dir to include path", setinclude); - flagcount("S", "print assembly and machine code", &debug['S']); - flagcount("m", "debug preprocessor macros", &debug['m']); - flagstr("o", "file: set output file", &outfile); - flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - - flagparse(&argc, &argv, usage); - ctxt->debugasm = debug['S']; - - if(argc < 1) - usage(); - if(argc > 1){ - print("can't assemble multiple files\n"); - errorexit(); - } - - if(assemble(argv[0])) - errorexit(); - Bflush(&bstdout); - if(nerrors > 0) - errorexit(); - exits(0); -} - -int -assemble(char *file) -{ - char *ofile, *p; - int i, of; - - ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) - strcpy(ofile, file); - p = utfrrune(ofile, pathchar()); - if(p) { - include[0] = ofile; - *p++ = 0; - } else - p = ofile; - if(outfile == 0) { - outfile = p; - if(outfile){ - p = utfrrune(outfile, '.'); - if(p) - if(p[1] == 's' && p[2] == 0) - p[0] = 0; - p = utfrune(outfile, 0); - p[0] = '.'; - p[1] = thechar; - p[2] = 0; - } else - outfile = "/dev/null"; - } - - of = create(outfile, OWRITE, 0664); - if(of < 0) { - yyerror("%ca: cannot create %s", thechar, outfile); - errorexit(); - } - Binit(&obuf, of, OWRITE); - Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - Bprint(&obuf, "!\n"); - - for(pass = 1; pass <= 2; pass++) { - pinit(file); - for(i=0; itype != LNAME) - yyerror("double initialization %s", itab[i].name); - s->type = itab[i].type; - s->value = itab[i].value; - } -} - -void -checkscale(int scale) -{ - - switch(scale) { - case 1: - case 2: - case 4: - case 8: - return; - } - yyerror("scale must be 1248: %d", scale); -} - -void -syminit(Sym *s) -{ - - s->type = LNAME; - s->value = 0; -} - -void -cclean(void) -{ - Addr2 g2; - - g2.from = nullgen; - g2.to = nullgen; - outcode(AEND, &g2); -} - -void -outcode(int a, Addr2 *g2) -{ - Prog *p; - Plist *pl; - - if(pass == 1) - goto out; - - p = malloc(sizeof *p); - memset(p, 0, sizeof *p); - p->as = a; - p->lineno = stmtline; - p->from = g2->from; - p->to = g2->to; - p->pc = pc; - - if(lastpc == nil) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastpc->link = p; - lastpc = p; - -out: - if(a != AGLOBL && a != ADATA) - pc++; -} - -#include "../cc/lexbody" -#include "../cc/macbody" diff --git a/src/cmd/8a/lex.go b/src/cmd/8a/lex.go new file mode 100644 index 0000000000..bbd8610ec4 --- /dev/null +++ b/src/cmd/8a/lex.go @@ -0,0 +1,771 @@ +// Inferno utils/8a/lex.c +// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//go:generate go tool yacc a.y + +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/i386" +) + +var ( + yyerror = asm.Yyerror + nullgen obj.Addr + stmtline int32 +) + +func main() { + cinit() + + asm.LSCONST = LSCONST + asm.LCONST = LCONST + asm.LFCONST = LFCONST + asm.LNAME = LNAME + asm.LVAR = LVAR + asm.LLAB = LLAB + + asm.Lexinit = lexinit + asm.Cclean = cclean + asm.Yyparse = yyparse + + asm.Thechar = '8' + asm.Thestring = "386" + asm.Thelinkarch = &i386.Link386 + + asm.Main() +} + +type yy struct{} + +func (yy) Lex(v *yySymType) int { + var av asm.Yylval + tok := asm.Yylex(&av) + v.sym = av.Sym + v.lval = av.Lval + v.sval = av.Sval + v.dval = av.Dval + return tok +} + +func (yy) Error(msg string) { + asm.Yyerror("%s", msg) +} + +func yyparse() { + yyParse(yy{}) +} + +var lexinit = []asm.Lextab{ + {"SP", LSP, obj.NAME_AUTO}, + {"SB", LSB, obj.NAME_EXTERN}, + {"FP", LFP, obj.NAME_PARAM}, + {"PC", LPC, obj.TYPE_BRANCH}, + {"AL", LBREG, i386.REG_AL}, + {"CL", LBREG, i386.REG_CL}, + {"DL", LBREG, i386.REG_DL}, + {"BL", LBREG, i386.REG_BL}, + {"AH", LBREG, i386.REG_AH}, + {"CH", LBREG, i386.REG_CH}, + {"DH", LBREG, i386.REG_DH}, + {"BH", LBREG, i386.REG_BH}, + {"AX", LLREG, i386.REG_AX}, + {"CX", LLREG, i386.REG_CX}, + {"DX", LLREG, i386.REG_DX}, + {"BX", LLREG, i386.REG_BX}, + /* "SP", LLREG, REG_SP, */ + {"BP", LLREG, i386.REG_BP}, + {"SI", LLREG, i386.REG_SI}, + {"DI", LLREG, i386.REG_DI}, + {"F0", LFREG, i386.REG_F0 + 0}, + {"F1", LFREG, i386.REG_F0 + 1}, + {"F2", LFREG, i386.REG_F0 + 2}, + {"F3", LFREG, i386.REG_F0 + 3}, + {"F4", LFREG, i386.REG_F0 + 4}, + {"F5", LFREG, i386.REG_F0 + 5}, + {"F6", LFREG, i386.REG_F0 + 6}, + {"F7", LFREG, i386.REG_F0 + 7}, + {"X0", LXREG, i386.REG_X0 + 0}, + {"X1", LXREG, i386.REG_X0 + 1}, + {"X2", LXREG, i386.REG_X0 + 2}, + {"X3", LXREG, i386.REG_X0 + 3}, + {"X4", LXREG, i386.REG_X0 + 4}, + {"X5", LXREG, i386.REG_X0 + 5}, + {"X6", LXREG, i386.REG_X0 + 6}, + {"X7", LXREG, i386.REG_X0 + 7}, + {"CS", LSREG, i386.REG_CS}, + {"SS", LSREG, i386.REG_SS}, + {"DS", LSREG, i386.REG_DS}, + {"ES", LSREG, i386.REG_ES}, + {"FS", LSREG, i386.REG_FS}, + {"GS", LSREG, i386.REG_GS}, + {"TLS", LSREG, i386.REG_TLS}, + {"GDTR", LBREG, i386.REG_GDTR}, + {"IDTR", LBREG, i386.REG_IDTR}, + {"LDTR", LBREG, i386.REG_LDTR}, + {"MSW", LBREG, i386.REG_MSW}, + {"TASK", LBREG, i386.REG_TASK}, + {"CR0", LBREG, i386.REG_CR + 0}, + {"CR1", LBREG, i386.REG_CR + 1}, + {"CR2", LBREG, i386.REG_CR + 2}, + {"CR3", LBREG, i386.REG_CR + 3}, + {"CR4", LBREG, i386.REG_CR + 4}, + {"CR5", LBREG, i386.REG_CR + 5}, + {"CR6", LBREG, i386.REG_CR + 6}, + {"CR7", LBREG, i386.REG_CR + 7}, + {"DR0", LBREG, i386.REG_DR + 0}, + {"DR1", LBREG, i386.REG_DR + 1}, + {"DR2", LBREG, i386.REG_DR + 2}, + {"DR3", LBREG, i386.REG_DR + 3}, + {"DR4", LBREG, i386.REG_DR + 4}, + {"DR5", LBREG, i386.REG_DR + 5}, + {"DR6", LBREG, i386.REG_DR + 6}, + {"DR7", LBREG, i386.REG_DR + 7}, + {"TR0", LBREG, i386.REG_TR + 0}, + {"TR1", LBREG, i386.REG_TR + 1}, + {"TR2", LBREG, i386.REG_TR + 2}, + {"TR3", LBREG, i386.REG_TR + 3}, + {"TR4", LBREG, i386.REG_TR + 4}, + {"TR5", LBREG, i386.REG_TR + 5}, + {"TR6", LBREG, i386.REG_TR + 6}, + {"TR7", LBREG, i386.REG_TR + 7}, + {"AAA", LTYPE0, i386.AAAA}, + {"AAD", LTYPE0, i386.AAAD}, + {"AAM", LTYPE0, i386.AAAM}, + {"AAS", LTYPE0, i386.AAAS}, + {"ADCB", LTYPE3, i386.AADCB}, + {"ADCL", LTYPE3, i386.AADCL}, + {"ADCW", LTYPE3, i386.AADCW}, + {"ADDB", LTYPE3, i386.AADDB}, + {"ADDL", LTYPE3, i386.AADDL}, + {"ADDW", LTYPE3, i386.AADDW}, + {"ADJSP", LTYPE2, i386.AADJSP}, + {"ANDB", LTYPE3, i386.AANDB}, + {"ANDL", LTYPE3, i386.AANDL}, + {"ANDW", LTYPE3, i386.AANDW}, + {"ARPL", LTYPE3, i386.AARPL}, + {"BOUNDL", LTYPE3, i386.ABOUNDL}, + {"BOUNDW", LTYPE3, i386.ABOUNDW}, + {"BSFL", LTYPE3, i386.ABSFL}, + {"BSFW", LTYPE3, i386.ABSFW}, + {"BSRL", LTYPE3, i386.ABSRL}, + {"BSRW", LTYPE3, i386.ABSRW}, + {"BSWAPL", LTYPE1, i386.ABSWAPL}, + {"BTCL", LTYPE3, i386.ABTCL}, + {"BTCW", LTYPE3, i386.ABTCW}, + {"BTL", LTYPE3, i386.ABTL}, + {"BTRL", LTYPE3, i386.ABTRL}, + {"BTRW", LTYPE3, i386.ABTRW}, + {"BTSL", LTYPE3, i386.ABTSL}, + {"BTSW", LTYPE3, i386.ABTSW}, + {"BTW", LTYPE3, i386.ABTW}, + {"BYTE", LTYPE2, i386.ABYTE}, + {"CALL", LTYPEC, obj.ACALL}, + {"CLC", LTYPE0, i386.ACLC}, + {"CLD", LTYPE0, i386.ACLD}, + {"CLI", LTYPE0, i386.ACLI}, + {"CLTS", LTYPE0, i386.ACLTS}, + {"CMC", LTYPE0, i386.ACMC}, + {"CMPB", LTYPE4, i386.ACMPB}, + {"CMPL", LTYPE4, i386.ACMPL}, + {"CMPW", LTYPE4, i386.ACMPW}, + {"CMPSB", LTYPE0, i386.ACMPSB}, + {"CMPSL", LTYPE0, i386.ACMPSL}, + {"CMPSW", LTYPE0, i386.ACMPSW}, + {"CMPXCHG8B", LTYPE1, i386.ACMPXCHG8B}, + {"CMPXCHGB", LTYPE3, i386.ACMPXCHGB}, + {"CMPXCHGL", LTYPE3, i386.ACMPXCHGL}, + {"CMPXCHGW", LTYPE3, i386.ACMPXCHGW}, + {"CPUID", LTYPE0, i386.ACPUID}, + {"DAA", LTYPE0, i386.ADAA}, + {"DAS", LTYPE0, i386.ADAS}, + {"DATA", LTYPED, obj.ADATA}, + {"DECB", LTYPE1, i386.ADECB}, + {"DECL", LTYPE1, i386.ADECL}, + {"DECW", LTYPE1, i386.ADECW}, + {"DIVB", LTYPE2, i386.ADIVB}, + {"DIVL", LTYPE2, i386.ADIVL}, + {"DIVW", LTYPE2, i386.ADIVW}, + {"END", LTYPE0, obj.AEND}, + {"ENTER", LTYPE2, i386.AENTER}, + {"GLOBL", LTYPEG, obj.AGLOBL}, + {"HLT", LTYPE0, i386.AHLT}, + {"IDIVB", LTYPE2, i386.AIDIVB}, + {"IDIVL", LTYPE2, i386.AIDIVL}, + {"IDIVW", LTYPE2, i386.AIDIVW}, + {"IMULB", LTYPE2, i386.AIMULB}, + {"IMULL", LTYPEI, i386.AIMULL}, + {"IMULW", LTYPEI, i386.AIMULW}, + {"INB", LTYPE0, i386.AINB}, + {"INL", LTYPE0, i386.AINL}, + {"INW", LTYPE0, i386.AINW}, + {"INCB", LTYPE1, i386.AINCB}, + {"INCL", LTYPE1, i386.AINCL}, + {"INCW", LTYPE1, i386.AINCW}, + {"INSB", LTYPE0, i386.AINSB}, + {"INSL", LTYPE0, i386.AINSL}, + {"INSW", LTYPE0, i386.AINSW}, + {"INT", LTYPE2, i386.AINT}, + {"INTO", LTYPE0, i386.AINTO}, + {"IRETL", LTYPE0, i386.AIRETL}, + {"IRETW", LTYPE0, i386.AIRETW}, + {"JOS", LTYPER, i386.AJOS}, /* overflow set (OF = 1) */ + {"JO", LTYPER, i386.AJOS}, /* alternate */ + {"JOC", LTYPER, i386.AJOC}, /* overflow clear (OF = 0) */ + {"JNO", LTYPER, i386.AJOC}, /* alternate */ + {"JCS", LTYPER, i386.AJCS}, /* carry set (CF = 1) */ + {"JB", LTYPER, i386.AJCS}, /* alternate */ + {"JC", LTYPER, i386.AJCS}, /* alternate */ + {"JNAE", LTYPER, i386.AJCS}, /* alternate */ + {"JLO", LTYPER, i386.AJCS}, /* alternate */ + {"JCC", LTYPER, i386.AJCC}, /* carry clear (CF = 0) */ + {"JAE", LTYPER, i386.AJCC}, /* alternate */ + {"JNB", LTYPER, i386.AJCC}, /* alternate */ + {"JNC", LTYPER, i386.AJCC}, /* alternate */ + {"JHS", LTYPER, i386.AJCC}, /* alternate */ + {"JEQ", LTYPER, i386.AJEQ}, /* equal (ZF = 1) */ + {"JE", LTYPER, i386.AJEQ}, /* alternate */ + {"JZ", LTYPER, i386.AJEQ}, /* alternate */ + {"JNE", LTYPER, i386.AJNE}, /* not equal (ZF = 0) */ + {"JNZ", LTYPER, i386.AJNE}, /* alternate */ + {"JLS", LTYPER, i386.AJLS}, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ + {"JBE", LTYPER, i386.AJLS}, /* alternate */ + {"JNA", LTYPER, i386.AJLS}, /* alternate */ + {"JHI", LTYPER, i386.AJHI}, /* higher (unsigned) (CF = 0 && ZF = 0) */ + {"JA", LTYPER, i386.AJHI}, /* alternate */ + {"JNBE", LTYPER, i386.AJHI}, /* alternate */ + {"JMI", LTYPER, i386.AJMI}, /* negative (minus) (SF = 1) */ + {"JS", LTYPER, i386.AJMI}, /* alternate */ + {"JPL", LTYPER, i386.AJPL}, /* non-negative (plus) (SF = 0) */ + {"JNS", LTYPER, i386.AJPL}, /* alternate */ + {"JPS", LTYPER, i386.AJPS}, /* parity set (PF = 1) */ + {"JP", LTYPER, i386.AJPS}, /* alternate */ + {"JPE", LTYPER, i386.AJPS}, /* alternate */ + {"JPC", LTYPER, i386.AJPC}, /* parity clear (PF = 0) */ + {"JNP", LTYPER, i386.AJPC}, /* alternate */ + {"JPO", LTYPER, i386.AJPC}, /* alternate */ + {"JLT", LTYPER, i386.AJLT}, /* less than (signed) (SF != OF) */ + {"JL", LTYPER, i386.AJLT}, /* alternate */ + {"JNGE", LTYPER, i386.AJLT}, /* alternate */ + {"JGE", LTYPER, i386.AJGE}, /* greater than or equal (signed) (SF = OF) */ + {"JNL", LTYPER, i386.AJGE}, /* alternate */ + {"JLE", LTYPER, i386.AJLE}, /* less than or equal (signed) (ZF = 1 || SF != OF) */ + {"JNG", LTYPER, i386.AJLE}, /* alternate */ + {"JGT", LTYPER, i386.AJGT}, /* greater than (signed) (ZF = 0 && SF = OF) */ + {"JG", LTYPER, i386.AJGT}, /* alternate */ + {"JNLE", LTYPER, i386.AJGT}, /* alternate */ + {"JCXZL", LTYPER, i386.AJCXZL}, + {"JCXZW", LTYPER, i386.AJCXZW}, + {"JMP", LTYPEC, obj.AJMP}, + {"LAHF", LTYPE0, i386.ALAHF}, + {"LARL", LTYPE3, i386.ALARL}, + {"LARW", LTYPE3, i386.ALARW}, + {"LEAL", LTYPE3, i386.ALEAL}, + {"LEAW", LTYPE3, i386.ALEAW}, + {"LEAVEL", LTYPE0, i386.ALEAVEL}, + {"LEAVEW", LTYPE0, i386.ALEAVEW}, + {"LOCK", LTYPE0, i386.ALOCK}, + {"LODSB", LTYPE0, i386.ALODSB}, + {"LODSL", LTYPE0, i386.ALODSL}, + {"LODSW", LTYPE0, i386.ALODSW}, + {"LONG", LTYPE2, i386.ALONG}, + {"LOOP", LTYPER, i386.ALOOP}, + {"LOOPEQ", LTYPER, i386.ALOOPEQ}, + {"LOOPNE", LTYPER, i386.ALOOPNE}, + {"LSLL", LTYPE3, i386.ALSLL}, + {"LSLW", LTYPE3, i386.ALSLW}, + {"MOVB", LTYPE3, i386.AMOVB}, + {"MOVL", LTYPEM, i386.AMOVL}, + {"MOVW", LTYPEM, i386.AMOVW}, + {"MOVQ", LTYPEM, i386.AMOVQ}, + {"MOVBLSX", LTYPE3, i386.AMOVBLSX}, + {"MOVBLZX", LTYPE3, i386.AMOVBLZX}, + {"MOVBWSX", LTYPE3, i386.AMOVBWSX}, + {"MOVBWZX", LTYPE3, i386.AMOVBWZX}, + {"MOVWLSX", LTYPE3, i386.AMOVWLSX}, + {"MOVWLZX", LTYPE3, i386.AMOVWLZX}, + {"MOVSB", LTYPE0, i386.AMOVSB}, + {"MOVSL", LTYPE0, i386.AMOVSL}, + {"MOVSW", LTYPE0, i386.AMOVSW}, + {"MULB", LTYPE2, i386.AMULB}, + {"MULL", LTYPE2, i386.AMULL}, + {"MULW", LTYPE2, i386.AMULW}, + {"NEGB", LTYPE1, i386.ANEGB}, + {"NEGL", LTYPE1, i386.ANEGL}, + {"NEGW", LTYPE1, i386.ANEGW}, + {"NOP", LTYPEN, obj.ANOP}, + {"NOTB", LTYPE1, i386.ANOTB}, + {"NOTL", LTYPE1, i386.ANOTL}, + {"NOTW", LTYPE1, i386.ANOTW}, + {"ORB", LTYPE3, i386.AORB}, + {"ORL", LTYPE3, i386.AORL}, + {"ORW", LTYPE3, i386.AORW}, + {"OUTB", LTYPE0, i386.AOUTB}, + {"OUTL", LTYPE0, i386.AOUTL}, + {"OUTW", LTYPE0, i386.AOUTW}, + {"OUTSB", LTYPE0, i386.AOUTSB}, + {"OUTSL", LTYPE0, i386.AOUTSL}, + {"OUTSW", LTYPE0, i386.AOUTSW}, + {"PAUSE", LTYPEN, i386.APAUSE}, + {"PINSRD", LTYPEX, i386.APINSRD}, + {"POPAL", LTYPE0, i386.APOPAL}, + {"POPAW", LTYPE0, i386.APOPAW}, + {"POPFL", LTYPE0, i386.APOPFL}, + {"POPFW", LTYPE0, i386.APOPFW}, + {"POPL", LTYPE1, i386.APOPL}, + {"POPW", LTYPE1, i386.APOPW}, + {"PUSHAL", LTYPE0, i386.APUSHAL}, + {"PUSHAW", LTYPE0, i386.APUSHAW}, + {"PUSHFL", LTYPE0, i386.APUSHFL}, + {"PUSHFW", LTYPE0, i386.APUSHFW}, + {"PUSHL", LTYPE2, i386.APUSHL}, + {"PUSHW", LTYPE2, i386.APUSHW}, + {"RCLB", LTYPE3, i386.ARCLB}, + {"RCLL", LTYPE3, i386.ARCLL}, + {"RCLW", LTYPE3, i386.ARCLW}, + {"RCRB", LTYPE3, i386.ARCRB}, + {"RCRL", LTYPE3, i386.ARCRL}, + {"RCRW", LTYPE3, i386.ARCRW}, + {"RDTSC", LTYPE0, i386.ARDTSC}, + {"REP", LTYPE0, i386.AREP}, + {"REPN", LTYPE0, i386.AREPN}, + {"RET", LTYPE0, obj.ARET}, + {"ROLB", LTYPE3, i386.AROLB}, + {"ROLL", LTYPE3, i386.AROLL}, + {"ROLW", LTYPE3, i386.AROLW}, + {"RORB", LTYPE3, i386.ARORB}, + {"RORL", LTYPE3, i386.ARORL}, + {"RORW", LTYPE3, i386.ARORW}, + {"SAHF", LTYPE0, i386.ASAHF}, + {"SALB", LTYPE3, i386.ASALB}, + {"SALL", LTYPE3, i386.ASALL}, + {"SALW", LTYPE3, i386.ASALW}, + {"SARB", LTYPE3, i386.ASARB}, + {"SARL", LTYPE3, i386.ASARL}, + {"SARW", LTYPE3, i386.ASARW}, + {"SBBB", LTYPE3, i386.ASBBB}, + {"SBBL", LTYPE3, i386.ASBBL}, + {"SBBW", LTYPE3, i386.ASBBW}, + {"SCASB", LTYPE0, i386.ASCASB}, + {"SCASL", LTYPE0, i386.ASCASL}, + {"SCASW", LTYPE0, i386.ASCASW}, + {"SETCC", LTYPE1, i386.ASETCC}, /* see JCC etc above for condition codes */ + {"SETCS", LTYPE1, i386.ASETCS}, + {"SETEQ", LTYPE1, i386.ASETEQ}, + {"SETGE", LTYPE1, i386.ASETGE}, + {"SETGT", LTYPE1, i386.ASETGT}, + {"SETHI", LTYPE1, i386.ASETHI}, + {"SETLE", LTYPE1, i386.ASETLE}, + {"SETLS", LTYPE1, i386.ASETLS}, + {"SETLT", LTYPE1, i386.ASETLT}, + {"SETMI", LTYPE1, i386.ASETMI}, + {"SETNE", LTYPE1, i386.ASETNE}, + {"SETOC", LTYPE1, i386.ASETOC}, + {"SETOS", LTYPE1, i386.ASETOS}, + {"SETPC", LTYPE1, i386.ASETPC}, + {"SETPL", LTYPE1, i386.ASETPL}, + {"SETPS", LTYPE1, i386.ASETPS}, + {"CDQ", LTYPE0, i386.ACDQ}, + {"CWD", LTYPE0, i386.ACWD}, + {"SHLB", LTYPE3, i386.ASHLB}, + {"SHLL", LTYPES, i386.ASHLL}, + {"SHLW", LTYPES, i386.ASHLW}, + {"SHRB", LTYPE3, i386.ASHRB}, + {"SHRL", LTYPES, i386.ASHRL}, + {"SHRW", LTYPES, i386.ASHRW}, + {"STC", LTYPE0, i386.ASTC}, + {"STD", LTYPE0, i386.ASTD}, + {"STI", LTYPE0, i386.ASTI}, + {"STOSB", LTYPE0, i386.ASTOSB}, + {"STOSL", LTYPE0, i386.ASTOSL}, + {"STOSW", LTYPE0, i386.ASTOSW}, + {"SUBB", LTYPE3, i386.ASUBB}, + {"SUBL", LTYPE3, i386.ASUBL}, + {"SUBW", LTYPE3, i386.ASUBW}, + {"SYSCALL", LTYPE0, i386.ASYSCALL}, + {"TESTB", LTYPE3, i386.ATESTB}, + {"TESTL", LTYPE3, i386.ATESTL}, + {"TESTW", LTYPE3, i386.ATESTW}, + {"TEXT", LTYPET, obj.ATEXT}, + {"VERR", LTYPE2, i386.AVERR}, + {"VERW", LTYPE2, i386.AVERW}, + {"WAIT", LTYPE0, i386.AWAIT}, + {"WORD", LTYPE2, i386.AWORD}, + {"XADDB", LTYPE3, i386.AXADDB}, + {"XADDL", LTYPE3, i386.AXADDL}, + {"XADDW", LTYPE3, i386.AXADDW}, + {"XCHGB", LTYPE3, i386.AXCHGB}, + {"XCHGL", LTYPE3, i386.AXCHGL}, + {"XCHGW", LTYPE3, i386.AXCHGW}, + {"XLAT", LTYPE2, i386.AXLAT}, + {"XORB", LTYPE3, i386.AXORB}, + {"XORL", LTYPE3, i386.AXORL}, + {"XORW", LTYPE3, i386.AXORW}, + {"CMOVLCC", LTYPE3, i386.ACMOVLCC}, + {"CMOVLCS", LTYPE3, i386.ACMOVLCS}, + {"CMOVLEQ", LTYPE3, i386.ACMOVLEQ}, + {"CMOVLGE", LTYPE3, i386.ACMOVLGE}, + {"CMOVLGT", LTYPE3, i386.ACMOVLGT}, + {"CMOVLHI", LTYPE3, i386.ACMOVLHI}, + {"CMOVLLE", LTYPE3, i386.ACMOVLLE}, + {"CMOVLLS", LTYPE3, i386.ACMOVLLS}, + {"CMOVLLT", LTYPE3, i386.ACMOVLLT}, + {"CMOVLMI", LTYPE3, i386.ACMOVLMI}, + {"CMOVLNE", LTYPE3, i386.ACMOVLNE}, + {"CMOVLOC", LTYPE3, i386.ACMOVLOC}, + {"CMOVLOS", LTYPE3, i386.ACMOVLOS}, + {"CMOVLPC", LTYPE3, i386.ACMOVLPC}, + {"CMOVLPL", LTYPE3, i386.ACMOVLPL}, + {"CMOVLPS", LTYPE3, i386.ACMOVLPS}, + {"CMOVWCC", LTYPE3, i386.ACMOVWCC}, + {"CMOVWCS", LTYPE3, i386.ACMOVWCS}, + {"CMOVWEQ", LTYPE3, i386.ACMOVWEQ}, + {"CMOVWGE", LTYPE3, i386.ACMOVWGE}, + {"CMOVWGT", LTYPE3, i386.ACMOVWGT}, + {"CMOVWHI", LTYPE3, i386.ACMOVWHI}, + {"CMOVWLE", LTYPE3, i386.ACMOVWLE}, + {"CMOVWLS", LTYPE3, i386.ACMOVWLS}, + {"CMOVWLT", LTYPE3, i386.ACMOVWLT}, + {"CMOVWMI", LTYPE3, i386.ACMOVWMI}, + {"CMOVWNE", LTYPE3, i386.ACMOVWNE}, + {"CMOVWOC", LTYPE3, i386.ACMOVWOC}, + {"CMOVWOS", LTYPE3, i386.ACMOVWOS}, + {"CMOVWPC", LTYPE3, i386.ACMOVWPC}, + {"CMOVWPL", LTYPE3, i386.ACMOVWPL}, + {"CMOVWPS", LTYPE3, i386.ACMOVWPS}, + {"FMOVB", LTYPE3, i386.AFMOVB}, + {"FMOVBP", LTYPE3, i386.AFMOVBP}, + {"FMOVD", LTYPE3, i386.AFMOVD}, + {"FMOVDP", LTYPE3, i386.AFMOVDP}, + {"FMOVF", LTYPE3, i386.AFMOVF}, + {"FMOVFP", LTYPE3, i386.AFMOVFP}, + {"FMOVL", LTYPE3, i386.AFMOVL}, + {"FMOVLP", LTYPE3, i386.AFMOVLP}, + {"FMOVV", LTYPE3, i386.AFMOVV}, + {"FMOVVP", LTYPE3, i386.AFMOVVP}, + {"FMOVW", LTYPE3, i386.AFMOVW}, + {"FMOVWP", LTYPE3, i386.AFMOVWP}, + {"FMOVX", LTYPE3, i386.AFMOVX}, + {"FMOVXP", LTYPE3, i386.AFMOVXP}, + {"FCMOVCC", LTYPE3, i386.AFCMOVCC}, + {"FCMOVCS", LTYPE3, i386.AFCMOVCS}, + {"FCMOVEQ", LTYPE3, i386.AFCMOVEQ}, + {"FCMOVHI", LTYPE3, i386.AFCMOVHI}, + {"FCMOVLS", LTYPE3, i386.AFCMOVLS}, + {"FCMOVNE", LTYPE3, i386.AFCMOVNE}, + {"FCMOVNU", LTYPE3, i386.AFCMOVNU}, + {"FCMOVUN", LTYPE3, i386.AFCMOVUN}, + {"FCOMB", LTYPE3, i386.AFCOMB}, + {"FCOMBP", LTYPE3, i386.AFCOMBP}, + {"FCOMD", LTYPE3, i386.AFCOMD}, + {"FCOMDP", LTYPE3, i386.AFCOMDP}, + {"FCOMDPP", LTYPE3, i386.AFCOMDPP}, + {"FCOMF", LTYPE3, i386.AFCOMF}, + {"FCOMFP", LTYPE3, i386.AFCOMFP}, + {"FCOMI", LTYPE3, i386.AFCOMI}, + {"FCOMIP", LTYPE3, i386.AFCOMIP}, + {"FCOML", LTYPE3, i386.AFCOML}, + {"FCOMLP", LTYPE3, i386.AFCOMLP}, + {"FCOMW", LTYPE3, i386.AFCOMW}, + {"FCOMWP", LTYPE3, i386.AFCOMWP}, + {"FUCOM", LTYPE3, i386.AFUCOM}, + {"FUCOMI", LTYPE3, i386.AFUCOMI}, + {"FUCOMIP", LTYPE3, i386.AFUCOMIP}, + {"FUCOMP", LTYPE3, i386.AFUCOMP}, + {"FUCOMPP", LTYPE3, i386.AFUCOMPP}, + {"FADDW", LTYPE3, i386.AFADDW}, + {"FADDL", LTYPE3, i386.AFADDL}, + {"FADDF", LTYPE3, i386.AFADDF}, + {"FADDD", LTYPE3, i386.AFADDD}, + {"FADDDP", LTYPE3, i386.AFADDDP}, + {"FSUBDP", LTYPE3, i386.AFSUBDP}, + {"FSUBW", LTYPE3, i386.AFSUBW}, + {"FSUBL", LTYPE3, i386.AFSUBL}, + {"FSUBF", LTYPE3, i386.AFSUBF}, + {"FSUBD", LTYPE3, i386.AFSUBD}, + {"FSUBRDP", LTYPE3, i386.AFSUBRDP}, + {"FSUBRW", LTYPE3, i386.AFSUBRW}, + {"FSUBRL", LTYPE3, i386.AFSUBRL}, + {"FSUBRF", LTYPE3, i386.AFSUBRF}, + {"FSUBRD", LTYPE3, i386.AFSUBRD}, + {"FMULDP", LTYPE3, i386.AFMULDP}, + {"FMULW", LTYPE3, i386.AFMULW}, + {"FMULL", LTYPE3, i386.AFMULL}, + {"FMULF", LTYPE3, i386.AFMULF}, + {"FMULD", LTYPE3, i386.AFMULD}, + {"FDIVDP", LTYPE3, i386.AFDIVDP}, + {"FDIVW", LTYPE3, i386.AFDIVW}, + {"FDIVL", LTYPE3, i386.AFDIVL}, + {"FDIVF", LTYPE3, i386.AFDIVF}, + {"FDIVD", LTYPE3, i386.AFDIVD}, + {"FDIVRDP", LTYPE3, i386.AFDIVRDP}, + {"FDIVRW", LTYPE3, i386.AFDIVRW}, + {"FDIVRL", LTYPE3, i386.AFDIVRL}, + {"FDIVRF", LTYPE3, i386.AFDIVRF}, + {"FDIVRD", LTYPE3, i386.AFDIVRD}, + {"FXCHD", LTYPE3, i386.AFXCHD}, + {"FFREE", LTYPE1, i386.AFFREE}, + {"FLDCW", LTYPE2, i386.AFLDCW}, + {"FLDENV", LTYPE1, i386.AFLDENV}, + {"FRSTOR", LTYPE2, i386.AFRSTOR}, + {"FSAVE", LTYPE1, i386.AFSAVE}, + {"FSTCW", LTYPE1, i386.AFSTCW}, + {"FSTENV", LTYPE1, i386.AFSTENV}, + {"FSTSW", LTYPE1, i386.AFSTSW}, + {"F2XM1", LTYPE0, i386.AF2XM1}, + {"FABS", LTYPE0, i386.AFABS}, + {"FCHS", LTYPE0, i386.AFCHS}, + {"FCLEX", LTYPE0, i386.AFCLEX}, + {"FCOS", LTYPE0, i386.AFCOS}, + {"FDECSTP", LTYPE0, i386.AFDECSTP}, + {"FINCSTP", LTYPE0, i386.AFINCSTP}, + {"FINIT", LTYPE0, i386.AFINIT}, + {"FLD1", LTYPE0, i386.AFLD1}, + {"FLDL2E", LTYPE0, i386.AFLDL2E}, + {"FLDL2T", LTYPE0, i386.AFLDL2T}, + {"FLDLG2", LTYPE0, i386.AFLDLG2}, + {"FLDLN2", LTYPE0, i386.AFLDLN2}, + {"FLDPI", LTYPE0, i386.AFLDPI}, + {"FLDZ", LTYPE0, i386.AFLDZ}, + {"FNOP", LTYPE0, i386.AFNOP}, + {"FPATAN", LTYPE0, i386.AFPATAN}, + {"FPREM", LTYPE0, i386.AFPREM}, + {"FPREM1", LTYPE0, i386.AFPREM1}, + {"FPTAN", LTYPE0, i386.AFPTAN}, + {"FRNDINT", LTYPE0, i386.AFRNDINT}, + {"FSCALE", LTYPE0, i386.AFSCALE}, + {"FSIN", LTYPE0, i386.AFSIN}, + {"FSINCOS", LTYPE0, i386.AFSINCOS}, + {"FSQRT", LTYPE0, i386.AFSQRT}, + {"FTST", LTYPE0, i386.AFTST}, + {"FXAM", LTYPE0, i386.AFXAM}, + {"FXTRACT", LTYPE0, i386.AFXTRACT}, + {"FYL2X", LTYPE0, i386.AFYL2X}, + {"FYL2XP1", LTYPE0, i386.AFYL2XP1}, + {"LFENCE", LTYPE0, i386.ALFENCE}, + {"MFENCE", LTYPE0, i386.AMFENCE}, + {"SFENCE", LTYPE0, i386.ASFENCE}, + {"EMMS", LTYPE0, i386.AEMMS}, + {"PREFETCHT0", LTYPE2, i386.APREFETCHT0}, + {"PREFETCHT1", LTYPE2, i386.APREFETCHT1}, + {"PREFETCHT2", LTYPE2, i386.APREFETCHT2}, + {"PREFETCHNTA", LTYPE2, i386.APREFETCHNTA}, + {"UNDEF", LTYPE0, obj.AUNDEF}, + {"ADDPD", LTYPE3, i386.AADDPD}, + {"ADDPS", LTYPE3, i386.AADDPS}, + {"ADDSD", LTYPE3, i386.AADDSD}, + {"ADDSS", LTYPE3, i386.AADDSS}, + {"AESENC", LTYPE3, i386.AAESENC}, + {"ANDNPD", LTYPE3, i386.AANDNPD}, + {"ANDNPS", LTYPE3, i386.AANDNPS}, + {"ANDPD", LTYPE3, i386.AANDPD}, + {"ANDPS", LTYPE3, i386.AANDPS}, + {"CMPPD", LTYPEXC, i386.ACMPPD}, + {"CMPPS", LTYPEXC, i386.ACMPPS}, + {"CMPSD", LTYPEXC, i386.ACMPSD}, + {"CMPSS", LTYPEXC, i386.ACMPSS}, + {"COMISD", LTYPE3, i386.ACOMISD}, + {"COMISS", LTYPE3, i386.ACOMISS}, + {"CVTPL2PD", LTYPE3, i386.ACVTPL2PD}, + {"CVTPL2PS", LTYPE3, i386.ACVTPL2PS}, + {"CVTPD2PL", LTYPE3, i386.ACVTPD2PL}, + {"CVTPD2PS", LTYPE3, i386.ACVTPD2PS}, + {"CVTPS2PL", LTYPE3, i386.ACVTPS2PL}, + {"CVTPS2PD", LTYPE3, i386.ACVTPS2PD}, + {"CVTSD2SL", LTYPE3, i386.ACVTSD2SL}, + {"CVTSD2SS", LTYPE3, i386.ACVTSD2SS}, + {"CVTSL2SD", LTYPE3, i386.ACVTSL2SD}, + {"CVTSL2SS", LTYPE3, i386.ACVTSL2SS}, + {"CVTSS2SD", LTYPE3, i386.ACVTSS2SD}, + {"CVTSS2SL", LTYPE3, i386.ACVTSS2SL}, + {"CVTTPD2PL", LTYPE3, i386.ACVTTPD2PL}, + {"CVTTPS2PL", LTYPE3, i386.ACVTTPS2PL}, + {"CVTTSD2SL", LTYPE3, i386.ACVTTSD2SL}, + {"CVTTSS2SL", LTYPE3, i386.ACVTTSS2SL}, + {"DIVPD", LTYPE3, i386.ADIVPD}, + {"DIVPS", LTYPE3, i386.ADIVPS}, + {"DIVSD", LTYPE3, i386.ADIVSD}, + {"DIVSS", LTYPE3, i386.ADIVSS}, + {"MASKMOVOU", LTYPE3, i386.AMASKMOVOU}, + {"MASKMOVDQU", LTYPE3, i386.AMASKMOVOU}, /* syn */ + {"MAXPD", LTYPE3, i386.AMAXPD}, + {"MAXPS", LTYPE3, i386.AMAXPS}, + {"MAXSD", LTYPE3, i386.AMAXSD}, + {"MAXSS", LTYPE3, i386.AMAXSS}, + {"MINPD", LTYPE3, i386.AMINPD}, + {"MINPS", LTYPE3, i386.AMINPS}, + {"MINSD", LTYPE3, i386.AMINSD}, + {"MINSS", LTYPE3, i386.AMINSS}, + {"MOVAPD", LTYPE3, i386.AMOVAPD}, + {"MOVAPS", LTYPE3, i386.AMOVAPS}, + {"MOVO", LTYPE3, i386.AMOVO}, + {"MOVOA", LTYPE3, i386.AMOVO}, /* syn */ + {"MOVOU", LTYPE3, i386.AMOVOU}, + {"MOVHLPS", LTYPE3, i386.AMOVHLPS}, + {"MOVHPD", LTYPE3, i386.AMOVHPD}, + {"MOVHPS", LTYPE3, i386.AMOVHPS}, + {"MOVLHPS", LTYPE3, i386.AMOVLHPS}, + {"MOVLPD", LTYPE3, i386.AMOVLPD}, + {"MOVLPS", LTYPE3, i386.AMOVLPS}, + {"MOVMSKPD", LTYPE3, i386.AMOVMSKPD}, + {"MOVMSKPS", LTYPE3, i386.AMOVMSKPS}, + {"MOVNTO", LTYPE3, i386.AMOVNTO}, + {"MOVNTDQ", LTYPE3, i386.AMOVNTO}, /* syn */ + {"MOVNTPD", LTYPE3, i386.AMOVNTPD}, + {"MOVNTPS", LTYPE3, i386.AMOVNTPS}, + {"MOVSD", LTYPE3, i386.AMOVSD}, + {"MOVSS", LTYPE3, i386.AMOVSS}, + {"MOVUPD", LTYPE3, i386.AMOVUPD}, + {"MOVUPS", LTYPE3, i386.AMOVUPS}, + {"MULPD", LTYPE3, i386.AMULPD}, + {"MULPS", LTYPE3, i386.AMULPS}, + {"MULSD", LTYPE3, i386.AMULSD}, + {"MULSS", LTYPE3, i386.AMULSS}, + {"ORPD", LTYPE3, i386.AORPD}, + {"ORPS", LTYPE3, i386.AORPS}, + {"PADDQ", LTYPE3, i386.APADDQ}, + {"PAND", LTYPE3, i386.APAND}, + {"PCMPEQB", LTYPE3, i386.APCMPEQB}, + {"PMAXSW", LTYPE3, i386.APMAXSW}, + {"PMAXUB", LTYPE3, i386.APMAXUB}, + {"PMINSW", LTYPE3, i386.APMINSW}, + {"PMINUB", LTYPE3, i386.APMINUB}, + {"PMOVMSKB", LTYPE3, i386.APMOVMSKB}, + {"PSADBW", LTYPE3, i386.APSADBW}, + {"PSHUFB", LTYPE3, i386.APSHUFB}, + {"PSHUFHW", LTYPEX, i386.APSHUFHW}, + {"PSHUFL", LTYPEX, i386.APSHUFL}, + {"PSHUFLW", LTYPEX, i386.APSHUFLW}, + {"PSUBB", LTYPE3, i386.APSUBB}, + {"PSUBL", LTYPE3, i386.APSUBL}, + {"PSUBQ", LTYPE3, i386.APSUBQ}, + {"PSUBSB", LTYPE3, i386.APSUBSB}, + {"PSUBSW", LTYPE3, i386.APSUBSW}, + {"PSUBUSB", LTYPE3, i386.APSUBUSB}, + {"PSUBUSW", LTYPE3, i386.APSUBUSW}, + {"PSUBW", LTYPE3, i386.APSUBW}, + {"PUNPCKHQDQ", LTYPE3, i386.APUNPCKHQDQ}, + {"PUNPCKLQDQ", LTYPE3, i386.APUNPCKLQDQ}, + {"PXOR", LTYPE3, i386.APXOR}, + {"RCPPS", LTYPE3, i386.ARCPPS}, + {"RCPSS", LTYPE3, i386.ARCPSS}, + {"RSQRTPS", LTYPE3, i386.ARSQRTPS}, + {"RSQRTSS", LTYPE3, i386.ARSQRTSS}, + {"SQRTPD", LTYPE3, i386.ASQRTPD}, + {"SQRTPS", LTYPE3, i386.ASQRTPS}, + {"SQRTSD", LTYPE3, i386.ASQRTSD}, + {"SQRTSS", LTYPE3, i386.ASQRTSS}, + {"SUBPD", LTYPE3, i386.ASUBPD}, + {"SUBPS", LTYPE3, i386.ASUBPS}, + {"SUBSD", LTYPE3, i386.ASUBSD}, + {"SUBSS", LTYPE3, i386.ASUBSS}, + {"UCOMISD", LTYPE3, i386.AUCOMISD}, + {"UCOMISS", LTYPE3, i386.AUCOMISS}, + {"UNPCKHPD", LTYPE3, i386.AUNPCKHPD}, + {"UNPCKHPS", LTYPE3, i386.AUNPCKHPS}, + {"UNPCKLPD", LTYPE3, i386.AUNPCKLPD}, + {"UNPCKLPS", LTYPE3, i386.AUNPCKLPS}, + {"XORPD", LTYPE3, i386.AXORPD}, + {"XORPS", LTYPE3, i386.AXORPS}, + {"USEFIELD", LTYPEN, obj.AUSEFIELD}, + {"PCDATA", LTYPEPC, obj.APCDATA}, + {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, +} + +func cinit() { + nullgen.Type = i386.REG_NONE + nullgen.Index = i386.REG_NONE +} + +func checkscale(scale int8) { + switch scale { + case 1, + 2, + 4, + 8: + return + } + + yyerror("scale must be 1248: %d", scale) +} + +func syminit(s *asm.Sym) { + s.Type = LNAME + s.Value = 0 +} + +func cclean() { + var g2 Addr2 + + g2.from = nullgen + g2.to = nullgen + outcode(obj.AEND, &g2) +} + +var lastpc *obj.Prog + +type Addr2 struct { + from obj.Addr + to obj.Addr +} + +func outcode(a int, g2 *Addr2) { + var p *obj.Prog + var pl *obj.Plist + + if asm.Pass == 1 { + goto out + } + + p = new(obj.Prog) + *p = obj.Prog{} + p.Ctxt = asm.Ctxt + p.As = int16(a) + p.Lineno = stmtline + p.From = g2.from + p.To = g2.to + p.Pc = int64(asm.PC) + + if lastpc == nil { + pl = obj.Linknewplist(asm.Ctxt) + pl.Firstpc = p + } else { + + lastpc.Link = p + } + lastpc = p + +out: + if a != obj.AGLOBL && a != obj.ADATA { + asm.PC++ + } +} diff --git a/src/cmd/8a/y.go b/src/cmd/8a/y.go new file mode 100644 index 0000000000..82c8a5fb2e --- /dev/null +++ b/src/cmd/8a/y.go @@ -0,0 +1,1308 @@ +//line a.y:32 +package main + +import __yyfmt__ "fmt" + +//line a.y:32 +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/i386" +) + +//line a.y:41 +type yySymType struct { + yys int + sym *asm.Sym + lval int64 + con2 struct { + v1 int32 + v2 int32 + } + dval float64 + sval string + addr obj.Addr + addr2 Addr2 +} + +const LTYPE0 = 57346 +const LTYPE1 = 57347 +const LTYPE2 = 57348 +const LTYPE3 = 57349 +const LTYPE4 = 57350 +const LTYPEC = 57351 +const LTYPED = 57352 +const LTYPEN = 57353 +const LTYPER = 57354 +const LTYPET = 57355 +const LTYPES = 57356 +const LTYPEM = 57357 +const LTYPEI = 57358 +const LTYPEG = 57359 +const LTYPEXC = 57360 +const LTYPEX = 57361 +const LTYPEPC = 57362 +const LTYPEF = 57363 +const LCONST = 57364 +const LFP = 57365 +const LPC = 57366 +const LSB = 57367 +const LBREG = 57368 +const LLREG = 57369 +const LSREG = 57370 +const LFREG = 57371 +const LXREG = 57372 +const LFCONST = 57373 +const LSCONST = 57374 +const LSP = 57375 +const LNAME = 57376 +const LLAB = 57377 +const LVAR = 57378 + +var yyToknames = []string{ + "'|'", + "'^'", + "'&'", + "'<'", + "'>'", + "'+'", + "'-'", + "'*'", + "'/'", + "'%'", + "LTYPE0", + "LTYPE1", + "LTYPE2", + "LTYPE3", + "LTYPE4", + "LTYPEC", + "LTYPED", + "LTYPEN", + "LTYPER", + "LTYPET", + "LTYPES", + "LTYPEM", + "LTYPEI", + "LTYPEG", + "LTYPEXC", + "LTYPEX", + "LTYPEPC", + "LTYPEF", + "LCONST", + "LFP", + "LPC", + "LSB", + "LBREG", + "LLREG", + "LSREG", + "LFREG", + "LXREG", + "LFCONST", + "LSCONST", + "LSP", + "LNAME", + "LLAB", + "LVAR", +} +var yyStatenames = []string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyMaxDepth = 200 + +//line yacctab:1 +var yyExca = []int{ + -1, 1, + 1, -1, + -2, 2, +} + +const yyNprod = 131 +const yyPrivate = 57344 + +var yyTokenNames []string +var yyStates []string + +const yyLast = 556 + +var yyAct = []int{ + + 50, 226, 120, 40, 48, 3, 268, 207, 62, 79, + 77, 169, 49, 267, 266, 72, 60, 262, 84, 254, + 52, 81, 82, 71, 70, 252, 83, 97, 115, 65, + 80, 240, 109, 99, 238, 109, 91, 93, 95, 236, + 220, 218, 101, 103, 209, 208, 170, 239, 104, 206, + 233, 210, 109, 168, 173, 142, 117, 118, 119, 135, + 108, 116, 112, 110, 125, 63, 248, 56, 55, 78, + 72, 230, 229, 225, 224, 109, 136, 84, 223, 133, + 81, 82, 140, 141, 126, 83, 153, 137, 143, 80, + 53, 152, 150, 149, 42, 44, 47, 43, 45, 139, + 61, 46, 85, 148, 54, 147, 146, 145, 76, 63, + 51, 39, 57, 154, 67, 144, 134, 132, 131, 39, + 124, 36, 34, 175, 176, 30, 222, 31, 33, 32, + 109, 117, 221, 58, 242, 72, 241, 183, 235, 111, + 165, 167, 140, 141, 182, 216, 166, 214, 172, 181, + 250, 251, 191, 193, 195, 215, 109, 109, 109, 109, + 109, 255, 194, 109, 109, 109, 189, 190, 165, 167, + 211, 183, 56, 130, 166, 56, 55, 217, 263, 117, + 256, 247, 37, 151, 196, 197, 198, 199, 200, 228, + 111, 203, 204, 205, 260, 53, 41, 35, 53, 56, + 55, 88, 109, 109, 128, 127, 259, 58, 234, 54, + 73, 227, 54, 237, 253, 129, 87, 57, 74, 212, + 57, 257, 53, 246, 243, 105, 106, 113, 244, 202, + 231, 232, 180, 114, 245, 121, 54, 122, 123, 249, + 122, 123, 74, 174, 57, 184, 185, 186, 187, 188, + 258, 7, 201, 22, 261, 42, 44, 47, 43, 45, + 264, 265, 46, 9, 10, 11, 12, 13, 17, 27, + 18, 14, 28, 19, 20, 21, 29, 23, 24, 25, + 26, 56, 55, 138, 163, 162, 160, 161, 155, 156, + 157, 158, 159, 4, 16, 8, 15, 5, 56, 55, + 6, 107, 56, 55, 53, 157, 158, 159, 42, 44, + 47, 43, 45, 2, 1, 46, 85, 102, 54, 100, + 98, 53, 96, 63, 51, 53, 57, 56, 55, 42, + 44, 47, 43, 45, 94, 54, 46, 58, 92, 54, + 63, 74, 90, 57, 63, 51, 86, 57, 56, 55, + 53, 75, 66, 64, 42, 44, 47, 43, 45, 59, + 68, 46, 58, 213, 54, 0, 0, 0, 89, 0, + 51, 53, 57, 56, 55, 42, 44, 47, 43, 45, + 0, 0, 46, 58, 0, 54, 0, 0, 0, 38, + 0, 51, 0, 57, 56, 55, 53, 0, 0, 0, + 42, 44, 47, 43, 45, 0, 0, 46, 58, 0, + 54, 155, 156, 157, 158, 159, 51, 53, 57, 0, + 0, 42, 44, 47, 43, 45, 0, 0, 46, 56, + 55, 54, 0, 0, 0, 0, 0, 51, 0, 57, + 164, 163, 162, 160, 161, 155, 156, 157, 158, 159, + 56, 55, 53, 0, 56, 55, 0, 56, 55, 0, + 0, 0, 0, 0, 73, 0, 54, 0, 0, 0, + 69, 63, 74, 53, 57, 56, 55, 53, 56, 178, + 53, 0, 219, 0, 0, 56, 55, 54, 0, 171, + 0, 54, 58, 74, 54, 57, 192, 74, 53, 57, + 51, 53, 57, 0, 0, 0, 0, 179, 53, 0, + 177, 0, 54, 0, 0, 54, 0, 0, 74, 0, + 57, 74, 54, 57, 0, 0, 0, 0, 74, 0, + 57, 164, 163, 162, 160, 161, 155, 156, 157, 158, + 159, 162, 160, 161, 155, 156, 157, 158, 159, 160, + 161, 155, 156, 157, 158, 159, +} +var yyPact = []int{ + + -1000, -1000, 249, -1000, 78, -1000, 81, 80, 73, 71, + 339, 293, 293, 364, 420, -1000, -1000, 58, 318, 293, + 293, 293, -1000, 219, 14, 293, 293, 89, 448, 448, + -1000, 476, -1000, -1000, 476, -1000, -1000, -1000, 364, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 10, 190, 9, -1000, -1000, 476, 476, 476, 228, -1000, + 70, -1000, -1000, 163, -1000, 68, -1000, 67, -1000, 166, + -1000, 66, 7, 231, 476, -1000, 272, -1000, 364, -1000, + -1000, -1000, -1000, -1000, 3, 228, -1000, -1000, -1000, 364, + -1000, 65, -1000, 57, -1000, 56, -1000, 55, -1000, 53, + -1000, 43, -1000, 42, 171, 41, 36, 249, 527, -1000, + 527, -1000, 131, 0, -7, 436, 111, -1000, -1000, -1000, + 2, 235, 476, 476, -1000, -1000, -1000, -1000, -1000, 469, + 466, 364, 293, -1000, 166, 137, -1000, -1000, 385, -1000, + -1000, -1000, 103, 2, 364, 364, 364, 364, 364, 293, + 293, 476, 445, 289, -1000, 476, 476, 476, 476, 476, + 245, 221, 476, 476, 476, -4, -8, -9, -1, 476, + -1000, -1000, 208, 112, 231, -1000, -1000, -12, 441, -1000, + -1000, -1000, -1000, -13, 85, 79, -1000, 28, 24, -1000, + -1000, 23, 179, 22, -1000, 21, 294, 294, -1000, -1000, + -1000, 476, 476, 542, 535, 279, -2, 476, -1000, -1000, + 101, -14, 476, -19, -1000, -1000, -1000, -5, -1000, -22, + -1000, 99, 96, 476, 219, 14, -1000, 213, 149, 15, + 14, 402, 402, 113, -28, 203, -1000, -34, -1000, 126, + -1000, -1000, -1000, -1000, -1000, -1000, 148, 211, 179, -1000, + 195, 183, -1000, 476, -1000, -36, -1000, 146, -1000, 476, + 476, -39, -1000, -1000, -40, -47, -1000, -1000, -1000, +} +var yyPgo = []int{ + + 0, 0, 28, 363, 2, 196, 8, 3, 20, 9, + 100, 16, 10, 4, 12, 1, 197, 360, 182, 359, + 353, 352, 351, 346, 342, 338, 334, 322, 320, 319, + 317, 314, 313, 5, 301, 300, 296, 294, 253, +} +var yyR1 = []int{ + + 0, 31, 32, 31, 34, 33, 33, 33, 33, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 16, + 16, 20, 21, 19, 19, 18, 18, 17, 17, 17, + 36, 37, 37, 38, 38, 22, 22, 22, 23, 23, + 24, 24, 25, 25, 26, 26, 26, 27, 28, 29, + 30, 10, 10, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 9, 9, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 15, 15, 15, + 15, 5, 5, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 8, 8, 4, 4, + 4, 3, 3, 3, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, +} +var yyR2 = []int{ + + 0, 0, 0, 3, 0, 4, 1, 2, 2, 3, + 3, 2, 2, 2, 2, 2, 2, 1, 1, 2, + 2, 2, 2, 2, 1, 2, 2, 2, 2, 0, + 1, 3, 3, 2, 1, 2, 1, 2, 1, 3, + 6, 5, 7, 4, 6, 2, 1, 2, 1, 1, + 3, 5, 3, 5, 2, 1, 3, 5, 5, 3, + 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, + 1, 1, 4, 2, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 4, 5, 3, 1, 2, 3, + 4, 1, 1, 1, 4, 4, 6, 9, 9, 3, + 3, 4, 5, 8, 1, 6, 5, 7, 0, 2, + 2, 1, 1, 1, 1, 1, 2, 2, 2, 3, + 1, 3, 3, 3, 3, 3, 4, 4, 3, 3, + 3, +} +var yyChk = []int{ + + -1000, -31, -32, -33, 44, 48, -35, 2, 46, 14, + 15, 16, 17, 18, 22, -36, -37, 19, 21, 24, + 25, 26, -38, 28, 29, 30, 31, 20, 23, 27, + 47, 49, 48, 48, 49, -16, 50, -18, 50, -10, + -7, -5, 36, 39, 37, 40, 43, 38, -13, -14, + -1, 52, -8, 32, 46, 10, 9, 54, 44, -19, + -11, -10, -6, 51, -20, -11, -21, -10, -17, 50, + -9, -6, -1, 44, 52, -22, 50, -12, 11, -9, + -14, -7, -13, -6, -1, 44, -23, -16, -18, 50, + -24, -11, -25, -11, -26, -11, -27, -7, -28, -6, + -29, -11, -30, -11, -8, -5, -5, -34, -2, -1, + -2, -10, 52, 37, 43, -2, 52, -1, -1, -1, + -4, 7, 9, 10, 50, -1, -8, 42, 41, 52, + 10, 50, 50, -9, 50, 52, -4, -12, 11, -8, + -7, -13, 52, -4, 50, 50, 50, 50, 50, 50, + 50, 12, 50, 50, -33, 9, 10, 11, 12, 13, + 7, 8, 6, 5, 4, 37, 43, 38, 53, 11, + 53, 53, 37, 52, 8, -1, -1, 41, 10, 41, + -10, -11, -9, 34, -10, -10, -10, -10, -10, -11, + -11, -1, 51, -1, -6, -1, -2, -2, -2, -2, + -2, 7, 8, -2, -2, -2, 53, 11, 53, 53, + 52, -1, 11, -3, 35, 43, 33, -4, 53, 41, + 53, 47, 47, 50, 50, 50, -15, 32, 10, 50, + 50, -2, -2, 52, -1, 37, 53, -1, 53, 52, + 53, 37, 38, -1, -7, -6, 10, 32, 51, -6, + 37, 38, 53, 11, 53, 35, 32, 10, -15, 11, + 11, -1, 53, 32, -1, -1, 53, 53, 53, +} +var yyDef = []int{ + + 1, -2, 0, 3, 0, 6, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 17, 18, 0, 29, 0, + 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 7, 8, 0, 11, 30, 12, 0, 36, + 61, 62, 74, 75, 76, 77, 78, 79, 91, 92, + 93, 0, 104, 114, 115, 0, 0, 0, 108, 13, + 34, 70, 71, 0, 14, 0, 15, 0, 16, 0, + 38, 0, 0, 108, 0, 19, 0, 46, 0, 63, + 64, 67, 68, 69, 93, 108, 20, 48, 49, 30, + 21, 0, 22, 0, 23, 55, 25, 0, 26, 0, + 27, 0, 28, 0, 0, 0, 0, 0, 9, 120, + 10, 35, 0, 0, 0, 0, 0, 116, 117, 118, + 0, 0, 0, 0, 33, 80, 81, 82, 83, 0, + 0, 0, 0, 37, 0, 0, 73, 45, 0, 47, + 65, 66, 0, 73, 0, 0, 54, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, + 100, 119, 0, 0, 108, 109, 110, 0, 0, 86, + 31, 32, 39, 0, 50, 52, 56, 0, 0, 59, + 60, 0, 0, 0, 43, 0, 121, 122, 123, 124, + 125, 0, 0, 128, 129, 130, 94, 0, 95, 101, + 0, 0, 0, 0, 111, 112, 113, 0, 84, 0, + 72, 0, 0, 0, 0, 0, 41, 87, 0, 0, + 0, 126, 127, 0, 0, 0, 102, 0, 106, 0, + 85, 51, 53, 57, 58, 40, 0, 88, 0, 44, + 0, 0, 96, 0, 105, 0, 89, 0, 42, 0, + 0, 0, 107, 90, 0, 0, 103, 97, 98, +} +var yyTok1 = []int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 51, 13, 6, 3, + 52, 53, 11, 9, 50, 10, 3, 12, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 47, 48, + 7, 49, 8, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 3, 54, +} +var yyTok2 = []int{ + + 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, +} +var yyTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yylex1(lex yyLexer, lval *yySymType) int { + c := 0 + char := lex.Lex(lval) + if char <= 0 { + c = yyTok1[0] + goto out + } + if char < len(yyTok1) { + c = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + c = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + c = yyTok3[i+0] + if c == char { + c = yyTok3[i+1] + goto out + } + } + +out: + if c == 0 { + c = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) + } + return c +} + +func yyParse(yylex yyLexer) int { + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, yyMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yychar := -1 + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + yyn += yychar + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yychar { /* valid shift */ + yychar = -1 + yyVAL = yylval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yychar { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error("syntax error") + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) + } + if yychar == yyEofCode { + goto ret1 + } + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 2: + //line a.y:74 + { + stmtline = asm.Lineno + } + case 4: + //line a.y:81 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { + yyerror("redeclaration of %s", yyS[yypt-1].sym.Labelname) + } + yyS[yypt-1].sym.Type = LLAB + yyS[yypt-1].sym.Value = int64(asm.PC) + } + case 9: + //line a.y:96 + { + yyS[yypt-2].sym.Type = LVAR + yyS[yypt-2].sym.Value = yyS[yypt-0].lval + } + case 10: + //line a.y:101 + { + if yyS[yypt-2].sym.Value != int64(yyS[yypt-0].lval) { + yyerror("redeclaration of %s", yyS[yypt-2].sym.Name) + } + yyS[yypt-2].sym.Value = yyS[yypt-0].lval + } + case 11: + //line a.y:107 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 12: + //line a.y:108 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 13: + //line a.y:109 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 14: + //line a.y:110 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 15: + //line a.y:111 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 16: + //line a.y:112 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 19: + //line a.y:115 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 20: + //line a.y:116 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 21: + //line a.y:117 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 22: + //line a.y:118 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 23: + //line a.y:119 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 25: + //line a.y:121 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 26: + //line a.y:122 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 27: + //line a.y:123 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 28: + //line a.y:124 + { + outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) + } + case 29: + //line a.y:127 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = nullgen + } + case 30: + //line a.y:132 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = nullgen + } + case 31: + //line a.y:139 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 32: + //line a.y:146 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 33: + //line a.y:153 + { + yyVAL.addr2.from = yyS[yypt-1].addr + yyVAL.addr2.to = nullgen + } + case 34: + //line a.y:158 + { + yyVAL.addr2.from = yyS[yypt-0].addr + yyVAL.addr2.to = nullgen + } + case 35: + //line a.y:165 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 36: + //line a.y:170 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 37: + //line a.y:177 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 38: + //line a.y:182 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 39: + //line a.y:187 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 40: + //line a.y:194 + { + outcode(obj.ADATA, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-2].lval + } + } + case 41: + //line a.y:204 + { + asm.Settext(yyS[yypt-3].addr.Sym) + outcode(obj.ATEXT, &Addr2{yyS[yypt-3].addr, yyS[yypt-0].addr}) + } + case 42: + //line a.y:209 + { + asm.Settext(yyS[yypt-5].addr.Sym) + outcode(obj.ATEXT, &Addr2{yyS[yypt-5].addr, yyS[yypt-0].addr}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-3].lval + } + } + case 43: + //line a.y:220 + { + asm.Settext(yyS[yypt-2].addr.Sym) + outcode(obj.AGLOBL, &Addr2{yyS[yypt-2].addr, yyS[yypt-0].addr}) + } + case 44: + //line a.y:225 + { + asm.Settext(yyS[yypt-4].addr.Sym) + outcode(obj.AGLOBL, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyS[yypt-2].lval + } + } + case 45: + //line a.y:237 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 46: + //line a.y:242 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 47: + //line a.y:247 + { + yyVAL.addr2.from = nullgen + yyVAL.addr2.to = yyS[yypt-0].addr + yyVAL.addr2.to.Type = obj.TYPE_INDIR + } + case 48: + yyVAL.addr2 = yyS[yypt-0].addr2 + case 49: + yyVAL.addr2 = yyS[yypt-0].addr2 + case 50: + //line a.y:259 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 51: + //line a.y:264 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + if yyVAL.addr2.from.Index != obj.TYPE_NONE { + yyerror("dp shift with lhs index") + } + yyVAL.addr2.from.Index = int16(yyS[yypt-0].lval) + } + case 52: + //line a.y:275 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 53: + //line a.y:280 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + if yyVAL.addr2.to.Index != obj.TYPE_NONE { + yyerror("dp move with lhs index") + } + yyVAL.addr2.to.Index = int16(yyS[yypt-0].lval) + } + case 54: + //line a.y:291 + { + yyVAL.addr2.from = yyS[yypt-1].addr + yyVAL.addr2.to = nullgen + } + case 55: + //line a.y:296 + { + yyVAL.addr2.from = yyS[yypt-0].addr + yyVAL.addr2.to = nullgen + } + case 56: + //line a.y:301 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 57: + //line a.y:308 + { + yyVAL.addr2.from = yyS[yypt-4].addr + yyVAL.addr2.to = yyS[yypt-2].addr + yyVAL.addr2.to.Offset = yyS[yypt-0].lval + } + case 58: + //line a.y:316 + { + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + if yyS[yypt-4].addr.Type != obj.TYPE_CONST { + yyerror("illegal constant") + } + yyVAL.addr2.to.Offset = yyS[yypt-4].addr.Offset + } + case 59: + //line a.y:327 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { + yyerror("arguments to PCDATA must be integer constants") + } + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 60: + //line a.y:337 + { + if yyS[yypt-2].addr.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if yyS[yypt-0].addr.Type != obj.TYPE_MEM || (yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC) { + yyerror("value for FUNCDATA must be symbol reference") + } + yyVAL.addr2.from = yyS[yypt-2].addr + yyVAL.addr2.to = yyS[yypt-0].addr + } + case 61: + yyVAL.addr = yyS[yypt-0].addr + case 62: + yyVAL.addr = yyS[yypt-0].addr + case 63: + yyVAL.addr = yyS[yypt-0].addr + case 64: + yyVAL.addr = yyS[yypt-0].addr + case 65: + //line a.y:356 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 66: + //line a.y:360 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 67: + yyVAL.addr = yyS[yypt-0].addr + case 68: + yyVAL.addr = yyS[yypt-0].addr + case 69: + yyVAL.addr = yyS[yypt-0].addr + case 70: + yyVAL.addr = yyS[yypt-0].addr + case 71: + yyVAL.addr = yyS[yypt-0].addr + case 72: + //line a.y:373 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyS[yypt-3].lval + int64(asm.PC) + } + case 73: + //line a.y:379 + { + yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) + yyVAL.addr = nullgen + if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { + yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) + } + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyS[yypt-1].sym.Value + yyS[yypt-0].lval + } + case 74: + //line a.y:391 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 75: + //line a.y:397 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 76: + //line a.y:403 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 77: + //line a.y:409 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 78: + //line a.y:415 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = REG_SP + } + case 79: + //line a.y:421 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyS[yypt-0].lval) + } + case 80: + //line a.y:429 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + yyVAL.addr.Offset = yyS[yypt-0].lval + } + case 81: + //line a.y:435 + { + yyVAL.addr = yyS[yypt-0].addr + yyVAL.addr.Type = obj.TYPE_ADDR + /* + if($2.Type == D_AUTO || $2.Type == D_PARAM) + yyerror("constant cannot be automatic: %s", + $2.Sym.name); + */ + } + case 82: + //line a.y:444 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SCONST + yyVAL.addr.U.Sval = yyS[yypt-0].sval + } + case 83: + //line a.y:450 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyS[yypt-0].dval + } + case 84: + //line a.y:456 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyS[yypt-1].dval + } + case 85: + //line a.y:462 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyS[yypt-1].dval + } + case 86: + //line a.y:468 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyS[yypt-0].dval + } + case 87: + //line a.y:476 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = yyS[yypt-0].lval + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 88: + //line a.y:483 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -yyS[yypt-0].lval + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 89: + //line a.y:490 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = yyS[yypt-2].lval + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 90: + //line a.y:497 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -yyS[yypt-2].lval + yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) + } + case 91: + yyVAL.addr = yyS[yypt-0].addr + case 92: + yyVAL.addr = yyS[yypt-0].addr + case 93: + //line a.y:511 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Offset = yyS[yypt-0].lval + } + case 94: + //line a.y:517 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 95: + //line a.y:524 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = REG_SP + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 96: + //line a.y:531 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Offset = yyS[yypt-5].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 97: + //line a.y:540 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Offset = yyS[yypt-8].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 98: + //line a.y:550 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Offset = yyS[yypt-8].lval + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 99: + //line a.y:560 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + } + case 100: + //line a.y:566 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = REG_SP + } + case 101: + //line a.y:572 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-1].lval) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 102: + //line a.y:579 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 103: + //line a.y:587 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyS[yypt-6].lval) + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 104: + //line a.y:598 + { + yyVAL.addr = yyS[yypt-0].addr + } + case 105: + //line a.y:602 + { + yyVAL.addr = yyS[yypt-5].addr + yyVAL.addr.Index = int16(yyS[yypt-3].lval) + yyVAL.addr.Scale = int8(yyS[yypt-1].lval) + checkscale(yyVAL.addr.Scale) + } + case 106: + //line a.y:611 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyS[yypt-1].lval) + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 107: + //line a.y:619 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = obj.NAME_STATIC + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) + yyVAL.addr.Offset = yyS[yypt-3].lval + } + case 108: + //line a.y:628 + { + yyVAL.lval = 0 + } + case 109: + //line a.y:632 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 110: + //line a.y:636 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 111: + yyVAL.lval = yyS[yypt-0].lval + case 112: + //line a.y:643 + { + yyVAL.lval = obj.NAME_AUTO + } + case 113: + yyVAL.lval = yyS[yypt-0].lval + case 114: + yyVAL.lval = yyS[yypt-0].lval + case 115: + //line a.y:651 + { + yyVAL.lval = yyS[yypt-0].sym.Value + } + case 116: + //line a.y:655 + { + yyVAL.lval = -yyS[yypt-0].lval + } + case 117: + //line a.y:659 + { + yyVAL.lval = yyS[yypt-0].lval + } + case 118: + //line a.y:663 + { + yyVAL.lval = ^yyS[yypt-0].lval + } + case 119: + //line a.y:667 + { + yyVAL.lval = yyS[yypt-1].lval + } + case 120: + yyVAL.lval = yyS[yypt-0].lval + case 121: + //line a.y:674 + { + yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval + } + case 122: + //line a.y:678 + { + yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval + } + case 123: + //line a.y:682 + { + yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval + } + case 124: + //line a.y:686 + { + yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval + } + case 125: + //line a.y:690 + { + yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval + } + case 126: + //line a.y:694 + { + yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) + } + case 127: + //line a.y:698 + { + yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) + } + case 128: + //line a.y:702 + { + yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval + } + case 129: + //line a.y:706 + { + yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval + } + case 130: + //line a.y:710 + { + yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval + } + } + goto yystack /* stack new state and value */ +} diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c deleted file mode 100644 index d80f0ee4de..0000000000 --- a/src/cmd/8a/y.tab.c +++ /dev/null @@ -1,2778 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.3" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE0 = 258, - LTYPE1 = 259, - LTYPE2 = 260, - LTYPE3 = 261, - LTYPE4 = 262, - LTYPEC = 263, - LTYPED = 264, - LTYPEN = 265, - LTYPER = 266, - LTYPET = 267, - LTYPES = 268, - LTYPEM = 269, - LTYPEI = 270, - LTYPEG = 271, - LTYPEXC = 272, - LTYPEX = 273, - LTYPEPC = 274, - LTYPEF = 275, - LCONST = 276, - LFP = 277, - LPC = 278, - LSB = 279, - LBREG = 280, - LLREG = 281, - LSREG = 282, - LFREG = 283, - LXREG = 284, - LFCONST = 285, - LSCONST = 286, - LSP = 287, - LNAME = 288, - LLAB = 289, - LVAR = 290 - }; -#endif -/* Tokens. */ -#define LTYPE0 258 -#define LTYPE1 259 -#define LTYPE2 260 -#define LTYPE3 261 -#define LTYPE4 262 -#define LTYPEC 263 -#define LTYPED 264 -#define LTYPEN 265 -#define LTYPER 266 -#define LTYPET 267 -#define LTYPES 268 -#define LTYPEM 269 -#define LTYPEI 270 -#define LTYPEG 271 -#define LTYPEXC 272 -#define LTYPEX 273 -#define LTYPEPC 274 -#define LTYPEF 275 -#define LCONST 276 -#define LFP 277 -#define LPC 278 -#define LSB 279 -#define LBREG 280 -#define LLREG 281 -#define LSREG 282 -#define LFREG 283 -#define LXREG 284 -#define LFCONST 285 -#define LSCONST 286 -#define LSP 287 -#define LNAME 288 -#define LLAB 289 -#define LVAR 290 - - - - -/* Copy the first part of user declarations. */ -#line 31 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; -} -/* Line 193 of yacc.c. */ -#line 183 "y.tab.c" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 216 of yacc.c. */ -#line 196 "y.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int i) -#else -static int -YYID (i) - int i; -#endif -{ - return i; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 2 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 544 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 54 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 39 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 131 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 270 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 290 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 50, 12, 5, 2, - 51, 52, 10, 8, 49, 9, 2, 11, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 46, 47, - 6, 48, 7, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 53, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 4, 5, 9, 10, 15, 17, 20, - 23, 27, 31, 34, 37, 40, 43, 46, 49, 51, - 53, 56, 59, 62, 65, 68, 70, 73, 76, 79, - 82, 83, 85, 89, 93, 96, 98, 101, 103, 106, - 108, 112, 119, 125, 133, 138, 145, 148, 150, 153, - 155, 157, 161, 167, 171, 177, 180, 182, 186, 192, - 198, 202, 206, 208, 210, 212, 214, 217, 220, 222, - 224, 226, 228, 230, 235, 238, 240, 242, 244, 246, - 248, 250, 253, 256, 259, 262, 267, 273, 277, 279, - 282, 286, 291, 293, 295, 297, 302, 307, 314, 324, - 334, 338, 342, 347, 353, 362, 364, 371, 377, 385, - 386, 389, 392, 394, 396, 398, 400, 402, 405, 408, - 411, 415, 417, 421, 425, 429, 433, 437, 442, 447, - 451, 455 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 55, 0, -1, -1, -1, 55, 56, 57, -1, -1, - 43, 46, 58, 57, -1, 47, -1, 59, 47, -1, - 1, 47, -1, 43, 48, 92, -1, 45, 48, 92, - -1, 13, 60, -1, 14, 64, -1, 15, 63, -1, - 16, 61, -1, 17, 62, -1, 21, 65, -1, 66, - -1, 67, -1, 18, 69, -1, 20, 70, -1, 23, - 71, -1, 24, 72, -1, 25, 73, -1, 68, -1, - 27, 74, -1, 28, 75, -1, 29, 76, -1, 30, - 77, -1, -1, 49, -1, 80, 49, 78, -1, 78, - 49, 80, -1, 80, 49, -1, 80, -1, 49, 78, - -1, 78, -1, 49, 81, -1, 81, -1, 83, 49, - 81, -1, 19, 88, 11, 91, 49, 83, -1, 22, - 85, 49, 50, 84, -1, 22, 85, 49, 91, 49, - 50, 84, -1, 26, 85, 49, 83, -1, 26, 85, - 49, 91, 49, 83, -1, 49, 79, -1, 79, -1, - 10, 88, -1, 60, -1, 64, -1, 80, 49, 78, - -1, 80, 49, 78, 46, 36, -1, 80, 49, 78, - -1, 80, 49, 78, 46, 37, -1, 80, 49, -1, - 80, -1, 80, 49, 78, -1, 82, 49, 78, 49, - 91, -1, 83, 49, 78, 49, 82, -1, 80, 49, - 80, -1, 80, 49, 80, -1, 82, -1, 85, -1, - 81, -1, 87, -1, 10, 82, -1, 10, 86, -1, - 82, -1, 86, -1, 83, -1, 78, -1, 83, -1, - 91, 51, 33, 52, -1, 43, 89, -1, 35, -1, - 38, -1, 36, -1, 39, -1, 42, -1, 37, -1, - 50, 91, -1, 50, 88, -1, 50, 41, -1, 50, - 40, -1, 50, 51, 40, 52, -1, 50, 51, 9, - 40, 52, -1, 50, 9, 40, -1, 31, -1, 9, - 31, -1, 31, 9, 31, -1, 9, 31, 9, 31, - -1, 86, -1, 87, -1, 91, -1, 91, 51, 36, - 52, -1, 91, 51, 42, 52, -1, 91, 51, 36, - 10, 91, 52, -1, 91, 51, 36, 52, 51, 36, - 10, 91, 52, -1, 91, 51, 36, 52, 51, 37, - 10, 91, 52, -1, 51, 36, 52, -1, 51, 42, - 52, -1, 91, 51, 37, 52, -1, 51, 36, 10, - 91, 52, -1, 51, 36, 52, 51, 36, 10, 91, - 52, -1, 88, -1, 88, 51, 36, 10, 91, 52, - -1, 43, 89, 51, 90, 52, -1, 43, 6, 7, - 89, 51, 34, 52, -1, -1, 8, 91, -1, 9, - 91, -1, 34, -1, 42, -1, 32, -1, 31, -1, - 45, -1, 9, 91, -1, 8, 91, -1, 53, 91, - -1, 51, 92, 52, -1, 91, -1, 92, 8, 92, - -1, 92, 9, 92, -1, 92, 10, 92, -1, 92, - 11, 92, -1, 92, 12, 92, -1, 92, 6, 6, - 92, -1, 92, 7, 7, 92, -1, 92, 5, 92, - -1, 92, 4, 92, -1, 92, 3, 92, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 64, 64, 66, 65, 73, 72, 81, 82, 83, - 86, 91, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 117, 121, 128, 135, 142, 147, 154, 159, 166, 171, - 176, 183, 196, 204, 218, 226, 240, 245, 250, 258, - 259, 262, 267, 277, 282, 292, 297, 302, 309, 317, - 327, 336, 347, 348, 351, 352, 353, 357, 361, 362, - 363, 366, 367, 370, 376, 387, 393, 399, 405, 411, - 417, 425, 431, 441, 447, 453, 459, 465, 473, 480, - 487, 494, 503, 504, 507, 514, 521, 528, 538, 548, - 558, 564, 570, 577, 586, 597, 601, 610, 618, 628, - 631, 635, 641, 642, 646, 649, 650, 654, 658, 662, - 666, 672, 673, 677, 681, 685, 689, 693, 697, 701, - 705, 709 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'", - "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3", - "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES", - "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF", - "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG", - "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'", - "';'", "'='", "','", "'$'", "'('", "')'", "'~'", "$accept", "prog", "@1", - "line", "@2", "inst", "nonnon", "rimrem", "remrim", "rimnon", "nonrem", - "nonrel", "spec1", "spec2", "spec8", "spec3", "spec4", "spec5", "spec6", - "spec7", "spec9", "spec10", "spec11", "spec12", "rem", "rom", "rim", - "rel", "reg", "imm", "textsize", "mem", "omem", "nmem", "nam", "offset", - "pointer", "con", "expr", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 124, 94, 38, 60, 62, 43, 45, - 42, 47, 37, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 58, 59, 61, 44, - 36, 40, 41, 126 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 54, 55, 56, 55, 58, 57, 57, 57, 57, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, - 60, 60, 61, 62, 63, 63, 64, 64, 65, 65, - 65, 66, 67, 67, 68, 68, 69, 69, 69, 70, - 70, 71, 71, 72, 72, 73, 73, 73, 74, 75, - 76, 77, 78, 78, 79, 79, 79, 79, 79, 79, - 79, 80, 80, 81, 81, 82, 82, 82, 82, 82, - 82, 83, 83, 83, 83, 83, 83, 83, 84, 84, - 84, 84, 85, 85, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 87, 87, 88, 88, 89, - 89, 89, 90, 90, 90, 91, 91, 91, 91, 91, - 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 92, 92 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 0, 0, 3, 0, 4, 1, 2, 2, - 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, - 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, - 0, 1, 3, 3, 2, 1, 2, 1, 2, 1, - 3, 6, 5, 7, 4, 6, 2, 1, 2, 1, - 1, 3, 5, 3, 5, 2, 1, 3, 5, 5, - 3, 3, 1, 1, 1, 1, 2, 2, 1, 1, - 1, 1, 1, 4, 2, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 4, 5, 3, 1, 2, - 3, 4, 1, 1, 1, 4, 4, 6, 9, 9, - 3, 3, 4, 5, 8, 1, 6, 5, 7, 0, - 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, - 3, 1, 3, 3, 3, 3, 3, 4, 4, 3, - 3, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 2, 3, 1, 0, 0, 30, 0, 0, 0, 0, - 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 7, 4, 0, 18, 19, - 25, 9, 31, 12, 0, 0, 115, 75, 77, 80, - 76, 78, 79, 109, 116, 0, 0, 0, 13, 37, - 62, 63, 92, 93, 105, 94, 0, 14, 71, 35, - 72, 15, 0, 16, 0, 0, 109, 0, 20, 47, - 64, 68, 70, 69, 65, 94, 0, 31, 49, 50, - 21, 109, 0, 0, 17, 39, 0, 0, 0, 22, - 0, 23, 0, 24, 56, 0, 26, 0, 27, 0, - 28, 0, 29, 0, 5, 0, 0, 8, 118, 117, - 0, 0, 0, 0, 36, 0, 0, 121, 0, 119, - 0, 0, 0, 84, 83, 0, 82, 81, 34, 0, - 0, 66, 67, 48, 74, 0, 46, 0, 0, 74, - 38, 0, 0, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 10, 11, 109, 110, 111, 0, 0, - 100, 101, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 120, 0, 0, 0, 0, 87, 0, 0, - 32, 33, 0, 0, 40, 0, 0, 51, 53, 57, - 44, 0, 0, 0, 60, 61, 6, 0, 114, 112, - 113, 0, 0, 0, 131, 130, 129, 0, 0, 122, - 123, 124, 125, 126, 0, 0, 95, 102, 96, 0, - 85, 73, 0, 0, 88, 42, 0, 0, 0, 0, - 0, 0, 0, 107, 103, 0, 127, 128, 0, 0, - 0, 86, 41, 89, 0, 0, 52, 54, 45, 58, - 59, 0, 0, 106, 97, 0, 0, 0, 90, 43, - 108, 0, 0, 0, 91, 104, 0, 0, 98, 99 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 3, 26, 152, 27, 33, 61, 63, 57, - 48, 84, 28, 29, 30, 68, 80, 89, 91, 93, - 96, 98, 100, 102, 58, 69, 59, 70, 50, 60, - 225, 51, 52, 53, 54, 113, 201, 55, 118 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -87 -static const yytype_int16 yypact[] = -{ - -87, 35, -87, 242, 2, -4, 164, 313, 313, 361, - 265, 8, 337, 60, 410, 313, 313, 313, 410, 241, - -11, 313, 313, -31, 17, -87, -87, 23, -87, -87, - -87, -87, -87, -87, 474, 474, -87, -87, -87, -87, - -87, -87, -87, 20, -87, 361, 401, 474, -87, -87, - -87, -87, -87, -87, 16, 28, 185, -87, -87, 22, - -87, -87, 25, -87, 31, 361, 20, 289, -87, -87, - -87, -87, -87, -87, -87, 48, 29, 361, -87, -87, - -87, 13, 417, 474, -87, -87, 51, 53, 57, -87, - 58, -87, 59, -87, 70, 71, -87, 75, -87, 80, - -87, 86, -87, 102, -87, 474, 474, -87, -87, -87, - 37, 474, 474, 76, -87, 1, 103, -87, 175, -87, - 126, 50, 85, -87, -87, 426, -87, -87, -87, 361, - 313, -87, -87, -87, 76, 385, -87, 81, 474, -87, - -87, 417, 130, 436, 361, 361, 361, 464, 361, 361, - 313, 313, 242, 525, 525, 13, -87, -87, 18, 474, - 113, -87, 474, 474, 474, 165, 167, 474, 474, 474, - 474, 474, -87, 186, 3, 123, 156, -87, 467, 158, - -87, -87, 159, 163, -87, 7, 169, 173, 177, -87, - -87, 182, 183, 184, -87, -87, -87, 178, -87, -87, - -87, 172, 187, 198, 136, 239, 532, 474, 474, 78, - 78, -87, -87, -87, 474, 474, 189, -87, -87, 202, - -87, -87, -11, 204, 228, -87, 191, 245, 247, -11, - 474, 241, 248, -87, -87, 276, 180, 180, 236, 238, - -5, -87, -87, 282, 261, 7, -87, -87, -87, -87, - -87, 243, 474, -87, -87, 283, 284, 274, -87, -87, - -87, 254, 474, 474, -87, -87, 257, 259, -87, -87 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -87, -87, -87, 160, -87, -87, 301, -87, -87, -87, - 305, -87, -87, -87, -87, -87, -87, -87, -87, -87, - -87, -87, -87, -87, 21, 252, 26, -7, -9, -8, - 84, 0, -3, -6, -2, -58, -87, -10, -86 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 -static const yytype_uint16 yytable[] = -{ - 75, 71, 72, 87, 74, 86, 85, 73, 134, 76, - 97, 159, 99, 215, 88, 104, 223, 105, 95, 153, - 154, 111, 112, 139, 108, 109, 110, 49, 111, 112, - 64, 255, 256, 49, 62, 2, 117, 119, 224, 56, - 138, 90, 92, 94, 155, 32, 127, 101, 103, 31, - 198, 43, 199, 160, 126, 216, 131, 75, 71, 72, - 200, 74, 132, 133, 73, 106, 114, 120, 34, 35, - 107, 128, 87, 117, 129, 140, 204, 205, 206, 121, - 130, 209, 210, 211, 212, 213, 174, 175, 169, 170, - 171, 36, 176, 34, 35, 117, 117, 197, 114, 137, - 141, 156, 157, 81, 142, 44, 143, 144, 145, 82, - 56, 83, 109, 47, 182, 117, 36, 174, 175, 146, - 147, 236, 237, 176, 148, 177, 131, 158, 183, 149, - 44, 87, 132, 186, 184, 150, 83, 191, 47, 190, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 202, - 180, 151, 117, 117, 117, 161, 181, 117, 117, 117, - 117, 117, 173, 182, 203, 187, 188, 189, 109, 192, - 193, 207, 34, 35, 208, 217, 194, 195, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 167, 168, - 169, 170, 171, 34, 122, 36, 214, 117, 117, 37, - 38, 39, 40, 41, 238, 239, 42, 43, 218, 44, - 220, 221, 222, 45, 242, 46, 36, 47, 226, 227, - 249, 248, 250, 228, 233, 123, 124, 172, 43, 232, - 44, 229, 230, 231, 235, 243, 125, 244, 47, 234, - 240, 245, 261, 4, 164, 165, 166, 167, 168, 169, - 170, 171, 266, 267, 241, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 34, 35, 65, 37, 38, 39, 40, - 41, 246, 251, 42, 247, 23, 252, 24, 253, 25, - 254, 257, 258, 262, 263, 260, 36, 34, 35, 135, - 37, 38, 39, 40, 41, 264, 265, 42, 66, 268, - 44, 269, 196, 78, 67, 56, 46, 79, 47, 136, - 36, 34, 35, 0, 37, 38, 39, 40, 41, 259, - 0, 42, 66, 0, 44, 0, 0, 0, 0, 56, - 46, 0, 47, 0, 36, 34, 35, 0, 37, 38, - 39, 40, 41, 0, 0, 42, 43, 0, 44, 0, - 0, 0, 0, 56, 46, 0, 47, 0, 36, 34, - 35, 0, 37, 38, 39, 40, 41, 0, 0, 42, - 43, 0, 44, 0, 0, 0, 77, 0, 46, 0, - 47, 0, 36, 34, 35, 0, 37, 38, 39, 40, - 41, 0, 0, 42, 43, 0, 44, 0, 0, 34, - 35, 0, 46, 0, 47, 0, 36, 0, 34, 35, - 37, 38, 39, 40, 41, 34, 35, 42, 0, 0, - 44, 0, 36, 0, 34, 178, 46, 115, 47, 0, - 0, 36, 0, 116, 34, 35, 44, 0, 36, 0, - 0, 0, 83, 43, 47, 44, 0, 36, 0, 0, - 81, 46, 44, 47, 0, 0, 179, 36, 83, 0, - 47, 44, 34, 35, 0, 34, 35, 83, 0, 47, - 0, 44, 34, 35, 0, 0, 185, 83, 0, 47, - 0, 0, 0, 0, 0, 36, 0, 0, 36, 0, - 0, 0, 0, 0, 0, 36, 0, 219, 0, 44, - 0, 0, 44, 0, 56, 83, 0, 47, 83, 44, - 47, 0, 0, 0, 0, 83, 0, 47, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 165, 166, - 167, 168, 169, 170, 171 -}; - -static const yytype_int16 yycheck[] = -{ - 10, 10, 10, 13, 10, 13, 13, 10, 66, 11, - 19, 10, 20, 10, 14, 46, 9, 48, 18, 105, - 106, 8, 9, 81, 34, 35, 6, 6, 8, 9, - 9, 36, 37, 12, 8, 0, 46, 47, 31, 50, - 11, 15, 16, 17, 7, 49, 56, 21, 22, 47, - 32, 43, 34, 52, 56, 52, 65, 67, 67, 67, - 42, 67, 65, 65, 67, 48, 45, 51, 8, 9, - 47, 49, 82, 83, 49, 82, 162, 163, 164, 51, - 49, 167, 168, 169, 170, 171, 36, 37, 10, 11, - 12, 31, 42, 8, 9, 105, 106, 155, 77, 51, - 49, 111, 112, 43, 51, 45, 49, 49, 49, 49, - 50, 51, 122, 53, 33, 125, 31, 36, 37, 49, - 49, 207, 208, 42, 49, 40, 135, 51, 138, 49, - 45, 141, 135, 143, 141, 49, 51, 147, 53, 147, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 159, - 129, 49, 162, 163, 164, 52, 130, 167, 168, 169, - 170, 171, 36, 33, 51, 144, 145, 146, 178, 148, - 149, 6, 8, 9, 7, 52, 150, 151, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 8, 9, - 10, 11, 12, 8, 9, 31, 10, 207, 208, 35, - 36, 37, 38, 39, 214, 215, 42, 43, 52, 45, - 52, 52, 49, 49, 222, 51, 31, 53, 49, 46, - 230, 229, 231, 46, 52, 40, 41, 52, 43, 51, - 45, 49, 49, 49, 36, 31, 51, 9, 53, 52, - 51, 50, 252, 1, 5, 6, 7, 8, 9, 10, - 11, 12, 262, 263, 52, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 8, 9, 10, 35, 36, 37, 38, - 39, 36, 34, 42, 37, 43, 10, 45, 52, 47, - 52, 9, 31, 10, 10, 52, 31, 8, 9, 10, - 35, 36, 37, 38, 39, 31, 52, 42, 43, 52, - 45, 52, 152, 12, 49, 50, 51, 12, 53, 67, - 31, 8, 9, -1, 35, 36, 37, 38, 39, 245, - -1, 42, 43, -1, 45, -1, -1, -1, -1, 50, - 51, -1, 53, -1, 31, 8, 9, -1, 35, 36, - 37, 38, 39, -1, -1, 42, 43, -1, 45, -1, - -1, -1, -1, 50, 51, -1, 53, -1, 31, 8, - 9, -1, 35, 36, 37, 38, 39, -1, -1, 42, - 43, -1, 45, -1, -1, -1, 49, -1, 51, -1, - 53, -1, 31, 8, 9, -1, 35, 36, 37, 38, - 39, -1, -1, 42, 43, -1, 45, -1, -1, 8, - 9, -1, 51, -1, 53, -1, 31, -1, 8, 9, - 35, 36, 37, 38, 39, 8, 9, 42, -1, -1, - 45, -1, 31, -1, 8, 9, 51, 36, 53, -1, - -1, 31, -1, 42, 8, 9, 45, -1, 31, -1, - -1, -1, 51, 43, 53, 45, -1, 31, -1, -1, - 43, 51, 45, 53, -1, -1, 40, 31, 51, -1, - 53, 45, 8, 9, -1, 8, 9, 51, -1, 53, - -1, 45, 8, 9, -1, -1, 50, 51, -1, 53, - -1, -1, -1, -1, -1, 31, -1, -1, 31, -1, - -1, -1, -1, -1, -1, 31, -1, 40, -1, 45, - -1, -1, 45, -1, 50, 51, -1, 53, 51, 45, - 53, -1, -1, -1, -1, 51, -1, 53, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 6, 7, - 8, 9, 10, 11, 12 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 55, 0, 56, 1, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 43, 45, 47, 57, 59, 66, 67, - 68, 47, 49, 60, 8, 9, 31, 35, 36, 37, - 38, 39, 42, 43, 45, 49, 51, 53, 64, 78, - 82, 85, 86, 87, 88, 91, 50, 63, 78, 80, - 83, 61, 80, 62, 78, 10, 43, 49, 69, 79, - 81, 82, 83, 86, 87, 91, 88, 49, 60, 64, - 70, 43, 49, 51, 65, 81, 83, 91, 85, 71, - 80, 72, 80, 73, 80, 85, 74, 82, 75, 83, - 76, 80, 77, 80, 46, 48, 48, 47, 91, 91, - 6, 8, 9, 89, 78, 36, 42, 91, 92, 91, - 51, 51, 9, 40, 41, 51, 88, 91, 49, 49, - 49, 82, 86, 88, 89, 10, 79, 51, 11, 89, - 81, 49, 51, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 58, 92, 92, 7, 91, 91, 51, 10, - 52, 52, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 52, 36, 36, 37, 42, 40, 9, 40, - 78, 80, 33, 91, 81, 50, 91, 78, 78, 78, - 83, 91, 78, 78, 80, 80, 57, 89, 32, 34, - 42, 90, 91, 51, 92, 92, 92, 6, 7, 92, - 92, 92, 92, 92, 10, 10, 52, 52, 52, 40, - 52, 52, 49, 9, 31, 84, 49, 46, 46, 49, - 49, 49, 51, 52, 52, 36, 92, 92, 91, 91, - 51, 52, 83, 31, 9, 50, 36, 37, 83, 91, - 82, 34, 10, 52, 52, 36, 37, 9, 31, 84, - 52, 91, 10, 10, 31, 52, 91, 91, 52, 52 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) -#else -static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - fprintf (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - fprintf (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The look-ahead symbol. */ -int yychar; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to look-ahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a look-ahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the look-ahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: -#line 66 "a.y" - { - stmtline = lineno; - } - break; - - case 5: -#line 73 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc) - yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyvsp[(1) - (2)].sym)->type = LLAB; - (yyvsp[(1) - (2)].sym)->value = pc; - } - break; - - case 10: -#line 87 "a.y" - { - (yyvsp[(1) - (3)].sym)->type = LVAR; - (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval); - } - break; - - case 11: -#line 92 "a.y" - { - if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval)) - yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name); - (yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval); - } - break; - - case 12: -#line 97 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 13: -#line 98 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 14: -#line 99 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 15: -#line 100 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 16: -#line 101 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 17: -#line 102 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 20: -#line 105 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 21: -#line 106 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 22: -#line 107 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 23: -#line 108 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 24: -#line 109 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 26: -#line 111 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 27: -#line 112 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 28: -#line 113 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 29: -#line 114 "a.y" - { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); } - break; - - case 30: -#line 117 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = nullgen; - } - break; - - case 31: -#line 122 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = nullgen; - } - break; - - case 32: -#line 129 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 33: -#line 136 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 34: -#line 143 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (2)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 35: -#line 148 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (1)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 36: -#line 155 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 37: -#line 160 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 38: -#line 167 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 39: -#line 172 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 40: -#line 177 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 41: -#line 184 "a.y" - { - Addr2 a; - a.from = (yyvsp[(2) - (6)].addr); - a.to = (yyvsp[(6) - (6)].addr); - outcode(ADATA, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 42: -#line 197 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (5)].addr).sym); - a.from = (yyvsp[(2) - (5)].addr); - a.to = (yyvsp[(5) - (5)].addr); - outcode(ATEXT, &a); - } - break; - - case 43: -#line 205 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (7)].addr).sym); - a.from = (yyvsp[(2) - (7)].addr); - a.to = (yyvsp[(7) - (7)].addr); - outcode(ATEXT, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (7)].lval); - } - } - break; - - case 44: -#line 219 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (4)].addr).sym); - a.from = (yyvsp[(2) - (4)].addr); - a.to = (yyvsp[(4) - (4)].addr); - outcode(AGLOBL, &a); - } - break; - - case 45: -#line 227 "a.y" - { - Addr2 a; - settext((yyvsp[(2) - (6)].addr).sym); - a.from = (yyvsp[(2) - (6)].addr); - a.to = (yyvsp[(6) - (6)].addr); - outcode(AGLOBL, &a); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 46: -#line 241 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - } - break; - - case 47: -#line 246 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(1) - (1)].addr); - } - break; - - case 48: -#line 251 "a.y" - { - (yyval.addr2).from = nullgen; - (yyval.addr2).to = (yyvsp[(2) - (2)].addr); - (yyval.addr2).to.type = TYPE_INDIR; - } - break; - - case 51: -#line 263 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 52: -#line 268 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - if((yyval.addr2).from.index != TYPE_NONE) - yyerror("dp shift with lhs index"); - (yyval.addr2).from.index = (yyvsp[(5) - (5)].lval); - } - break; - - case 53: -#line 278 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 54: -#line 283 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - if((yyval.addr2).to.index != TYPE_NONE) - yyerror("dp move with lhs index"); - (yyval.addr2).to.index = (yyvsp[(5) - (5)].lval); - } - break; - - case 55: -#line 293 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (2)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 56: -#line 298 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (1)].addr); - (yyval.addr2).to = nullgen; - } - break; - - case 57: -#line 303 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 58: -#line 310 "a.y" - { - (yyval.addr2).from = (yyvsp[(1) - (5)].addr); - (yyval.addr2).to = (yyvsp[(3) - (5)].addr); - (yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval); - } - break; - - case 59: -#line 318 "a.y" - { - (yyval.addr2).from = (yyvsp[(3) - (5)].addr); - (yyval.addr2).to = (yyvsp[(5) - (5)].addr); - if((yyvsp[(1) - (5)].addr).type != TYPE_CONST) - yyerror("illegal constant"); - (yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset; - } - break; - - case 60: -#line 328 "a.y" - { - if((yyvsp[(1) - (3)].addr).type != TYPE_CONST || (yyvsp[(3) - (3)].addr).type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 61: -#line 337 "a.y" - { - if((yyvsp[(1) - (3)].addr).type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(3) - (3)].addr).type != TYPE_MEM || ((yyvsp[(3) - (3)].addr).name != NAME_EXTERN && (yyvsp[(3) - (3)].addr).name != NAME_STATIC)) - yyerror("value for FUNCDATA must be symbol reference"); - (yyval.addr2).from = (yyvsp[(1) - (3)].addr); - (yyval.addr2).to = (yyvsp[(3) - (3)].addr); - } - break; - - case 66: -#line 354 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - } - break; - - case 67: -#line 358 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - } - break; - - case 73: -#line 371 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; - } - break; - - case 74: -#line 377 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - (yyval.addr) = nullgen; - if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB) - yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); - } - break; - - case 75: -#line 388 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 76: -#line 394 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 77: -#line 400 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 78: -#line 406 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 79: -#line 412 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = REG_SP; - } - break; - - case 80: -#line 418 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 81: -#line 426 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - (yyval.addr).offset = (yyvsp[(2) - (2)].lval); - } - break; - - case 82: -#line 432 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - (yyval.addr).type = TYPE_ADDR; - /* - if($2.name == NAME_AUTO || $2.name == NAME_PARAM) - yyerror("constant cannot be automatic: %s", - $2.sym->name); - */ - } - break; - - case 83: -#line 442 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SCONST; - memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); - } - break; - - case 84: -#line 448 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); - } - break; - - case 85: -#line 454 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(3) - (4)].dval); - } - break; - - case 86: -#line 460 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval); - } - break; - - case 87: -#line 466 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); - } - break; - - case 88: -#line 474 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 89: -#line 481 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (2)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 90: -#line 488 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (3)].lval); - (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval); - } - break; - - case 91: -#line 495 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (4)].lval); - (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval); - } - break; - - case 94: -#line 508 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_NONE; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - } - break; - - case 95: -#line 515 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 96: -#line 522 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_SP; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 97: -#line 529 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_NONE; - (yyval.addr).offset = (yyvsp[(1) - (6)].lval); - (yyval.addr).index = (yyvsp[(3) - (6)].lval); - (yyval.addr).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 98: -#line 539 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (9)].lval); - (yyval.addr).offset = (yyvsp[(1) - (9)].lval); - (yyval.addr).index = (yyvsp[(6) - (9)].lval); - (yyval.addr).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 99: -#line 549 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (9)].lval); - (yyval.addr).offset = (yyvsp[(1) - (9)].lval); - (yyval.addr).index = (yyvsp[(6) - (9)].lval); - (yyval.addr).scale = (yyvsp[(8) - (9)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 100: -#line 559 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (3)].lval); - } - break; - - case 101: -#line 565 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_SP; - } - break; - - case 102: -#line 571 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 103: -#line 578 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = REG_NONE; - (yyval.addr).index = (yyvsp[(2) - (5)].lval); - (yyval.addr).scale = (yyvsp[(4) - (5)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 104: -#line 587 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (8)].lval); - (yyval.addr).index = (yyvsp[(5) - (8)].lval); - (yyval.addr).scale = (yyvsp[(7) - (8)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 105: -#line 598 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (1)].addr); - } - break; - - case 106: -#line 602 "a.y" - { - (yyval.addr) = (yyvsp[(1) - (6)].addr); - (yyval.addr).index = (yyvsp[(3) - (6)].lval); - (yyval.addr).scale = (yyvsp[(5) - (6)].lval); - checkscale((yyval.addr).scale); - } - break; - - case 107: -#line 611 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(4) - (5)].lval); - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); - (yyval.addr).offset = (yyvsp[(2) - (5)].lval); - } - break; - - case 108: -#line 619 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = NAME_STATIC; - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); - (yyval.addr).offset = (yyvsp[(4) - (7)].lval); - } - break; - - case 109: -#line 628 "a.y" - { - (yyval.lval) = 0; - } - break; - - case 110: -#line 632 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 111: -#line 636 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 113: -#line 643 "a.y" - { - (yyval.lval) = NAME_AUTO; - } - break; - - case 116: -#line 651 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; - } - break; - - case 117: -#line 655 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 118: -#line 659 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 119: -#line 663 "a.y" - { - (yyval.lval) = ~(yyvsp[(2) - (2)].lval); - } - break; - - case 120: -#line 667 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (3)].lval); - } - break; - - case 122: -#line 674 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); - } - break; - - case 123: -#line 678 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); - } - break; - - case 124: -#line 682 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); - } - break; - - case 125: -#line 686 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); - } - break; - - case 126: -#line 690 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); - } - break; - - case 127: -#line 694 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); - } - break; - - case 128: -#line 698 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); - } - break; - - case 129: -#line 702 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); - } - break; - - case 130: -#line 706 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); - } - break; - - case 131: -#line 710 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); - } - break; - - -/* Line 1267 of yacc.c. */ -#line 2565 "y.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse look-ahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse look-ahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h deleted file mode 100644 index 3ab1bfa0f4..0000000000 --- a/src/cmd/8a/y.tab.h +++ /dev/null @@ -1,135 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LTYPE0 = 258, - LTYPE1 = 259, - LTYPE2 = 260, - LTYPE3 = 261, - LTYPE4 = 262, - LTYPEC = 263, - LTYPED = 264, - LTYPEN = 265, - LTYPER = 266, - LTYPET = 267, - LTYPES = 268, - LTYPEM = 269, - LTYPEI = 270, - LTYPEG = 271, - LTYPEXC = 272, - LTYPEX = 273, - LTYPEPC = 274, - LTYPEF = 275, - LCONST = 276, - LFP = 277, - LPC = 278, - LSB = 279, - LBREG = 280, - LLREG = 281, - LSREG = 282, - LFREG = 283, - LXREG = 284, - LFCONST = 285, - LSCONST = 286, - LSP = 287, - LNAME = 288, - LLAB = 289, - LVAR = 290 - }; -#endif -/* Tokens. */ -#define LTYPE0 258 -#define LTYPE1 259 -#define LTYPE2 260 -#define LTYPE3 261 -#define LTYPE4 262 -#define LTYPEC 263 -#define LTYPED 264 -#define LTYPEN 265 -#define LTYPER 266 -#define LTYPET 267 -#define LTYPES 268 -#define LTYPEM 269 -#define LTYPEI 270 -#define LTYPEG 271 -#define LTYPEXC 272 -#define LTYPEX 273 -#define LTYPEPC 274 -#define LTYPEF 275 -#define LCONST 276 -#define LFP 277 -#define LPC 278 -#define LSB 279 -#define LBREG 280 -#define LLREG 281 -#define LSREG 282 -#define LFREG 283 -#define LXREG 284 -#define LFCONST 285 -#define LSCONST 286 -#define LSP 287 -#define LNAME 288 -#define LLAB 289 -#define LVAR 290 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - int32 lval; - double dval; - char sval[8]; - Addr addr; - Addr2 addr2; -} -/* Line 1529 of yacc.c. */ -#line 128 "y.tab.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile deleted file mode 100644 index 3f528d7517..0000000000 --- a/src/cmd/8g/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c deleted file mode 100644 index f06927c905..0000000000 --- a/src/cmd/8g/cgen.c +++ /dev/null @@ -1,1590 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO(rsc): -// assume CLD? - -#include -#include -#include "gg.h" - -void -mgen(Node *n, Node *n1, Node *rg) -{ - Node n2; - - n1->op = OEMPTY; - - if(n->addable) { - *n1 = *n; - if(n1->op == OREGISTER || n1->op == OINDREG) - reg[n->val.u.reg]++; - return; - } - tempname(n1, n->type); - cgen(n, n1); - if(n->type->width <= widthptr || isfloat[n->type->etype]) { - n2 = *n1; - regalloc(n1, n->type, rg); - gmove(&n2, n1); - } -} - -void -mfree(Node *n) -{ - if(n->op == OREGISTER) - regfree(n); -} - -/* - * generate: - * res = n; - * simplifies and calls gmove. - * - * TODO: - * sudoaddable - */ -void -cgen(Node *n, Node *res) -{ - Node *nl, *nr, *r, n1, n2, nt; - Prog *p1, *p2, *p3; - int a; - - if(debug['g']) { - dump("\ncgen-n", n); - dump("cgen-res", res); - } - - if(n == N || n->type == T) - fatal("cgen: n nil"); - if(res == N || res->type == T) - fatal("cgen: res nil"); - - switch(n->op) { - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_slice(n, &n1); - cgen(&n1, res); - } else - cgen_slice(n, res); - return; - case OEFACE: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_eface(n, &n1); - cgen(&n1, res); - } else - cgen_eface(n, res); - return; - } - - while(n->op == OCONVNOP) - n = n->left; - - // function calls on both sides? introduce temporary - if(n->ullman >= UINF && res->ullman >= UINF) { - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - return; - } - - // structs etc get handled specially - if(isfat(n->type)) { - if(n->type->width < 0) - fatal("forgot to compute width for %T", n->type); - sgen(n, res, n->type->width); - return; - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch(n->op) { - case OSPTR: - case OLEN: - if(isslice(n->left->type) || istype(n->left->type, TSTRING)) - n->addable = n->left->addable; - break; - case OCAP: - if(isslice(n->left->type)) - n->addable = n->left->addable; - break; - case OITAB: - n->addable = n->left->addable; - break; - } - - // if both are addressable, move - if(n->addable && res->addable) { - gmove(n, res); - return; - } - - // if both are not addressable, use a temporary. - if(!n->addable && !res->addable) { - // could use regalloc here sometimes, - // but have to check for ullman >= UINF. - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - return; - } - - // if result is not addressable directly but n is, - // compute its address and then store via the address. - if(!res->addable) { - igen(res, &n1, N); - cgen(n, &n1); - regfree(&n1); - return; - } - - // complex types - if(complexop(n, res)) { - complexgen(n, res); - return; - } - - // otherwise, the result is addressable but n is not. - // let's do some computation. - - // use ullman to pick operand to eval first. - nl = n->left; - nr = n->right; - if(nl != N && nl->ullman >= UINF) - if(nr != N && nr->ullman >= UINF) { - // both are hard - tempname(&n1, nl->type); - cgen(nl, &n1); - n2 = *n; - n2.left = &n1; - cgen(&n2, res); - return; - } - - // 64-bit ops are hard on 32-bit machine. - if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) { - switch(n->op) { - // math goes to cgen64. - case OMINUS: - case OCOM: - case OADD: - case OSUB: - case OMUL: - case OLROT: - case OLSH: - case ORSH: - case OAND: - case OOR: - case OXOR: - cgen64(n, res); - return; - } - } - - if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) { - cgen_float(n, res); - return; - } - - switch(n->op) { - default: - dump("cgen", n); - fatal("cgen %O", n->op); - break; - - case OREAL: - case OIMAG: - case OCOMPLEX: - fatal("unexpected complex"); - return; - - // these call bgen to get a bool value - case OOROR: - case OANDAND: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case ONOT: - p1 = gbranch(AJMP, T, 0); - p2 = pc; - gmove(nodbool(1), res); - p3 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n, 1, 0, p2); - gmove(nodbool(0), res); - patch(p3, pc); - return; - - case OPLUS: - cgen(nl, res); - return; - - case OMINUS: - case OCOM: - a = optoas(n->op, nl->type); - goto uop; - - // symmetric binary - case OAND: - case OOR: - case OXOR: - case OADD: - case OMUL: - a = optoas(n->op, nl->type); - if(a == AIMULB) { - cgen_bmul(n->op, nl, nr, res); - break; - } - goto sbop; - - // asymmetric binary - case OSUB: - a = optoas(n->op, nl->type); - goto abop; - - case OHMUL: - cgen_hmul(nl, nr, res); - break; - - case OCONV: - if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) { - cgen(nl, res); - break; - } - - tempname(&n2, n->type); - mgen(nl, &n1, res); - gmove(&n1, &n2); - gmove(&n2, res); - mfree(&n1); - break; - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case OITAB: - igen(nl, &n1, res); - n1.type = ptrto(types[TUINTPTR]); - gmove(&n1, res); - regfree(&n1); - break; - - case OSPTR: - // pointer is the first word of string or slice. - if(isconst(nl, CTSTR)) { - regalloc(&n1, types[tptr], res); - p1 = gins(ALEAL, N, &n1); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - gmove(&n1, res); - regfree(&n1); - break; - } - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OLEN: - if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { - // map has len in the first 32-bit word. - // a zero pointer means zero length - tempname(&n1, types[tptr]); - cgen(nl, &n1); - regalloc(&n2, types[tptr], N); - gmove(&n1, &n2); - n1 = n2; - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); - - n2 = n1; - n2.op = OINDREG; - n2.type = types[TINT32]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(istype(nl->type, TSTRING) || isslice(nl->type)) { - // both slice and string have len one pointer into the struct. - igen(nl, &n1, res); - n1.type = types[TUINT32]; - n1.xoffset += Array_nel; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OLEN: unknown type %lT", nl->type); - break; - - case OCAP: - if(istype(nl->type, TCHAN)) { - // chan has cap in the second 32-bit word. - // a zero pointer means zero length - tempname(&n1, types[tptr]); - cgen(nl, &n1); - regalloc(&n2, types[tptr], N); - gmove(&n1, &n2); - n1 = n2; - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, -1); - - n2 = n1; - n2.op = OINDREG; - n2.xoffset = 4; - n2.type = types[TINT32]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(isslice(nl->type)) { - igen(nl, &n1, res); - n1.type = types[TUINT32]; - n1.xoffset += Array_cap; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OCAP: unknown type %lT", nl->type); - break; - - case OADDR: - agen(nl, res); - break; - - case OCALLMETH: - cgen_callmeth(n, 0); - cgen_callret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_callret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_callret(n, res); - break; - - case OMOD: - case ODIV: - cgen_div(n->op, nl, nr, res); - break; - - case OLSH: - case ORSH: - case OLROT: - cgen_shift(n->op, n->bounded, nl, nr, res); - break; - } - return; - -sbop: // symmetric binary - if(nl->ullman < nr->ullman || nl->op == OLITERAL) { - r = nl; - nl = nr; - nr = r; - } - -abop: // asymmetric binary - if(smallintconst(nr)) { - mgen(nl, &n1, res); - regalloc(&n2, nl->type, &n1); - gmove(&n1, &n2); - gins(a, nr, &n2); - gmove(&n2, res); - regfree(&n2); - mfree(&n1); - } else if(nl->ullman >= nr->ullman) { - tempname(&nt, nl->type); - cgen(nl, &nt); - mgen(nr, &n2, N); - regalloc(&n1, nl->type, res); - gmove(&nt, &n1); - gins(a, &n2, &n1); - gmove(&n1, res); - regfree(&n1); - mfree(&n2); - } else { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - gins(a, &n2, &n1); - regfree(&n2); - gmove(&n1, res); - regfree(&n1); - } - return; - -uop: // unary - tempname(&n1, nl->type); - cgen(nl, &n1); - gins(a, N, &n1); - gmove(&n1, res); - return; -} - -/* - * generate an addressable node in res, containing the value of n. - * n is an array index, and might be any size; res width is <= 32-bit. - * returns Prog* to patch to panic call. - */ -static Prog* -igenindex(Node *n, Node *res, int bounded) -{ - Node tmp, lo, hi, zero; - - if(!is64(n->type)) { - if(n->addable) { - // nothing to do. - *res = *n; - } else { - tempname(res, types[TUINT32]); - cgen(n, res); - } - return nil; - } - - tempname(&tmp, types[TINT64]); - cgen(n, &tmp); - split64(&tmp, &lo, &hi); - tempname(res, types[TUINT32]); - gmove(&lo, res); - if(bounded) { - splitclean(); - return nil; - } - nodconst(&zero, types[TINT32], 0); - gins(ACMPL, &hi, &zero); - splitclean(); - return gbranch(AJNE, T, +1); -} - -/* - * address gen - * res = &n; - * The generated code checks that the result is not nil. - */ -void -agen(Node *n, Node *res) -{ - Node *nl, *nr; - Node n1, n2, n3, tmp, nlen; - Type *t; - uint32 w; - uint64 v; - Prog *p1, *p2; - int bounded; - - if(debug['g']) { - dump("\nagen-res", res); - dump("agen-r", n); - } - if(n == N || n->type == T || res == N || res->type == T) - fatal("agen"); - - while(n->op == OCONVNOP) - n = n->left; - - if(isconst(n, CTNIL) && n->type->width > widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - tempname(&n1, n->type); - gvardef(&n1); - clearfat(&n1); - regalloc(&n2, types[tptr], res); - gins(ALEAL, &n1, &n2); - gmove(&n2, res); - regfree(&n2); - return; - } - - // addressable var is easy - if(n->addable) { - if(n->op == OREGISTER) - fatal("agen OREGISTER"); - regalloc(&n1, types[tptr], res); - gins(ALEAL, n, &n1); - gmove(&n1, res); - regfree(&n1); - return; - } - - // let's compute - nl = n->left; - nr = n->right; - - switch(n->op) { - default: - fatal("agen %O", n->op); - - case OCALLMETH: - cgen_callmeth(n, 0); - cgen_aret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_aret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_aret(n, res); - break; - - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - tempname(&n1, n->type); - cgen_slice(n, &n1); - agen(&n1, res); - break; - - case OEFACE: - tempname(&n1, n->type); - cgen_eface(n, &n1); - agen(&n1, res); - break; - - case OINDEX: - p2 = nil; // to be patched to panicindex. - w = n->type->width; - bounded = debug['B'] || n->bounded; - if(nr->addable) { - // Generate &nl first, and move nr into register. - if(!isconst(nl, CTSTR)) - igen(nl, &n3, res); - if(!isconst(nr, CTINT)) { - p2 = igenindex(nr, &tmp, bounded); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - } else if(nl->addable) { - // Generate nr first, and move &nl into register. - if(!isconst(nr, CTINT)) { - p2 = igenindex(nr, &tmp, bounded); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - if(!isconst(nl, CTSTR)) - igen(nl, &n3, res); - } else { - p2 = igenindex(nr, &tmp, bounded); - nr = &tmp; - if(!isconst(nl, CTSTR)) - igen(nl, &n3, res); - regalloc(&n1, tmp.type, N); - gins(optoas(OAS, tmp.type), &tmp, &n1); - } - - // For fixed array we really want the pointer in n3. - if(isfixedarray(nl->type)) { - regalloc(&n2, types[tptr], &n3); - agen(&n3, &n2); - regfree(&n3); - n3 = n2; - } - - // &a[0] is in n3 (allocated in res) - // i is in n1 (if not constant) - // len(a) is in nlen (if needed) - // w is width - - // constant index - if(isconst(nr, CTINT)) { - if(isconst(nl, CTSTR)) - fatal("constant string constant index"); // front end should handle - v = mpgetfix(nr->val.u.xval); - if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(!debug['B'] && !n->bounded) { - nlen = n3; - nlen.type = types[TUINT32]; - nlen.xoffset += Array_nel; - nodconst(&n2, types[TUINT32], v); - gins(optoas(OCMP, types[TUINT32]), &nlen, &n2); - p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1); - ginscall(panicindex, -1); - patch(p1, pc); - } - } - - // Load base pointer in n2 = n3. - regalloc(&n2, types[tptr], &n3); - n3.type = types[tptr]; - n3.xoffset += Array_array; - gmove(&n3, &n2); - regfree(&n3); - if (v*w != 0) { - nodconst(&n1, types[tptr], v*w); - gins(optoas(OADD, types[tptr]), &n1, &n2); - } - gmove(&n2, res); - regfree(&n2); - break; - } - - // i is in register n1, extend to 32 bits. - t = types[TUINT32]; - if(issigned[n1.type->etype]) - t = types[TINT32]; - - regalloc(&n2, t, &n1); // i - gmove(&n1, &n2); - regfree(&n1); - - if(!debug['B'] && !n->bounded) { - // check bounds - t = types[TUINT32]; - if(isconst(nl, CTSTR)) { - nodconst(&nlen, t, nl->val.u.sval->len); - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { - nlen = n3; - nlen.type = t; - nlen.xoffset += Array_nel; - } else { - nodconst(&nlen, t, nl->type->bound); - } - gins(optoas(OCMP, t), &n2, &nlen); - p1 = gbranch(optoas(OLT, t), T, +1); - if(p2) - patch(p2, pc); - ginscall(panicindex, -1); - patch(p1, pc); - } - - if(isconst(nl, CTSTR)) { - regalloc(&n3, types[tptr], res); - p1 = gins(ALEAL, N, &n3); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - p1->from.scale = 1; - p1->from.index = n2.val.u.reg; - goto indexdone; - } - - // Load base pointer in n3. - regalloc(&tmp, types[tptr], &n3); - if(isslice(nl->type) || nl->type->etype == TSTRING) { - n3.type = types[tptr]; - n3.xoffset += Array_array; - gmove(&n3, &tmp); - } - regfree(&n3); - n3 = tmp; - - if(w == 0) { - // nothing to do - } else if(w == 1 || w == 2 || w == 4 || w == 8) { - // LEAL (n3)(n2*w), n3 - p1 = gins(ALEAL, &n2, &n3); - p1->from.scale = w; - p1->from.type = TYPE_MEM; - p1->from.index = p1->from.reg; - p1->from.reg = p1->to.reg; - } else { - nodconst(&tmp, types[TUINT32], w); - gins(optoas(OMUL, types[TUINT32]), &tmp, &n2); - gins(optoas(OADD, types[tptr]), &n2, &n3); - } - - indexdone: - gmove(&n3, res); - regfree(&n2); - regfree(&n3); - break; - - case ONAME: - // should only get here with names in this func. - if(n->funcdepth > 0 && n->funcdepth != funcdepth) { - dump("bad agen", n); - fatal("agen: bad ONAME funcdepth %d != %d", - n->funcdepth, funcdepth); - } - - // should only get here for heap vars or paramref - if(!(n->class & PHEAP) && n->class != PPARAMREF) { - dump("bad agen", n); - fatal("agen: bad ONAME class %#x", n->class); - } - cgen(n->heapaddr, res); - if(n->xoffset != 0) { - nodconst(&n1, types[tptr], n->xoffset); - gins(optoas(OADD, types[tptr]), &n1, res); - } - break; - - case OIND: - cgen(nl, res); - cgen_checknil(res); - break; - - case ODOT: - agen(nl, res); - if(n->xoffset != 0) { - nodconst(&n1, types[tptr], n->xoffset); - gins(optoas(OADD, types[tptr]), &n1, res); - } - break; - - case ODOTPTR: - t = nl->type; - if(!isptr[t->etype]) - fatal("agen: not ptr %N", n); - cgen(nl, res); - cgen_checknil(res); - if(n->xoffset != 0) { - nodconst(&n1, types[tptr], n->xoffset); - gins(optoas(OADD, types[tptr]), &n1, res); - } - break; - } -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -void -igen(Node *n, Node *a, Node *res) -{ - Type *fp; - Iter flist; - Node n1; - - if(debug['g']) { - dump("\nigen-n", n); - } - switch(n->op) { - case ONAME: - if((n->class&PHEAP) || n->class == PPARAMREF) - break; - *a = *n; - return; - - case OINDREG: - // Increase the refcount of the register so that igen's caller - // has to call regfree. - if(n->val.u.reg != REG_SP) - reg[n->val.u.reg]++; - *a = *n; - return; - - case ODOT: - igen(n->left, a, res); - a->xoffset += n->xoffset; - a->type = n->type; - return; - - case ODOTPTR: - switch(n->left->op) { - case ODOT: - case ODOTPTR: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - // igen-able nodes. - igen(n->left, &n1, res); - regalloc(a, types[tptr], &n1); - gmove(&n1, a); - regfree(&n1); - break; - default: - regalloc(a, types[tptr], res); - cgen(n->left, a); - } - cgen_checknil(a); - a->op = OINDREG; - a->xoffset += n->xoffset; - a->type = n->type; - return; - - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - switch(n->op) { - case OCALLFUNC: - cgen_call(n, 0); - break; - case OCALLMETH: - cgen_callmeth(n, 0); - break; - case OCALLINTER: - cgen_callinter(n, N, 0); - break; - } - fp = structfirst(&flist, getoutarg(n->left->type)); - memset(a, 0, sizeof *a); - a->op = OINDREG; - a->val.u.reg = REG_SP; - a->addable = 1; - a->xoffset = fp->width; - a->type = n->type; - return; - - case OINDEX: - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - if(isfixedarray(n->left->type) || - (isptr[n->left->type->etype] && isfixedarray(n->left->left->type))) - if(isconst(n->right, CTINT)) { - // Compute &a. - if(!isptr[n->left->type->etype]) - igen(n->left, a, res); - else { - igen(n->left, &n1, res); - cgen_checknil(&n1); - regalloc(a, types[tptr], res); - gmove(&n1, a); - regfree(&n1); - a->op = OINDREG; - } - - // Compute &a[i] as &a + i*width. - a->type = n->type; - a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width; - return; - } - break; - } - - // release register for now, to avoid - // confusing tempname. - if(res != N && res->op == OREGISTER) - reg[res->val.u.reg]--; - tempname(&n1, types[tptr]); - agen(n, &n1); - if(res != N && res->op == OREGISTER) - reg[res->val.u.reg]++; - regalloc(a, types[tptr], res); - gmove(&n1, a); - a->op = OINDREG; - a->type = n->type; -} - -/* - * branch gen - * if(n == true) goto to; - */ -void -bgen(Node *n, int true, int likely, Prog *to) -{ - int et, a; - Node *nl, *nr, *r; - Node n1, n2, tmp; - Prog *p1, *p2; - - if(debug['g']) { - dump("\nbgen", n); - } - - if(n == N) - n = nodbool(1); - - if(n->ninit != nil) - genlist(n->ninit); - - if(n->type == T) { - convlit(&n, types[TBOOL]); - if(n->type == T) - return; - } - - et = n->type->etype; - if(et != TBOOL) { - yyerror("cgen: bad type %T for %O", n->type, n->op); - patch(gins(AEND, N, N), to); - return; - } - - while(n->op == OCONVNOP) { - n = n->left; - if(n->ninit != nil) - genlist(n->ninit); - } - - nl = n->left; - nr = N; - - if(nl != N && isfloat[nl->type->etype]) { - bgen_float(n, true, likely, to); - return; - } - - switch(n->op) { - default: - goto def; - - case OLITERAL: - // need to ask if it is bool? - if(!true == !n->val.u.bval) - patch(gbranch(AJMP, T, 0), to); - return; - - case ONAME: - if(!n->addable) - goto def; - nodconst(&n1, n->type, 0); - gins(optoas(OCMP, n->type), n, &n1); - a = AJNE; - if(!true) - a = AJEQ; - patch(gbranch(a, n->type, likely), to); - return; - - case OANDAND: - case OOROR: - if((n->op == OANDAND) == true) { - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n->left, !true, -likely, p2); - bgen(n->right, !true, -likely, p2); - p1 = gbranch(AJMP, T, 0); - patch(p1, to); - patch(p2, pc); - } else { - bgen(n->left, true, likely, to); - bgen(n->right, true, likely, to); - } - return; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - nr = n->right; - if(nr == N || nr->type == T) - return; - - case ONOT: // unary - nl = n->left; - if(nl == N || nl->type == T) - return; - } - - switch(n->op) { - case ONOT: - bgen(nl, !true, likely, to); - break; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - a = n->op; - if(!true) { - a = brcom(a); - true = !true; - } - - // make simplest on right - if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) { - a = brrev(a); - r = nl; - nl = nr; - nr = r; - } - - if(isslice(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal slice comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.xoffset += Array_array; - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &tmp); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - - if(isinter(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal interface comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &tmp); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - - if(iscomplex[nl->type->etype]) { - complexbool(a, nl, nr, true, likely, to); - break; - } - - if(is64(nr->type)) { - if(!nl->addable || isconst(nl, CTINT)) { - tempname(&n1, nl->type); - cgen(nl, &n1); - nl = &n1; - } - if(!nr->addable) { - tempname(&n2, nr->type); - cgen(nr, &n2); - nr = &n2; - } - cmp64(nl, nr, a, likely, to); - break; - } - - if(nr->ullman >= UINF) { - if(!nl->addable) { - tempname(&n1, nl->type); - cgen(nl, &n1); - nl = &n1; - } - if(!nr->addable) { - tempname(&tmp, nr->type); - cgen(nr, &tmp); - nr = &tmp; - } - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - nr = &n2; - goto cmp; - } - - if(!nl->addable) { - tempname(&n1, nl->type); - cgen(nl, &n1); - nl = &n1; - } - - if(smallintconst(nr)) { - gins(optoas(OCMP, nr->type), nl, nr); - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - break; - } - - if(!nr->addable) { - tempname(&tmp, nr->type); - cgen(nr, &tmp); - nr = &tmp; - } - regalloc(&n2, nr->type, N); - gmove(nr, &n2); - nr = &n2; - -cmp: - gins(optoas(OCMP, nr->type), nl, nr); - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - - if(nl->op == OREGISTER) - regfree(nl); - regfree(nr); - break; - } - return; - -def: - regalloc(&n1, n->type, N); - cgen(n, &n1); - nodconst(&n2, n->type, 0); - gins(optoas(OCMP, n->type), &n1, &n2); - a = AJNE; - if(!true) - a = AJEQ; - patch(gbranch(a, n->type, likely), to); - regfree(&n1); - return; -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -int32 -stkof(Node *n) -{ - Type *t; - Iter flist; - int32 off; - - switch(n->op) { - case OINDREG: - return n->xoffset; - - case ODOT: - t = n->left->type; - if(isptr[t->etype]) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - return off + n->xoffset; - - case OINDEX: - t = n->left->type; - if(!isfixedarray(t)) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - if(isconst(n->right, CTINT)) - return off + t->type->width * mpgetfix(n->right->val.u.xval); - return 1000; - - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - t = structfirst(&flist, getoutarg(t)); - if(t != T) - return t->width; - break; - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000; -} - -/* - * struct gen - * memmove(&res, &n, w); - */ -void -sgen(Node *n, Node *res, int64 w) -{ - Node dst, src, tdst, tsrc, cx; - int32 c, q, odst, osrc; - NodeList *l; - Prog *p; - - if(debug['g']) { - print("\nsgen w=%lld\n", w); - dump("r", n); - dump("res", res); - } - if(n->ullman >= UINF && res->ullman >= UINF) - fatal("sgen UINF"); - - if(w < 0 || (int32)w != w) - fatal("sgen copy %lld", w); - - if(w == 0) { - // evaluate side effects only. - tempname(&tdst, types[tptr]); - agen(res, &tdst); - agen(n, &tdst); - return; - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0) - for(l = curfn->dcl; l != nil; l = l->next) - if(l->n->class == PPARAMOUT) - gvardef(l->n); - - // Avoid taking the address for simple enough types. - if(componentgen(n, res)) - return; - - // offset on the stack - osrc = stkof(n); - odst = stkof(res); - - if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - tempname(&tsrc, n->type); - sgen(n, &tsrc, w); - sgen(&tsrc, res, w); - return; - } - - nodreg(&dst, types[tptr], REG_DI); - nodreg(&src, types[tptr], REG_SI); - - tempname(&tsrc, types[tptr]); - tempname(&tdst, types[tptr]); - if(!n->addable) - agen(n, &tsrc); - if(!res->addable) - agen(res, &tdst); - if(n->addable) - agen(n, &src); - else - gmove(&tsrc, &src); - - if(res->op == ONAME) - gvardef(res); - - if(res->addable) - agen(res, &dst); - else - gmove(&tdst, &dst); - - c = w % 4; // bytes - q = w / 4; // doublewords - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - if(osrc < odst && odst < osrc+w) { - // reverse direction - gins(ASTD, N, N); // set direction flag - if(c > 0) { - gconreg(AADDL, w-1, REG_SI); - gconreg(AADDL, w-1, REG_DI); - - gconreg(AMOVL, c, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSB, N, N); // MOVB *(SI)-,*(DI)- - } - - if(q > 0) { - if(c > 0) { - gconreg(AADDL, -3, REG_SI); - gconreg(AADDL, -3, REG_DI); - } else { - gconreg(AADDL, w-4, REG_SI); - gconreg(AADDL, w-4, REG_DI); - } - gconreg(AMOVL, q, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSL, N, N); // MOVL *(SI)-,*(DI)- - } - // we leave with the flag clear - gins(ACLD, N, N); - } else { - gins(ACLD, N, N); // paranoia. TODO(rsc): remove? - // normal direction - if(q > 128 || (q >= 4 && nacl)) { - gconreg(AMOVL, q, REG_CX); - gins(AREP, N, N); // repeat - gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ - } else if(q >= 4) { - p = gins(ADUFFCOPY, N, N); - p->to.type = TYPE_ADDR; - p->to.sym = linksym(pkglookup("duffcopy", runtimepkg)); - // 10 and 128 = magic constants: see ../../runtime/asm_386.s - p->to.offset = 10*(128-q); - } else if(!nacl && c == 0) { - nodreg(&cx, types[TINT32], REG_CX); - // We don't need the MOVSL side-effect of updating SI and DI, - // and issuing a sequence of MOVLs directly is faster. - src.op = OINDREG; - dst.op = OINDREG; - while(q > 0) { - gmove(&src, &cx); // MOVL x+(SI),CX - gmove(&cx, &dst); // MOVL CX,x+(DI) - src.xoffset += 4; - dst.xoffset += 4; - q--; - } - } else - while(q > 0) { - gins(AMOVSL, N, N); // MOVL *(SI)+,*(DI)+ - q--; - } - while(c > 0) { - gins(AMOVSB, N, N); // MOVB *(SI)+,*(DI)+ - c--; - } - } -} - -static int -cadable(Node *n) -{ - if(!n->addable) { - // dont know how it happens, - // but it does - return 0; - } - - switch(n->op) { - case ONAME: - return 1; - } - return 0; -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -int -componentgen(Node *nr, Node *nl) -{ - Node nodl, nodr, tmp; - Type *t; - int freel, freer; - vlong fldcount; - vlong loffset, roffset; - - freel = 0; - freer = 0; - - switch(nl->type->etype) { - default: - goto no; - - case TARRAY: - t = nl->type; - - // Slices are ok. - if(isslice(t)) - break; - // Small arrays are ok. - if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) - break; - - goto no; - - case TSTRUCT: - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - fldcount = 0; - for(t=nl->type->type; t; t=t->down) { - if(isfat(t->type)) - goto no; - if(t->etype != TFIELD) - fatal("componentgen: not a TFIELD: %lT", t); - fldcount++; - } - if(fldcount == 0 || fldcount > 4) - goto no; - - break; - - case TSTRING: - case TINTER: - break; - } - - nodl = *nl; - if(!cadable(nl)) { - if(nr != N && !cadable(nr)) - goto no; - igen(nl, &nodl, N); - freel = 1; - } - - if(nr != N) { - nodr = *nr; - if(!cadable(nr)) { - igen(nr, &nodr, N); - freer = 1; - } - } else { - // When zeroing, prepare a register containing zero. - nodconst(&tmp, nl->type, 0); - regalloc(&nodr, types[TUINT], N); - gmove(&tmp, &nodr); - freer = 1; - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) - goto yes; - - switch(nl->type->etype) { - case TARRAY: - // componentgen for arrays. - if(nl->op == ONAME) - gvardef(nl); - t = nl->type; - if(!isslice(t)) { - nodl.type = t->type; - nodr.type = nodl.type; - for(fldcount=0; fldcount < t->bound; fldcount++) { - if(nr == N) - clearslim(&nodl); - else - gmove(&nodr, &nodl); - nodl.xoffset += t->type->width; - nodr.xoffset += t->type->width; - } - goto yes; - } - - // componentgen for slices. - nodl.xoffset += Array_array; - nodl.type = ptrto(nl->type->type); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_cap-Array_nel; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_cap-Array_nel; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRING: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TINTER: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRUCT: - if(nl->op == ONAME) - gvardef(nl); - loffset = nodl.xoffset; - roffset = nodr.xoffset; - // funarg structs may not begin at offset zero. - if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) - loffset -= nl->type->type->width; - if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) - roffset -= nr->type->type->width; - - for(t=nl->type->type; t; t=t->down) { - nodl.xoffset = loffset + t->width; - nodl.type = t->type; - - if(nr == N) - clearslim(&nodl); - else { - nodr.xoffset = roffset + t->width; - nodr.type = nodl.type; - gmove(&nodr, &nodl); - } - } - goto yes; - } - -no: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 0; - -yes: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 1; -} diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go new file mode 100644 index 0000000000..9f736b1745 --- /dev/null +++ b/src/cmd/8g/cgen.go @@ -0,0 +1,1730 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" + "fmt" +) +import "cmd/internal/gc" + +/* + * reg.c + */ + +/* + * peep.c + */ +func mgen(n *gc.Node, n1 *gc.Node, rg *gc.Node) { + var n2 gc.Node + + n1.Op = gc.OEMPTY + + if n.Addable != 0 { + *n1 = *n + if n1.Op == gc.OREGISTER || n1.Op == gc.OINDREG { + reg[n.Val.U.Reg]++ + } + return + } + + gc.Tempname(n1, n.Type) + cgen(n, n1) + if n.Type.Width <= int64(gc.Widthptr) || gc.Isfloat[n.Type.Etype] != 0 { + n2 = *n1 + regalloc(n1, n.Type, rg) + gmove(&n2, n1) + } +} + +func mfree(n *gc.Node) { + if n.Op == gc.OREGISTER { + regfree(n) + } +} + +/* + * generate: + * res = n; + * simplifies and calls gmove. + * + * TODO: + * sudoaddable + */ +func cgen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var nt gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var a int + + if gc.Debug['g'] != 0 { + gc.Dump("\ncgen-n", n) + gc.Dump("cgen-res", res) + } + + if n == nil || n.Type == nil { + gc.Fatal("cgen: n nil") + } + if res == nil || res.Type == nil { + gc.Fatal("cgen: res nil") + } + + switch n.Op { + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_slice(n, res) + } + return + + case gc.OEFACE: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_eface(n, res) + } + return + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + // function calls on both sides? introduce temporary + if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { + gc.Tempname(&n1, n.Type) + cgen(n, &n1) + cgen(&n1, res) + return + } + + // structs etc get handled specially + if gc.Isfat(n.Type) { + if n.Type.Width < 0 { + gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) + } + sgen(n, res, n.Type.Width) + return + } + + // update addressability for string, slice + // can't do in walk because n->left->addable + // changes if n->left is an escaping local variable. + switch n.Op { + case gc.OSPTR, + gc.OLEN: + if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { + n.Addable = n.Left.Addable + } + + case gc.OCAP: + if gc.Isslice(n.Left.Type) { + n.Addable = n.Left.Addable + } + + case gc.OITAB: + n.Addable = n.Left.Addable + } + + // if both are addressable, move + if n.Addable != 0 && res.Addable != 0 { + gmove(n, res) + return + } + + // if both are not addressable, use a temporary. + if n.Addable == 0 && res.Addable == 0 { + // could use regalloc here sometimes, + // but have to check for ullman >= UINF. + gc.Tempname(&n1, n.Type) + + cgen(n, &n1) + cgen(&n1, res) + return + } + + // if result is not addressable directly but n is, + // compute its address and then store via the address. + if res.Addable == 0 { + igen(res, &n1, nil) + cgen(n, &n1) + regfree(&n1) + return + } + + // complex types + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + return + } + + // otherwise, the result is addressable but n is not. + // let's do some computation. + + // use ullman to pick operand to eval first. + nl = n.Left + + nr = n.Right + if nl != nil && nl.Ullman >= gc.UINF { + if nr != nil && nr.Ullman >= gc.UINF { + // both are hard + gc.Tempname(&n1, nl.Type) + + cgen(nl, &n1) + n2 = *n + n2.Left = &n1 + cgen(&n2, res) + return + } + } + + // 64-bit ops are hard on 32-bit machine. + if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) { + switch n.Op { + // math goes to cgen64. + case gc.OMINUS, + gc.OCOM, + gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OLROT, + gc.OLSH, + gc.ORSH, + gc.OAND, + gc.OOR, + gc.OXOR: + cgen64(n, res) + + return + } + } + + if nl != nil && gc.Isfloat[n.Type.Etype] != 0 && gc.Isfloat[nl.Type.Etype] != 0 { + cgen_float(n, res) + return + } + + switch n.Op { + default: + gc.Dump("cgen", n) + gc.Fatal("cgen %v", gc.Oconv(int(n.Op), 0)) + + case gc.OREAL, + gc.OIMAG, + gc.OCOMPLEX: + gc.Fatal("unexpected complex") + return + + // these call bgen to get a bool value + case gc.OOROR, + gc.OANDAND, + gc.OEQ, + gc.ONE, + gc.OLT, + gc.OLE, + gc.OGE, + gc.OGT, + gc.ONOT: + p1 = gc.Gbranch(obj.AJMP, nil, 0) + + p2 = gc.Pc + gmove(gc.Nodbool(true), res) + p3 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n, true, 0, p2) + gmove(gc.Nodbool(false), res) + gc.Patch(p3, gc.Pc) + return + + case gc.OPLUS: + cgen(nl, res) + return + + case gc.OMINUS, + gc.OCOM: + a = optoas(int(n.Op), nl.Type) + goto uop + + // symmetric binary + case gc.OAND, + gc.OOR, + gc.OXOR, + gc.OADD, + gc.OMUL: + a = optoas(int(n.Op), nl.Type) + + if a == i386.AIMULB { + cgen_bmul(int(n.Op), nl, nr, res) + break + } + + goto sbop + + // asymmetric binary + case gc.OSUB: + a = optoas(int(n.Op), nl.Type) + + goto abop + + case gc.OHMUL: + cgen_hmul(nl, nr, res) + + case gc.OCONV: + if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { + cgen(nl, res) + break + } + + gc.Tempname(&n2, n.Type) + mgen(nl, &n1, res) + gmove(&n1, &n2) + gmove(&n2, res) + mfree(&n1) + + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: // PHEAP or PPARAMREF var + igen(n, &n1, res) + + gmove(&n1, res) + regfree(&n1) + + case gc.OITAB: + igen(nl, &n1, res) + n1.Type = gc.Ptrto(gc.Types[gc.TUINTPTR]) + gmove(&n1, res) + regfree(&n1) + + // pointer is the first word of string or slice. + case gc.OSPTR: + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n1, gc.Types[gc.Tptr], res) + p1 = gins(i386.ALEAL, nil, &n1) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + gmove(&n1, res) + regfree(&n1) + break + } + + igen(nl, &n1, res) + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + case gc.OLEN: + if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { + // map has len in the first 32-bit word. + // a zero pointer means zero length + gc.Tempname(&n1, gc.Types[gc.Tptr]) + + cgen(nl, &n1) + regalloc(&n2, gc.Types[gc.Tptr], nil) + gmove(&n1, &n2) + n1 = n2 + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.TINT32] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { + // both slice and string have len one pointer into the struct. + igen(nl, &n1, res) + + n1.Type = gc.Types[gc.TUINT32] + n1.Xoffset += int64(gc.Array_nel) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OCAP: + if gc.Istype(nl.Type, gc.TCHAN) { + // chan has cap in the second 32-bit word. + // a zero pointer means zero length + gc.Tempname(&n1, gc.Types[gc.Tptr]) + + cgen(nl, &n1) + regalloc(&n2, gc.Types[gc.Tptr], nil) + gmove(&n1, &n2) + n1 = n2 + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Xoffset = 4 + n2.Type = gc.Types[gc.TINT32] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Isslice(nl.Type) { + igen(nl, &n1, res) + n1.Type = gc.Types[gc.TUINT32] + n1.Xoffset += int64(gc.Array_cap) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OADDR: + agen(nl, res) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + cgen_callret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_callret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_callret(n, res) + + case gc.OMOD, + gc.ODIV: + cgen_div(int(n.Op), nl, nr, res) + + case gc.OLSH, + gc.ORSH, + gc.OLROT: + cgen_shift(int(n.Op), n.Bounded, nl, nr, res) + } + + return + +sbop: // symmetric binary + if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL { + r = nl + nl = nr + nr = r + } + +abop: // asymmetric binary + if gc.Smallintconst(nr) { + mgen(nl, &n1, res) + regalloc(&n2, nl.Type, &n1) + gmove(&n1, &n2) + gins(a, nr, &n2) + gmove(&n2, res) + regfree(&n2) + mfree(&n1) + } else if nl.Ullman >= nr.Ullman { + gc.Tempname(&nt, nl.Type) + cgen(nl, &nt) + mgen(nr, &n2, nil) + regalloc(&n1, nl.Type, res) + gmove(&nt, &n1) + gins(a, &n2, &n1) + gmove(&n1, res) + regfree(&n1) + mfree(&n2) + } else { + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gins(a, &n2, &n1) + regfree(&n2) + gmove(&n1, res) + regfree(&n1) + } + + return + +uop: // unary + gc.Tempname(&n1, nl.Type) + + cgen(nl, &n1) + gins(a, nil, &n1) + gmove(&n1, res) + return +} + +/* + * generate an addressable node in res, containing the value of n. + * n is an array index, and might be any size; res width is <= 32-bit. + * returns Prog* to patch to panic call. + */ +func igenindex(n *gc.Node, res *gc.Node, bounded int) *obj.Prog { + var tmp gc.Node + var lo gc.Node + var hi gc.Node + var zero gc.Node + + if !gc.Is64(n.Type) { + if n.Addable != 0 { + // nothing to do. + *res = *n + } else { + gc.Tempname(res, gc.Types[gc.TUINT32]) + cgen(n, res) + } + + return nil + } + + gc.Tempname(&tmp, gc.Types[gc.TINT64]) + cgen(n, &tmp) + split64(&tmp, &lo, &hi) + gc.Tempname(res, gc.Types[gc.TUINT32]) + gmove(&lo, res) + if bounded != 0 { + splitclean() + return nil + } + + gc.Nodconst(&zero, gc.Types[gc.TINT32], 0) + gins(i386.ACMPL, &hi, &zero) + splitclean() + return gc.Gbranch(i386.AJNE, nil, +1) +} + +/* + * address gen + * res = &n; + * The generated code checks that the result is not nil. + */ +func agen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var tmp gc.Node + var nlen gc.Node + var t *gc.Type + var w uint32 + var v uint64 + var p1 *obj.Prog + var p2 *obj.Prog + var bounded bool + + if gc.Debug['g'] != 0 { + gc.Dump("\nagen-res", res) + gc.Dump("agen-r", n) + } + + if n == nil || n.Type == nil || res == nil || res.Type == nil { + gc.Fatal("agen") + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { + // Use of a nil interface or nil slice. + // Create a temporary we can take the address of and read. + // The generated code is just going to panic, so it need not + // be terribly efficient. See issue 3670. + gc.Tempname(&n1, n.Type) + + gc.Gvardef(&n1) + clearfat(&n1) + regalloc(&n2, gc.Types[gc.Tptr], res) + gins(i386.ALEAL, &n1, &n2) + gmove(&n2, res) + regfree(&n2) + return + } + + // addressable var is easy + if n.Addable != 0 { + if n.Op == gc.OREGISTER { + gc.Fatal("agen OREGISTER") + } + regalloc(&n1, gc.Types[gc.Tptr], res) + gins(i386.ALEAL, n, &n1) + gmove(&n1, res) + regfree(&n1) + return + } + + // let's compute + nl = n.Left + + nr = n.Right + + switch n.Op { + default: + gc.Fatal("agen %v", gc.Oconv(int(n.Op), 0)) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + cgen_aret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_aret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_aret(n, res) + + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + agen(&n1, res) + + case gc.OEFACE: + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + agen(&n1, res) + + case gc.OINDEX: + p2 = nil // to be patched to panicindex. + w = uint32(n.Type.Width) + bounded = gc.Debug['B'] != 0 || n.Bounded + if nr.Addable != 0 { + // Generate &nl first, and move nr into register. + if !gc.Isconst(nl, gc.CTSTR) { + igen(nl, &n3, res) + } + if !gc.Isconst(nr, gc.CTINT) { + p2 = igenindex(nr, &tmp, bool2int(bounded)) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + } else if nl.Addable != 0 { + // Generate nr first, and move &nl into register. + if !gc.Isconst(nr, gc.CTINT) { + p2 = igenindex(nr, &tmp, bool2int(bounded)) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + + if !gc.Isconst(nl, gc.CTSTR) { + igen(nl, &n3, res) + } + } else { + p2 = igenindex(nr, &tmp, bool2int(bounded)) + nr = &tmp + if !gc.Isconst(nl, gc.CTSTR) { + igen(nl, &n3, res) + } + regalloc(&n1, tmp.Type, nil) + gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) + } + + // For fixed array we really want the pointer in n3. + if gc.Isfixedarray(nl.Type) { + regalloc(&n2, gc.Types[gc.Tptr], &n3) + agen(&n3, &n2) + regfree(&n3) + n3 = n2 + } + + // &a[0] is in n3 (allocated in res) + // i is in n1 (if not constant) + // len(a) is in nlen (if needed) + // w is width + + // constant index + if gc.Isconst(nr, gc.CTINT) { + if gc.Isconst(nl, gc.CTSTR) { + gc.Fatal("constant string constant index") // front end should handle + } + v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + if gc.Debug['B'] == 0 && !n.Bounded { + nlen = n3 + nlen.Type = gc.Types[gc.TUINT32] + nlen.Xoffset += int64(gc.Array_nel) + gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v)) + gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &nlen, &n2) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + } + + // Load base pointer in n2 = n3. + regalloc(&n2, gc.Types[gc.Tptr], &n3) + + n3.Type = gc.Types[gc.Tptr] + n3.Xoffset += int64(gc.Array_array) + gmove(&n3, &n2) + regfree(&n3) + if v*uint64(w) != 0 { + gc.Nodconst(&n1, gc.Types[gc.Tptr], int64(v*uint64(w))) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, &n2) + } + + gmove(&n2, res) + regfree(&n2) + break + } + + // i is in register n1, extend to 32 bits. + t = gc.Types[gc.TUINT32] + + if gc.Issigned[n1.Type.Etype] != 0 { + t = gc.Types[gc.TINT32] + } + + regalloc(&n2, t, &n1) // i + gmove(&n1, &n2) + regfree(&n1) + + if gc.Debug['B'] == 0 && !n.Bounded { + // check bounds + t = gc.Types[gc.TUINT32] + + if gc.Isconst(nl, gc.CTSTR) { + gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval.S))) + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + nlen = n3 + nlen.Type = t + nlen.Xoffset += int64(gc.Array_nel) + } else { + gc.Nodconst(&nlen, t, nl.Type.Bound) + } + + gins(optoas(gc.OCMP, t), &n2, &nlen) + p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) + if p2 != nil { + gc.Patch(p2, gc.Pc) + } + ginscall(gc.Panicindex, -1) + gc.Patch(p1, gc.Pc) + } + + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n3, gc.Types[gc.Tptr], res) + p1 = gins(i386.ALEAL, nil, &n3) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + p1.From.Scale = 1 + p1.From.Index = n2.Val.U.Reg + goto indexdone + } + + // Load base pointer in n3. + regalloc(&tmp, gc.Types[gc.Tptr], &n3) + + if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + n3.Type = gc.Types[gc.Tptr] + n3.Xoffset += int64(gc.Array_array) + gmove(&n3, &tmp) + } + + regfree(&n3) + n3 = tmp + + if w == 0 { + } else // nothing to do + if w == 1 || w == 2 || w == 4 || w == 8 { + // LEAL (n3)(n2*w), n3 + p1 = gins(i386.ALEAL, &n2, &n3) + + p1.From.Scale = int8(w) + p1.From.Type = obj.TYPE_MEM + p1.From.Index = p1.From.Reg + p1.From.Reg = p1.To.Reg + } else { + gc.Nodconst(&tmp, gc.Types[gc.TUINT32], int64(w)) + gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &tmp, &n2) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + } + + indexdone: + gmove(&n3, res) + regfree(&n2) + regfree(&n3) + + // should only get here with names in this func. + case gc.ONAME: + if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) + } + + // should only get here for heap vars or paramref + if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME class %#x", n.Class) + } + + cgen(n.Heapaddr, res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) + } + + case gc.OIND: + cgen(nl, res) + gc.Cgen_checknil(res) + + case gc.ODOT: + agen(nl, res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) + } + + case gc.ODOTPTR: + t = nl.Type + if gc.Isptr[t.Etype] == 0 { + gc.Fatal("agen: not ptr %v", gc.Nconv(n, 0)) + } + cgen(nl, res) + gc.Cgen_checknil(res) + if n.Xoffset != 0 { + gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) + } + } +} + +/* + * generate: + * newreg = &n; + * res = newreg + * + * on exit, a has been changed to be *newreg. + * caller must regfree(a). + * The generated code checks that the result is not *nil. + */ +func igen(n *gc.Node, a *gc.Node, res *gc.Node) { + var fp *gc.Type + var flist gc.Iter + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("\nigen-n", n) + } + + switch n.Op { + case gc.ONAME: + if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { + break + } + *a = *n + return + + // Increase the refcount of the register so that igen's caller + // has to call regfree. + case gc.OINDREG: + if n.Val.U.Reg != i386.REG_SP { + reg[n.Val.U.Reg]++ + } + *a = *n + return + + case gc.ODOT: + igen(n.Left, a, res) + a.Xoffset += n.Xoffset + a.Type = n.Type + return + + case gc.ODOTPTR: + switch n.Left.Op { + // igen-able nodes. + case gc.ODOT, + gc.ODOTPTR, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n.Left, &n1, res) + + regalloc(a, gc.Types[gc.Tptr], &n1) + gmove(&n1, a) + regfree(&n1) + + default: + regalloc(a, gc.Types[gc.Tptr], res) + cgen(n.Left, a) + } + + gc.Cgen_checknil(a) + a.Op = gc.OINDREG + a.Xoffset += n.Xoffset + a.Type = n.Type + return + + case gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + switch n.Op { + case gc.OCALLFUNC: + cgen_call(n, 0) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + + case gc.OCALLINTER: + cgen_callinter(n, nil, 0) + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) + *a = gc.Node{} + a.Op = gc.OINDREG + a.Val.U.Reg = i386.REG_SP + a.Addable = 1 + a.Xoffset = fp.Width + a.Type = n.Type + return + + // Index of fixed-size array by constant can + // put the offset in the addressing. + // Could do the same for slice except that we need + // to use the real index for the bounds checking. + case gc.OINDEX: + if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { + if gc.Isconst(n.Right, gc.CTINT) { + // Compute &a. + if gc.Isptr[n.Left.Type.Etype] == 0 { + igen(n.Left, a, res) + } else { + igen(n.Left, &n1, res) + gc.Cgen_checknil(&n1) + regalloc(a, gc.Types[gc.Tptr], res) + gmove(&n1, a) + regfree(&n1) + a.Op = gc.OINDREG + } + + // Compute &a[i] as &a + i*width. + a.Type = n.Type + + a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width + return + } + } + } + + // release register for now, to avoid + // confusing tempname. + if res != nil && res.Op == gc.OREGISTER { + reg[res.Val.U.Reg]-- + } + gc.Tempname(&n1, gc.Types[gc.Tptr]) + agen(n, &n1) + if res != nil && res.Op == gc.OREGISTER { + reg[res.Val.U.Reg]++ + } + regalloc(a, gc.Types[gc.Tptr], res) + gmove(&n1, a) + a.Op = gc.OINDREG + a.Type = n.Type +} + +/* + * branch gen + * if(n == true) goto to; + */ +func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { + var et int + var a int + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var tmp gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['g'] != 0 { + gc.Dump("\nbgen", n) + } + + if n == nil { + n = gc.Nodbool(true) + } + + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + + if n.Type == nil { + gc.Convlit(&n, gc.Types[gc.TBOOL]) + if n.Type == nil { + return + } + } + + et = int(n.Type.Etype) + if et != gc.TBOOL { + gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) + gc.Patch(gins(obj.AEND, nil, nil), to) + return + } + + for n.Op == gc.OCONVNOP { + n = n.Left + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + } + + nl = n.Left + nr = nil + + if nl != nil && gc.Isfloat[nl.Type.Etype] != 0 { + bgen_float(n, bool2int(true_), likely, to) + return + } + + switch n.Op { + default: + goto def + + // need to ask if it is bool? + case gc.OLITERAL: + if !true_ == (n.Val.U.Bval == 0) { + gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) + } + return + + case gc.ONAME: + if n.Addable == 0 { + goto def + } + gc.Nodconst(&n1, n.Type, 0) + gins(optoas(gc.OCMP, n.Type), n, &n1) + a = i386.AJNE + if !true_ { + a = i386.AJEQ + } + gc.Patch(gc.Gbranch(a, n.Type, likely), to) + return + + case gc.OANDAND, + gc.OOROR: + if (n.Op == gc.OANDAND) == true_ { + p1 = gc.Gbranch(obj.AJMP, nil, 0) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n.Left, !true_, -likely, p2) + bgen(n.Right, !true_, -likely, p2) + p1 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, to) + gc.Patch(p2, gc.Pc) + } else { + bgen(n.Left, true_, likely, to) + bgen(n.Right, true_, likely, to) + } + + return + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + nr = n.Right + if nr == nil || nr.Type == nil { + return + } + fallthrough + + case gc.ONOT: // unary + nl = n.Left + + if nl == nil || nl.Type == nil { + return + } + } + + switch n.Op { + case gc.ONOT: + bgen(nl, !true_, likely, to) + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + a = int(n.Op) + if !true_ { + a = gc.Brcom(a) + true_ = !true_ + } + + // make simplest on right + if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { + a = gc.Brrev(a) + r = nl + nl = nr + nr = r + } + + if gc.Isslice(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal slice comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Xoffset += int64(gc.Array_array) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Isinter(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal interface comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Iscomplex[nl.Type.Etype] != 0 { + gc.Complexbool(a, nl, nr, true_, likely, to) + break + } + + if gc.Is64(nr.Type) { + if nl.Addable == 0 || gc.Isconst(nl, gc.CTINT) { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + nl = &n1 + } + + if nr.Addable == 0 { + gc.Tempname(&n2, nr.Type) + cgen(nr, &n2) + nr = &n2 + } + + cmp64(nl, nr, a, likely, to) + break + } + + if nr.Ullman >= gc.UINF { + if nl.Addable == 0 { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + nl = &n1 + } + + if nr.Addable == 0 { + gc.Tempname(&tmp, nr.Type) + cgen(nr, &tmp) + nr = &tmp + } + + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + nr = &n2 + goto cmp + } + + if nl.Addable == 0 { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + nl = &n1 + } + + if gc.Smallintconst(nr) { + gins(optoas(gc.OCMP, nr.Type), nl, nr) + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + break + } + + if nr.Addable == 0 { + gc.Tempname(&tmp, nr.Type) + cgen(nr, &tmp) + nr = &tmp + } + + regalloc(&n2, nr.Type, nil) + gmove(nr, &n2) + nr = &n2 + + cmp: + gins(optoas(gc.OCMP, nr.Type), nl, nr) + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + + if nl.Op == gc.OREGISTER { + regfree(nl) + } + regfree(nr) + } + + return + +def: + regalloc(&n1, n.Type, nil) + cgen(n, &n1) + gc.Nodconst(&n2, n.Type, 0) + gins(optoas(gc.OCMP, n.Type), &n1, &n2) + a = i386.AJNE + if !true_ { + a = i386.AJEQ + } + gc.Patch(gc.Gbranch(a, n.Type, likely), to) + regfree(&n1) + return +} + +/* + * n is on stack, either local variable + * or return value from function call. + * return n's offset from SP. + */ +func stkof(n *gc.Node) int32 { + var t *gc.Type + var flist gc.Iter + var off int32 + + switch n.Op { + case gc.OINDREG: + return int32(n.Xoffset) + + case gc.ODOT: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + return int32(int64(off) + n.Xoffset) + + case gc.OINDEX: + t = n.Left.Type + if !gc.Isfixedarray(t) { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + if gc.Isconst(n.Right, gc.CTINT) { + return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)) + } + return 1000 + + case gc.OCALLMETH, + gc.OCALLINTER, + gc.OCALLFUNC: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + t = gc.Structfirst(&flist, gc.Getoutarg(t)) + if t != nil { + return int32(t.Width) + } + } + + // botch - probably failing to recognize address + // arithmetic on the above. eg INDEX and DOT + return -1000 +} + +/* + * struct gen + * memmove(&res, &n, w); + */ +func sgen(n *gc.Node, res *gc.Node, w int64) { + var dst gc.Node + var src gc.Node + var tdst gc.Node + var tsrc gc.Node + var cx gc.Node + var c int32 + var q int32 + var odst int32 + var osrc int32 + var l *gc.NodeList + var p *obj.Prog + + if gc.Debug['g'] != 0 { + fmt.Printf("\nsgen w=%d\n", w) + gc.Dump("r", n) + gc.Dump("res", res) + } + + if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { + gc.Fatal("sgen UINF") + } + + if w < 0 || int64(int32(w)) != w { + gc.Fatal("sgen copy %d", w) + } + + if w == 0 { + // evaluate side effects only. + gc.Tempname(&tdst, gc.Types[gc.Tptr]) + + agen(res, &tdst) + agen(n, &tdst) + return + } + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if res.Op == gc.ONAME && res.Sym.Name == ".args" { + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + if l.N.Class == gc.PPARAMOUT { + gc.Gvardef(l.N) + } + } + } + + // Avoid taking the address for simple enough types. + if componentgen(n, res) { + return + } + + // offset on the stack + osrc = stkof(n) + + odst = stkof(res) + + if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + gc.Tempname(&tsrc, n.Type) + + sgen(n, &tsrc, w) + sgen(&tsrc, res, w) + return + } + + gc.Nodreg(&dst, gc.Types[gc.Tptr], i386.REG_DI) + gc.Nodreg(&src, gc.Types[gc.Tptr], i386.REG_SI) + + gc.Tempname(&tsrc, gc.Types[gc.Tptr]) + gc.Tempname(&tdst, gc.Types[gc.Tptr]) + if n.Addable == 0 { + agen(n, &tsrc) + } + if res.Addable == 0 { + agen(res, &tdst) + } + if n.Addable != 0 { + agen(n, &src) + } else { + gmove(&tsrc, &src) + } + + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + + if res.Addable != 0 { + agen(res, &dst) + } else { + gmove(&tdst, &dst) + } + + c = int32(w % 4) // bytes + q = int32(w / 4) // doublewords + + // if we are copying forward on the stack and + // the src and dst overlap, then reverse direction + if osrc < odst && int64(odst) < int64(osrc)+w { + // reverse direction + gins(i386.ASTD, nil, nil) // set direction flag + if c > 0 { + gconreg(i386.AADDL, w-1, i386.REG_SI) + gconreg(i386.AADDL, w-1, i386.REG_DI) + + gconreg(i386.AMOVL, int64(c), i386.REG_CX) + gins(i386.AREP, nil, nil) // repeat + gins(i386.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)- + } + + if q > 0 { + if c > 0 { + gconreg(i386.AADDL, -3, i386.REG_SI) + gconreg(i386.AADDL, -3, i386.REG_DI) + } else { + gconreg(i386.AADDL, w-4, i386.REG_SI) + gconreg(i386.AADDL, w-4, i386.REG_DI) + } + + gconreg(i386.AMOVL, int64(q), i386.REG_CX) + gins(i386.AREP, nil, nil) // repeat + gins(i386.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)- + } + + // we leave with the flag clear + gins(i386.ACLD, nil, nil) + } else { + gins(i386.ACLD, nil, nil) // paranoia. TODO(rsc): remove? + + // normal direction + if q > 128 || (q >= 4 && gc.Nacl) { + gconreg(i386.AMOVL, int64(q), i386.REG_CX) + gins(i386.AREP, nil, nil) // repeat + gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+ + } else if q >= 4 { + p = gins(obj.ADUFFCOPY, nil, nil) + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg)) + + // 10 and 128 = magic constants: see ../../runtime/asm_386.s + p.To.Offset = 10 * (128 - int64(q)) + } else if !gc.Nacl && c == 0 { + gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX) + + // We don't need the MOVSL side-effect of updating SI and DI, + // and issuing a sequence of MOVLs directly is faster. + src.Op = gc.OINDREG + + dst.Op = gc.OINDREG + for q > 0 { + gmove(&src, &cx) // MOVL x+(SI),CX + gmove(&cx, &dst) // MOVL CX,x+(DI) + src.Xoffset += 4 + dst.Xoffset += 4 + q-- + } + } else { + for q > 0 { + gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+ + q-- + } + } + + for c > 0 { + gins(i386.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+ + c-- + } + } +} + +func cadable(n *gc.Node) bool { + if n.Addable == 0 { + // dont know how it happens, + // but it does + return false + } + + switch n.Op { + case gc.ONAME: + return true + } + + return false +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * Small structs or arrays with elements of basic type are + * also supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if can't. + */ +func componentgen(nr *gc.Node, nl *gc.Node) bool { + var nodl gc.Node + var nodr gc.Node + var tmp gc.Node + var t *gc.Type + var freel int + var freer int + var fldcount int64 + var loffset int64 + var roffset int64 + + freel = 0 + freer = 0 + + switch nl.Type.Etype { + default: + goto no + + case gc.TARRAY: + t = nl.Type + + // Slices are ok. + if gc.Isslice(t) { + break + } + + // Small arrays are ok. + if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { + break + } + + goto no + + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + case gc.TSTRUCT: + fldcount = 0 + + for t = nl.Type.Type; t != nil; t = t.Down { + if gc.Isfat(t.Type) { + goto no + } + if t.Etype != gc.TFIELD { + gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) + } + fldcount++ + } + + if fldcount == 0 || fldcount > 4 { + goto no + } + + case gc.TSTRING, + gc.TINTER: + break + } + + nodl = *nl + if !cadable(nl) { + if nr != nil && !cadable(nr) { + goto no + } + igen(nl, &nodl, nil) + freel = 1 + } + + if nr != nil { + nodr = *nr + if !cadable(nr) { + igen(nr, &nodr, nil) + freer = 1 + } + } else { + // When zeroing, prepare a register containing zero. + gc.Nodconst(&tmp, nl.Type, 0) + + regalloc(&nodr, gc.Types[gc.TUINT], nil) + gmove(&tmp, &nodr) + freer = 1 + } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { + goto yes + } + + switch nl.Type.Etype { + // componentgen for arrays. + case gc.TARRAY: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + t = nl.Type + if !gc.Isslice(t) { + nodl.Type = t.Type + nodr.Type = nodl.Type + for fldcount = 0; fldcount < t.Bound; fldcount++ { + if nr == nil { + gc.Clearslim(&nodl) + } else { + gmove(&nodr, &nodl) + } + nodl.Xoffset += t.Type.Width + nodr.Xoffset += t.Type.Width + } + + goto yes + } + + // componentgen for slices. + nodl.Xoffset += int64(gc.Array_array) + + nodl.Type = gc.Ptrto(nl.Type.Type) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRING: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TINTER: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRUCT: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + loffset = nodl.Xoffset + roffset = nodr.Xoffset + + // funarg structs may not begin at offset zero. + if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { + loffset -= nl.Type.Type.Width + } + if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { + roffset -= nr.Type.Type.Width + } + + for t = nl.Type.Type; t != nil; t = t.Down { + nodl.Xoffset = loffset + t.Width + nodl.Type = t.Type + + if nr == nil { + gc.Clearslim(&nodl) + } else { + nodr.Xoffset = roffset + t.Width + nodr.Type = nodl.Type + gmove(&nodr, &nodl) + } + } + + goto yes + } + +no: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return false + +yes: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return true +} diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c deleted file mode 100644 index d9e812f384..0000000000 --- a/src/cmd/8g/cgen64.c +++ /dev/null @@ -1,549 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -/* - * attempt to generate 64-bit - * res = n - * return 1 on success, 0 if op not handled. - */ -void -cgen64(Node *n, Node *res) -{ - Node t1, t2, ax, dx, cx, ex, fx, *l, *r; - Node lo1, lo2, hi1, hi2; - Prog *p1, *p2; - uint64 v; - uint32 lv, hv; - - if(res->op != OINDREG && res->op != ONAME) { - dump("n", n); - dump("res", res); - fatal("cgen64 %O of %O", n->op, res->op); - } - switch(n->op) { - default: - fatal("cgen64 %O", n->op); - - case OMINUS: - cgen(n->left, res); - split64(res, &lo1, &hi1); - gins(ANEGL, N, &lo1); - gins(AADCL, ncon(0), &hi1); - gins(ANEGL, N, &hi1); - splitclean(); - return; - - case OCOM: - cgen(n->left, res); - split64(res, &lo1, &hi1); - gins(ANOTL, N, &lo1); - gins(ANOTL, N, &hi1); - splitclean(); - return; - - case OADD: - case OSUB: - case OMUL: - case OLROT: - case OLSH: - case ORSH: - case OAND: - case OOR: - case OXOR: - // binary operators. - // common setup below. - break; - } - - l = n->left; - r = n->right; - if(!l->addable) { - tempname(&t1, l->type); - cgen(l, &t1); - l = &t1; - } - if(r != N && !r->addable) { - tempname(&t2, r->type); - cgen(r, &t2); - r = &t2; - } - - nodreg(&ax, types[TINT32], REG_AX); - nodreg(&cx, types[TINT32], REG_CX); - nodreg(&dx, types[TINT32], REG_DX); - - // Setup for binary operation. - split64(l, &lo1, &hi1); - if(is64(r->type)) - split64(r, &lo2, &hi2); - - // Do op. Leave result in DX:AX. - switch(n->op) { - case OADD: - // TODO: Constants - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - gins(AADDL, &lo2, &ax); - gins(AADCL, &hi2, &dx); - break; - - case OSUB: - // TODO: Constants. - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - gins(ASUBL, &lo2, &ax); - gins(ASBBL, &hi2, &dx); - break; - - case OMUL: - // let's call the next two EX and FX. - regalloc(&ex, types[TPTR32], N); - regalloc(&fx, types[TPTR32], N); - - // load args into DX:AX and EX:CX. - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - gins(AMOVL, &lo2, &cx); - gins(AMOVL, &hi2, &ex); - - // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply. - gins(AMOVL, &dx, &fx); - gins(AORL, &ex, &fx); - p1 = gbranch(AJNE, T, 0); - gins(AMULL, &cx, N); // implicit &ax - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - - // full 64x64 -> 64, from 32x32 -> 64. - gins(AIMULL, &cx, &dx); - gins(AMOVL, &ax, &fx); - gins(AIMULL, &ex, &fx); - gins(AADDL, &dx, &fx); - gins(AMOVL, &cx, &dx); - gins(AMULL, &dx, N); // implicit &ax - gins(AADDL, &fx, &dx); - patch(p2, pc); - - regfree(&ex); - regfree(&fx); - break; - - case OLROT: - // We only rotate by a constant c in [0,64). - // if c >= 32: - // lo, hi = hi, lo - // c -= 32 - // if c == 0: - // no-op - // else: - // t = hi - // shld hi:lo, c - // shld lo:t, c - v = mpgetfix(r->val.u.xval); - if(v >= 32) { - // reverse during load to do the first 32 bits of rotate - v -= 32; - gins(AMOVL, &lo1, &dx); - gins(AMOVL, &hi1, &ax); - } else { - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - } - if(v == 0) { - // done - } else { - gins(AMOVL, &dx, &cx); - p1 = gins(ASHLL, ncon(v), &dx); - p1->from.index = REG_AX; // double-width shift - p1->from.scale = 0; - p1 = gins(ASHLL, ncon(v), &ax); - p1->from.index = REG_CX; // double-width shift - p1->from.scale = 0; - } - break; - - case OLSH: - if(r->op == OLITERAL) { - v = mpgetfix(r->val.u.xval); - if(v >= 64) { - if(is64(r->type)) - splitclean(); - splitclean(); - split64(res, &lo2, &hi2); - gins(AMOVL, ncon(0), &lo2); - gins(AMOVL, ncon(0), &hi2); - splitclean(); - goto out; - } - if(v >= 32) { - if(is64(r->type)) - splitclean(); - split64(res, &lo2, &hi2); - gmove(&lo1, &hi2); - if(v > 32) { - gins(ASHLL, ncon(v - 32), &hi2); - } - gins(AMOVL, ncon(0), &lo2); - splitclean(); - splitclean(); - goto out; - } - - // general shift - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - p1 = gins(ASHLL, ncon(v), &dx); - p1->from.index = REG_AX; // double-width shift - p1->from.scale = 0; - gins(ASHLL, ncon(v), &ax); - break; - } - - // load value into DX:AX. - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - - // load shift value into register. - // if high bits are set, zero value. - p1 = P; - if(is64(r->type)) { - gins(ACMPL, &hi2, ncon(0)); - p1 = gbranch(AJNE, T, +1); - gins(AMOVL, &lo2, &cx); - } else { - cx.type = types[TUINT32]; - gmove(r, &cx); - } - - // if shift count is >=64, zero value - gins(ACMPL, &cx, ncon(64)); - p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - if(p1 != P) - patch(p1, pc); - gins(AXORL, &dx, &dx); - gins(AXORL, &ax, &ax); - patch(p2, pc); - - // if shift count is >= 32, zero low. - gins(ACMPL, &cx, ncon(32)); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - gins(AMOVL, &ax, &dx); - gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count - gins(AXORL, &ax, &ax); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - - // general shift - p1 = gins(ASHLL, &cx, &dx); - p1->from.index = REG_AX; // double-width shift - p1->from.scale = 0; - gins(ASHLL, &cx, &ax); - patch(p2, pc); - break; - - case ORSH: - if(r->op == OLITERAL) { - v = mpgetfix(r->val.u.xval); - if(v >= 64) { - if(is64(r->type)) - splitclean(); - splitclean(); - split64(res, &lo2, &hi2); - if(hi1.type->etype == TINT32) { - gmove(&hi1, &lo2); - gins(ASARL, ncon(31), &lo2); - gmove(&hi1, &hi2); - gins(ASARL, ncon(31), &hi2); - } else { - gins(AMOVL, ncon(0), &lo2); - gins(AMOVL, ncon(0), &hi2); - } - splitclean(); - goto out; - } - if(v >= 32) { - if(is64(r->type)) - splitclean(); - split64(res, &lo2, &hi2); - gmove(&hi1, &lo2); - if(v > 32) - gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2); - if(hi1.type->etype == TINT32) { - gmove(&hi1, &hi2); - gins(ASARL, ncon(31), &hi2); - } else - gins(AMOVL, ncon(0), &hi2); - splitclean(); - splitclean(); - goto out; - } - - // general shift - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - p1 = gins(ASHRL, ncon(v), &ax); - p1->from.index = REG_DX; // double-width shift - p1->from.scale = 0; - gins(optoas(ORSH, hi1.type), ncon(v), &dx); - break; - } - - // load value into DX:AX. - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - - // load shift value into register. - // if high bits are set, zero value. - p1 = P; - if(is64(r->type)) { - gins(ACMPL, &hi2, ncon(0)); - p1 = gbranch(AJNE, T, +1); - gins(AMOVL, &lo2, &cx); - } else { - cx.type = types[TUINT32]; - gmove(r, &cx); - } - - // if shift count is >=64, zero or sign-extend value - gins(ACMPL, &cx, ncon(64)); - p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - if(p1 != P) - patch(p1, pc); - if(hi1.type->etype == TINT32) { - gins(ASARL, ncon(31), &dx); - gins(AMOVL, &dx, &ax); - } else { - gins(AXORL, &dx, &dx); - gins(AXORL, &ax, &ax); - } - patch(p2, pc); - - // if shift count is >= 32, sign-extend hi. - gins(ACMPL, &cx, ncon(32)); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - gins(AMOVL, &dx, &ax); - if(hi1.type->etype == TINT32) { - gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count - gins(ASARL, ncon(31), &dx); - } else { - gins(ASHRL, &cx, &ax); - gins(AXORL, &dx, &dx); - } - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - - // general shift - p1 = gins(ASHRL, &cx, &ax); - p1->from.index = REG_DX; // double-width shift - p1->from.scale = 0; - gins(optoas(ORSH, hi1.type), &cx, &dx); - patch(p2, pc); - break; - - case OXOR: - case OAND: - case OOR: - // make constant the right side (it usually is anyway). - if(lo1.op == OLITERAL) { - nswap(&lo1, &lo2); - nswap(&hi1, &hi2); - } - if(lo2.op == OLITERAL) { - // special cases for constants. - lv = mpgetfix(lo2.val.u.xval); - hv = mpgetfix(hi2.val.u.xval); - splitclean(); // right side - split64(res, &lo2, &hi2); - switch(n->op) { - case OXOR: - gmove(&lo1, &lo2); - gmove(&hi1, &hi2); - switch(lv) { - case 0: - break; - case 0xffffffffu: - gins(ANOTL, N, &lo2); - break; - default: - gins(AXORL, ncon(lv), &lo2); - break; - } - switch(hv) { - case 0: - break; - case 0xffffffffu: - gins(ANOTL, N, &hi2); - break; - default: - gins(AXORL, ncon(hv), &hi2); - break; - } - break; - - case OAND: - switch(lv) { - case 0: - gins(AMOVL, ncon(0), &lo2); - break; - default: - gmove(&lo1, &lo2); - if(lv != 0xffffffffu) - gins(AANDL, ncon(lv), &lo2); - break; - } - switch(hv) { - case 0: - gins(AMOVL, ncon(0), &hi2); - break; - default: - gmove(&hi1, &hi2); - if(hv != 0xffffffffu) - gins(AANDL, ncon(hv), &hi2); - break; - } - break; - - case OOR: - switch(lv) { - case 0: - gmove(&lo1, &lo2); - break; - case 0xffffffffu: - gins(AMOVL, ncon(0xffffffffu), &lo2); - break; - default: - gmove(&lo1, &lo2); - gins(AORL, ncon(lv), &lo2); - break; - } - switch(hv) { - case 0: - gmove(&hi1, &hi2); - break; - case 0xffffffffu: - gins(AMOVL, ncon(0xffffffffu), &hi2); - break; - default: - gmove(&hi1, &hi2); - gins(AORL, ncon(hv), &hi2); - break; - } - break; - } - splitclean(); - splitclean(); - goto out; - } - gins(AMOVL, &lo1, &ax); - gins(AMOVL, &hi1, &dx); - gins(optoas(n->op, lo1.type), &lo2, &ax); - gins(optoas(n->op, lo1.type), &hi2, &dx); - break; - } - if(is64(r->type)) - splitclean(); - splitclean(); - - split64(res, &lo1, &hi1); - gins(AMOVL, &ax, &lo1); - gins(AMOVL, &dx, &hi1); - splitclean(); - -out:; -} - -/* - * generate comparison of nl, nr, both 64-bit. - * nl is memory; nr is constant or memory. - */ -void -cmp64(Node *nl, Node *nr, int op, int likely, Prog *to) -{ - Node lo1, hi1, lo2, hi2, rr; - Prog *br; - Type *t; - - split64(nl, &lo1, &hi1); - split64(nr, &lo2, &hi2); - - // compare most significant word; - // if they differ, we're done. - t = hi1.type; - if(nl->op == OLITERAL || nr->op == OLITERAL) - gins(ACMPL, &hi1, &hi2); - else { - regalloc(&rr, types[TINT32], N); - gins(AMOVL, &hi1, &rr); - gins(ACMPL, &rr, &hi2); - regfree(&rr); - } - br = P; - switch(op) { - default: - fatal("cmp64 %O %T", op, t); - case OEQ: - // cmp hi - // jne L - // cmp lo - // jeq to - // L: - br = gbranch(AJNE, T, -likely); - break; - case ONE: - // cmp hi - // jne to - // cmp lo - // jne to - patch(gbranch(AJNE, T, likely), to); - break; - case OGE: - case OGT: - // cmp hi - // jgt to - // jlt L - // cmp lo - // jge to (or jgt to) - // L: - patch(gbranch(optoas(OGT, t), T, likely), to); - br = gbranch(optoas(OLT, t), T, -likely); - break; - case OLE: - case OLT: - // cmp hi - // jlt to - // jgt L - // cmp lo - // jle to (or jlt to) - // L: - patch(gbranch(optoas(OLT, t), T, likely), to); - br = gbranch(optoas(OGT, t), T, -likely); - break; - } - - // compare least significant word - t = lo1.type; - if(nl->op == OLITERAL || nr->op == OLITERAL) - gins(ACMPL, &lo1, &lo2); - else { - regalloc(&rr, types[TINT32], N); - gins(AMOVL, &lo1, &rr); - gins(ACMPL, &rr, &lo2); - regfree(&rr); - } - - // jump again - patch(gbranch(optoas(op, t), T, likely), to); - - // point first branch down here if appropriate - if(br != P) - patch(br, pc); - - splitclean(); - splitclean(); -} - diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go new file mode 100644 index 0000000000..1937ae0941 --- /dev/null +++ b/src/cmd/8g/cgen64.go @@ -0,0 +1,607 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" +) +import "cmd/internal/gc" + +/* + * attempt to generate 64-bit + * res = n + * return 1 on success, 0 if op not handled. + */ +func cgen64(n *gc.Node, res *gc.Node) { + var t1 gc.Node + var t2 gc.Node + var ax gc.Node + var dx gc.Node + var cx gc.Node + var ex gc.Node + var fx gc.Node + var l *gc.Node + var r *gc.Node + var lo1 gc.Node + var lo2 gc.Node + var hi1 gc.Node + var hi2 gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var v uint64 + var lv uint32 + var hv uint32 + + if res.Op != gc.OINDREG && res.Op != gc.ONAME { + gc.Dump("n", n) + gc.Dump("res", res) + gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) + } + + switch n.Op { + default: + gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0)) + + case gc.OMINUS: + cgen(n.Left, res) + split64(res, &lo1, &hi1) + gins(i386.ANEGL, nil, &lo1) + gins(i386.AADCL, ncon(0), &hi1) + gins(i386.ANEGL, nil, &hi1) + splitclean() + return + + case gc.OCOM: + cgen(n.Left, res) + split64(res, &lo1, &hi1) + gins(i386.ANOTL, nil, &lo1) + gins(i386.ANOTL, nil, &hi1) + splitclean() + return + + // binary operators. + // common setup below. + case gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OLROT, + gc.OLSH, + gc.ORSH, + gc.OAND, + gc.OOR, + gc.OXOR: + break + } + + l = n.Left + r = n.Right + if l.Addable == 0 { + gc.Tempname(&t1, l.Type) + cgen(l, &t1) + l = &t1 + } + + if r != nil && r.Addable == 0 { + gc.Tempname(&t2, r.Type) + cgen(r, &t2) + r = &t2 + } + + gc.Nodreg(&ax, gc.Types[gc.TINT32], i386.REG_AX) + gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX) + gc.Nodreg(&dx, gc.Types[gc.TINT32], i386.REG_DX) + + // Setup for binary operation. + split64(l, &lo1, &hi1) + + if gc.Is64(r.Type) { + split64(r, &lo2, &hi2) + } + + // Do op. Leave result in DX:AX. + switch n.Op { + // TODO: Constants + case gc.OADD: + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + gins(i386.AADDL, &lo2, &ax) + gins(i386.AADCL, &hi2, &dx) + + // TODO: Constants. + case gc.OSUB: + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + gins(i386.ASUBL, &lo2, &ax) + gins(i386.ASBBL, &hi2, &dx) + + // let's call the next two EX and FX. + case gc.OMUL: + regalloc(&ex, gc.Types[gc.TPTR32], nil) + + regalloc(&fx, gc.Types[gc.TPTR32], nil) + + // load args into DX:AX and EX:CX. + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + gins(i386.AMOVL, &lo2, &cx) + gins(i386.AMOVL, &hi2, &ex) + + // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply. + gins(i386.AMOVL, &dx, &fx) + + gins(i386.AORL, &ex, &fx) + p1 = gc.Gbranch(i386.AJNE, nil, 0) + gins(i386.AMULL, &cx, nil) // implicit &ax + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + + // full 64x64 -> 64, from 32x32 -> 64. + gins(i386.AIMULL, &cx, &dx) + + gins(i386.AMOVL, &ax, &fx) + gins(i386.AIMULL, &ex, &fx) + gins(i386.AADDL, &dx, &fx) + gins(i386.AMOVL, &cx, &dx) + gins(i386.AMULL, &dx, nil) // implicit &ax + gins(i386.AADDL, &fx, &dx) + gc.Patch(p2, gc.Pc) + + regfree(&ex) + regfree(&fx) + + // We only rotate by a constant c in [0,64). + // if c >= 32: + // lo, hi = hi, lo + // c -= 32 + // if c == 0: + // no-op + // else: + // t = hi + // shld hi:lo, c + // shld lo:t, c + case gc.OLROT: + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + + if v >= 32 { + // reverse during load to do the first 32 bits of rotate + v -= 32 + + gins(i386.AMOVL, &lo1, &dx) + gins(i386.AMOVL, &hi1, &ax) + } else { + gins(i386.AMOVL, &lo1, &ax) + gins(i386.AMOVL, &hi1, &dx) + } + + if v == 0 { + } else // done + { + gins(i386.AMOVL, &dx, &cx) + p1 = gins(i386.ASHLL, ncon(uint32(v)), &dx) + p1.From.Index = i386.REG_AX // double-width shift + p1.From.Scale = 0 + p1 = gins(i386.ASHLL, ncon(uint32(v)), &ax) + p1.From.Index = i386.REG_CX // double-width shift + p1.From.Scale = 0 + } + + case gc.OLSH: + if r.Op == gc.OLITERAL { + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + if v >= 64 { + if gc.Is64(r.Type) { + splitclean() + } + splitclean() + split64(res, &lo2, &hi2) + gins(i386.AMOVL, ncon(0), &lo2) + gins(i386.AMOVL, ncon(0), &hi2) + splitclean() + goto out + } + + if v >= 32 { + if gc.Is64(r.Type) { + splitclean() + } + split64(res, &lo2, &hi2) + gmove(&lo1, &hi2) + if v > 32 { + gins(i386.ASHLL, ncon(uint32(v-32)), &hi2) + } + + gins(i386.AMOVL, ncon(0), &lo2) + splitclean() + splitclean() + goto out + } + + // general shift + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + p1 = gins(i386.ASHLL, ncon(uint32(v)), &dx) + p1.From.Index = i386.REG_AX // double-width shift + p1.From.Scale = 0 + gins(i386.ASHLL, ncon(uint32(v)), &ax) + break + } + + // load value into DX:AX. + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + + // load shift value into register. + // if high bits are set, zero value. + p1 = nil + + if gc.Is64(r.Type) { + gins(i386.ACMPL, &hi2, ncon(0)) + p1 = gc.Gbranch(i386.AJNE, nil, +1) + gins(i386.AMOVL, &lo2, &cx) + } else { + cx.Type = gc.Types[gc.TUINT32] + gmove(r, &cx) + } + + // if shift count is >=64, zero value + gins(i386.ACMPL, &cx, ncon(64)) + + p2 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + if p1 != nil { + gc.Patch(p1, gc.Pc) + } + gins(i386.AXORL, &dx, &dx) + gins(i386.AXORL, &ax, &ax) + gc.Patch(p2, gc.Pc) + + // if shift count is >= 32, zero low. + gins(i386.ACMPL, &cx, ncon(32)) + + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + gins(i386.AMOVL, &ax, &dx) + gins(i386.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count + gins(i386.AXORL, &ax, &ax) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + + // general shift + p1 = gins(i386.ASHLL, &cx, &dx) + + p1.From.Index = i386.REG_AX // double-width shift + p1.From.Scale = 0 + gins(i386.ASHLL, &cx, &ax) + gc.Patch(p2, gc.Pc) + + case gc.ORSH: + if r.Op == gc.OLITERAL { + v = uint64(gc.Mpgetfix(r.Val.U.Xval)) + if v >= 64 { + if gc.Is64(r.Type) { + splitclean() + } + splitclean() + split64(res, &lo2, &hi2) + if hi1.Type.Etype == gc.TINT32 { + gmove(&hi1, &lo2) + gins(i386.ASARL, ncon(31), &lo2) + gmove(&hi1, &hi2) + gins(i386.ASARL, ncon(31), &hi2) + } else { + gins(i386.AMOVL, ncon(0), &lo2) + gins(i386.AMOVL, ncon(0), &hi2) + } + + splitclean() + goto out + } + + if v >= 32 { + if gc.Is64(r.Type) { + splitclean() + } + split64(res, &lo2, &hi2) + gmove(&hi1, &lo2) + if v > 32 { + gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2) + } + if hi1.Type.Etype == gc.TINT32 { + gmove(&hi1, &hi2) + gins(i386.ASARL, ncon(31), &hi2) + } else { + gins(i386.AMOVL, ncon(0), &hi2) + } + splitclean() + splitclean() + goto out + } + + // general shift + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + p1 = gins(i386.ASHRL, ncon(uint32(v)), &ax) + p1.From.Index = i386.REG_DX // double-width shift + p1.From.Scale = 0 + gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx) + break + } + + // load value into DX:AX. + gins(i386.AMOVL, &lo1, &ax) + + gins(i386.AMOVL, &hi1, &dx) + + // load shift value into register. + // if high bits are set, zero value. + p1 = nil + + if gc.Is64(r.Type) { + gins(i386.ACMPL, &hi2, ncon(0)) + p1 = gc.Gbranch(i386.AJNE, nil, +1) + gins(i386.AMOVL, &lo2, &cx) + } else { + cx.Type = gc.Types[gc.TUINT32] + gmove(r, &cx) + } + + // if shift count is >=64, zero or sign-extend value + gins(i386.ACMPL, &cx, ncon(64)) + + p2 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + if p1 != nil { + gc.Patch(p1, gc.Pc) + } + if hi1.Type.Etype == gc.TINT32 { + gins(i386.ASARL, ncon(31), &dx) + gins(i386.AMOVL, &dx, &ax) + } else { + gins(i386.AXORL, &dx, &dx) + gins(i386.AXORL, &ax, &ax) + } + + gc.Patch(p2, gc.Pc) + + // if shift count is >= 32, sign-extend hi. + gins(i386.ACMPL, &cx, ncon(32)) + + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + gins(i386.AMOVL, &dx, &ax) + if hi1.Type.Etype == gc.TINT32 { + gins(i386.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count + gins(i386.ASARL, ncon(31), &dx) + } else { + gins(i386.ASHRL, &cx, &ax) + gins(i386.AXORL, &dx, &dx) + } + + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + + // general shift + p1 = gins(i386.ASHRL, &cx, &ax) + + p1.From.Index = i386.REG_DX // double-width shift + p1.From.Scale = 0 + gins(optoas(gc.ORSH, hi1.Type), &cx, &dx) + gc.Patch(p2, gc.Pc) + + // make constant the right side (it usually is anyway). + case gc.OXOR, + gc.OAND, + gc.OOR: + if lo1.Op == gc.OLITERAL { + nswap(&lo1, &lo2) + nswap(&hi1, &hi2) + } + + if lo2.Op == gc.OLITERAL { + // special cases for constants. + lv = uint32(gc.Mpgetfix(lo2.Val.U.Xval)) + + hv = uint32(gc.Mpgetfix(hi2.Val.U.Xval)) + splitclean() // right side + split64(res, &lo2, &hi2) + switch n.Op { + case gc.OXOR: + gmove(&lo1, &lo2) + gmove(&hi1, &hi2) + switch lv { + case 0: + break + + case 0xffffffff: + gins(i386.ANOTL, nil, &lo2) + + default: + gins(i386.AXORL, ncon(lv), &lo2) + } + + switch hv { + case 0: + break + + case 0xffffffff: + gins(i386.ANOTL, nil, &hi2) + + default: + gins(i386.AXORL, ncon(hv), &hi2) + } + + case gc.OAND: + switch lv { + case 0: + gins(i386.AMOVL, ncon(0), &lo2) + + default: + gmove(&lo1, &lo2) + if lv != 0xffffffff { + gins(i386.AANDL, ncon(lv), &lo2) + } + } + + switch hv { + case 0: + gins(i386.AMOVL, ncon(0), &hi2) + + default: + gmove(&hi1, &hi2) + if hv != 0xffffffff { + gins(i386.AANDL, ncon(hv), &hi2) + } + } + + case gc.OOR: + switch lv { + case 0: + gmove(&lo1, &lo2) + + case 0xffffffff: + gins(i386.AMOVL, ncon(0xffffffff), &lo2) + + default: + gmove(&lo1, &lo2) + gins(i386.AORL, ncon(lv), &lo2) + } + + switch hv { + case 0: + gmove(&hi1, &hi2) + + case 0xffffffff: + gins(i386.AMOVL, ncon(0xffffffff), &hi2) + + default: + gmove(&hi1, &hi2) + gins(i386.AORL, ncon(hv), &hi2) + } + } + + splitclean() + splitclean() + goto out + } + + gins(i386.AMOVL, &lo1, &ax) + gins(i386.AMOVL, &hi1, &dx) + gins(optoas(int(n.Op), lo1.Type), &lo2, &ax) + gins(optoas(int(n.Op), lo1.Type), &hi2, &dx) + } + + if gc.Is64(r.Type) { + splitclean() + } + splitclean() + + split64(res, &lo1, &hi1) + gins(i386.AMOVL, &ax, &lo1) + gins(i386.AMOVL, &dx, &hi1) + splitclean() + +out: +} + +/* + * generate comparison of nl, nr, both 64-bit. + * nl is memory; nr is constant or memory. + */ +func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) { + var lo1 gc.Node + var hi1 gc.Node + var lo2 gc.Node + var hi2 gc.Node + var rr gc.Node + var br *obj.Prog + var t *gc.Type + + split64(nl, &lo1, &hi1) + split64(nr, &lo2, &hi2) + + // compare most significant word; + // if they differ, we're done. + t = hi1.Type + + if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { + gins(i386.ACMPL, &hi1, &hi2) + } else { + regalloc(&rr, gc.Types[gc.TINT32], nil) + gins(i386.AMOVL, &hi1, &rr) + gins(i386.ACMPL, &rr, &hi2) + regfree(&rr) + } + + br = nil + switch op { + default: + gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + // cmp hi + // jne L + // cmp lo + // jeq to + // L: + case gc.OEQ: + br = gc.Gbranch(i386.AJNE, nil, -likely) + + // cmp hi + // jne to + // cmp lo + // jne to + case gc.ONE: + gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to) + + // cmp hi + // jgt to + // jlt L + // cmp lo + // jge to (or jgt to) + // L: + case gc.OGE, + gc.OGT: + gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) + + br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) + + // cmp hi + // jlt to + // jgt L + // cmp lo + // jle to (or jlt to) + // L: + case gc.OLE, + gc.OLT: + gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) + + br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) + } + + // compare least significant word + t = lo1.Type + + if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { + gins(i386.ACMPL, &lo1, &lo2) + } else { + regalloc(&rr, gc.Types[gc.TINT32], nil) + gins(i386.AMOVL, &lo1, &rr) + gins(i386.ACMPL, &rr, &lo2) + regfree(&rr) + } + + // jump again + gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) + + // point first branch down here if appropriate + if br != nil { + gc.Patch(br, gc.Pc) + } + + splitclean() + splitclean() +} diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go deleted file mode 100644 index 9e46dcad8f..0000000000 --- a/src/cmd/8g/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -8g is the version of the gc compiler for the x86. -The $GOARCH for these tools is 386. - -It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go. - -*/ -package main diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c deleted file mode 100644 index 33951adfd2..0000000000 --- a/src/cmd/8g/galign.c +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -int thechar = '8'; -char* thestring = "386"; -LinkArch* thelinkarch = &link386; - -void -linkarchinit(void) -{ -} - -vlong MAXWIDTH = (1LL<<32) - 1; - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -Typedef typedefs[] = -{ - {"int", TINT, TINT32}, - {"uint", TUINT, TUINT32}, - {"uintptr", TUINTPTR, TUINT32}, - {0} -}; - -void -betypeinit(void) -{ - widthptr = 4; - widthint = 4; - widthreg = 4; - - listinit8(); -} - -void -main(int argc, char **argv) -{ - thearch.thechar = thechar; - thearch.thestring = thestring; - thearch.thelinkarch = thelinkarch; - thearch.typedefs = typedefs; - thearch.REGSP = REGSP; - thearch.REGCTXT = REGCTXT; - thearch.MAXWIDTH = MAXWIDTH; - thearch.anyregalloc = anyregalloc; - thearch.betypeinit = betypeinit; - thearch.bgen = bgen; - thearch.cgen = cgen; - thearch.cgen_call = cgen_call; - thearch.cgen_callinter = cgen_callinter; - thearch.cgen_ret = cgen_ret; - thearch.clearfat = clearfat; - thearch.defframe = defframe; - thearch.excise = excise; - thearch.expandchecks = expandchecks; - thearch.gclean = gclean; - thearch.ginit = ginit; - thearch.gins = gins; - thearch.ginscall = ginscall; - thearch.igen = igen; - thearch.linkarchinit = linkarchinit; - thearch.peep = peep; - thearch.proginfo = proginfo; - thearch.regalloc = regalloc; - thearch.regfree = regfree; - thearch.regtyp = regtyp; - thearch.sameaddr = sameaddr; - thearch.smallindir = smallindir; - thearch.stackaddr = stackaddr; - thearch.excludedregs = excludedregs; - thearch.RtoB = RtoB; - thearch.FtoB = FtoB; - thearch.BtoR = BtoR; - thearch.BtoF = BtoF; - thearch.optoas = optoas; - thearch.doregbits = doregbits; - thearch.regnames = regnames; - - gcmain(argc, argv); -} diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go new file mode 100644 index 0000000000..45ef1302f3 --- /dev/null +++ b/src/cmd/8g/galign.go @@ -0,0 +1,85 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" +) +import "cmd/internal/gc" + +var thechar int = '8' + +var thestring string = "386" + +var thelinkarch *obj.LinkArch = &i386.Link386 + +func linkarchinit() { +} + +var MAXWIDTH int64 = (1 << 32) - 1 + +/* + * go declares several platform-specific type aliases: + * int, uint, float, and uintptr + */ +var typedefs = []gc.Typedef{ + gc.Typedef{"int", gc.TINT, gc.TINT32}, + gc.Typedef{"uint", gc.TUINT, gc.TUINT32}, + gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32}, +} + +func betypeinit() { + gc.Widthptr = 4 + gc.Widthint = 4 + gc.Widthreg = 4 + +} + +func main() { + gc.Thearch.Thechar = thechar + gc.Thearch.Thestring = thestring + gc.Thearch.Thelinkarch = thelinkarch + gc.Thearch.Typedefs = typedefs + gc.Thearch.REGSP = i386.REGSP + gc.Thearch.REGCTXT = i386.REGCTXT + gc.Thearch.MAXWIDTH = MAXWIDTH + gc.Thearch.Anyregalloc = anyregalloc + gc.Thearch.Betypeinit = betypeinit + gc.Thearch.Bgen = bgen + gc.Thearch.Cgen = cgen + gc.Thearch.Cgen_call = cgen_call + gc.Thearch.Cgen_callinter = cgen_callinter + gc.Thearch.Cgen_ret = cgen_ret + gc.Thearch.Clearfat = clearfat + gc.Thearch.Defframe = defframe + gc.Thearch.Excise = excise + gc.Thearch.Expandchecks = expandchecks + gc.Thearch.Gclean = gclean + gc.Thearch.Ginit = ginit + gc.Thearch.Gins = gins + gc.Thearch.Ginscall = ginscall + gc.Thearch.Igen = igen + gc.Thearch.Linkarchinit = linkarchinit + gc.Thearch.Peep = peep + gc.Thearch.Proginfo = proginfo + gc.Thearch.Regalloc = regalloc + gc.Thearch.Regfree = regfree + gc.Thearch.Regtyp = regtyp + gc.Thearch.Sameaddr = sameaddr + gc.Thearch.Smallindir = smallindir + gc.Thearch.Stackaddr = stackaddr + gc.Thearch.Excludedregs = excludedregs + gc.Thearch.RtoB = RtoB + gc.Thearch.FtoB = FtoB + gc.Thearch.BtoR = BtoR + gc.Thearch.BtoF = BtoF + gc.Thearch.Optoas = optoas + gc.Thearch.Doregbits = doregbits + gc.Thearch.Regnames = regnames + + gc.Main() + gc.Exit(0) +} diff --git a/src/cmd/8g/gg.go b/src/cmd/8g/gg.go new file mode 100644 index 0000000000..4aeff92952 --- /dev/null +++ b/src/cmd/8g/gg.go @@ -0,0 +1,34 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "cmd/internal/obj/i386" +import "cmd/internal/gc" + +// TODO(rsc): +// assume CLD? + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// foptoas flags +const ( + Frev = 1 << 0 + Fpop = 1 << 1 + Fpop2 = 1 << 2 +) + +var reg [i386.MAXREG]uint8 + +var panicdiv *gc.Node + +/* + * cgen.c + */ + +/* + * list.c + */ diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h deleted file mode 100644 index 872d946592..0000000000 --- a/src/cmd/8g/gg.h +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef EXTERN -#define EXTERN extern -#endif - -#include "../gc/go.h" -#include "../8l/8.out.h" - -// foptoas flags -enum -{ - Frev = 1<<0, - Fpop = 1<<1, - Fpop2 = 1<<2, -}; - -EXTERN uchar reg[MAXREG]; -EXTERN Node* panicdiv; -extern uint32 unmappedzero; - - -/* - * ggen.c - */ -void compile(Node*); -void gen(Node*); -Node* lookdot(Node*, Node*, int); -void cgen_as(Node*, Node*); -void cgen_callmeth(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_proc(Node*, int); -void cgen_callret(Node*, Node*); -void cgen_div(int, Node*, Node*, Node*); -void cgen_bmul(int, Node*, Node*, Node*); -void cgen_hmul(Node*, Node*, Node*); -void cgen_shift(int, int, Node*, Node*, Node*); -void cgen_float(Node*, Node*); -void bgen_float(Node *n, int true, int likely, Prog *to); -void cgen_dcl(Node*); -int needconvert(Type*, Type*); -void genconv(Type*, Type*); -void allocparams(void); -void checklabels(void); -void ginscall(Node*, int); - -/* - * cgen.c - */ -void agen(Node*, Node*); -void igen(Node*, Node*, Node*); -vlong fieldoffset(Type*, Node*); -void sgen(Node*, Node*, int64); -void gmove(Node*, Node*); -Prog* gins(int, Node*, Node*); -int samaddr(Node*, Node*); -void naddr(Node*, Addr*, int); -void cgen_aret(Node*, Node*); -Node* ncon(uint32); -void mgen(Node*, Node*, Node*); -void mfree(Node*); -int componentgen(Node*, Node*); - -/* - * cgen64.c - */ -void cmp64(Node*, Node*, int, int, Prog*); -void cgen64(Node*, Node*); - -/* - * gsubr.c - */ -void clearp(Prog*); -Prog* gbranch(int, Type*, int); -Prog* prog(int); -void gconv(int, int); -int conv2pt(Type*); -vlong convvtox(vlong, int); -void fnparam(Type*, int, int); -Prog* gop(int, Node*, Node*, Node*); -int optoas(int, Type*); -int foptoas(int, Type*, int); -void ginit(void); -void gclean(void); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -Node* nodarg(Type*, int); -void nodreg(Node*, Type*, int); -void nodindreg(Node*, Type*, int); -void nodconst(Node*, Type*, int64); -void gconreg(int, vlong, int); -void buildtxt(void); -Plist* newplist(void); -int isfat(Type*); -void sudoclean(void); -int sudoaddable(int, Node*, Addr*); -int dotaddable(Node*, Node*); -void afunclit(Addr*, Node*); -void split64(Node*, Node*, Node*); -void splitclean(void); -void nswap(Node*, Node*); -void gtrack(Sym*); -/* - * cplx.c - */ -int complexop(Node*, Node*); -void complexmove(Node*, Node*); -void complexgen(Node*, Node*); - -/* - * gobj.c - */ -void datastring(char*, int, Addr*); -void datagostring(Strlit*, Addr*); - -/* - * list.c - */ -void listinit(void); - -void zaddr(Biobuf*, Addr*, int, int); - -void afunclit(Addr*, Node*); -int anyregalloc(void); -void betypeinit(void); -void bgen(Node*, int, int, Prog*); -void cgen(Node*, Node*); -void cgen_call(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_ret(Node*); -void clearfat(Node*); -void clearp(Prog*); -void defframe(Prog*); -int dgostringptr(Sym*, int, char*); -int dgostrlitptr(Sym*, int, Strlit*); -int dsname(Sym*, int, char*, int); -int dsymptr(Sym*, int, Sym*, int); -void dumpdata(void); -void dumpit(char*, Flow*, int); -void excise(Flow*); -void expandchecks(Prog*); -void fixautoused(Prog*); -void gclean(void); -void gdata(Node*, Node*, int); -void gdatacomplex(Node*, Mpcplx*); -void gdatastring(Node*, Strlit*); -void ggloblnod(Node *nam); -void ggloblsym(Sym *s, int32 width, int8 flags); -void ginit(void); -Prog* gins(int, Node*, Node*); -void ginscall(Node*, int); -Prog* gjmp(Prog*); -void gtrack(Sym*); -void gused(Node*); -void igen(Node*, Node*, Node*); -int isfat(Type*); -void linkarchinit(void); -void markautoused(Prog*); -void naddr(Node*, Addr*, int); -Plist* newplist(void); -Node* nodarg(Type*, int); -void patch(Prog*, Prog*); -void proginfo(ProgInfo*, Prog*); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -void regopt(Prog*); -int regtyp(Addr*); -int sameaddr(Addr*, Addr*); -int smallindir(Addr*, Addr*); -int stackaddr(Addr*); -Prog* unpatch(Prog*); - -/* - * reg.c - */ -uint64 excludedregs(void); -uint64 RtoB(int); -uint64 FtoB(int); -int BtoR(uint64); -int BtoF(uint64); -uint64 doregbits(int); -char** regnames(int*); - -/* - * peep.c - */ -void peep(Prog*); diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c deleted file mode 100644 index 8188348282..0000000000 --- a/src/cmd/8g/ggen.c +++ /dev/null @@ -1,1165 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#undef EXTERN -#define EXTERN -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static Prog *appendpp(Prog*, int, int, int, vlong, int, int, vlong); -static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax); - -void -defframe(Prog *ptxt) -{ - uint32 frame, ax; - Prog *p; - vlong lo, hi; - NodeList *l; - Node *n; - - // fill in argument size, stack size - ptxt->to.type = TYPE_TEXTSIZE; - ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr); - frame = rnd(stksize+maxarg, widthreg); - ptxt->to.offset = frame; - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt; - hi = 0; - lo = hi; - ax = 0; - for(l=curfn->dcl; l != nil; l = l->next) { - n = l->n; - if(!n->needzero) - continue; - if(n->class != PAUTO) - fatal("needzero class %d", n->class); - if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) - fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); - if(lo != hi && n->xoffset + n->type->width == lo - 2*widthptr) { - // merge with range we already have - lo = n->xoffset; - continue; - } - // zero old range - p = zerorange(p, frame, lo, hi, &ax); - - // set new range - hi = n->xoffset + n->type->width; - lo = n->xoffset; - } - // zero final range - zerorange(p, frame, lo, hi, &ax); -} - -static Prog* -zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax) -{ - vlong cnt, i; - - cnt = hi - lo; - if(cnt == 0) - return p; - if(*ax == 0) { - p = appendpp(p, AMOVL, TYPE_CONST, 0, 0, TYPE_REG, REG_AX, 0); - *ax = 1; - } - if(cnt <= 4*widthreg) { - for(i = 0; i < cnt; i += widthreg) { - p = appendpp(p, AMOVL, TYPE_REG, REG_AX, 0, TYPE_MEM, REG_SP, frame+lo+i); - } - } else if(!nacl && cnt <= 128*widthreg) { - p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0); - p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_ADDR, 0, 1*(128-cnt/widthreg)); - p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - } else { - p = appendpp(p, AMOVL, TYPE_CONST, 0, cnt/widthreg, TYPE_REG, REG_CX, 0); - p = appendpp(p, ALEAL, TYPE_MEM, REG_SP, frame+lo, TYPE_REG, REG_DI, 0); - p = appendpp(p, AREP, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0); - p = appendpp(p, ASTOSL, TYPE_NONE, 0, 0, TYPE_NONE, 0, 0); - } - return p; -} - -static Prog* -appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset) -{ - Prog *q; - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; -} - -void -clearfat(Node *nl) -{ - uint32 w, c, q; - Node n1, z; - Prog *p; - - /* clear a fat object */ - if(debug['g']) - dump("\nclearfat", nl); - - w = nl->type->width; - // Avoid taking the address for simple enough types. - if(componentgen(N, nl)) - return; - - c = w % 4; // bytes - q = w / 4; // quads - - if(q < 4) { - // Write sequence of MOV 0, off(base) instead of using STOSL. - // The hope is that although the code will be slightly longer, - // the MOVs will have no dependencies and pipeline better - // than the unrolled STOSL loop. - // NOTE: Must use agen, not igen, so that optimizer sees address - // being taken. We are not writing on field boundaries. - regalloc(&n1, types[tptr], N); - agen(nl, &n1); - n1.op = OINDREG; - nodconst(&z, types[TUINT64], 0); - while(q-- > 0) { - n1.type = z.type; - gins(AMOVL, &z, &n1); - n1.xoffset += 4; - } - nodconst(&z, types[TUINT8], 0); - while(c-- > 0) { - n1.type = z.type; - gins(AMOVB, &z, &n1); - n1.xoffset++; - } - regfree(&n1); - return; - } - - nodreg(&n1, types[tptr], REG_DI); - agen(nl, &n1); - gconreg(AMOVL, 0, REG_AX); - - if(q > 128 || (q >= 4 && nacl)) { - gconreg(AMOVL, q, REG_CX); - gins(AREP, N, N); // repeat - gins(ASTOSL, N, N); // STOL AL,*(DI)+ - } else if(q >= 4) { - p = gins(ADUFFZERO, N, N); - p->to.type = TYPE_ADDR; - p->to.sym = linksym(pkglookup("duffzero", runtimepkg)); - // 1 and 128 = magic constants: see ../../runtime/asm_386.s - p->to.offset = 1*(128-q); - } else - while(q > 0) { - gins(ASTOSL, N, N); // STOL AL,*(DI)+ - q--; - } - - while(c > 0) { - gins(ASTOSB, N, N); // STOB AL,*(DI)+ - c--; - } -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) - */ -void -ginscall(Node *f, int proc) -{ - Prog *p; - Node reg, r1, con, stk; - int32 extra; - - if(f->type != T) { - extra = 0; - if(proc == 1 || proc == 2) - extra = 2 * widthptr; - setmaxarg(f->type, extra); - } - - switch(proc) { - default: - fatal("ginscall: bad proc %d", proc); - break; - - case 0: // normal call - case -1: // normal call but no return - if(f->op == ONAME && f->class == PFUNC) { - if(f == deferreturn) { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an x86 NOP that we will have the right line number. - // x86 NOP 0x90 is really XCHG AX, AX; use that description - // because the NOP pseudo-instruction will be removed by - // the linker. - nodreg(®, types[TINT], REG_AX); - gins(AXCHGL, ®, ®); - } - p = gins(ACALL, N, f); - afunclit(&p->to, f); - if(proc == -1 || noreturn(p)) - gins(AUNDEF, N, N); - break; - } - nodreg(®, types[tptr], REG_DX); - nodreg(&r1, types[tptr], REG_BX); - gmove(f, ®); - reg.op = OINDREG; - gmove(®, &r1); - reg.op = OREGISTER; - gins(ACALL, ®, &r1); - break; - - case 3: // normal call of c function pointer - gins(ACALL, N, f); - break; - - case 1: // call in new proc (go) - case 2: // deferred call (defer) - memset(&stk, 0, sizeof(stk)); - stk.op = OINDREG; - stk.val.u.reg = REG_SP; - stk.xoffset = 0; - - // size of arguments at 0(SP) - nodconst(&con, types[TINT32], argsize(f->type)); - gins(AMOVL, &con, &stk); - - // FuncVal* at 4(SP) - stk.xoffset = widthptr; - gins(AMOVL, f, &stk); - - if(proc == 1) - ginscall(newproc, 0); - else - ginscall(deferproc, 0); - if(proc == 2) { - nodreg(®, types[TINT32], REG_AX); - gins(ATESTL, ®, ®); - p = gbranch(AJEQ, T, +1); - cgen_ret(N); - patch(p, pc); - } - break; - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -void -cgen_callinter(Node *n, Node *res, int proc) -{ - Node *i, *f; - Node tmpi, nodi, nodo, nodr, nodsp; - - i = n->left; - if(i->op != ODOTINTER) - fatal("cgen_callinter: not ODOTINTER %O", i->op); - - f = i->right; // field - if(f->op != ONAME) - fatal("cgen_callinter: not ONAME %O", f->op); - - i = i->left; // interface - - if(!i->addable) { - tempname(&tmpi, i->type); - cgen(i, &tmpi); - i = &tmpi; - } - - genlist(n->list); // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res); // REG = &inter - - nodindreg(&nodsp, types[tptr], REG_SP); - nodsp.xoffset = 0; - if(proc != 0) - nodsp.xoffset += 2 * widthptr; // leave room for size & fn - nodi.type = types[tptr]; - nodi.xoffset += widthptr; - cgen(&nodi, &nodsp); // {0 or 8}(SP) = 4(REG) -- i.data - - regalloc(&nodo, types[tptr], res); - nodi.type = types[tptr]; - nodi.xoffset -= widthptr; - cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab - regfree(&nodi); - - regalloc(&nodr, types[tptr], &nodo); - if(n->left->xoffset == BADWIDTH) - fatal("cgen_callinter: badwidth"); - cgen_checknil(&nodo); - nodo.op = OINDREG; - nodo.xoffset = n->left->xoffset + 3*widthptr + 8; - - if(proc == 0) { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr); // REG = 20+offset(REG) -- i.tab->fun[f] - proc = 3; - } else { - // go/defer. generate go func value. - gins(ALEAL, &nodo, &nodr); // REG = &(20+offset(REG)) -- i.tab->fun[f] - } - - nodr.type = n->left->type; - ginscall(&nodr, proc); - - regfree(&nodr); - regfree(&nodo); -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -void -cgen_call(Node *n, int proc) -{ - Type *t; - Node nod, afun; - - if(n == N) - return; - - if(n->left->ullman >= UINF) { - // if name involves a fn call - // precompute the address of the fn - tempname(&afun, types[tptr]); - cgen(n->left, &afun); - } - - genlist(n->list); // assign the args - t = n->left->type; - - // call tempname pointer - if(n->left->ullman >= UINF) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, &afun); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call pointer - if(n->left->op != ONAME || n->left->class != PFUNC) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, n->left); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call direct - n->left->method = 1; - ginscall(n->left, proc); -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -void -cgen_callret(Node *n, Node *res) -{ - Node nod; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(t->etype == TPTR32 || t->etype == TPTR64) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_callret: nil"); - - memset(&nod, 0, sizeof(nod)); - nod.op = OINDREG; - nod.val.u.reg = REG_SP; - nod.addable = 1; - - nod.xoffset = fp->width; - nod.type = fp->type; - cgen_as(res, &nod); -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -void -cgen_aret(Node *n, Node *res) -{ - Node nod1, nod2; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_aret: nil"); - - memset(&nod1, 0, sizeof(nod1)); - nod1.op = OINDREG; - nod1.val.u.reg = REG_SP; - nod1.addable = 1; - - nod1.xoffset = fp->width; - nod1.type = fp->type; - - if(res->op != OREGISTER) { - regalloc(&nod2, types[tptr], res); - gins(ALEAL, &nod1, &nod2); - gins(AMOVL, &nod2, res); - regfree(&nod2); - } else - gins(ALEAL, &nod1, res); -} - -/* - * generate return. - * n->left is assignments to return values. - */ -void -cgen_ret(Node *n) -{ - Prog *p; - - if(n != N) - genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - genlist(curfn->exit); - p = gins(ARET, N, N); - if(n != N && n->op == ORETJMP) { - p->to.type = TYPE_MEM; - p->to.name = NAME_EXTERN; - p->to.sym = linksym(n->left->sym); - } -} - -/* - * generate division. - * caller must set: - * ax = allocated AX register - * dx = allocated DX register - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -void -dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) -{ - int check; - Node n1, t1, t2, t3, t4, n4, nz; - Type *t, *t0; - Prog *p1, *p2; - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will trap. - // Also the byte divide instruction needs AH, - // which we otherwise don't have to deal with. - // Easiest way to avoid for int8, int16: use int32. - // For int32 and int64, use explicit test. - // Could use int64 hw for int32. - t = nl->type; - t0 = t; - check = 0; - if(issigned[t->etype]) { - check = 1; - if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1)) - check = 0; - else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1) - check = 0; - } - if(t->width < 4) { - if(issigned[t->etype]) - t = types[TINT32]; - else - t = types[TUINT32]; - check = 0; - } - - tempname(&t1, t); - tempname(&t2, t); - if(t0 != t) { - tempname(&t3, t0); - tempname(&t4, t0); - cgen(nl, &t3); - cgen(nr, &t4); - // Convert. - gmove(&t3, &t1); - gmove(&t4, &t2); - } else { - cgen(nl, &t1); - cgen(nr, &t2); - } - - if(!samereg(ax, res) && !samereg(dx, res)) - regalloc(&n1, t, res); - else - regalloc(&n1, t, N); - gmove(&t2, &n1); - gmove(&t1, ax); - p2 = P; - if(nacl) { - // Native Client does not relay the divide-by-zero trap - // to the executing program, so we must insert a check - // for ourselves. - nodconst(&n4, t, 0); - gins(optoas(OCMP, t), &n1, &n4); - p1 = gbranch(optoas(ONE, t), T, +1); - if(panicdiv == N) - panicdiv = sysfunc("panicdivide"); - ginscall(panicdiv, -1); - patch(p1, pc); - } - if(check) { - nodconst(&n4, t, -1); - gins(optoas(OCMP, t), &n1, &n4); - p1 = gbranch(optoas(ONE, t), T, +1); - if(op == ODIV) { - // a / (-1) is -a. - gins(optoas(OMINUS, t), N, ax); - gmove(ax, res); - } else { - // a % (-1) is 0. - nodconst(&n4, t, 0); - gmove(&n4, res); - } - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - } - if(!issigned[t->etype]) { - nodconst(&nz, t, 0); - gmove(&nz, dx); - } else - gins(optoas(OEXTEND, t), N, N); - gins(optoas(op, t), &n1, N); - regfree(&n1); - - if(op == ODIV) - gmove(ax, res); - else - gmove(dx, res); - if(check) - patch(p2, pc); -} - -static void -savex(int dr, Node *x, Node *oldx, Node *res, Type *t) -{ - int r; - - r = reg[dr]; - nodreg(x, types[TINT32], dr); - - // save current ax and dx if they are live - // and not the destination - memset(oldx, 0, sizeof *oldx); - if(r > 0 && !samereg(x, res)) { - tempname(oldx, types[TINT32]); - gmove(x, oldx); - } - - regalloc(x, t, x); -} - -static void -restx(Node *x, Node *oldx) -{ - regfree(x); - - if(oldx->op != 0) { - x->type = types[TINT32]; - gmove(oldx, x); - } -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -void -cgen_div(int op, Node *nl, Node *nr, Node *res) -{ - Node ax, dx, oldax, olddx; - Type *t; - - if(is64(nl->type)) - fatal("cgen_div %T", nl->type); - - if(issigned[nl->type->etype]) - t = types[TINT32]; - else - t = types[TUINT32]; - savex(REG_AX, &ax, &oldax, res, t); - savex(REG_DX, &dx, &olddx, res, t); - dodiv(op, nl, nr, res, &ax, &dx); - restx(&dx, &olddx); - restx(&ax, &oldax); -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -void -cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, nt, cx, oldcx, hi, lo; - int a, w; - Prog *p1, *p2; - uvlong sc; - - if(nl->type->width > 4) - fatal("cgen_shift %T", nl->type); - - w = nl->type->width * 8; - - a = optoas(op, nl->type); - - if(nr->op == OLITERAL) { - tempname(&n2, nl->type); - cgen(nl, &n2); - regalloc(&n1, nl->type, res); - gmove(&n2, &n1); - sc = mpgetfix(nr->val.u.xval); - if(sc >= nl->type->width*8) { - // large shift gets 2 shifts by width-1 - gins(a, ncon(w-1), &n1); - gins(a, ncon(w-1), &n1); - } else - gins(a, nr, &n1); - gmove(&n1, res); - regfree(&n1); - return; - } - - memset(&oldcx, 0, sizeof oldcx); - nodreg(&cx, types[TUINT32], REG_CX); - if(reg[REG_CX] > 1 && !samereg(&cx, res)) { - tempname(&oldcx, types[TUINT32]); - gmove(&cx, &oldcx); - } - - if(nr->type->width > 4) { - tempname(&nt, nr->type); - n1 = nt; - } else { - nodreg(&n1, types[TUINT32], REG_CX); - regalloc(&n1, nr->type, &n1); // to hold the shift type in CX - } - - if(samereg(&cx, res)) - regalloc(&n2, nl->type, N); - else - regalloc(&n2, nl->type, res); - if(nl->ullman >= nr->ullman) { - cgen(nl, &n2); - cgen(nr, &n1); - } else { - cgen(nr, &n1); - cgen(nl, &n2); - } - - // test and fix up large shifts - if(bounded) { - if(nr->type->width > 4) { - // delayed reg alloc - nodreg(&n1, types[TUINT32], REG_CX); - regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX - split64(&nt, &lo, &hi); - gmove(&lo, &n1); - splitclean(); - } - } else { - if(nr->type->width > 4) { - // delayed reg alloc - nodreg(&n1, types[TUINT32], REG_CX); - regalloc(&n1, types[TUINT32], &n1); // to hold the shift type in CX - split64(&nt, &lo, &hi); - gmove(&lo, &n1); - gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0)); - p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1); - gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w)); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - splitclean(); - patch(p2, pc); - } else { - gins(optoas(OCMP, nr->type), &n1, ncon(w)); - p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1); - } - if(op == ORSH && issigned[nl->type->etype]) { - gins(a, ncon(w-1), &n2); - } else { - gmove(ncon(0), &n2); - } - patch(p1, pc); - } - gins(a, &n1, &n2); - - if(oldcx.op != 0) - gmove(&oldcx, &cx); - - gmove(&n2, res); - - regfree(&n1); - regfree(&n2); -} - -/* - * generate byte multiply: - * res = nl * nr - * there is no 2-operand byte multiply instruction so - * we do a full-width multiplication and truncate afterwards. - */ -void -cgen_bmul(int op, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, nt, *tmp; - Type *t; - int a; - - // copy from byte to full registers - t = types[TUINT32]; - if(issigned[nl->type->etype]) - t = types[TINT32]; - - // largest ullman on left. - if(nl->ullman < nr->ullman) { - tmp = nl; - nl = nr; - nr = tmp; - } - - tempname(&nt, nl->type); - cgen(nl, &nt); - regalloc(&n1, t, res); - cgen(nr, &n1); - regalloc(&n2, t, N); - gmove(&nt, &n2); - a = optoas(op, t); - gins(a, &n2, &n1); - regfree(&n2); - gmove(&n1, res); - regfree(&n1); -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -void -cgen_hmul(Node *nl, Node *nr, Node *res) -{ - Type *t; - int a; - Node n1, n2, ax, dx; - - t = nl->type; - a = optoas(OHMUL, t); - // gen nl in n1. - tempname(&n1, t); - cgen(nl, &n1); - // gen nr in n2. - regalloc(&n2, t, res); - cgen(nr, &n2); - - // multiply. - nodreg(&ax, t, REG_AX); - gmove(&n2, &ax); - gins(a, &n1, N); - regfree(&n2); - - if(t->width == 1) { - // byte multiply behaves differently. - nodreg(&ax, t, REG_AH); - nodreg(&dx, t, REG_DX); - gmove(&ax, &dx); - } - nodreg(&dx, t, REG_DX); - gmove(&dx, res); -} - -static void cgen_float387(Node *n, Node *res); -static void cgen_floatsse(Node *n, Node *res); - -/* - * generate floating-point operation. - */ -void -cgen_float(Node *n, Node *res) -{ - Node *nl; - Node n1, n2; - Prog *p1, *p2, *p3; - - nl = n->left; - switch(n->op) { - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - p1 = gbranch(AJMP, T, 0); - p2 = pc; - gmove(nodbool(1), res); - p3 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n, 1, 0, p2); - gmove(nodbool(0), res); - patch(p3, pc); - return; - - case OPLUS: - cgen(nl, res); - return; - - case OCONV: - if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) { - cgen(nl, res); - return; - } - - tempname(&n2, n->type); - mgen(nl, &n1, res); - gmove(&n1, &n2); - gmove(&n2, res); - mfree(&n1); - return; - } - - if(use_sse) - cgen_floatsse(n, res); - else - cgen_float387(n, res); -} - -// floating-point. 387 (not SSE2) -static void -cgen_float387(Node *n, Node *res) -{ - Node f0, f1; - Node *nl, *nr; - - nl = n->left; - nr = n->right; - nodreg(&f0, nl->type, REG_F0); - nodreg(&f1, n->type, REG_F0+1); - if(nr != N) - goto flt2; - - // unary - cgen(nl, &f0); - if(n->op != OCONV && n->op != OPLUS) - gins(foptoas(n->op, n->type, 0), N, N); - gmove(&f0, res); - return; - -flt2: // binary - if(nl->ullman >= nr->ullman) { - cgen(nl, &f0); - if(nr->addable) - gins(foptoas(n->op, n->type, 0), nr, &f0); - else { - cgen(nr, &f0); - gins(foptoas(n->op, n->type, Fpop), &f0, &f1); - } - } else { - cgen(nr, &f0); - if(nl->addable) - gins(foptoas(n->op, n->type, Frev), nl, &f0); - else { - cgen(nl, &f0); - gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1); - } - } - gmove(&f0, res); - return; - -} - -static void -cgen_floatsse(Node *n, Node *res) -{ - Node *nl, *nr, *r; - Node n1, n2, nt; - int a; - - nl = n->left; - nr = n->right; - switch(n->op) { - default: - dump("cgen_floatsse", n); - fatal("cgen_floatsse %O", n->op); - return; - - case OMINUS: - case OCOM: - nr = nodintconst(-1); - convlit(&nr, n->type); - a = foptoas(OMUL, nl->type, 0); - goto sbop; - - // symmetric binary - case OADD: - case OMUL: - a = foptoas(n->op, nl->type, 0); - goto sbop; - - // asymmetric binary - case OSUB: - case OMOD: - case ODIV: - a = foptoas(n->op, nl->type, 0); - goto abop; - } - -sbop: // symmetric binary - if(nl->ullman < nr->ullman || nl->op == OLITERAL) { - r = nl; - nl = nr; - nr = r; - } - -abop: // asymmetric binary - if(nl->ullman >= nr->ullman) { - tempname(&nt, nl->type); - cgen(nl, &nt); - mgen(nr, &n2, N); - regalloc(&n1, nl->type, res); - gmove(&nt, &n1); - gins(a, &n2, &n1); - gmove(&n1, res); - regfree(&n1); - mfree(&n2); - } else { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - gins(a, &n2, &n1); - regfree(&n2); - gmove(&n1, res); - regfree(&n1); - } - return; -} - -void -bgen_float(Node *n, int true, int likely, Prog *to) -{ - int et, a; - Node *nl, *nr, *r; - Node n1, n2, n3, tmp, t1, t2, ax; - Prog *p1, *p2; - - nl = n->left; - nr = n->right; - a = n->op; - if(!true) { - // brcom is not valid on floats when NaN is involved. - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - // No need to avoid re-genning ninit. - bgen_float(n, 1, -likely, p2); - patch(gbranch(AJMP, T, 0), to); - patch(p2, pc); - return; - } - - if(use_sse) - goto sse; - else - goto x87; - -x87: - a = brrev(a); // because the args are stacked - if(a == OGE || a == OGT) { - // only < and <= work right with NaN; reverse if needed - r = nr; - nr = nl; - nl = r; - a = brrev(a); - } - - nodreg(&tmp, nr->type, REG_F0); - nodreg(&n2, nr->type, REG_F0 + 1); - nodreg(&ax, types[TUINT16], REG_AX); - et = simsimtype(nr->type); - if(et == TFLOAT64) { - if(nl->ullman > nr->ullman) { - cgen(nl, &tmp); - cgen(nr, &tmp); - gins(AFXCHD, &tmp, &n2); - } else { - cgen(nr, &tmp); - cgen(nl, &tmp); - } - gins(AFUCOMIP, &tmp, &n2); - gins(AFMOVDP, &tmp, &tmp); // annoying pop but still better than STSW+SAHF - } else { - // TODO(rsc): The moves back and forth to memory - // here are for truncating the value to 32 bits. - // This handles 32-bit comparison but presumably - // all the other ops have the same problem. - // We need to figure out what the right general - // solution is, besides telling people to use float64. - tempname(&t1, types[TFLOAT32]); - tempname(&t2, types[TFLOAT32]); - cgen(nr, &t1); - cgen(nl, &t2); - gmove(&t2, &tmp); - gins(AFCOMFP, &t1, &tmp); - gins(AFSTSW, N, &ax); - gins(ASAHF, N, N); - } - - goto ret; - -sse: - if(!nl->addable) { - tempname(&n1, nl->type); - cgen(nl, &n1); - nl = &n1; - } - if(!nr->addable) { - tempname(&tmp, nr->type); - cgen(nr, &tmp); - nr = &tmp; - } - regalloc(&n2, nr->type, N); - gmove(nr, &n2); - nr = &n2; - - if(nl->op != OREGISTER) { - regalloc(&n3, nl->type, N); - gmove(nl, &n3); - nl = &n3; - } - - if(a == OGE || a == OGT) { - // only < and <= work right with NaN; reverse if needed - r = nr; - nr = nl; - nl = r; - a = brrev(a); - } - - gins(foptoas(OCMP, nr->type, 0), nl, nr); - if(nl->op == OREGISTER) - regfree(nl); - regfree(nr); - -ret: - if(a == OEQ) { - // neither NE nor P - p1 = gbranch(AJNE, T, -likely); - p2 = gbranch(AJPS, T, -likely); - patch(gbranch(AJMP, T, 0), to); - patch(p1, pc); - patch(p2, pc); - } else if(a == ONE) { - // either NE or P - patch(gbranch(AJNE, T, likely), to); - patch(gbranch(AJPS, T, likely), to); - } else - patch(gbranch(optoas(a, nr->type), T, likely), to); - -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -void -expandchecks(Prog *firstp) -{ - Prog *p, *p1, *p2; - - for(p = firstp; p != P; p = p->link) { - if(p->as != ACHECKNIL) - continue; - if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers - warnl(p->lineno, "generated nil check"); - // check is - // CMP arg, $0 - // JNE 2(PC) (likely) - // MOV AX, 0 - p1 = mal(sizeof *p1); - p2 = mal(sizeof *p2); - clearp(p1); - clearp(p2); - p1->link = p2; - p2->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - p2->lineno = p->lineno; - p1->pc = 9999; - p2->pc = 9999; - p->as = ACMPL; - p->to.type = TYPE_CONST; - p->to.offset = 0; - p1->as = AJNE; - p1->from.type = TYPE_CONST; - p1->from.offset = 1; // likely - p1->to.type = TYPE_BRANCH; - p1->to.u.branch = p2->link; - // crash by write to memory address 0. - // if possible, since we know arg is 0, use 0(arg), - // which will be shorter to encode than plain 0. - p2->as = AMOVL; - p2->from.type = TYPE_REG; - p2->from.reg = REG_AX; - if(regtyp(&p->from)) { - p2->to.type = TYPE_MEM; - p2->to.reg = p->from.reg; - } else - p2->to.type = TYPE_MEM; - p2->to.offset = 0; - } -} diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go new file mode 100644 index 0000000000..f72beda21a --- /dev/null +++ b/src/cmd/8g/ggen.go @@ -0,0 +1,1297 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" +) +import "cmd/internal/gc" + +func defframe(ptxt *obj.Prog) { + var frame uint32 + var ax uint32 + var p *obj.Prog + var lo int64 + var hi int64 + var l *gc.NodeList + var n *gc.Node + + // fill in argument size, stack size + ptxt.To.Type = obj.TYPE_TEXTSIZE + + ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) + frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) + ptxt.To.Offset = int64(frame) + + // insert code to zero ambiguously live variables + // so that the garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt + + hi = 0 + lo = hi + ax = 0 + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + n = l.N + if n.Needzero == 0 { + continue + } + if n.Class != gc.PAUTO { + gc.Fatal("needzero class %d", n.Class) + } + if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { + gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) + } + if lo != hi && n.Xoffset+n.Type.Width == lo-int64(2*gc.Widthptr) { + // merge with range we already have + lo = n.Xoffset + + continue + } + + // zero old range + p = zerorange(p, int64(frame), lo, hi, &ax) + + // set new range + hi = n.Xoffset + n.Type.Width + + lo = n.Xoffset + } + + // zero final range + zerorange(p, int64(frame), lo, hi, &ax) +} + +func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog { + var cnt int64 + var i int64 + + cnt = hi - lo + if cnt == 0 { + return p + } + if *ax == 0 { + p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, i386.REG_AX, 0) + *ax = 1 + } + + if cnt <= int64(4*gc.Widthreg) { + for i = 0; i < cnt; i += int64(gc.Widthreg) { + p = appendpp(p, i386.AMOVL, obj.TYPE_REG, i386.REG_AX, 0, obj.TYPE_MEM, i386.REG_SP, frame+lo+i) + } + } else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) { + p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0) + p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg))) + p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) + } else { + p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, i386.REG_CX, 0) + p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0) + p = appendpp(p, i386.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) + p = appendpp(p, i386.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) + } + + return p +} + +func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { + var q *obj.Prog + q = gc.Ctxt.NewProg() + gc.Clearp(q) + q.As = int16(as) + q.Lineno = p.Lineno + q.From.Type = int16(ftype) + q.From.Reg = int16(freg) + q.From.Offset = foffset + q.To.Type = int16(ttype) + q.To.Reg = int16(treg) + q.To.Offset = toffset + q.Link = p.Link + p.Link = q + return q +} + +func clearfat(nl *gc.Node) { + var w uint32 + var c uint32 + var q uint32 + var n1 gc.Node + var z gc.Node + var p *obj.Prog + + /* clear a fat object */ + if gc.Debug['g'] != 0 { + gc.Dump("\nclearfat", nl) + } + + w = uint32(nl.Type.Width) + + // Avoid taking the address for simple enough types. + if componentgen(nil, nl) { + return + } + + c = w % 4 // bytes + q = w / 4 // quads + + if q < 4 { + // Write sequence of MOV 0, off(base) instead of using STOSL. + // The hope is that although the code will be slightly longer, + // the MOVs will have no dependencies and pipeline better + // than the unrolled STOSL loop. + // NOTE: Must use agen, not igen, so that optimizer sees address + // being taken. We are not writing on field boundaries. + regalloc(&n1, gc.Types[gc.Tptr], nil) + + agen(nl, &n1) + n1.Op = gc.OINDREG + gc.Nodconst(&z, gc.Types[gc.TUINT64], 0) + for { + tmp14 := q + q-- + if tmp14 <= 0 { + break + } + n1.Type = z.Type + gins(i386.AMOVL, &z, &n1) + n1.Xoffset += 4 + } + + gc.Nodconst(&z, gc.Types[gc.TUINT8], 0) + for { + tmp15 := c + c-- + if tmp15 <= 0 { + break + } + n1.Type = z.Type + gins(i386.AMOVB, &z, &n1) + n1.Xoffset++ + } + + regfree(&n1) + return + } + + gc.Nodreg(&n1, gc.Types[gc.Tptr], i386.REG_DI) + agen(nl, &n1) + gconreg(i386.AMOVL, 0, i386.REG_AX) + + if q > 128 || (q >= 4 && gc.Nacl) { + gconreg(i386.AMOVL, int64(q), i386.REG_CX) + gins(i386.AREP, nil, nil) // repeat + gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+ + } else if q >= 4 { + p = gins(obj.ADUFFZERO, nil, nil) + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) + + // 1 and 128 = magic constants: see ../../runtime/asm_386.s + p.To.Offset = 1 * (128 - int64(q)) + } else { + for q > 0 { + gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+ + q-- + } + } + + for c > 0 { + gins(i386.ASTOSB, nil, nil) // STOB AL,*(DI)+ + c-- + } +} + +/* + * generate: + * call f + * proc=-1 normal call but no return + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + * proc=3 normal call to C pointer (not Go func value) +*/ +func ginscall(f *gc.Node, proc int) { + var p *obj.Prog + var reg gc.Node + var r1 gc.Node + var con gc.Node + var stk gc.Node + var extra int32 + + if f.Type != nil { + extra = 0 + if proc == 1 || proc == 2 { + extra = 2 * int32(gc.Widthptr) + } + gc.Setmaxarg(f.Type, extra) + } + + switch proc { + default: + gc.Fatal("ginscall: bad proc %d", proc) + + case 0, // normal call + -1: // normal call but no return + if f.Op == gc.ONAME && f.Class == gc.PFUNC { + if f == gc.Deferreturn { + // Deferred calls will appear to be returning to + // the CALL deferreturn(SB) that we are about to emit. + // However, the stack trace code will show the line + // of the instruction byte before the return PC. + // To avoid that being an unrelated instruction, + // insert an x86 NOP that we will have the right line number. + // x86 NOP 0x90 is really XCHG AX, AX; use that description + // because the NOP pseudo-instruction will be removed by + // the linker. + gc.Nodreg(®, gc.Types[gc.TINT], i386.REG_AX) + + gins(i386.AXCHGL, ®, ®) + } + + p = gins(obj.ACALL, nil, f) + gc.Afunclit(&p.To, f) + if proc == -1 || gc.Noreturn(p) { + gins(obj.AUNDEF, nil, nil) + } + break + } + + gc.Nodreg(®, gc.Types[gc.Tptr], i386.REG_DX) + gc.Nodreg(&r1, gc.Types[gc.Tptr], i386.REG_BX) + gmove(f, ®) + reg.Op = gc.OINDREG + gmove(®, &r1) + reg.Op = gc.OREGISTER + gins(obj.ACALL, ®, &r1) + + case 3: // normal call of c function pointer + gins(obj.ACALL, nil, f) + + case 1, // call in new proc (go) + 2: // deferred call (defer) + stk = gc.Node{} + + stk.Op = gc.OINDREG + stk.Val.U.Reg = i386.REG_SP + stk.Xoffset = 0 + + // size of arguments at 0(SP) + gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type))) + + gins(i386.AMOVL, &con, &stk) + + // FuncVal* at 4(SP) + stk.Xoffset = int64(gc.Widthptr) + + gins(i386.AMOVL, f, &stk) + + if proc == 1 { + ginscall(gc.Newproc, 0) + } else { + ginscall(gc.Deferproc, 0) + } + if proc == 2 { + gc.Nodreg(®, gc.Types[gc.TINT32], i386.REG_AX) + gins(i386.ATESTL, ®, ®) + p = gc.Gbranch(i386.AJEQ, nil, +1) + cgen_ret(nil) + gc.Patch(p, gc.Pc) + } + } +} + +/* + * n is call to interface method. + * generate res = n. + */ +func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { + var i *gc.Node + var f *gc.Node + var tmpi gc.Node + var nodi gc.Node + var nodo gc.Node + var nodr gc.Node + var nodsp gc.Node + + i = n.Left + if i.Op != gc.ODOTINTER { + gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) + } + + f = i.Right // field + if f.Op != gc.ONAME { + gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) + } + + i = i.Left // interface + + if i.Addable == 0 { + gc.Tempname(&tmpi, i.Type) + cgen(i, &tmpi) + i = &tmpi + } + + gc.Genlist(n.List) // assign the args + + // i is now addable, prepare an indirected + // register to hold its address. + igen(i, &nodi, res) // REG = &inter + + gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], i386.REG_SP) + + nodsp.Xoffset = 0 + if proc != 0 { + nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn + } + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset += int64(gc.Widthptr) + cgen(&nodi, &nodsp) // {0 or 8}(SP) = 4(REG) -- i.data + + regalloc(&nodo, gc.Types[gc.Tptr], res) + + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset -= int64(gc.Widthptr) + cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab + regfree(&nodi) + + regalloc(&nodr, gc.Types[gc.Tptr], &nodo) + if n.Left.Xoffset == gc.BADWIDTH { + gc.Fatal("cgen_callinter: badwidth") + } + gc.Cgen_checknil(&nodo) + nodo.Op = gc.OINDREG + nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 + + if proc == 0 { + // plain call: use direct c function pointer - more efficient + cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] + proc = 3 + } else { + // go/defer. generate go func value. + gins(i386.ALEAL, &nodo, &nodr) // REG = &(20+offset(REG)) -- i.tab->fun[f] + } + + nodr.Type = n.Left.Type + ginscall(&nodr, proc) + + regfree(&nodr) + regfree(&nodo) +} + +/* + * generate function call; + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + */ +func cgen_call(n *gc.Node, proc int) { + var t *gc.Type + var nod gc.Node + var afun gc.Node + + if n == nil { + return + } + + if n.Left.Ullman >= gc.UINF { + // if name involves a fn call + // precompute the address of the fn + gc.Tempname(&afun, gc.Types[gc.Tptr]) + + cgen(n.Left, &afun) + } + + gc.Genlist(n.List) // assign the args + t = n.Left.Type + + // call tempname pointer + if n.Left.Ullman >= gc.UINF { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, &afun) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call pointer + if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, n.Left) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call direct + n.Left.Method = 1 + + ginscall(n.Left, proc) +} + +/* + * call to n has already been generated. + * generate: + * res = return value from call. + */ +func cgen_callret(n *gc.Node, res *gc.Node) { + var nod gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_callret: nil") + } + + nod = gc.Node{} + nod.Op = gc.OINDREG + nod.Val.U.Reg = i386.REG_SP + nod.Addable = 1 + + nod.Xoffset = fp.Width + nod.Type = fp.Type + gc.Cgen_as(res, &nod) +} + +/* + * call to n has already been generated. + * generate: + * res = &return value from call. + */ +func cgen_aret(n *gc.Node, res *gc.Node) { + var nod1 gc.Node + var nod2 gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_aret: nil") + } + + nod1 = gc.Node{} + nod1.Op = gc.OINDREG + nod1.Val.U.Reg = i386.REG_SP + nod1.Addable = 1 + + nod1.Xoffset = fp.Width + nod1.Type = fp.Type + + if res.Op != gc.OREGISTER { + regalloc(&nod2, gc.Types[gc.Tptr], res) + gins(i386.ALEAL, &nod1, &nod2) + gins(i386.AMOVL, &nod2, res) + regfree(&nod2) + } else { + gins(i386.ALEAL, &nod1, res) + } +} + +/* + * generate return. + * n->left is assignments to return values. + */ +func cgen_ret(n *gc.Node) { + var p *obj.Prog + + if n != nil { + gc.Genlist(n.List) // copy out args + } + if gc.Hasdefer != 0 { + ginscall(gc.Deferreturn, 0) + } + gc.Genlist(gc.Curfn.Exit) + p = gins(obj.ARET, nil, nil) + if n != nil && n.Op == gc.ORETJMP { + p.To.Type = obj.TYPE_MEM + p.To.Name = obj.NAME_EXTERN + p.To.Sym = gc.Linksym(n.Left.Sym) + } +} + +/* + * generate division. + * caller must set: + * ax = allocated AX register + * dx = allocated DX register + * generates one of: + * res = nl / nr + * res = nl % nr + * according to op. + */ +func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.Node) { + var check int + var n1 gc.Node + var t1 gc.Node + var t2 gc.Node + var t3 gc.Node + var t4 gc.Node + var n4 gc.Node + var nz gc.Node + var t *gc.Type + var t0 *gc.Type + var p1 *obj.Prog + var p2 *obj.Prog + + // Have to be careful about handling + // most negative int divided by -1 correctly. + // The hardware will trap. + // Also the byte divide instruction needs AH, + // which we otherwise don't have to deal with. + // Easiest way to avoid for int8, int16: use int32. + // For int32 and int64, use explicit test. + // Could use int64 hw for int32. + t = nl.Type + + t0 = t + check = 0 + if gc.Issigned[t.Etype] != 0 { + check = 1 + if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1< 0 && !gc.Samereg(x, res) { + gc.Tempname(oldx, gc.Types[gc.TINT32]) + gmove(x, oldx) + } + + regalloc(x, t, x) +} + +func restx(x *gc.Node, oldx *gc.Node) { + regfree(x) + + if oldx.Op != 0 { + x.Type = gc.Types[gc.TINT32] + gmove(oldx, x) + } +} + +/* + * generate division according to op, one of: + * res = nl / nr + * res = nl % nr + */ +func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var ax gc.Node + var dx gc.Node + var oldax gc.Node + var olddx gc.Node + var t *gc.Type + + if gc.Is64(nl.Type) { + gc.Fatal("cgen_div %v", gc.Tconv(nl.Type, 0)) + } + + if gc.Issigned[nl.Type.Etype] != 0 { + t = gc.Types[gc.TINT32] + } else { + t = gc.Types[gc.TUINT32] + } + savex(i386.REG_AX, &ax, &oldax, res, t) + savex(i386.REG_DX, &dx, &olddx, res, t) + dodiv(op, nl, nr, res, &ax, &dx) + restx(&dx, &olddx) + restx(&ax, &oldax) +} + +/* + * generate shift according to op, one of: + * res = nl << nr + * res = nl >> nr + */ +func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var nt gc.Node + var cx gc.Node + var oldcx gc.Node + var hi gc.Node + var lo gc.Node + var a int + var w int + var p1 *obj.Prog + var p2 *obj.Prog + var sc uint64 + + if nl.Type.Width > 4 { + gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0)) + } + + w = int(nl.Type.Width * 8) + + a = optoas(op, nl.Type) + + if nr.Op == gc.OLITERAL { + gc.Tempname(&n2, nl.Type) + cgen(nl, &n2) + regalloc(&n1, nl.Type, res) + gmove(&n2, &n1) + sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if sc >= uint64(nl.Type.Width*8) { + // large shift gets 2 shifts by width-1 + gins(a, ncon(uint32(w)-1), &n1) + + gins(a, ncon(uint32(w)-1), &n1) + } else { + gins(a, nr, &n1) + } + gmove(&n1, res) + regfree(&n1) + return + } + + oldcx = gc.Node{} + gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX) + if reg[i386.REG_CX] > 1 && !gc.Samereg(&cx, res) { + gc.Tempname(&oldcx, gc.Types[gc.TUINT32]) + gmove(&cx, &oldcx) + } + + if nr.Type.Width > 4 { + gc.Tempname(&nt, nr.Type) + n1 = nt + } else { + gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) + regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX + } + + if gc.Samereg(&cx, res) { + regalloc(&n2, nl.Type, nil) + } else { + regalloc(&n2, nl.Type, res) + } + if nl.Ullman >= nr.Ullman { + cgen(nl, &n2) + cgen(nr, &n1) + } else { + cgen(nr, &n1) + cgen(nl, &n2) + } + + // test and fix up large shifts + if bounded { + if nr.Type.Width > 4 { + // delayed reg alloc + gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) + + regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX + split64(&nt, &lo, &hi) + gmove(&lo, &n1) + splitclean() + } + } else { + if nr.Type.Width > 4 { + // delayed reg alloc + gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) + + regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX + split64(&nt, &lo, &hi) + gmove(&lo, &n1) + gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &hi, ncon(0)) + p2 = gc.Gbranch(optoas(gc.ONE, gc.Types[gc.TUINT32]), nil, +1) + gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n1, ncon(uint32(w))) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + splitclean() + gc.Patch(p2, gc.Pc) + } else { + gins(optoas(gc.OCMP, nr.Type), &n1, ncon(uint32(w))) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) + } + + if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { + gins(a, ncon(uint32(w)-1), &n2) + } else { + gmove(ncon(0), &n2) + } + + gc.Patch(p1, gc.Pc) + } + + gins(a, &n1, &n2) + + if oldcx.Op != 0 { + gmove(&oldcx, &cx) + } + + gmove(&n2, res) + + regfree(&n1) + regfree(&n2) +} + +/* + * generate byte multiply: + * res = nl * nr + * there is no 2-operand byte multiply instruction so + * we do a full-width multiplication and truncate afterwards. + */ +func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var nt gc.Node + var tmp *gc.Node + var t *gc.Type + var a int + + // copy from byte to full registers + t = gc.Types[gc.TUINT32] + + if gc.Issigned[nl.Type.Etype] != 0 { + t = gc.Types[gc.TINT32] + } + + // largest ullman on left. + if nl.Ullman < nr.Ullman { + tmp = nl + nl = nr + nr = tmp + } + + gc.Tempname(&nt, nl.Type) + cgen(nl, &nt) + regalloc(&n1, t, res) + cgen(nr, &n1) + regalloc(&n2, t, nil) + gmove(&nt, &n2) + a = optoas(op, t) + gins(a, &n2, &n1) + regfree(&n2) + gmove(&n1, res) + regfree(&n1) +} + +/* + * generate high multiply: + * res = (nl*nr) >> width + */ +func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { + var t *gc.Type + var a int + var n1 gc.Node + var n2 gc.Node + var ax gc.Node + var dx gc.Node + + t = nl.Type + a = optoas(gc.OHMUL, t) + + // gen nl in n1. + gc.Tempname(&n1, t) + + cgen(nl, &n1) + + // gen nr in n2. + regalloc(&n2, t, res) + + cgen(nr, &n2) + + // multiply. + gc.Nodreg(&ax, t, i386.REG_AX) + + gmove(&n2, &ax) + gins(a, &n1, nil) + regfree(&n2) + + if t.Width == 1 { + // byte multiply behaves differently. + gc.Nodreg(&ax, t, i386.REG_AH) + + gc.Nodreg(&dx, t, i386.REG_DX) + gmove(&ax, &dx) + } + + gc.Nodreg(&dx, t, i386.REG_DX) + gmove(&dx, res) +} + +/* + * generate floating-point operation. + */ +func cgen_float(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var n1 gc.Node + var n2 gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + + nl = n.Left + switch n.Op { + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OLE, + gc.OGE: + p1 = gc.Gbranch(obj.AJMP, nil, 0) + p2 = gc.Pc + gmove(gc.Nodbool(true), res) + p3 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n, true, 0, p2) + gmove(gc.Nodbool(false), res) + gc.Patch(p3, gc.Pc) + return + + case gc.OPLUS: + cgen(nl, res) + return + + case gc.OCONV: + if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { + cgen(nl, res) + return + } + + gc.Tempname(&n2, n.Type) + mgen(nl, &n1, res) + gmove(&n1, &n2) + gmove(&n2, res) + mfree(&n1) + return + } + + if gc.Use_sse != 0 { + cgen_floatsse(n, res) + } else { + cgen_float387(n, res) + } +} + +// floating-point. 387 (not SSE2) +func cgen_float387(n *gc.Node, res *gc.Node) { + var f0 gc.Node + var f1 gc.Node + var nl *gc.Node + var nr *gc.Node + + nl = n.Left + nr = n.Right + gc.Nodreg(&f0, nl.Type, i386.REG_F0) + gc.Nodreg(&f1, n.Type, i386.REG_F0+1) + if nr != nil { + goto flt2 + } + + // unary + cgen(nl, &f0) + + if n.Op != gc.OCONV && n.Op != gc.OPLUS { + gins(foptoas(int(n.Op), n.Type, 0), nil, nil) + } + gmove(&f0, res) + return + +flt2: // binary + if nl.Ullman >= nr.Ullman { + cgen(nl, &f0) + if nr.Addable != 0 { + gins(foptoas(int(n.Op), n.Type, 0), nr, &f0) + } else { + cgen(nr, &f0) + gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1) + } + } else { + cgen(nr, &f0) + if nl.Addable != 0 { + gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0) + } else { + cgen(nl, &f0) + gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1) + } + } + + gmove(&f0, res) + return +} + +func cgen_floatsse(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var nt gc.Node + var a int + + nl = n.Left + nr = n.Right + switch n.Op { + default: + gc.Dump("cgen_floatsse", n) + gc.Fatal("cgen_floatsse %v", gc.Oconv(int(n.Op), 0)) + return + + case gc.OMINUS, + gc.OCOM: + nr = gc.Nodintconst(-1) + gc.Convlit(&nr, n.Type) + a = foptoas(gc.OMUL, nl.Type, 0) + goto sbop + + // symmetric binary + case gc.OADD, + gc.OMUL: + a = foptoas(int(n.Op), nl.Type, 0) + + goto sbop + + // asymmetric binary + case gc.OSUB, + gc.OMOD, + gc.ODIV: + a = foptoas(int(n.Op), nl.Type, 0) + + goto abop + } + +sbop: // symmetric binary + if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL { + r = nl + nl = nr + nr = r + } + +abop: // asymmetric binary + if nl.Ullman >= nr.Ullman { + gc.Tempname(&nt, nl.Type) + cgen(nl, &nt) + mgen(nr, &n2, nil) + regalloc(&n1, nl.Type, res) + gmove(&nt, &n1) + gins(a, &n2, &n1) + gmove(&n1, res) + regfree(&n1) + mfree(&n2) + } else { + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gins(a, &n2, &n1) + regfree(&n2) + gmove(&n1, res) + regfree(&n1) + } + + return +} + +func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) { + var et int + var a int + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var tmp gc.Node + var t1 gc.Node + var t2 gc.Node + var ax gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + nl = n.Left + nr = n.Right + a = int(n.Op) + if true_ == 0 { + // brcom is not valid on floats when NaN is involved. + p1 = gc.Gbranch(obj.AJMP, nil, 0) + + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + + // No need to avoid re-genning ninit. + bgen_float(n, 1, -likely, p2) + + gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) + gc.Patch(p2, gc.Pc) + return + } + + if gc.Use_sse != 0 { + goto sse + } else { + goto x87 + } + +x87: + a = gc.Brrev(a) // because the args are stacked + if a == gc.OGE || a == gc.OGT { + // only < and <= work right with NaN; reverse if needed + r = nr + + nr = nl + nl = r + a = gc.Brrev(a) + } + + gc.Nodreg(&tmp, nr.Type, i386.REG_F0) + gc.Nodreg(&n2, nr.Type, i386.REG_F0+1) + gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX) + et = gc.Simsimtype(nr.Type) + if et == gc.TFLOAT64 { + if nl.Ullman > nr.Ullman { + cgen(nl, &tmp) + cgen(nr, &tmp) + gins(i386.AFXCHD, &tmp, &n2) + } else { + cgen(nr, &tmp) + cgen(nl, &tmp) + } + + gins(i386.AFUCOMIP, &tmp, &n2) + gins(i386.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF + } else { + // TODO(rsc): The moves back and forth to memory + // here are for truncating the value to 32 bits. + // This handles 32-bit comparison but presumably + // all the other ops have the same problem. + // We need to figure out what the right general + // solution is, besides telling people to use float64. + gc.Tempname(&t1, gc.Types[gc.TFLOAT32]) + + gc.Tempname(&t2, gc.Types[gc.TFLOAT32]) + cgen(nr, &t1) + cgen(nl, &t2) + gmove(&t2, &tmp) + gins(i386.AFCOMFP, &t1, &tmp) + gins(i386.AFSTSW, nil, &ax) + gins(i386.ASAHF, nil, nil) + } + + goto ret + +sse: + if nl.Addable == 0 { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + nl = &n1 + } + + if nr.Addable == 0 { + gc.Tempname(&tmp, nr.Type) + cgen(nr, &tmp) + nr = &tmp + } + + regalloc(&n2, nr.Type, nil) + gmove(nr, &n2) + nr = &n2 + + if nl.Op != gc.OREGISTER { + regalloc(&n3, nl.Type, nil) + gmove(nl, &n3) + nl = &n3 + } + + if a == gc.OGE || a == gc.OGT { + // only < and <= work right with NaN; reverse if needed + r = nr + + nr = nl + nl = r + a = gc.Brrev(a) + } + + gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr) + if nl.Op == gc.OREGISTER { + regfree(nl) + } + regfree(nr) + +ret: + if a == gc.OEQ { + // neither NE nor P + p1 = gc.Gbranch(i386.AJNE, nil, -likely) + + p2 = gc.Gbranch(i386.AJPS, nil, -likely) + gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) + gc.Patch(p1, gc.Pc) + gc.Patch(p2, gc.Pc) + } else if a == gc.ONE { + // either NE or P + gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to) + + gc.Patch(gc.Gbranch(i386.AJPS, nil, likely), to) + } else { + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to) + } +} + +// Called after regopt and peep have run. +// Expand CHECKNIL pseudo-op into actual nil pointer check. +func expandchecks(firstp *obj.Prog) { + var p *obj.Prog + var p1 *obj.Prog + var p2 *obj.Prog + + for p = firstp; p != nil; p = p.Link { + if p.As != obj.ACHECKNIL { + continue + } + if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers + gc.Warnl(int(p.Lineno), "generated nil check") + } + + // check is + // CMP arg, $0 + // JNE 2(PC) (likely) + // MOV AX, 0 + p1 = gc.Ctxt.NewProg() + + p2 = gc.Ctxt.NewProg() + gc.Clearp(p1) + gc.Clearp(p2) + p1.Link = p2 + p2.Link = p.Link + p.Link = p1 + p1.Lineno = p.Lineno + p2.Lineno = p.Lineno + p1.Pc = 9999 + p2.Pc = 9999 + p.As = i386.ACMPL + p.To.Type = obj.TYPE_CONST + p.To.Offset = 0 + p1.As = i386.AJNE + p1.From.Type = obj.TYPE_CONST + p1.From.Offset = 1 // likely + p1.To.Type = obj.TYPE_BRANCH + p1.To.U.Branch = p2.Link + + // crash by write to memory address 0. + // if possible, since we know arg is 0, use 0(arg), + // which will be shorter to encode than plain 0. + p2.As = i386.AMOVL + + p2.From.Type = obj.TYPE_REG + p2.From.Reg = i386.REG_AX + if regtyp(&p.From) { + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = p.From.Reg + } else { + p2.To.Type = obj.TYPE_MEM + } + p2.To.Offset = 0 + } +} diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c deleted file mode 100644 index b82f7622ef..0000000000 --- a/src/cmd/8g/gsubr.c +++ /dev/null @@ -1,1874 +0,0 @@ -// Derived from Inferno utils/8c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../../runtime/funcdata.h" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 8l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -uint32 unmappedzero = 4096; - -#define CASE(a,b) (((a)<<16)|((b)<<0)) -/*c2go int CASE(int, int);*/ - -/* - * return Axxx for Oxxx on type t. - */ -int -optoas(int op, Type *t) -{ - int a; - - if(t == T) - fatal("optoas: t is nil"); - - a = AXXX; - switch(CASE(op, simtype[t->etype])) { - default: - fatal("optoas: no entry %O-%T", op, t); - break; - - case CASE(OADDR, TPTR32): - a = ALEAL; - break; - - case CASE(OEQ, TBOOL): - case CASE(OEQ, TINT8): - case CASE(OEQ, TUINT8): - case CASE(OEQ, TINT16): - case CASE(OEQ, TUINT16): - case CASE(OEQ, TINT32): - case CASE(OEQ, TUINT32): - case CASE(OEQ, TINT64): - case CASE(OEQ, TUINT64): - case CASE(OEQ, TPTR32): - case CASE(OEQ, TPTR64): - case CASE(OEQ, TFLOAT32): - case CASE(OEQ, TFLOAT64): - a = AJEQ; - break; - - case CASE(ONE, TBOOL): - case CASE(ONE, TINT8): - case CASE(ONE, TUINT8): - case CASE(ONE, TINT16): - case CASE(ONE, TUINT16): - case CASE(ONE, TINT32): - case CASE(ONE, TUINT32): - case CASE(ONE, TINT64): - case CASE(ONE, TUINT64): - case CASE(ONE, TPTR32): - case CASE(ONE, TPTR64): - case CASE(ONE, TFLOAT32): - case CASE(ONE, TFLOAT64): - a = AJNE; - break; - - case CASE(OLT, TINT8): - case CASE(OLT, TINT16): - case CASE(OLT, TINT32): - case CASE(OLT, TINT64): - a = AJLT; - break; - - case CASE(OLT, TUINT8): - case CASE(OLT, TUINT16): - case CASE(OLT, TUINT32): - case CASE(OLT, TUINT64): - a = AJCS; - break; - - case CASE(OLE, TINT8): - case CASE(OLE, TINT16): - case CASE(OLE, TINT32): - case CASE(OLE, TINT64): - a = AJLE; - break; - - case CASE(OLE, TUINT8): - case CASE(OLE, TUINT16): - case CASE(OLE, TUINT32): - case CASE(OLE, TUINT64): - a = AJLS; - break; - - case CASE(OGT, TINT8): - case CASE(OGT, TINT16): - case CASE(OGT, TINT32): - case CASE(OGT, TINT64): - a = AJGT; - break; - - case CASE(OGT, TUINT8): - case CASE(OGT, TUINT16): - case CASE(OGT, TUINT32): - case CASE(OGT, TUINT64): - case CASE(OLT, TFLOAT32): - case CASE(OLT, TFLOAT64): - a = AJHI; - break; - - case CASE(OGE, TINT8): - case CASE(OGE, TINT16): - case CASE(OGE, TINT32): - case CASE(OGE, TINT64): - a = AJGE; - break; - - case CASE(OGE, TUINT8): - case CASE(OGE, TUINT16): - case CASE(OGE, TUINT32): - case CASE(OGE, TUINT64): - case CASE(OLE, TFLOAT32): - case CASE(OLE, TFLOAT64): - a = AJCC; - break; - - case CASE(OCMP, TBOOL): - case CASE(OCMP, TINT8): - case CASE(OCMP, TUINT8): - a = ACMPB; - break; - - case CASE(OCMP, TINT16): - case CASE(OCMP, TUINT16): - a = ACMPW; - break; - - case CASE(OCMP, TINT32): - case CASE(OCMP, TUINT32): - case CASE(OCMP, TPTR32): - a = ACMPL; - break; - - case CASE(OAS, TBOOL): - case CASE(OAS, TINT8): - case CASE(OAS, TUINT8): - a = AMOVB; - break; - - case CASE(OAS, TINT16): - case CASE(OAS, TUINT16): - a = AMOVW; - break; - - case CASE(OAS, TINT32): - case CASE(OAS, TUINT32): - case CASE(OAS, TPTR32): - a = AMOVL; - break; - - case CASE(OAS, TFLOAT32): - a = AMOVSS; - break; - - case CASE(OAS, TFLOAT64): - a = AMOVSD; - break; - - case CASE(OADD, TINT8): - case CASE(OADD, TUINT8): - a = AADDB; - break; - - case CASE(OADD, TINT16): - case CASE(OADD, TUINT16): - a = AADDW; - break; - - case CASE(OADD, TINT32): - case CASE(OADD, TUINT32): - case CASE(OADD, TPTR32): - a = AADDL; - break; - - case CASE(OSUB, TINT8): - case CASE(OSUB, TUINT8): - a = ASUBB; - break; - - case CASE(OSUB, TINT16): - case CASE(OSUB, TUINT16): - a = ASUBW; - break; - - case CASE(OSUB, TINT32): - case CASE(OSUB, TUINT32): - case CASE(OSUB, TPTR32): - a = ASUBL; - break; - - case CASE(OINC, TINT8): - case CASE(OINC, TUINT8): - a = AINCB; - break; - - case CASE(OINC, TINT16): - case CASE(OINC, TUINT16): - a = AINCW; - break; - - case CASE(OINC, TINT32): - case CASE(OINC, TUINT32): - case CASE(OINC, TPTR32): - a = AINCL; - break; - - case CASE(ODEC, TINT8): - case CASE(ODEC, TUINT8): - a = ADECB; - break; - - case CASE(ODEC, TINT16): - case CASE(ODEC, TUINT16): - a = ADECW; - break; - - case CASE(ODEC, TINT32): - case CASE(ODEC, TUINT32): - case CASE(ODEC, TPTR32): - a = ADECL; - break; - - case CASE(OCOM, TINT8): - case CASE(OCOM, TUINT8): - a = ANOTB; - break; - - case CASE(OCOM, TINT16): - case CASE(OCOM, TUINT16): - a = ANOTW; - break; - - case CASE(OCOM, TINT32): - case CASE(OCOM, TUINT32): - case CASE(OCOM, TPTR32): - a = ANOTL; - break; - - case CASE(OMINUS, TINT8): - case CASE(OMINUS, TUINT8): - a = ANEGB; - break; - - case CASE(OMINUS, TINT16): - case CASE(OMINUS, TUINT16): - a = ANEGW; - break; - - case CASE(OMINUS, TINT32): - case CASE(OMINUS, TUINT32): - case CASE(OMINUS, TPTR32): - a = ANEGL; - break; - - case CASE(OAND, TINT8): - case CASE(OAND, TUINT8): - a = AANDB; - break; - - case CASE(OAND, TINT16): - case CASE(OAND, TUINT16): - a = AANDW; - break; - - case CASE(OAND, TINT32): - case CASE(OAND, TUINT32): - case CASE(OAND, TPTR32): - a = AANDL; - break; - - case CASE(OOR, TINT8): - case CASE(OOR, TUINT8): - a = AORB; - break; - - case CASE(OOR, TINT16): - case CASE(OOR, TUINT16): - a = AORW; - break; - - case CASE(OOR, TINT32): - case CASE(OOR, TUINT32): - case CASE(OOR, TPTR32): - a = AORL; - break; - - case CASE(OXOR, TINT8): - case CASE(OXOR, TUINT8): - a = AXORB; - break; - - case CASE(OXOR, TINT16): - case CASE(OXOR, TUINT16): - a = AXORW; - break; - - case CASE(OXOR, TINT32): - case CASE(OXOR, TUINT32): - case CASE(OXOR, TPTR32): - a = AXORL; - break; - - case CASE(OLROT, TINT8): - case CASE(OLROT, TUINT8): - a = AROLB; - break; - - case CASE(OLROT, TINT16): - case CASE(OLROT, TUINT16): - a = AROLW; - break; - - case CASE(OLROT, TINT32): - case CASE(OLROT, TUINT32): - case CASE(OLROT, TPTR32): - a = AROLL; - break; - - case CASE(OLSH, TINT8): - case CASE(OLSH, TUINT8): - a = ASHLB; - break; - - case CASE(OLSH, TINT16): - case CASE(OLSH, TUINT16): - a = ASHLW; - break; - - case CASE(OLSH, TINT32): - case CASE(OLSH, TUINT32): - case CASE(OLSH, TPTR32): - a = ASHLL; - break; - - case CASE(ORSH, TUINT8): - a = ASHRB; - break; - - case CASE(ORSH, TUINT16): - a = ASHRW; - break; - - case CASE(ORSH, TUINT32): - case CASE(ORSH, TPTR32): - a = ASHRL; - break; - - case CASE(ORSH, TINT8): - a = ASARB; - break; - - case CASE(ORSH, TINT16): - a = ASARW; - break; - - case CASE(ORSH, TINT32): - a = ASARL; - break; - - case CASE(OHMUL, TINT8): - case CASE(OMUL, TINT8): - case CASE(OMUL, TUINT8): - a = AIMULB; - break; - - case CASE(OHMUL, TINT16): - case CASE(OMUL, TINT16): - case CASE(OMUL, TUINT16): - a = AIMULW; - break; - - case CASE(OHMUL, TINT32): - case CASE(OMUL, TINT32): - case CASE(OMUL, TUINT32): - case CASE(OMUL, TPTR32): - a = AIMULL; - break; - - case CASE(OHMUL, TUINT8): - a = AMULB; - break; - - case CASE(OHMUL, TUINT16): - a = AMULW; - break; - - case CASE(OHMUL, TUINT32): - case CASE(OHMUL, TPTR32): - a = AMULL; - break; - - case CASE(ODIV, TINT8): - case CASE(OMOD, TINT8): - a = AIDIVB; - break; - - case CASE(ODIV, TUINT8): - case CASE(OMOD, TUINT8): - a = ADIVB; - break; - - case CASE(ODIV, TINT16): - case CASE(OMOD, TINT16): - a = AIDIVW; - break; - - case CASE(ODIV, TUINT16): - case CASE(OMOD, TUINT16): - a = ADIVW; - break; - - case CASE(ODIV, TINT32): - case CASE(OMOD, TINT32): - a = AIDIVL; - break; - - case CASE(ODIV, TUINT32): - case CASE(ODIV, TPTR32): - case CASE(OMOD, TUINT32): - case CASE(OMOD, TPTR32): - a = ADIVL; - break; - - case CASE(OEXTEND, TINT16): - a = ACWD; - break; - - case CASE(OEXTEND, TINT32): - a = ACDQ; - break; - } - return a; -} - -#define FCASE(a, b, c) (((a)<<16)|((b)<<8)|(c)) -/*c2go int FCASE(int, int, int); */ -int -foptoas(int op, Type *t, int flg) -{ - int et, a; - - a = AXXX; - et = simtype[t->etype]; - - if(use_sse) - goto sse; - - // If we need Fpop, it means we're working on - // two different floating-point registers, not memory. - // There the instruction only has a float64 form. - if(flg & Fpop) - et = TFLOAT64; - - // clear Frev if unneeded - switch(op) { - case OADD: - case OMUL: - flg &= ~Frev; - break; - } - - switch(FCASE(op, et, flg)) { - case FCASE(OADD, TFLOAT32, 0): - return AFADDF; - case FCASE(OADD, TFLOAT64, 0): - return AFADDD; - case FCASE(OADD, TFLOAT64, Fpop): - return AFADDDP; - - case FCASE(OSUB, TFLOAT32, 0): - return AFSUBF; - case FCASE(OSUB, TFLOAT32, Frev): - return AFSUBRF; - - case FCASE(OSUB, TFLOAT64, 0): - return AFSUBD; - case FCASE(OSUB, TFLOAT64, Frev): - return AFSUBRD; - case FCASE(OSUB, TFLOAT64, Fpop): - return AFSUBDP; - case FCASE(OSUB, TFLOAT64, Fpop|Frev): - return AFSUBRDP; - - case FCASE(OMUL, TFLOAT32, 0): - return AFMULF; - case FCASE(OMUL, TFLOAT64, 0): - return AFMULD; - case FCASE(OMUL, TFLOAT64, Fpop): - return AFMULDP; - - case FCASE(ODIV, TFLOAT32, 0): - return AFDIVF; - case FCASE(ODIV, TFLOAT32, Frev): - return AFDIVRF; - - case FCASE(ODIV, TFLOAT64, 0): - return AFDIVD; - case FCASE(ODIV, TFLOAT64, Frev): - return AFDIVRD; - case FCASE(ODIV, TFLOAT64, Fpop): - return AFDIVDP; - case FCASE(ODIV, TFLOAT64, Fpop|Frev): - return AFDIVRDP; - - case FCASE(OCMP, TFLOAT32, 0): - return AFCOMF; - case FCASE(OCMP, TFLOAT32, Fpop): - return AFCOMFP; - case FCASE(OCMP, TFLOAT64, 0): - return AFCOMD; - case FCASE(OCMP, TFLOAT64, Fpop): - return AFCOMDP; - case FCASE(OCMP, TFLOAT64, Fpop2): - return AFCOMDPP; - - case FCASE(OMINUS, TFLOAT32, 0): - return AFCHS; - case FCASE(OMINUS, TFLOAT64, 0): - return AFCHS; - } - - fatal("foptoas %O %T %#x", op, t, flg); - return 0; - -sse: - switch(CASE(op, et)) { - default: - fatal("foptoas-sse: no entry %O-%T", op, t); - break; - - case CASE(OCMP, TFLOAT32): - a = AUCOMISS; - break; - - case CASE(OCMP, TFLOAT64): - a = AUCOMISD; - break; - - case CASE(OAS, TFLOAT32): - a = AMOVSS; - break; - - case CASE(OAS, TFLOAT64): - a = AMOVSD; - break; - - case CASE(OADD, TFLOAT32): - a = AADDSS; - break; - - case CASE(OADD, TFLOAT64): - a = AADDSD; - break; - - case CASE(OSUB, TFLOAT32): - a = ASUBSS; - break; - - case CASE(OSUB, TFLOAT64): - a = ASUBSD; - break; - - case CASE(OMUL, TFLOAT32): - a = AMULSS; - break; - - case CASE(OMUL, TFLOAT64): - a = AMULSD; - break; - - case CASE(ODIV, TFLOAT32): - a = ADIVSS; - break; - - case CASE(ODIV, TFLOAT64): - a = ADIVSD; - break; - } - return a; -} - - -static int resvd[] = -{ -// REG_DI, // for movstring -// REG_SI, // for movstring - - REG_AX, // for divide - REG_CX, // for shift - REG_DX, // for divide - REG_SP, // for stack - - REG_BL, // because REG_BX can be allocated - REG_BH, -}; - -void -ginit(void) -{ - int i; - - for(i=0; ietype]; - - switch(et) { - case TINT64: - case TUINT64: - fatal("regalloc64"); - - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TPTR32: - case TPTR64: - case TBOOL: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REG_AX && i <= REG_DI) - goto out; - } - for(i=REG_AX; i<=REG_DI; i++) - if(reg[i] == 0) - goto out; - - print("registers allocated at\n"); - for(i=REG_AX; i<=REG_DI; i++) - print("\t%R\t%#lux\n", i, regpc[i]); - fatal("out of fixed registers"); - goto err; - - case TFLOAT32: - case TFLOAT64: - if(!use_sse) { - i = REG_F0; - goto out; - } - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REG_X0 && i <= REG_X7) - goto out; - } - for(i=REG_X0; i<=REG_X7; i++) - if(reg[i] == 0) - goto out; - print("registers allocated at\n"); - for(i=REG_X0; i<=REG_X7; i++) - print("\t%R\t%#lux\n", i, regpc[i]); - fatal("out of floating registers"); - } - yyerror("regalloc: unknown type %T", t); - -err: - nodreg(n, t, 0); - return; - -out: - if(i == REG_SP) - print("alloc SP\n"); - if(reg[i] == 0) { - regpc[i] = (uintptr)getcallerpc(&n); - if(i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP) { - dump("regalloc-o", o); - fatal("regalloc %R", i); - } - } - reg[i]++; - nodreg(n, t, i); -} - -void -regfree(Node *n) -{ - int i; - - if(n->op == ONAME) - return; - if(n->op != OREGISTER && n->op != OINDREG) - fatal("regfree: not a register"); - i = n->val.u.reg; - if(i == REG_SP) - return; - if(i < 0 || i >= nelem(reg)) - fatal("regfree: reg out of range"); - if(reg[i] <= 0) - fatal("regfree: reg not allocated"); - reg[i]--; - if(reg[i] == 0 && (i == REG_AX || i == REG_CX || i == REG_DX || i == REG_SP)) - fatal("regfree %R", i); -} - -/* - * generate - * as $c, reg - */ -void -gconreg(int as, vlong c, int reg) -{ - Node n1, n2; - - nodconst(&n1, types[TINT64], c); - nodreg(&n2, types[TINT64], reg); - gins(as, &n1, &n2); -} - -/* - * swap node contents - */ -void -nswap(Node *a, Node *b) -{ - Node t; - - t = *a; - *a = *b; - *b = t; -} - -/* - * return constant i node. - * overwritten by next call, but useful in calls to gins. - */ -Node* -ncon(uint32 i) -{ - static Node n; - - if(n.type == T) - nodconst(&n, types[TUINT32], 0); - mpmovecfix(n.val.u.xval, i); - return &n; -} - -Node sclean[10]; -int nsclean; - -/* - * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. - */ -void -split64(Node *n, Node *lo, Node *hi) -{ - Node n1; - int64 i; - - if(!is64(n->type)) - fatal("split64 %T", n->type); - - if(nsclean >= nelem(sclean)) - fatal("split64 clean"); - sclean[nsclean].op = OEMPTY; - nsclean++; - switch(n->op) { - default: - switch(n->op) { - default: - if(!dotaddable(n, &n1)) { - igen(n, &n1, N); - sclean[nsclean-1] = n1; - } - n = &n1; - break; - case ONAME: - if(n->class == PPARAMREF) { - cgen(n->heapaddr, &n1); - sclean[nsclean-1] = n1; - n = &n1; - } - break; - case OINDREG: - // nothing - break; - } - *lo = *n; - *hi = *n; - lo->type = types[TUINT32]; - if(n->type->etype == TINT64) - hi->type = types[TINT32]; - else - hi->type = types[TUINT32]; - hi->xoffset += 4; - break; - - case OLITERAL: - convconst(&n1, n->type, &n->val); - i = mpgetfix(n1.val.u.xval); - nodconst(lo, types[TUINT32], (uint32)i); - i >>= 32; - if(n->type->etype == TINT64) - nodconst(hi, types[TINT32], (int32)i); - else - nodconst(hi, types[TUINT32], (uint32)i); - break; - } -} - -void -splitclean(void) -{ - if(nsclean <= 0) - fatal("splitclean"); - nsclean--; - if(sclean[nsclean].op != OEMPTY) - regfree(&sclean[nsclean]); -} - -/* - * set up nodes representing fp constants - */ -Node zerof; -Node two64f; -Node two63f; - -void -bignodes(void) -{ - static int did; - - if(did) - return; - did = 1; - - two64f = *ncon(0); - two64f.type = types[TFLOAT64]; - two64f.val.ctype = CTFLT; - two64f.val.u.fval = mal(sizeof *two64f.val.u.fval); - mpmovecflt(two64f.val.u.fval, 18446744073709551616.); - - two63f = two64f; - two63f.val.u.fval = mal(sizeof *two63f.val.u.fval); - mpmovecflt(two63f.val.u.fval, 9223372036854775808.); - - zerof = two64f; - zerof.val.u.fval = mal(sizeof *zerof.val.u.fval); - mpmovecflt(zerof.val.u.fval, 0); -} - -void -memname(Node *n, Type *t) -{ - tempname(n, t); - strcpy(namebuf, n->sym->name); - namebuf[0] = '.'; // keep optimizer from registerizing - n->sym = lookup(namebuf); - n->orig->sym = n->sym; -} - -static void floatmove(Node *f, Node *t); -static void floatmove_387(Node *f, Node *t); -static void floatmove_sse(Node *f, Node *t); - -void -gmove(Node *f, Node *t) -{ - int a, ft, tt; - Type *cvt; - Node r1, r2, flo, fhi, tlo, thi, con; - - if(debug['M']) - print("gmove %N -> %N\n", f, t); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); - return; - } - if(isfloat[ft] || isfloat[tt]) { - floatmove(f, t); - return; - } - - // cannot have two integer memory operands; - // except 64-bit, which always copies via registers anyway. - if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - convconst(&con, t->type, &f->val); - f = &con; - ft = simsimtype(con.type); - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - goto fatal; - - /* - * integer copy and truncate - */ - case CASE(TINT8, TINT8): // same size - case CASE(TINT8, TUINT8): - case CASE(TUINT8, TINT8): - case CASE(TUINT8, TUINT8): - a = AMOVB; - break; - - case CASE(TINT16, TINT8): // truncate - case CASE(TUINT16, TINT8): - case CASE(TINT32, TINT8): - case CASE(TUINT32, TINT8): - case CASE(TINT16, TUINT8): - case CASE(TUINT16, TUINT8): - case CASE(TINT32, TUINT8): - case CASE(TUINT32, TUINT8): - a = AMOVB; - goto rsrc; - - case CASE(TINT64, TINT8): // truncate low word - case CASE(TUINT64, TINT8): - case CASE(TINT64, TUINT8): - case CASE(TUINT64, TUINT8): - split64(f, &flo, &fhi); - nodreg(&r1, t->type, REG_AX); - gmove(&flo, &r1); - gins(AMOVB, &r1, t); - splitclean(); - return; - - case CASE(TINT16, TINT16): // same size - case CASE(TINT16, TUINT16): - case CASE(TUINT16, TINT16): - case CASE(TUINT16, TUINT16): - a = AMOVW; - break; - - case CASE(TINT32, TINT16): // truncate - case CASE(TUINT32, TINT16): - case CASE(TINT32, TUINT16): - case CASE(TUINT32, TUINT16): - a = AMOVW; - goto rsrc; - - case CASE(TINT64, TINT16): // truncate low word - case CASE(TUINT64, TINT16): - case CASE(TINT64, TUINT16): - case CASE(TUINT64, TUINT16): - split64(f, &flo, &fhi); - nodreg(&r1, t->type, REG_AX); - gmove(&flo, &r1); - gins(AMOVW, &r1, t); - splitclean(); - return; - - case CASE(TINT32, TINT32): // same size - case CASE(TINT32, TUINT32): - case CASE(TUINT32, TINT32): - case CASE(TUINT32, TUINT32): - a = AMOVL; - break; - - case CASE(TINT64, TINT32): // truncate - case CASE(TUINT64, TINT32): - case CASE(TINT64, TUINT32): - case CASE(TUINT64, TUINT32): - split64(f, &flo, &fhi); - nodreg(&r1, t->type, REG_AX); - gmove(&flo, &r1); - gins(AMOVL, &r1, t); - splitclean(); - return; - - case CASE(TINT64, TINT64): // same size - case CASE(TINT64, TUINT64): - case CASE(TUINT64, TINT64): - case CASE(TUINT64, TUINT64): - split64(f, &flo, &fhi); - split64(t, &tlo, &thi); - if(f->op == OLITERAL) { - gins(AMOVL, &flo, &tlo); - gins(AMOVL, &fhi, &thi); - } else { - nodreg(&r1, types[TUINT32], REG_AX); - nodreg(&r2, types[TUINT32], REG_DX); - gins(AMOVL, &flo, &r1); - gins(AMOVL, &fhi, &r2); - gins(AMOVL, &r1, &tlo); - gins(AMOVL, &r2, &thi); - } - splitclean(); - splitclean(); - return; - - /* - * integer up-conversions - */ - case CASE(TINT8, TINT16): // sign extend int8 - case CASE(TINT8, TUINT16): - a = AMOVBWSX; - goto rdst; - case CASE(TINT8, TINT32): - case CASE(TINT8, TUINT32): - a = AMOVBLSX; - goto rdst; - case CASE(TINT8, TINT64): // convert via int32 - case CASE(TINT8, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT8, TINT16): // zero extend uint8 - case CASE(TUINT8, TUINT16): - a = AMOVBWZX; - goto rdst; - case CASE(TUINT8, TINT32): - case CASE(TUINT8, TUINT32): - a = AMOVBLZX; - goto rdst; - case CASE(TUINT8, TINT64): // convert via uint32 - case CASE(TUINT8, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT16, TINT32): // sign extend int16 - case CASE(TINT16, TUINT32): - a = AMOVWLSX; - goto rdst; - case CASE(TINT16, TINT64): // convert via int32 - case CASE(TINT16, TUINT64): - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT16, TINT32): // zero extend uint16 - case CASE(TUINT16, TUINT32): - a = AMOVWLZX; - goto rdst; - case CASE(TUINT16, TINT64): // convert via uint32 - case CASE(TUINT16, TUINT64): - cvt = types[TUINT32]; - goto hard; - - case CASE(TINT32, TINT64): // sign extend int32 - case CASE(TINT32, TUINT64): - split64(t, &tlo, &thi); - nodreg(&flo, tlo.type, REG_AX); - nodreg(&fhi, thi.type, REG_DX); - gmove(f, &flo); - gins(ACDQ, N, N); - gins(AMOVL, &flo, &tlo); - gins(AMOVL, &fhi, &thi); - splitclean(); - return; - - case CASE(TUINT32, TINT64): // zero extend uint32 - case CASE(TUINT32, TUINT64): - split64(t, &tlo, &thi); - gmove(f, &tlo); - gins(AMOVL, ncon(0), &thi); - splitclean(); - return; - } - - gins(a, f, t); - return; - -rsrc: - // requires register source - regalloc(&r1, f->type, t); - gmove(f, &r1); - gins(a, &r1, t); - regfree(&r1); - return; - -rdst: - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -fatal: - // should not happen - fatal("gmove %N -> %N", f, t); -} - -static void -floatmove(Node *f, Node *t) -{ - Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx; - Type *cvt; - int ft, tt; - Prog *p1, *p2, *p3; - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - // cannot have two floating point memory operands. - if(isfloat[ft] && isfloat[tt] && ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - convconst(&con, t->type, &f->val); - f = &con; - ft = simsimtype(con.type); - - // some constants can't move directly to memory. - if(ismem(t)) { - // float constants come from memory. - if(isfloat[tt]) - goto hard; - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - if(use_sse) - floatmove_sse(f, t); - else - floatmove_387(f, t); - return; - - // float to very long integer. - case CASE(TFLOAT32, TINT64): - case CASE(TFLOAT64, TINT64): - if(f->op == OREGISTER) { - cvt = f->type; - goto hardmem; - } - nodreg(&r1, types[ft], REG_F0); - if(ft == TFLOAT32) - gins(AFMOVF, f, &r1); - else - gins(AFMOVD, f, &r1); - - // set round to zero mode during conversion - memname(&t1, types[TUINT16]); - memname(&t2, types[TUINT16]); - gins(AFSTCW, N, &t1); - gins(AMOVW, ncon(0xf7f), &t2); - gins(AFLDCW, &t2, N); - if(tt == TINT16) - gins(AFMOVWP, &r1, t); - else if(tt == TINT32) - gins(AFMOVLP, &r1, t); - else - gins(AFMOVVP, &r1, t); - gins(AFLDCW, &t1, N); - return; - - case CASE(TFLOAT32, TUINT64): - case CASE(TFLOAT64, TUINT64): - if(!ismem(f)) { - cvt = f->type; - goto hardmem; - } - bignodes(); - nodreg(&f0, types[ft], REG_F0); - nodreg(&f1, types[ft], REG_F0 + 1); - nodreg(&ax, types[TUINT16], REG_AX); - - if(ft == TFLOAT32) - gins(AFMOVF, f, &f0); - else - gins(AFMOVD, f, &f0); - - // if 0 > v { answer = 0 } - gins(AFMOVD, &zerof, &f0); - gins(AFUCOMIP, &f0, &f1); - p1 = gbranch(optoas(OGT, types[tt]), T, 0); - // if 1<<64 <= v { answer = 0 too } - gins(AFMOVD, &two64f, &f0); - gins(AFUCOMIP, &f0, &f1); - p2 = gbranch(optoas(OGT, types[tt]), T, 0); - patch(p1, pc); - gins(AFMOVVP, &f0, t); // don't care about t, but will pop the stack - split64(t, &tlo, &thi); - gins(AMOVL, ncon(0), &tlo); - gins(AMOVL, ncon(0), &thi); - splitclean(); - p1 = gbranch(AJMP, T, 0); - patch(p2, pc); - - // in range; algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - - // set round to zero mode during conversion - memname(&t1, types[TUINT16]); - memname(&t2, types[TUINT16]); - gins(AFSTCW, N, &t1); - gins(AMOVW, ncon(0xf7f), &t2); - gins(AFLDCW, &t2, N); - - // actual work - gins(AFMOVD, &two63f, &f0); - gins(AFUCOMIP, &f0, &f1); - p2 = gbranch(optoas(OLE, types[tt]), T, 0); - gins(AFMOVVP, &f0, t); - p3 = gbranch(AJMP, T, 0); - patch(p2, pc); - gins(AFMOVD, &two63f, &f0); - gins(AFSUBDP, &f0, &f1); - gins(AFMOVVP, &f0, t); - split64(t, &tlo, &thi); - gins(AXORL, ncon(0x80000000), &thi); // + 2^63 - patch(p3, pc); - splitclean(); - // restore rounding mode - gins(AFLDCW, &t1, N); - - patch(p1, pc); - return; - - /* - * integer to float - */ - case CASE(TINT64, TFLOAT32): - case CASE(TINT64, TFLOAT64): - if(t->op == OREGISTER) - goto hardmem; - nodreg(&f0, t->type, REG_F0); - gins(AFMOVV, f, &f0); - if(tt == TFLOAT32) - gins(AFMOVFP, &f0, t); - else - gins(AFMOVDP, &f0, t); - return; - - case CASE(TUINT64, TFLOAT32): - case CASE(TUINT64, TFLOAT64): - // algorithm is: - // if small enough, use native int64 -> float64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - nodreg(&ax, types[TUINT32], REG_AX); - nodreg(&dx, types[TUINT32], REG_DX); - nodreg(&cx, types[TUINT32], REG_CX); - tempname(&t1, f->type); - split64(&t1, &tlo, &thi); - gmove(f, &t1); - gins(ACMPL, &thi, ncon(0)); - p1 = gbranch(AJLT, T, 0); - // native - nodreg(&r1, types[tt], REG_F0); - gins(AFMOVV, &t1, &r1); - if(tt == TFLOAT32) - gins(AFMOVFP, &r1, t); - else - gins(AFMOVDP, &r1, t); - p2 = gbranch(AJMP, T, 0); - // simulated - patch(p1, pc); - gmove(&tlo, &ax); - gmove(&thi, &dx); - p1 = gins(ASHRL, ncon(1), &ax); - p1->from.index = REG_DX; // double-width shift DX -> AX - p1->from.scale = 0; - gins(AMOVL, ncon(0), &cx); - gins(ASETCC, N, &cx); - gins(AORL, &cx, &ax); - gins(ASHRL, ncon(1), &dx); - gmove(&dx, &thi); - gmove(&ax, &tlo); - nodreg(&r1, types[tt], REG_F0); - nodreg(&r2, types[tt], REG_F0 + 1); - gins(AFMOVV, &t1, &r1); - gins(AFMOVD, &r1, &r1); - gins(AFADDDP, &r1, &r2); - if(tt == TFLOAT32) - gins(AFMOVFP, &r1, t); - else - gins(AFMOVDP, &r1, t); - patch(p2, pc); - splitclean(); - return; - } - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hardmem: - // requires memory intermediate - tempname(&r1, cvt); - gmove(f, &r1); - gmove(&r1, t); - return; -} - -static void -floatmove_387(Node *f, Node *t) -{ - Node r1, t1, t2; - Type *cvt; - Prog *p1, *p2, *p3; - int a, ft, tt; - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - switch(CASE(ft, tt)) { - default: - goto fatal; - - /* - * float to integer - */ - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TINT32): - case CASE(TFLOAT32, TINT64): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TINT32): - case CASE(TFLOAT64, TINT64): - if(t->op == OREGISTER) - goto hardmem; - nodreg(&r1, types[ft], REG_F0); - if(f->op != OREGISTER) { - if(ft == TFLOAT32) - gins(AFMOVF, f, &r1); - else - gins(AFMOVD, f, &r1); - } - - // set round to zero mode during conversion - memname(&t1, types[TUINT16]); - memname(&t2, types[TUINT16]); - gins(AFSTCW, N, &t1); - gins(AMOVW, ncon(0xf7f), &t2); - gins(AFLDCW, &t2, N); - if(tt == TINT16) - gins(AFMOVWP, &r1, t); - else if(tt == TINT32) - gins(AFMOVLP, &r1, t); - else - gins(AFMOVVP, &r1, t); - gins(AFLDCW, &t1, N); - return; - - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TUINT8): - // convert via int32. - tempname(&t1, types[TINT32]); - gmove(f, &t1); - switch(tt) { - default: - fatal("gmove %N", t); - case TINT8: - gins(ACMPL, &t1, ncon(-0x80)); - p1 = gbranch(optoas(OLT, types[TINT32]), T, -1); - gins(ACMPL, &t1, ncon(0x7f)); - p2 = gbranch(optoas(OGT, types[TINT32]), T, -1); - p3 = gbranch(AJMP, T, 0); - patch(p1, pc); - patch(p2, pc); - gmove(ncon(-0x80), &t1); - patch(p3, pc); - gmove(&t1, t); - break; - case TUINT8: - gins(ATESTL, ncon(0xffffff00), &t1); - p1 = gbranch(AJEQ, T, +1); - gins(AMOVL, ncon(0), &t1); - patch(p1, pc); - gmove(&t1, t); - break; - case TUINT16: - gins(ATESTL, ncon(0xffff0000), &t1); - p1 = gbranch(AJEQ, T, +1); - gins(AMOVL, ncon(0), &t1); - patch(p1, pc); - gmove(&t1, t); - break; - } - return; - - case CASE(TFLOAT32, TUINT32): - case CASE(TFLOAT64, TUINT32): - // convert via int64. - cvt = types[TINT64]; - goto hardmem; - - /* - * integer to float - */ - case CASE(TINT16, TFLOAT32): - case CASE(TINT16, TFLOAT64): - case CASE(TINT32, TFLOAT32): - case CASE(TINT32, TFLOAT64): - case CASE(TINT64, TFLOAT32): - case CASE(TINT64, TFLOAT64): - if(t->op != OREGISTER) - goto hard; - if(f->op == OREGISTER) { - cvt = f->type; - goto hardmem; - } - switch(ft) { - case TINT16: - a = AFMOVW; - break; - case TINT32: - a = AFMOVL; - break; - default: - a = AFMOVV; - break; - } - break; - - case CASE(TINT8, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT64): - case CASE(TUINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT64): - // convert via int32 memory - cvt = types[TINT32]; - goto hardmem; - - case CASE(TUINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT64): - // convert via int64 memory - cvt = types[TINT64]; - goto hardmem; - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - case CASE(TFLOAT64, TFLOAT64): - // The way the code generator uses floating-point - // registers, a move from F0 to F0 is intended as a no-op. - // On the x86, it's not: it pushes a second copy of F0 - // on the floating point stack. So toss it away here. - // Also, F0 is the *only* register we ever evaluate - // into, so we should only see register/register as F0/F0. - if(ismem(f) && ismem(t)) - goto hard; - if(f->op == OREGISTER && t->op == OREGISTER) { - if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0) - goto fatal; - return; - } - a = AFMOVF; - if(ft == TFLOAT64) - a = AFMOVD; - if(ismem(t)) { - if(f->op != OREGISTER || f->val.u.reg != REG_F0) - fatal("gmove %N", f); - a = AFMOVFP; - if(ft == TFLOAT64) - a = AFMOVDP; - } - break; - - case CASE(TFLOAT32, TFLOAT64): - if(ismem(f) && ismem(t)) - goto hard; - if(f->op == OREGISTER && t->op == OREGISTER) { - if(f->val.u.reg != REG_F0 || t->val.u.reg != REG_F0) - goto fatal; - return; - } - if(f->op == OREGISTER) - gins(AFMOVDP, f, t); - else - gins(AFMOVF, f, t); - return; - - case CASE(TFLOAT64, TFLOAT32): - if(ismem(f) && ismem(t)) - goto hard; - if(f->op == OREGISTER && t->op == OREGISTER) { - tempname(&r1, types[TFLOAT32]); - gins(AFMOVFP, f, &r1); - gins(AFMOVF, &r1, t); - return; - } - if(f->op == OREGISTER) - gins(AFMOVFP, f, t); - else - gins(AFMOVD, f, t); - return; - } - - gins(a, f, t); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hardmem: - // requires memory intermediate - tempname(&r1, cvt); - gmove(f, &r1); - gmove(&r1, t); - return; - -fatal: - // should not happen - fatal("gmove %lN -> %lN", f, t); - return; -} - -static void -floatmove_sse(Node *f, Node *t) -{ - Node r1; - Type *cvt; - int a, ft, tt; - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - - switch(CASE(ft, tt)) { - default: - // should not happen - fatal("gmove %N -> %N", f, t); - return; - /* - * float to integer - */ - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TUINT8): - // convert via int32. - cvt = types[TINT32]; - goto hard; - - case CASE(TFLOAT32, TUINT32): - case CASE(TFLOAT64, TUINT32): - // convert via int64. - cvt = types[TINT64]; - goto hardmem; - - case CASE(TFLOAT32, TINT32): - a = ACVTTSS2SL; - goto rdst; - - case CASE(TFLOAT64, TINT32): - a = ACVTTSD2SL; - goto rdst; - - /* - * integer to float - */ - case CASE(TINT8, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TINT16, TFLOAT32): - case CASE(TINT16, TFLOAT64): - case CASE(TUINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT64): - case CASE(TUINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT64): - // convert via int32 memory - cvt = types[TINT32]; - goto hard; - - case CASE(TUINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT64): - // convert via int64 memory - cvt = types[TINT64]; - goto hardmem; - - case CASE(TINT32, TFLOAT32): - a = ACVTSL2SS; - goto rdst; - - case CASE(TINT32, TFLOAT64): - a = ACVTSL2SD; - goto rdst; - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - a = AMOVSS; - break; - - case CASE(TFLOAT64, TFLOAT64): - a = AMOVSD; - break; - - case CASE(TFLOAT32, TFLOAT64): - a = ACVTSS2SD; - goto rdst; - - case CASE(TFLOAT64, TFLOAT32): - a = ACVTSD2SS; - goto rdst; - } - - gins(a, f, t); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hardmem: - // requires memory intermediate - tempname(&r1, cvt); - gmove(f, &r1); - gmove(&r1, t); - return; - -rdst: - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; -} - -int -samaddr(Node *f, Node *t) -{ - - if(f->op != t->op) - return 0; - - switch(f->op) { - case OREGISTER: - if(f->val.u.reg != t->val.u.reg) - break; - return 1; - } - return 0; -} -/* - * generate one instruction: - * as f, t - */ -Prog* -gins(int as, Node *f, Node *t) -{ - Prog *p; - Addr af, at; - int w; - - if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER) - fatal("gins MOVF reg, reg"); - if(as == ACVTSD2SS && f && f->op == OLITERAL) - fatal("gins CVTSD2SS const"); - if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == REG_F0) - fatal("gins MOVSD into F0"); - - switch(as) { - case AMOVB: - case AMOVW: - case AMOVL: - if(f != N && t != N && samaddr(f, t)) - return nil; - break; - - case ALEAL: - if(f != N && isconst(f, CTNIL)) - fatal("gins LEAL nil %T", f->type); - break; - } - - memset(&af, 0, sizeof af); - memset(&at, 0, sizeof at); - if(f != N) - naddr(f, &af, 1); - if(t != N) - naddr(t, &at, 1); - p = prog(as); - if(f != N) - p->from = af; - if(t != N) - p->to = at; - if(debug['g']) - print("%P\n", p); - - w = 0; - switch(as) { - case AMOVB: - w = 1; - break; - case AMOVW: - w = 2; - break; - case AMOVL: - w = 4; - break; - } - - if(1 && w != 0 && f != N && (af.width > w || at.width > w)) { - dump("bad width from:", f); - dump("bad width to:", t); - fatal("bad width: %P (%d, %d)\n", p, af.width, at.width); - } - if(p->to.type == TYPE_ADDR && w > 0) - fatal("bad use of addr: %P", p); - - return p; -} - -int -dotaddable(Node *n, Node *n1) -{ - int o; - int64 oary[10]; - Node *nn; - - if(n->op != ODOT) - return 0; - - o = dotoffset(n, oary, &nn); - if(nn != N && nn->addable && o == 1 && oary[0] >= 0) { - *n1 = *nn; - n1->type = n->type; - n1->xoffset += oary[0]; - return 1; - } - return 0; -} - -void -sudoclean(void) -{ -} - -int -sudoaddable(int as, Node *n, Addr *a) -{ - USED(as); - USED(n); - - memset(a, 0, sizeof *a); - return 0; -} diff --git a/src/cmd/8g/gsubr.go b/src/cmd/8g/gsubr.go new file mode 100644 index 0000000000..2728c2a276 --- /dev/null +++ b/src/cmd/8g/gsubr.go @@ -0,0 +1,1931 @@ +// Derived from Inferno utils/8c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" + "fmt" +) +import "cmd/internal/gc" + +// TODO(rsc): Can make this bigger if we move +// the text segment up higher in 8l for all GOOS. +// At the same time, can raise StackBig in ../../runtime/stack.h. +var unmappedzero uint32 = 4096 + +/* + * return Axxx for Oxxx on type t. + */ +func optoas(op int, t *gc.Type) int { + var a int + + if t == nil { + gc.Fatal("optoas: t is nil") + } + + a = obj.AXXX + switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { + default: + gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + case gc.OADDR<<16 | gc.TPTR32: + a = i386.ALEAL + + case gc.OEQ<<16 | gc.TBOOL, + gc.OEQ<<16 | gc.TINT8, + gc.OEQ<<16 | gc.TUINT8, + gc.OEQ<<16 | gc.TINT16, + gc.OEQ<<16 | gc.TUINT16, + gc.OEQ<<16 | gc.TINT32, + gc.OEQ<<16 | gc.TUINT32, + gc.OEQ<<16 | gc.TINT64, + gc.OEQ<<16 | gc.TUINT64, + gc.OEQ<<16 | gc.TPTR32, + gc.OEQ<<16 | gc.TPTR64, + gc.OEQ<<16 | gc.TFLOAT32, + gc.OEQ<<16 | gc.TFLOAT64: + a = i386.AJEQ + + case gc.ONE<<16 | gc.TBOOL, + gc.ONE<<16 | gc.TINT8, + gc.ONE<<16 | gc.TUINT8, + gc.ONE<<16 | gc.TINT16, + gc.ONE<<16 | gc.TUINT16, + gc.ONE<<16 | gc.TINT32, + gc.ONE<<16 | gc.TUINT32, + gc.ONE<<16 | gc.TINT64, + gc.ONE<<16 | gc.TUINT64, + gc.ONE<<16 | gc.TPTR32, + gc.ONE<<16 | gc.TPTR64, + gc.ONE<<16 | gc.TFLOAT32, + gc.ONE<<16 | gc.TFLOAT64: + a = i386.AJNE + + case gc.OLT<<16 | gc.TINT8, + gc.OLT<<16 | gc.TINT16, + gc.OLT<<16 | gc.TINT32, + gc.OLT<<16 | gc.TINT64: + a = i386.AJLT + + case gc.OLT<<16 | gc.TUINT8, + gc.OLT<<16 | gc.TUINT16, + gc.OLT<<16 | gc.TUINT32, + gc.OLT<<16 | gc.TUINT64: + a = i386.AJCS + + case gc.OLE<<16 | gc.TINT8, + gc.OLE<<16 | gc.TINT16, + gc.OLE<<16 | gc.TINT32, + gc.OLE<<16 | gc.TINT64: + a = i386.AJLE + + case gc.OLE<<16 | gc.TUINT8, + gc.OLE<<16 | gc.TUINT16, + gc.OLE<<16 | gc.TUINT32, + gc.OLE<<16 | gc.TUINT64: + a = i386.AJLS + + case gc.OGT<<16 | gc.TINT8, + gc.OGT<<16 | gc.TINT16, + gc.OGT<<16 | gc.TINT32, + gc.OGT<<16 | gc.TINT64: + a = i386.AJGT + + case gc.OGT<<16 | gc.TUINT8, + gc.OGT<<16 | gc.TUINT16, + gc.OGT<<16 | gc.TUINT32, + gc.OGT<<16 | gc.TUINT64, + gc.OLT<<16 | gc.TFLOAT32, + gc.OLT<<16 | gc.TFLOAT64: + a = i386.AJHI + + case gc.OGE<<16 | gc.TINT8, + gc.OGE<<16 | gc.TINT16, + gc.OGE<<16 | gc.TINT32, + gc.OGE<<16 | gc.TINT64: + a = i386.AJGE + + case gc.OGE<<16 | gc.TUINT8, + gc.OGE<<16 | gc.TUINT16, + gc.OGE<<16 | gc.TUINT32, + gc.OGE<<16 | gc.TUINT64, + gc.OLE<<16 | gc.TFLOAT32, + gc.OLE<<16 | gc.TFLOAT64: + a = i386.AJCC + + case gc.OCMP<<16 | gc.TBOOL, + gc.OCMP<<16 | gc.TINT8, + gc.OCMP<<16 | gc.TUINT8: + a = i386.ACMPB + + case gc.OCMP<<16 | gc.TINT16, + gc.OCMP<<16 | gc.TUINT16: + a = i386.ACMPW + + case gc.OCMP<<16 | gc.TINT32, + gc.OCMP<<16 | gc.TUINT32, + gc.OCMP<<16 | gc.TPTR32: + a = i386.ACMPL + + case gc.OAS<<16 | gc.TBOOL, + gc.OAS<<16 | gc.TINT8, + gc.OAS<<16 | gc.TUINT8: + a = i386.AMOVB + + case gc.OAS<<16 | gc.TINT16, + gc.OAS<<16 | gc.TUINT16: + a = i386.AMOVW + + case gc.OAS<<16 | gc.TINT32, + gc.OAS<<16 | gc.TUINT32, + gc.OAS<<16 | gc.TPTR32: + a = i386.AMOVL + + case gc.OAS<<16 | gc.TFLOAT32: + a = i386.AMOVSS + + case gc.OAS<<16 | gc.TFLOAT64: + a = i386.AMOVSD + + case gc.OADD<<16 | gc.TINT8, + gc.OADD<<16 | gc.TUINT8: + a = i386.AADDB + + case gc.OADD<<16 | gc.TINT16, + gc.OADD<<16 | gc.TUINT16: + a = i386.AADDW + + case gc.OADD<<16 | gc.TINT32, + gc.OADD<<16 | gc.TUINT32, + gc.OADD<<16 | gc.TPTR32: + a = i386.AADDL + + case gc.OSUB<<16 | gc.TINT8, + gc.OSUB<<16 | gc.TUINT8: + a = i386.ASUBB + + case gc.OSUB<<16 | gc.TINT16, + gc.OSUB<<16 | gc.TUINT16: + a = i386.ASUBW + + case gc.OSUB<<16 | gc.TINT32, + gc.OSUB<<16 | gc.TUINT32, + gc.OSUB<<16 | gc.TPTR32: + a = i386.ASUBL + + case gc.OINC<<16 | gc.TINT8, + gc.OINC<<16 | gc.TUINT8: + a = i386.AINCB + + case gc.OINC<<16 | gc.TINT16, + gc.OINC<<16 | gc.TUINT16: + a = i386.AINCW + + case gc.OINC<<16 | gc.TINT32, + gc.OINC<<16 | gc.TUINT32, + gc.OINC<<16 | gc.TPTR32: + a = i386.AINCL + + case gc.ODEC<<16 | gc.TINT8, + gc.ODEC<<16 | gc.TUINT8: + a = i386.ADECB + + case gc.ODEC<<16 | gc.TINT16, + gc.ODEC<<16 | gc.TUINT16: + a = i386.ADECW + + case gc.ODEC<<16 | gc.TINT32, + gc.ODEC<<16 | gc.TUINT32, + gc.ODEC<<16 | gc.TPTR32: + a = i386.ADECL + + case gc.OCOM<<16 | gc.TINT8, + gc.OCOM<<16 | gc.TUINT8: + a = i386.ANOTB + + case gc.OCOM<<16 | gc.TINT16, + gc.OCOM<<16 | gc.TUINT16: + a = i386.ANOTW + + case gc.OCOM<<16 | gc.TINT32, + gc.OCOM<<16 | gc.TUINT32, + gc.OCOM<<16 | gc.TPTR32: + a = i386.ANOTL + + case gc.OMINUS<<16 | gc.TINT8, + gc.OMINUS<<16 | gc.TUINT8: + a = i386.ANEGB + + case gc.OMINUS<<16 | gc.TINT16, + gc.OMINUS<<16 | gc.TUINT16: + a = i386.ANEGW + + case gc.OMINUS<<16 | gc.TINT32, + gc.OMINUS<<16 | gc.TUINT32, + gc.OMINUS<<16 | gc.TPTR32: + a = i386.ANEGL + + case gc.OAND<<16 | gc.TINT8, + gc.OAND<<16 | gc.TUINT8: + a = i386.AANDB + + case gc.OAND<<16 | gc.TINT16, + gc.OAND<<16 | gc.TUINT16: + a = i386.AANDW + + case gc.OAND<<16 | gc.TINT32, + gc.OAND<<16 | gc.TUINT32, + gc.OAND<<16 | gc.TPTR32: + a = i386.AANDL + + case gc.OOR<<16 | gc.TINT8, + gc.OOR<<16 | gc.TUINT8: + a = i386.AORB + + case gc.OOR<<16 | gc.TINT16, + gc.OOR<<16 | gc.TUINT16: + a = i386.AORW + + case gc.OOR<<16 | gc.TINT32, + gc.OOR<<16 | gc.TUINT32, + gc.OOR<<16 | gc.TPTR32: + a = i386.AORL + + case gc.OXOR<<16 | gc.TINT8, + gc.OXOR<<16 | gc.TUINT8: + a = i386.AXORB + + case gc.OXOR<<16 | gc.TINT16, + gc.OXOR<<16 | gc.TUINT16: + a = i386.AXORW + + case gc.OXOR<<16 | gc.TINT32, + gc.OXOR<<16 | gc.TUINT32, + gc.OXOR<<16 | gc.TPTR32: + a = i386.AXORL + + case gc.OLROT<<16 | gc.TINT8, + gc.OLROT<<16 | gc.TUINT8: + a = i386.AROLB + + case gc.OLROT<<16 | gc.TINT16, + gc.OLROT<<16 | gc.TUINT16: + a = i386.AROLW + + case gc.OLROT<<16 | gc.TINT32, + gc.OLROT<<16 | gc.TUINT32, + gc.OLROT<<16 | gc.TPTR32: + a = i386.AROLL + + case gc.OLSH<<16 | gc.TINT8, + gc.OLSH<<16 | gc.TUINT8: + a = i386.ASHLB + + case gc.OLSH<<16 | gc.TINT16, + gc.OLSH<<16 | gc.TUINT16: + a = i386.ASHLW + + case gc.OLSH<<16 | gc.TINT32, + gc.OLSH<<16 | gc.TUINT32, + gc.OLSH<<16 | gc.TPTR32: + a = i386.ASHLL + + case gc.ORSH<<16 | gc.TUINT8: + a = i386.ASHRB + + case gc.ORSH<<16 | gc.TUINT16: + a = i386.ASHRW + + case gc.ORSH<<16 | gc.TUINT32, + gc.ORSH<<16 | gc.TPTR32: + a = i386.ASHRL + + case gc.ORSH<<16 | gc.TINT8: + a = i386.ASARB + + case gc.ORSH<<16 | gc.TINT16: + a = i386.ASARW + + case gc.ORSH<<16 | gc.TINT32: + a = i386.ASARL + + case gc.OHMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TUINT8: + a = i386.AIMULB + + case gc.OHMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TUINT16: + a = i386.AIMULW + + case gc.OHMUL<<16 | gc.TINT32, + gc.OMUL<<16 | gc.TINT32, + gc.OMUL<<16 | gc.TUINT32, + gc.OMUL<<16 | gc.TPTR32: + a = i386.AIMULL + + case gc.OHMUL<<16 | gc.TUINT8: + a = i386.AMULB + + case gc.OHMUL<<16 | gc.TUINT16: + a = i386.AMULW + + case gc.OHMUL<<16 | gc.TUINT32, + gc.OHMUL<<16 | gc.TPTR32: + a = i386.AMULL + + case gc.ODIV<<16 | gc.TINT8, + gc.OMOD<<16 | gc.TINT8: + a = i386.AIDIVB + + case gc.ODIV<<16 | gc.TUINT8, + gc.OMOD<<16 | gc.TUINT8: + a = i386.ADIVB + + case gc.ODIV<<16 | gc.TINT16, + gc.OMOD<<16 | gc.TINT16: + a = i386.AIDIVW + + case gc.ODIV<<16 | gc.TUINT16, + gc.OMOD<<16 | gc.TUINT16: + a = i386.ADIVW + + case gc.ODIV<<16 | gc.TINT32, + gc.OMOD<<16 | gc.TINT32: + a = i386.AIDIVL + + case gc.ODIV<<16 | gc.TUINT32, + gc.ODIV<<16 | gc.TPTR32, + gc.OMOD<<16 | gc.TUINT32, + gc.OMOD<<16 | gc.TPTR32: + a = i386.ADIVL + + case gc.OEXTEND<<16 | gc.TINT16: + a = i386.ACWD + + case gc.OEXTEND<<16 | gc.TINT32: + a = i386.ACDQ + } + + return a +} + +func foptoas(op int, t *gc.Type, flg int) int { + var et int + var a int + + a = obj.AXXX + et = int(gc.Simtype[t.Etype]) + + if gc.Use_sse != 0 { + goto sse + } + + // If we need Fpop, it means we're working on + // two different floating-point registers, not memory. + // There the instruction only has a float64 form. + if flg&Fpop != 0 { + et = gc.TFLOAT64 + } + + // clear Frev if unneeded + switch op { + case gc.OADD, + gc.OMUL: + flg &^= Frev + } + + switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) { + case gc.OADD<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFADDF + + case gc.OADD<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFADDD + + case gc.OADD<<16 | (gc.TFLOAT64<<8 | Fpop): + return i386.AFADDDP + + case gc.OSUB<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFSUBF + + case gc.OSUB<<16 | (gc.TFLOAT32<<8 | Frev): + return i386.AFSUBRF + + case gc.OSUB<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFSUBD + + case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Frev): + return i386.AFSUBRD + + case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Fpop): + return i386.AFSUBDP + + case gc.OSUB<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)): + return i386.AFSUBRDP + + case gc.OMUL<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFMULF + + case gc.OMUL<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFMULD + + case gc.OMUL<<16 | (gc.TFLOAT64<<8 | Fpop): + return i386.AFMULDP + + case gc.ODIV<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFDIVF + + case gc.ODIV<<16 | (gc.TFLOAT32<<8 | Frev): + return i386.AFDIVRF + + case gc.ODIV<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFDIVD + + case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Frev): + return i386.AFDIVRD + + case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Fpop): + return i386.AFDIVDP + + case gc.ODIV<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)): + return i386.AFDIVRDP + + case gc.OCMP<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFCOMF + + case gc.OCMP<<16 | (gc.TFLOAT32<<8 | Fpop): + return i386.AFCOMFP + + case gc.OCMP<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFCOMD + + case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop): + return i386.AFCOMDP + + case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop2): + return i386.AFCOMDPP + + case gc.OMINUS<<16 | (gc.TFLOAT32<<8 | 0): + return i386.AFCHS + + case gc.OMINUS<<16 | (gc.TFLOAT64<<8 | 0): + return i386.AFCHS + } + + gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), gc.Tconv(t, 0), flg) + return 0 + +sse: + switch uint32(op)<<16 | uint32(et) { + default: + gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + case gc.OCMP<<16 | gc.TFLOAT32: + a = i386.AUCOMISS + + case gc.OCMP<<16 | gc.TFLOAT64: + a = i386.AUCOMISD + + case gc.OAS<<16 | gc.TFLOAT32: + a = i386.AMOVSS + + case gc.OAS<<16 | gc.TFLOAT64: + a = i386.AMOVSD + + case gc.OADD<<16 | gc.TFLOAT32: + a = i386.AADDSS + + case gc.OADD<<16 | gc.TFLOAT64: + a = i386.AADDSD + + case gc.OSUB<<16 | gc.TFLOAT32: + a = i386.ASUBSS + + case gc.OSUB<<16 | gc.TFLOAT64: + a = i386.ASUBSD + + case gc.OMUL<<16 | gc.TFLOAT32: + a = i386.AMULSS + + case gc.OMUL<<16 | gc.TFLOAT64: + a = i386.AMULSD + + case gc.ODIV<<16 | gc.TFLOAT32: + a = i386.ADIVSS + + case gc.ODIV<<16 | gc.TFLOAT64: + a = i386.ADIVSD + } + + return a +} + +var resvd = []int{ + // REG_DI, // for movstring + // REG_SI, // for movstring + + i386.REG_AX, // for divide + i386.REG_CX, // for shift + i386.REG_DX, // for divide + i386.REG_SP, // for stack + + i386.REG_BL, // because REG_BX can be allocated + i386.REG_BH, +} + +func ginit() { + var i int + + for i = 0; i < len(reg); i++ { + reg[i] = 1 + } + for i = i386.REG_AX; i <= i386.REG_DI; i++ { + reg[i] = 0 + } + for i = i386.REG_X0; i <= i386.REG_X7; i++ { + reg[i] = 0 + } + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]++ + } +} + +var regpc [i386.MAXREG]uint32 + +func gclean() { + var i int + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]]-- + } + + for i = i386.REG_AX; i <= i386.REG_DI; i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated at %x", gc.Ctxt.Rconv(i), regpc[i]) + } + } + for i = i386.REG_X0; i <= i386.REG_X7; i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) + } + } +} + +func anyregalloc() bool { + var i int + var j int + + for i = i386.REG_AX; i <= i386.REG_DI; i++ { + if reg[i] == 0 { + goto ok + } + for j = 0; j < len(resvd); j++ { + if resvd[j] == i { + goto ok + } + } + return true + ok: + } + + for i = i386.REG_X0; i <= i386.REG_X7; i++ { + if reg[i] != 0 { + return true + } + } + return false +} + +/* + * allocate register of type t, leave in n. + * if o != N, o is desired fixed register. + * caller must regfree(n). + */ +func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { + var i int + var et int + + if t == nil { + gc.Fatal("regalloc: t nil") + } + et = int(gc.Simtype[t.Etype]) + + switch et { + case gc.TINT64, + gc.TUINT64: + gc.Fatal("regalloc64") + + case gc.TINT8, + gc.TUINT8, + gc.TINT16, + gc.TUINT16, + gc.TINT32, + gc.TUINT32, + gc.TPTR32, + gc.TPTR64, + gc.TBOOL: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= i386.REG_AX && i <= i386.REG_DI { + goto out + } + } + + for i = i386.REG_AX; i <= i386.REG_DI; i++ { + if reg[i] == 0 { + goto out + } + } + + fmt.Printf("registers allocated at\n") + for i = i386.REG_AX; i <= i386.REG_DI; i++ { + fmt.Printf("\t%v\t%#x\n", gc.Ctxt.Rconv(i), regpc[i]) + } + gc.Fatal("out of fixed registers") + goto err + + case gc.TFLOAT32, + gc.TFLOAT64: + if gc.Use_sse == 0 { + i = i386.REG_F0 + goto out + } + + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= i386.REG_X0 && i <= i386.REG_X7 { + goto out + } + } + + for i = i386.REG_X0; i <= i386.REG_X7; i++ { + if reg[i] == 0 { + goto out + } + } + fmt.Printf("registers allocated at\n") + for i = i386.REG_X0; i <= i386.REG_X7; i++ { + fmt.Printf("\t%v\t%#x\n", gc.Ctxt.Rconv(i), regpc[i]) + } + gc.Fatal("out of floating registers") + } + + gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0)) + +err: + gc.Nodreg(n, t, 0) + return + +out: + if i == i386.REG_SP { + fmt.Printf("alloc SP\n") + } + if reg[i] == 0 { + regpc[i] = uint32(obj.Getcallerpc(&n)) + if i == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.REG_SP { + gc.Dump("regalloc-o", o) + gc.Fatal("regalloc %v", gc.Ctxt.Rconv(i)) + } + } + + reg[i]++ + gc.Nodreg(n, t, i) +} + +func regfree(n *gc.Node) { + var i int + + if n.Op == gc.ONAME { + return + } + if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { + gc.Fatal("regfree: not a register") + } + i = int(n.Val.U.Reg) + if i == i386.REG_SP { + return + } + if i < 0 || i >= len(reg) { + gc.Fatal("regfree: reg out of range") + } + if reg[i] <= 0 { + gc.Fatal("regfree: reg not allocated") + } + reg[i]-- + if reg[i] == 0 && (i == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.REG_SP) { + gc.Fatal("regfree %v", gc.Ctxt.Rconv(i)) + } +} + +/* + * generate + * as $c, reg + */ +func gconreg(as int, c int64, reg int) { + var n1 gc.Node + var n2 gc.Node + + gc.Nodconst(&n1, gc.Types[gc.TINT64], c) + gc.Nodreg(&n2, gc.Types[gc.TINT64], reg) + gins(as, &n1, &n2) +} + +/* + * swap node contents + */ +func nswap(a *gc.Node, b *gc.Node) { + var t gc.Node + + t = *a + *a = *b + *b = t +} + +/* + * return constant i node. + * overwritten by next call, but useful in calls to gins. + */ + +var ncon_n gc.Node + +func ncon(i uint32) *gc.Node { + if ncon_n.Type == nil { + gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) + } + gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) + return &ncon_n +} + +var sclean [10]gc.Node + +var nsclean int + +/* + * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. + */ +func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { + var n1 gc.Node + var i int64 + + if !gc.Is64(n.Type) { + gc.Fatal("split64 %v", gc.Tconv(n.Type, 0)) + } + + if nsclean >= len(sclean) { + gc.Fatal("split64 clean") + } + sclean[nsclean].Op = gc.OEMPTY + nsclean++ + switch n.Op { + default: + switch n.Op { + default: + if !dotaddable(n, &n1) { + igen(n, &n1, nil) + sclean[nsclean-1] = n1 + } + + n = &n1 + + case gc.ONAME: + if n.Class == gc.PPARAMREF { + cgen(n.Heapaddr, &n1) + sclean[nsclean-1] = n1 + n = &n1 + } + + // nothing + case gc.OINDREG: + break + } + + *lo = *n + *hi = *n + lo.Type = gc.Types[gc.TUINT32] + if n.Type.Etype == gc.TINT64 { + hi.Type = gc.Types[gc.TINT32] + } else { + hi.Type = gc.Types[gc.TUINT32] + } + hi.Xoffset += 4 + + case gc.OLITERAL: + gc.Convconst(&n1, n.Type, &n.Val) + i = gc.Mpgetfix(n1.Val.U.Xval) + gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) + i >>= 32 + if n.Type.Etype == gc.TINT64 { + gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i))) + } else { + gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i))) + } + } +} + +func splitclean() { + if nsclean <= 0 { + gc.Fatal("splitclean") + } + nsclean-- + if sclean[nsclean].Op != gc.OEMPTY { + regfree(&sclean[nsclean]) + } +} + +/* + * set up nodes representing fp constants + */ +var zerof gc.Node + +var two64f gc.Node + +var two63f gc.Node + +var bignodes_did int + +func bignodes() { + if bignodes_did != 0 { + return + } + bignodes_did = 1 + + two64f = *ncon(0) + two64f.Type = gc.Types[gc.TFLOAT64] + two64f.Val.Ctype = gc.CTFLT + two64f.Val.U.Fval = new(gc.Mpflt) + gc.Mpmovecflt(two64f.Val.U.Fval, 18446744073709551616.) + + two63f = two64f + two63f.Val.U.Fval = new(gc.Mpflt) + gc.Mpmovecflt(two63f.Val.U.Fval, 9223372036854775808.) + + zerof = two64f + zerof.Val.U.Fval = new(gc.Mpflt) + gc.Mpmovecflt(zerof.Val.U.Fval, 0) +} + +func memname(n *gc.Node, t *gc.Type) { + gc.Tempname(n, t) + n.Sym = gc.Lookup("." + n.Sym.Name[1:]) // keep optimizer from registerizing + n.Orig.Sym = n.Sym +} + +func gmove(f *gc.Node, t *gc.Node) { + var a int + var ft int + var tt int + var cvt *gc.Type + var r1 gc.Node + var r2 gc.Node + var flo gc.Node + var fhi gc.Node + var tlo gc.Node + var thi gc.Node + var con gc.Node + + if gc.Debug['M'] != 0 { + fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0)) + } + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { + gc.Complexmove(f, t) + return + } + + if gc.Isfloat[ft] != 0 || gc.Isfloat[tt] != 0 { + floatmove(f, t) + return + } + + // cannot have two integer memory operands; + // except 64-bit, which always copies via registers anyway. + if gc.Isint[ft] != 0 && gc.Isint[tt] != 0 && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + + // convert constant to desired type + if f.Op == gc.OLITERAL { + gc.Convconst(&con, t.Type, &f.Val) + f = &con + ft = gc.Simsimtype(con.Type) + } + + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + + switch uint32(ft)<<16 | uint32(tt) { + default: + goto fatal + + /* + * integer copy and truncate + */ + case gc.TINT8<<16 | gc.TINT8, // same size + gc.TINT8<<16 | gc.TUINT8, + gc.TUINT8<<16 | gc.TINT8, + gc.TUINT8<<16 | gc.TUINT8: + a = i386.AMOVB + + case gc.TINT16<<16 | gc.TINT8, // truncate + gc.TUINT16<<16 | gc.TINT8, + gc.TINT32<<16 | gc.TINT8, + gc.TUINT32<<16 | gc.TINT8, + gc.TINT16<<16 | gc.TUINT8, + gc.TUINT16<<16 | gc.TUINT8, + gc.TINT32<<16 | gc.TUINT8, + gc.TUINT32<<16 | gc.TUINT8: + a = i386.AMOVB + + goto rsrc + + case gc.TINT64<<16 | gc.TINT8, // truncate low word + gc.TUINT64<<16 | gc.TINT8, + gc.TINT64<<16 | gc.TUINT8, + gc.TUINT64<<16 | gc.TUINT8: + split64(f, &flo, &fhi) + + gc.Nodreg(&r1, t.Type, i386.REG_AX) + gmove(&flo, &r1) + gins(i386.AMOVB, &r1, t) + splitclean() + return + + case gc.TINT16<<16 | gc.TINT16, // same size + gc.TINT16<<16 | gc.TUINT16, + gc.TUINT16<<16 | gc.TINT16, + gc.TUINT16<<16 | gc.TUINT16: + a = i386.AMOVW + + case gc.TINT32<<16 | gc.TINT16, // truncate + gc.TUINT32<<16 | gc.TINT16, + gc.TINT32<<16 | gc.TUINT16, + gc.TUINT32<<16 | gc.TUINT16: + a = i386.AMOVW + + goto rsrc + + case gc.TINT64<<16 | gc.TINT16, // truncate low word + gc.TUINT64<<16 | gc.TINT16, + gc.TINT64<<16 | gc.TUINT16, + gc.TUINT64<<16 | gc.TUINT16: + split64(f, &flo, &fhi) + + gc.Nodreg(&r1, t.Type, i386.REG_AX) + gmove(&flo, &r1) + gins(i386.AMOVW, &r1, t) + splitclean() + return + + case gc.TINT32<<16 | gc.TINT32, // same size + gc.TINT32<<16 | gc.TUINT32, + gc.TUINT32<<16 | gc.TINT32, + gc.TUINT32<<16 | gc.TUINT32: + a = i386.AMOVL + + case gc.TINT64<<16 | gc.TINT32, // truncate + gc.TUINT64<<16 | gc.TINT32, + gc.TINT64<<16 | gc.TUINT32, + gc.TUINT64<<16 | gc.TUINT32: + split64(f, &flo, &fhi) + + gc.Nodreg(&r1, t.Type, i386.REG_AX) + gmove(&flo, &r1) + gins(i386.AMOVL, &r1, t) + splitclean() + return + + case gc.TINT64<<16 | gc.TINT64, // same size + gc.TINT64<<16 | gc.TUINT64, + gc.TUINT64<<16 | gc.TINT64, + gc.TUINT64<<16 | gc.TUINT64: + split64(f, &flo, &fhi) + + split64(t, &tlo, &thi) + if f.Op == gc.OLITERAL { + gins(i386.AMOVL, &flo, &tlo) + gins(i386.AMOVL, &fhi, &thi) + } else { + gc.Nodreg(&r1, gc.Types[gc.TUINT32], i386.REG_AX) + gc.Nodreg(&r2, gc.Types[gc.TUINT32], i386.REG_DX) + gins(i386.AMOVL, &flo, &r1) + gins(i386.AMOVL, &fhi, &r2) + gins(i386.AMOVL, &r1, &tlo) + gins(i386.AMOVL, &r2, &thi) + } + + splitclean() + splitclean() + return + + /* + * integer up-conversions + */ + case gc.TINT8<<16 | gc.TINT16, // sign extend int8 + gc.TINT8<<16 | gc.TUINT16: + a = i386.AMOVBWSX + + goto rdst + + case gc.TINT8<<16 | gc.TINT32, + gc.TINT8<<16 | gc.TUINT32: + a = i386.AMOVBLSX + goto rdst + + case gc.TINT8<<16 | gc.TINT64, // convert via int32 + gc.TINT8<<16 | gc.TUINT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 + gc.TUINT8<<16 | gc.TUINT16: + a = i386.AMOVBWZX + + goto rdst + + case gc.TUINT8<<16 | gc.TINT32, + gc.TUINT8<<16 | gc.TUINT32: + a = i386.AMOVBLZX + goto rdst + + case gc.TUINT8<<16 | gc.TINT64, // convert via uint32 + gc.TUINT8<<16 | gc.TUINT64: + cvt = gc.Types[gc.TUINT32] + + goto hard + + case gc.TINT16<<16 | gc.TINT32, // sign extend int16 + gc.TINT16<<16 | gc.TUINT32: + a = i386.AMOVWLSX + + goto rdst + + case gc.TINT16<<16 | gc.TINT64, // convert via int32 + gc.TINT16<<16 | gc.TUINT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 + gc.TUINT16<<16 | gc.TUINT32: + a = i386.AMOVWLZX + + goto rdst + + case gc.TUINT16<<16 | gc.TINT64, // convert via uint32 + gc.TUINT16<<16 | gc.TUINT64: + cvt = gc.Types[gc.TUINT32] + + goto hard + + case gc.TINT32<<16 | gc.TINT64, // sign extend int32 + gc.TINT32<<16 | gc.TUINT64: + split64(t, &tlo, &thi) + + gc.Nodreg(&flo, tlo.Type, i386.REG_AX) + gc.Nodreg(&fhi, thi.Type, i386.REG_DX) + gmove(f, &flo) + gins(i386.ACDQ, nil, nil) + gins(i386.AMOVL, &flo, &tlo) + gins(i386.AMOVL, &fhi, &thi) + splitclean() + return + + case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 + gc.TUINT32<<16 | gc.TUINT64: + split64(t, &tlo, &thi) + + gmove(f, &tlo) + gins(i386.AMOVL, ncon(0), &thi) + splitclean() + return + } + + gins(a, f, t) + return + + // requires register source +rsrc: + regalloc(&r1, f.Type, t) + + gmove(f, &r1) + gins(a, &r1, t) + regfree(&r1) + return + + // requires register destination +rdst: + regalloc(&r1, t.Type, t) + + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // should not happen +fatal: + gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) +} + +func floatmove(f *gc.Node, t *gc.Node) { + var r1 gc.Node + var r2 gc.Node + var t1 gc.Node + var t2 gc.Node + var tlo gc.Node + var thi gc.Node + var con gc.Node + var f0 gc.Node + var f1 gc.Node + var ax gc.Node + var dx gc.Node + var cx gc.Node + var cvt *gc.Type + var ft int + var tt int + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + // cannot have two floating point memory operands. + if gc.Isfloat[ft] != 0 && gc.Isfloat[tt] != 0 && gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + + // convert constant to desired type + if f.Op == gc.OLITERAL { + gc.Convconst(&con, t.Type, &f.Val) + f = &con + ft = gc.Simsimtype(con.Type) + + // some constants can't move directly to memory. + if gc.Ismem(t) { + // float constants come from memory. + if gc.Isfloat[tt] != 0 { + goto hard + } + } + } + + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + + switch uint32(ft)<<16 | uint32(tt) { + default: + if gc.Use_sse != 0 { + floatmove_sse(f, t) + } else { + floatmove_387(f, t) + } + return + + // float to very long integer. + case gc.TFLOAT32<<16 | gc.TINT64, + gc.TFLOAT64<<16 | gc.TINT64: + if f.Op == gc.OREGISTER { + cvt = f.Type + goto hardmem + } + + gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0) + if ft == gc.TFLOAT32 { + gins(i386.AFMOVF, f, &r1) + } else { + gins(i386.AFMOVD, f, &r1) + } + + // set round to zero mode during conversion + memname(&t1, gc.Types[gc.TUINT16]) + + memname(&t2, gc.Types[gc.TUINT16]) + gins(i386.AFSTCW, nil, &t1) + gins(i386.AMOVW, ncon(0xf7f), &t2) + gins(i386.AFLDCW, &t2, nil) + if tt == gc.TINT16 { + gins(i386.AFMOVWP, &r1, t) + } else if tt == gc.TINT32 { + gins(i386.AFMOVLP, &r1, t) + } else { + gins(i386.AFMOVVP, &r1, t) + } + gins(i386.AFLDCW, &t1, nil) + return + + case gc.TFLOAT32<<16 | gc.TUINT64, + gc.TFLOAT64<<16 | gc.TUINT64: + if !gc.Ismem(f) { + cvt = f.Type + goto hardmem + } + + bignodes() + gc.Nodreg(&f0, gc.Types[ft], i386.REG_F0) + gc.Nodreg(&f1, gc.Types[ft], i386.REG_F0+1) + gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX) + + if ft == gc.TFLOAT32 { + gins(i386.AFMOVF, f, &f0) + } else { + gins(i386.AFMOVD, f, &f0) + } + + // if 0 > v { answer = 0 } + gins(i386.AFMOVD, &zerof, &f0) + + gins(i386.AFUCOMIP, &f0, &f1) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0) + + // if 1<<64 <= v { answer = 0 too } + gins(i386.AFMOVD, &two64f, &f0) + + gins(i386.AFUCOMIP, &f0, &f1) + p2 = gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0) + gc.Patch(p1, gc.Pc) + gins(i386.AFMOVVP, &f0, t) // don't care about t, but will pop the stack + split64(t, &tlo, &thi) + gins(i386.AMOVL, ncon(0), &tlo) + gins(i386.AMOVL, ncon(0), &thi) + splitclean() + p1 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p2, gc.Pc) + + // in range; algorithm is: + // if small enough, use native float64 -> int64 conversion. + // otherwise, subtract 2^63, convert, and add it back. + + // set round to zero mode during conversion + memname(&t1, gc.Types[gc.TUINT16]) + + memname(&t2, gc.Types[gc.TUINT16]) + gins(i386.AFSTCW, nil, &t1) + gins(i386.AMOVW, ncon(0xf7f), &t2) + gins(i386.AFLDCW, &t2, nil) + + // actual work + gins(i386.AFMOVD, &two63f, &f0) + + gins(i386.AFUCOMIP, &f0, &f1) + p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0) + gins(i386.AFMOVVP, &f0, t) + p3 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p2, gc.Pc) + gins(i386.AFMOVD, &two63f, &f0) + gins(i386.AFSUBDP, &f0, &f1) + gins(i386.AFMOVVP, &f0, t) + split64(t, &tlo, &thi) + gins(i386.AXORL, ncon(0x80000000), &thi) // + 2^63 + gc.Patch(p3, gc.Pc) + splitclean() + + // restore rounding mode + gins(i386.AFLDCW, &t1, nil) + + gc.Patch(p1, gc.Pc) + return + + /* + * integer to float + */ + case gc.TINT64<<16 | gc.TFLOAT32, + gc.TINT64<<16 | gc.TFLOAT64: + if t.Op == gc.OREGISTER { + goto hardmem + } + gc.Nodreg(&f0, t.Type, i386.REG_F0) + gins(i386.AFMOVV, f, &f0) + if tt == gc.TFLOAT32 { + gins(i386.AFMOVFP, &f0, t) + } else { + gins(i386.AFMOVDP, &f0, t) + } + return + + // algorithm is: + // if small enough, use native int64 -> float64 conversion. + // otherwise, halve (rounding to odd?), convert, and double. + case gc.TUINT64<<16 | gc.TFLOAT32, + gc.TUINT64<<16 | gc.TFLOAT64: + gc.Nodreg(&ax, gc.Types[gc.TUINT32], i386.REG_AX) + + gc.Nodreg(&dx, gc.Types[gc.TUINT32], i386.REG_DX) + gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX) + gc.Tempname(&t1, f.Type) + split64(&t1, &tlo, &thi) + gmove(f, &t1) + gins(i386.ACMPL, &thi, ncon(0)) + p1 = gc.Gbranch(i386.AJLT, nil, 0) + + // native + gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0) + + gins(i386.AFMOVV, &t1, &r1) + if tt == gc.TFLOAT32 { + gins(i386.AFMOVFP, &r1, t) + } else { + gins(i386.AFMOVDP, &r1, t) + } + p2 = gc.Gbranch(obj.AJMP, nil, 0) + + // simulated + gc.Patch(p1, gc.Pc) + + gmove(&tlo, &ax) + gmove(&thi, &dx) + p1 = gins(i386.ASHRL, ncon(1), &ax) + p1.From.Index = i386.REG_DX // double-width shift DX -> AX + p1.From.Scale = 0 + gins(i386.AMOVL, ncon(0), &cx) + gins(i386.ASETCC, nil, &cx) + gins(i386.AORL, &cx, &ax) + gins(i386.ASHRL, ncon(1), &dx) + gmove(&dx, &thi) + gmove(&ax, &tlo) + gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0) + gc.Nodreg(&r2, gc.Types[tt], i386.REG_F0+1) + gins(i386.AFMOVV, &t1, &r1) + gins(i386.AFMOVD, &r1, &r1) + gins(i386.AFADDDP, &r1, &r2) + if tt == gc.TFLOAT32 { + gins(i386.AFMOVFP, &r1, t) + } else { + gins(i386.AFMOVDP, &r1, t) + } + gc.Patch(p2, gc.Pc) + splitclean() + return + } + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires memory intermediate +hardmem: + gc.Tempname(&r1, cvt) + + gmove(f, &r1) + gmove(&r1, t) + return +} + +func floatmove_387(f *gc.Node, t *gc.Node) { + var r1 gc.Node + var t1 gc.Node + var t2 gc.Node + var cvt *gc.Type + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var a int + var ft int + var tt int + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + switch uint32(ft)<<16 | uint32(tt) { + default: + goto fatal + + /* + * float to integer + */ + case gc.TFLOAT32<<16 | gc.TINT16, + gc.TFLOAT32<<16 | gc.TINT32, + gc.TFLOAT32<<16 | gc.TINT64, + gc.TFLOAT64<<16 | gc.TINT16, + gc.TFLOAT64<<16 | gc.TINT32, + gc.TFLOAT64<<16 | gc.TINT64: + if t.Op == gc.OREGISTER { + goto hardmem + } + gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0) + if f.Op != gc.OREGISTER { + if ft == gc.TFLOAT32 { + gins(i386.AFMOVF, f, &r1) + } else { + gins(i386.AFMOVD, f, &r1) + } + } + + // set round to zero mode during conversion + memname(&t1, gc.Types[gc.TUINT16]) + + memname(&t2, gc.Types[gc.TUINT16]) + gins(i386.AFSTCW, nil, &t1) + gins(i386.AMOVW, ncon(0xf7f), &t2) + gins(i386.AFLDCW, &t2, nil) + if tt == gc.TINT16 { + gins(i386.AFMOVWP, &r1, t) + } else if tt == gc.TINT32 { + gins(i386.AFMOVLP, &r1, t) + } else { + gins(i386.AFMOVVP, &r1, t) + } + gins(i386.AFLDCW, &t1, nil) + return + + // convert via int32. + case gc.TFLOAT32<<16 | gc.TINT8, + gc.TFLOAT32<<16 | gc.TUINT16, + gc.TFLOAT32<<16 | gc.TUINT8, + gc.TFLOAT64<<16 | gc.TINT8, + gc.TFLOAT64<<16 | gc.TUINT16, + gc.TFLOAT64<<16 | gc.TUINT8: + gc.Tempname(&t1, gc.Types[gc.TINT32]) + + gmove(f, &t1) + switch tt { + default: + gc.Fatal("gmove %v", gc.Nconv(t, 0)) + + case gc.TINT8: + gins(i386.ACMPL, &t1, ncon(-0x80&(1<<32-1))) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1) + gins(i386.ACMPL, &t1, ncon(0x7f)) + p2 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TINT32]), nil, -1) + p3 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + gc.Patch(p2, gc.Pc) + gmove(ncon(-0x80&(1<<32-1)), &t1) + gc.Patch(p3, gc.Pc) + gmove(&t1, t) + + case gc.TUINT8: + gins(i386.ATESTL, ncon(0xffffff00), &t1) + p1 = gc.Gbranch(i386.AJEQ, nil, +1) + gins(i386.AMOVL, ncon(0), &t1) + gc.Patch(p1, gc.Pc) + gmove(&t1, t) + + case gc.TUINT16: + gins(i386.ATESTL, ncon(0xffff0000), &t1) + p1 = gc.Gbranch(i386.AJEQ, nil, +1) + gins(i386.AMOVL, ncon(0), &t1) + gc.Patch(p1, gc.Pc) + gmove(&t1, t) + } + + return + + // convert via int64. + case gc.TFLOAT32<<16 | gc.TUINT32, + gc.TFLOAT64<<16 | gc.TUINT32: + cvt = gc.Types[gc.TINT64] + + goto hardmem + + /* + * integer to float + */ + case gc.TINT16<<16 | gc.TFLOAT32, + gc.TINT16<<16 | gc.TFLOAT64, + gc.TINT32<<16 | gc.TFLOAT32, + gc.TINT32<<16 | gc.TFLOAT64, + gc.TINT64<<16 | gc.TFLOAT32, + gc.TINT64<<16 | gc.TFLOAT64: + if t.Op != gc.OREGISTER { + goto hard + } + if f.Op == gc.OREGISTER { + cvt = f.Type + goto hardmem + } + + switch ft { + case gc.TINT16: + a = i386.AFMOVW + + case gc.TINT32: + a = i386.AFMOVL + + default: + a = i386.AFMOVV + } + + // convert via int32 memory + case gc.TINT8<<16 | gc.TFLOAT32, + gc.TINT8<<16 | gc.TFLOAT64, + gc.TUINT16<<16 | gc.TFLOAT32, + gc.TUINT16<<16 | gc.TFLOAT64, + gc.TUINT8<<16 | gc.TFLOAT32, + gc.TUINT8<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT32] + + goto hardmem + + // convert via int64 memory + case gc.TUINT32<<16 | gc.TFLOAT32, + gc.TUINT32<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT64] + + goto hardmem + + // The way the code generator uses floating-point + // registers, a move from F0 to F0 is intended as a no-op. + // On the x86, it's not: it pushes a second copy of F0 + // on the floating point stack. So toss it away here. + // Also, F0 is the *only* register we ever evaluate + // into, so we should only see register/register as F0/F0. + /* + * float to float + */ + case gc.TFLOAT32<<16 | gc.TFLOAT32, + gc.TFLOAT64<<16 | gc.TFLOAT64: + if gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { + if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 { + goto fatal + } + return + } + + a = i386.AFMOVF + if ft == gc.TFLOAT64 { + a = i386.AFMOVD + } + if gc.Ismem(t) { + if f.Op != gc.OREGISTER || f.Val.U.Reg != i386.REG_F0 { + gc.Fatal("gmove %v", gc.Nconv(f, 0)) + } + a = i386.AFMOVFP + if ft == gc.TFLOAT64 { + a = i386.AFMOVDP + } + } + + case gc.TFLOAT32<<16 | gc.TFLOAT64: + if gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { + if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 { + goto fatal + } + return + } + + if f.Op == gc.OREGISTER { + gins(i386.AFMOVDP, f, t) + } else { + gins(i386.AFMOVF, f, t) + } + return + + case gc.TFLOAT64<<16 | gc.TFLOAT32: + if gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { + gc.Tempname(&r1, gc.Types[gc.TFLOAT32]) + gins(i386.AFMOVFP, f, &r1) + gins(i386.AFMOVF, &r1, t) + return + } + + if f.Op == gc.OREGISTER { + gins(i386.AFMOVFP, f, t) + } else { + gins(i386.AFMOVD, f, t) + } + return + } + + gins(a, f, t) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires memory intermediate +hardmem: + gc.Tempname(&r1, cvt) + + gmove(f, &r1) + gmove(&r1, t) + return + + // should not happen +fatal: + gc.Fatal("gmove %v -> %v", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) + + return +} + +func floatmove_sse(f *gc.Node, t *gc.Node) { + var r1 gc.Node + var cvt *gc.Type + var a int + var ft int + var tt int + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + + switch uint32(ft)<<16 | uint32(tt) { + // should not happen + default: + gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) + + return + + // convert via int32. + /* + * float to integer + */ + case gc.TFLOAT32<<16 | gc.TINT16, + gc.TFLOAT32<<16 | gc.TINT8, + gc.TFLOAT32<<16 | gc.TUINT16, + gc.TFLOAT32<<16 | gc.TUINT8, + gc.TFLOAT64<<16 | gc.TINT16, + gc.TFLOAT64<<16 | gc.TINT8, + gc.TFLOAT64<<16 | gc.TUINT16, + gc.TFLOAT64<<16 | gc.TUINT8: + cvt = gc.Types[gc.TINT32] + + goto hard + + // convert via int64. + case gc.TFLOAT32<<16 | gc.TUINT32, + gc.TFLOAT64<<16 | gc.TUINT32: + cvt = gc.Types[gc.TINT64] + + goto hardmem + + case gc.TFLOAT32<<16 | gc.TINT32: + a = i386.ACVTTSS2SL + goto rdst + + case gc.TFLOAT64<<16 | gc.TINT32: + a = i386.ACVTTSD2SL + goto rdst + + // convert via int32 memory + /* + * integer to float + */ + case gc.TINT8<<16 | gc.TFLOAT32, + gc.TINT8<<16 | gc.TFLOAT64, + gc.TINT16<<16 | gc.TFLOAT32, + gc.TINT16<<16 | gc.TFLOAT64, + gc.TUINT16<<16 | gc.TFLOAT32, + gc.TUINT16<<16 | gc.TFLOAT64, + gc.TUINT8<<16 | gc.TFLOAT32, + gc.TUINT8<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT32] + + goto hard + + // convert via int64 memory + case gc.TUINT32<<16 | gc.TFLOAT32, + gc.TUINT32<<16 | gc.TFLOAT64: + cvt = gc.Types[gc.TINT64] + + goto hardmem + + case gc.TINT32<<16 | gc.TFLOAT32: + a = i386.ACVTSL2SS + goto rdst + + case gc.TINT32<<16 | gc.TFLOAT64: + a = i386.ACVTSL2SD + goto rdst + + /* + * float to float + */ + case gc.TFLOAT32<<16 | gc.TFLOAT32: + a = i386.AMOVSS + + case gc.TFLOAT64<<16 | gc.TFLOAT64: + a = i386.AMOVSD + + case gc.TFLOAT32<<16 | gc.TFLOAT64: + a = i386.ACVTSS2SD + goto rdst + + case gc.TFLOAT64<<16 | gc.TFLOAT32: + a = i386.ACVTSD2SS + goto rdst + } + + gins(a, f, t) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires memory intermediate +hardmem: + gc.Tempname(&r1, cvt) + + gmove(f, &r1) + gmove(&r1, t) + return + + // requires register destination +rdst: + regalloc(&r1, t.Type, t) + + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return +} + +func samaddr(f *gc.Node, t *gc.Node) bool { + if f.Op != t.Op { + return false + } + + switch f.Op { + case gc.OREGISTER: + if f.Val.U.Reg != t.Val.U.Reg { + break + } + return true + } + + return false +} + +/* + * generate one instruction: + * as f, t + */ +func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { + var p *obj.Prog + var af obj.Addr + var at obj.Addr + var w int + + if as == i386.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER { + gc.Fatal("gins MOVF reg, reg") + } + if as == i386.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL { + gc.Fatal("gins CVTSD2SS const") + } + if as == i386.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Val.U.Reg == i386.REG_F0 { + gc.Fatal("gins MOVSD into F0") + } + + switch as { + case i386.AMOVB, + i386.AMOVW, + i386.AMOVL: + if f != nil && t != nil && samaddr(f, t) { + return nil + } + + case i386.ALEAL: + if f != nil && gc.Isconst(f, gc.CTNIL) { + gc.Fatal("gins LEAL nil %v", gc.Tconv(f.Type, 0)) + } + } + + af = obj.Addr{} + at = obj.Addr{} + if f != nil { + gc.Naddr(f, &af, 1) + } + if t != nil { + gc.Naddr(t, &at, 1) + } + p = gc.Prog(as) + if f != nil { + p.From = af + } + if t != nil { + p.To = at + } + if gc.Debug['g'] != 0 { + fmt.Printf("%v\n", p) + } + + w = 0 + switch as { + case i386.AMOVB: + w = 1 + + case i386.AMOVW: + w = 2 + + case i386.AMOVL: + w = 4 + } + + if true && w != 0 && f != nil && (af.Width > int64(w) || at.Width > int64(w)) { + gc.Dump("bad width from:", f) + gc.Dump("bad width to:", t) + gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) + } + + if p.To.Type == obj.TYPE_ADDR && w > 0 { + gc.Fatal("bad use of addr: %v", p) + } + + return p +} + +func dotaddable(n *gc.Node, n1 *gc.Node) bool { + var o int + var oary [10]int64 + var nn *gc.Node + + if n.Op != gc.ODOT { + return false + } + + o = gc.Dotoffset(n, oary[:], &nn) + if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 { + *n1 = *nn + n1.Type = n.Type + n1.Xoffset += oary[0] + return true + } + + return false +} + +func sudoclean() { +} + +func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { + *a = obj.Addr{} + return false +} diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c deleted file mode 100644 index 712c8fe11b..0000000000 --- a/src/cmd/8g/peep.c +++ /dev/null @@ -1,773 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -enum { - REGEXT = 0, - exregoffset = REG_DI, -}; - -static void conprop(Flow *r); -static void elimshortmov(Graph*); -static int subprop(Flow*); -static int copyprop(Graph*, Flow*); -static int copy1(Adr*, Adr*, Flow*, int); -static int copyas(Adr*, Adr*); -static int copyau(Adr*, Adr*); -static int copysub(Adr*, Adr*, Adr*, int); -static int copyu(Prog*, Adr*, Adr*); - -static uint32 gactive; - -// do we need the carry bit -static int -needc(Prog *p) -{ - ProgInfo info; - - while(p != P) { - proginfo(&info, p); - if(info.flags & UseCarry) - return 1; - if(info.flags & (SetCarry|KillCarry)) - return 0; - p = p->link; - } - return 0; -} - -static Flow* -rnops(Flow *r) -{ - Prog *p; - Flow *r1; - - if(r != nil) - for(;;) { - p = r->prog; - if(p->as != ANOP || p->from.type != TYPE_NONE || p->to.type != TYPE_NONE) - break; - r1 = uniqs(r); - if(r1 == nil) - break; - r = r1; - } - return r; -} - -void -peep(Prog *firstp) -{ - Flow *r, *r1; - Graph *g; - Prog *p, *p1; - int t; - - g = flowstart(firstp, 0); - if(g == nil) - return; - gactive = 0; - - // byte, word arithmetic elimination. - elimshortmov(g); - - // constant propagation - // find MOV $con,R followed by - // another MOV $con,R without - // setting R in the interim - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case ALEAL: - if(regtyp(&p->to)) - if(p->from.sym != nil) - if(p->from.index == REG_NONE) - conprop(r); - break; - - case AMOVB: - case AMOVW: - case AMOVL: - case AMOVSS: - case AMOVSD: - if(regtyp(&p->to)) - if(p->from.type == TYPE_CONST || p->from.type == TYPE_FCONST) - conprop(r); - break; - } - } - -loop1: - if(debug['P'] && debug['v']) - dumpit("loop1", g->start, 0); - - t = 0; - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case AMOVL: - case AMOVSS: - case AMOVSD: - if(regtyp(&p->to)) - if(regtyp(&p->from)) { - if(copyprop(g, r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(g, r)) { - excise(r); - t++; - } - } - break; - - case AMOVBLZX: - case AMOVWLZX: - case AMOVBLSX: - case AMOVWLSX: - if(regtyp(&p->to)) { - r1 = rnops(uniqs(r)); - if(r1 != nil) { - p1 = r1->prog; - if(p->as == p1->as && p->to.type == p1->from.type && p->to.reg == p1->from.reg){ - p1->as = AMOVL; - t++; - } - } - } - break; - - case AADDL: - case AADDW: - if(p->from.type != TYPE_CONST || needc(p->link)) - break; - if(p->from.offset == -1){ - if(p->as == AADDL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - break; - } - if(p->from.offset == 1){ - if(p->as == AADDL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - break; - } - break; - - case ASUBL: - case ASUBW: - if(p->from.type != TYPE_CONST || needc(p->link)) - break; - if(p->from.offset == -1) { - if(p->as == ASUBL) - p->as = AINCL; - else - p->as = AINCW; - p->from = zprog.from; - break; - } - if(p->from.offset == 1){ - if(p->as == ASUBL) - p->as = ADECL; - else - p->as = ADECW; - p->from = zprog.from; - break; - } - break; - } - } - if(t) - goto loop1; - - // MOVSD removal. - // We never use packed registers, so a MOVSD between registers - // can be replaced by MOVAPD, which moves the pair of float64s - // instead of just the lower one. We only use the lower one, but - // the processor can do better if we do moves using both. - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - if(p->as == AMOVSD) - if(regtyp(&p->from)) - if(regtyp(&p->to)) - p->as = AMOVAPD; - } - - flowend(g); -} - -void -excise(Flow *r) -{ - Prog *p; - - p = r->prog; - if(debug['P'] && debug['v']) - print("%P ===delete===\n", p); - - nopout(p); - - ostats.ndelmov++; -} - -int -regtyp(Adr *a) -{ - return a->type == TYPE_REG && (REG_AX <= a->reg && a->reg <= REG_DI || REG_X0 <= a->reg && a->reg <= REG_X7); -} - -// movb elimination. -// movb is simulated by the linker -// when a register other than ax, bx, cx, dx -// is used, so rewrite to other instructions -// when possible. a movb into a register -// can smash the entire 64-bit register without -// causing any trouble. -static void -elimshortmov(Graph *g) -{ - Prog *p; - Flow *r; - - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - if(regtyp(&p->to)) { - switch(p->as) { - case AINCB: - case AINCW: - p->as = AINCL; - break; - case ADECB: - case ADECW: - p->as = ADECL; - break; - case ANEGB: - case ANEGW: - p->as = ANEGL; - break; - case ANOTB: - case ANOTW: - p->as = ANOTL; - break; - } - if(regtyp(&p->from) || p->from.type == TYPE_CONST) { - // move or artihmetic into partial register. - // from another register or constant can be movl. - // we don't switch to 32-bit arithmetic if it can - // change how the carry bit is set (and the carry bit is needed). - switch(p->as) { - case AMOVB: - case AMOVW: - p->as = AMOVL; - break; - case AADDB: - case AADDW: - if(!needc(p->link)) - p->as = AADDL; - break; - case ASUBB: - case ASUBW: - if(!needc(p->link)) - p->as = ASUBL; - break; - case AMULB: - case AMULW: - p->as = AMULL; - break; - case AIMULB: - case AIMULW: - p->as = AIMULL; - break; - case AANDB: - case AANDW: - p->as = AANDL; - break; - case AORB: - case AORW: - p->as = AORL; - break; - case AXORB: - case AXORW: - p->as = AXORL; - break; - case ASHLB: - case ASHLW: - p->as = ASHLL; - break; - } - } else { - // explicit zero extension - switch(p->as) { - case AMOVB: - p->as = AMOVBLZX; - break; - case AMOVW: - p->as = AMOVWLZX; - break; - } - } - } - } -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -static int -subprop(Flow *r0) -{ - Prog *p; - Adr *v1, *v2; - Flow *r; - int t; - ProgInfo info; - - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) - return 0; - v2 = &p->to; - if(!regtyp(v2)) - return 0; - for(r=uniqp(r0); r!=nil; r=uniqp(r)) { - if(debug['P'] && debug['v']) - print("\t? %P\n", r->prog); - if(uniqs(r) == nil) - break; - p = r->prog; - if(p->as == AVARDEF || p->as == AVARKILL) - continue; - proginfo(&info, p); - if(info.flags & Call) - return 0; - - if(info.reguse | info.regset) - return 0; - - if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type && p->to.reg == v1->reg) - goto gotit; - - if(copyau(&p->from, v2) || copyau(&p->to, v2)) - break; - if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) - break; - } - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type && p->from.reg == v2->reg) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -static int -copyprop(Graph *g, Flow *r0) -{ - Prog *p; - Adr *v1, *v2; - - USED(g); - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) - return 1; - gactive++; - return copy1(v1, v2, r0->s1, 0); -} - -static int -copy1(Adr *v1, Adr *v2, Flow *r, int f) -{ - int t; - Prog *p; - - if(r->active == gactive) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = gactive; - if(debug['P']) - print("copy %D->%D f=%d\n", v1, v2, f); - for(; r != nil; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == nil) { - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, can't split */ - if(debug['P']) - print("; %D rar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %D set; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %D used+set and f=%d; return 0\n", v2, f); - else - print("; %D used and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub %D/%D", v2, v1); - if(t == 4) { - if(debug['P']) - print("; %D used+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %D set and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -static int -copyu(Prog *p, Adr *v, Adr *s) -{ - ProgInfo info; - - switch(p->as) { - case AJMP: - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARET: - if(s != nil) - return 1; - return 3; - - case ACALL: - if(REGEXT && v->type == TYPE_REG && v->reg <= REGEXT && v->reg > exregoffset) - return 2; - if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG) - return 2; - if(v->type == p->from.type && v->reg == p->from.reg) - return 2; - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - - case ATEXT: - if(REGARG >= 0 && v->type == TYPE_REG && v->reg == REGARG) - return 3; - return 0; - } - - if(p->as == AVARDEF || p->as == AVARKILL) - return 0; - proginfo(&info, p); - - if((info.reguse|info.regset) & RtoB(v->reg)) - return 2; - - if(info.flags & LeftAddr) - if(copyas(&p->from, v)) - return 2; - - if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite)) - if(copyas(&p->to, v)) - return 2; - - if(info.flags & RightWrite) { - if(copyas(&p->to, v)) { - if(s != nil) - return copysub(&p->from, v, s, 1); - if(copyau(&p->from, v)) - return 4; - return 3; - } - } - - if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - } - - return 0; -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -static int -copyas(Adr *a, Adr *v) -{ - if(REG_AL <= a->reg && a->reg <= REG_BL) - fatal("use of byte register"); - if(REG_AL <= v->reg && v->reg <= REG_BL) - fatal("use of byte register"); - - if(a->type != v->type || a->name != v->name || a->reg != v->reg) - return 0; - if(regtyp(v)) - return 1; - if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM)) - if(v->offset == a->offset) - return 1; - return 0; -} - -int -sameaddr(Addr *a, Addr *v) -{ - if(a->type != v->type || a->name != v->name || a->reg != v->reg) - return 0; - if(regtyp(v)) - return 1; - if(v->type == TYPE_MEM && (v->name == NAME_AUTO || v->name == NAME_PARAM)) - if(v->offset == a->offset) - return 1; - return 0; -} - -/* - * either direct or indirect - */ -static int -copyau(Adr *a, Adr *v) -{ - - if(copyas(a, v)) - return 1; - if(regtyp(v)) { - if(a->type == TYPE_MEM && a->reg == v->reg) - return 1; - if(a->index == v->reg) - return 1; - } - return 0; -} - -/* - * substitute s for v in a - * return failure to substitute - */ -static int -copysub(Adr *a, Adr *v, Adr *s, int f) -{ - int reg; - - if(copyas(a, v)) { - reg = s->reg; - if(reg >= REG_AX && reg <= REG_DI || reg >= REG_X0 && reg <= REG_X7) { - if(f) - a->reg = reg; - } - return 0; - } - if(regtyp(v)) { - reg = v->reg; - if(a->type == TYPE_MEM && a->reg == reg) { - if((s->reg == REG_BP) && a->index != TYPE_NONE) - return 1; /* can't use BP-base with index */ - if(f) - a->reg = s->reg; -// return 0; - } - if(a->index == reg) { - if(f) - a->index = s->reg; - return 0; - } - return 0; - } - return 0; -} - -static void -conprop(Flow *r0) -{ - Flow *r; - Prog *p, *p0; - int t; - Adr *v0; - - p0 = r0->prog; - v0 = &p0->to; - r = r0; - -loop: - r = uniqs(r); - if(r == nil || r == r0) - return; - if(uniqp(r) == nil) - return; - - p = r->prog; - t = copyu(p, v0, nil); - switch(t) { - case 0: // miss - case 1: // use - goto loop; - - case 2: // rar - case 4: // use and set - break; - - case 3: // set - if(p->as == p0->as) - if(p->from.type == p0->from.type) - if(p->from.reg == p0->from.reg) - if(p->from.node == p0->from.node) - if(p->from.offset == p0->from.offset) - if(p->from.scale == p0->from.scale) - if(p->from.type == TYPE_FCONST && p->from.u.dval == p0->from.u.dval) - if(p->from.index == p0->from.index) { - excise(r); - goto loop; - } - break; - } -} - -int -smallindir(Addr *a, Addr *reg) -{ - return regtyp(reg) && - a->type == TYPE_MEM && a->reg == reg->reg && - a->index == REG_NONE && - 0 <= a->offset && a->offset < 4096; -} - -int -stackaddr(Addr *a) -{ - return a->type == TYPE_REG && a->reg == REG_SP; -} diff --git a/src/cmd/8g/peep.go b/src/cmd/8g/peep.go new file mode 100644 index 0000000000..0838882e38 --- /dev/null +++ b/src/cmd/8g/peep.go @@ -0,0 +1,847 @@ +// Derived from Inferno utils/6c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" + "fmt" +) +import "cmd/internal/gc" + +const ( + REGEXT = 0 + exregoffset = i386.REG_DI +) + +var gactive uint32 + +// do we need the carry bit +func needc(p *obj.Prog) bool { + var info gc.ProgInfo + + for p != nil { + proginfo(&info, p) + if info.Flags&gc.UseCarry != 0 { + return true + } + if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 { + return false + } + p = p.Link + } + + return false +} + +func rnops(r *gc.Flow) *gc.Flow { + var p *obj.Prog + var r1 *gc.Flow + + if r != nil { + for { + p = r.Prog + if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE { + break + } + r1 = gc.Uniqs(r) + if r1 == nil { + break + } + r = r1 + } + } + + return r +} + +func peep(firstp *obj.Prog) { + var r *gc.Flow + var r1 *gc.Flow + var g *gc.Graph + var p *obj.Prog + var p1 *obj.Prog + var t int + + g = gc.Flowstart(firstp, nil) + if g == nil { + return + } + gactive = 0 + + // byte, word arithmetic elimination. + elimshortmov(g) + + // constant propagation + // find MOV $con,R followed by + // another MOV $con,R without + // setting R in the interim + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case i386.ALEAL: + if regtyp(&p.To) { + if p.From.Sym != nil { + if p.From.Index == i386.REG_NONE { + conprop(r) + } + } + } + + case i386.AMOVB, + i386.AMOVW, + i386.AMOVL, + i386.AMOVSS, + i386.AMOVSD: + if regtyp(&p.To) { + if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST { + conprop(r) + } + } + } + } + +loop1: + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + gc.Dumpit("loop1", g.Start, 0) + } + + t = 0 + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case i386.AMOVL, + i386.AMOVSS, + i386.AMOVSD: + if regtyp(&p.To) { + if regtyp(&p.From) { + if copyprop(g, r) { + excise(r) + t++ + } else if subprop(r) && copyprop(g, r) { + excise(r) + t++ + } + } + } + + case i386.AMOVBLZX, + i386.AMOVWLZX, + i386.AMOVBLSX, + i386.AMOVWLSX: + if regtyp(&p.To) { + r1 = rnops(gc.Uniqs(r)) + if r1 != nil { + p1 = r1.Prog + if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { + p1.As = i386.AMOVL + t++ + } + } + } + + case i386.AADDL, + i386.AADDW: + if p.From.Type != obj.TYPE_CONST || needc(p.Link) { + break + } + if p.From.Offset == -1 { + if p.As == i386.AADDL { + p.As = i386.ADECL + } else { + p.As = i386.ADECW + } + p.From = obj.Addr{} + break + } + + if p.From.Offset == 1 { + if p.As == i386.AADDL { + p.As = i386.AINCL + } else { + p.As = i386.AINCW + } + p.From = obj.Addr{} + break + } + + case i386.ASUBL, + i386.ASUBW: + if p.From.Type != obj.TYPE_CONST || needc(p.Link) { + break + } + if p.From.Offset == -1 { + if p.As == i386.ASUBL { + p.As = i386.AINCL + } else { + p.As = i386.AINCW + } + p.From = obj.Addr{} + break + } + + if p.From.Offset == 1 { + if p.As == i386.ASUBL { + p.As = i386.ADECL + } else { + p.As = i386.ADECW + } + p.From = obj.Addr{} + break + } + } + } + + if t != 0 { + goto loop1 + } + + // MOVSD removal. + // We never use packed registers, so a MOVSD between registers + // can be replaced by MOVAPD, which moves the pair of float64s + // instead of just the lower one. We only use the lower one, but + // the processor can do better if we do moves using both. + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + if p.As == i386.AMOVSD { + if regtyp(&p.From) { + if regtyp(&p.To) { + p.As = i386.AMOVAPD + } + } + } + } + + gc.Flowend(g) +} + +func excise(r *gc.Flow) { + var p *obj.Prog + + p = r.Prog + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("%v ===delete===\n", p) + } + + obj.Nopout(p) + + gc.Ostats.Ndelmov++ +} + +func regtyp(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && (i386.REG_AX <= a.Reg && a.Reg <= i386.REG_DI || i386.REG_X0 <= a.Reg && a.Reg <= i386.REG_X7) +} + +// movb elimination. +// movb is simulated by the linker +// when a register other than ax, bx, cx, dx +// is used, so rewrite to other instructions +// when possible. a movb into a register +// can smash the entire 64-bit register without +// causing any trouble. +func elimshortmov(g *gc.Graph) { + var p *obj.Prog + var r *gc.Flow + + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + if regtyp(&p.To) { + switch p.As { + case i386.AINCB, + i386.AINCW: + p.As = i386.AINCL + + case i386.ADECB, + i386.ADECW: + p.As = i386.ADECL + + case i386.ANEGB, + i386.ANEGW: + p.As = i386.ANEGL + + case i386.ANOTB, + i386.ANOTW: + p.As = i386.ANOTL + } + + if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST { + // move or artihmetic into partial register. + // from another register or constant can be movl. + // we don't switch to 32-bit arithmetic if it can + // change how the carry bit is set (and the carry bit is needed). + switch p.As { + case i386.AMOVB, + i386.AMOVW: + p.As = i386.AMOVL + + case i386.AADDB, + i386.AADDW: + if !needc(p.Link) { + p.As = i386.AADDL + } + + case i386.ASUBB, + i386.ASUBW: + if !needc(p.Link) { + p.As = i386.ASUBL + } + + case i386.AMULB, + i386.AMULW: + p.As = i386.AMULL + + case i386.AIMULB, + i386.AIMULW: + p.As = i386.AIMULL + + case i386.AANDB, + i386.AANDW: + p.As = i386.AANDL + + case i386.AORB, + i386.AORW: + p.As = i386.AORL + + case i386.AXORB, + i386.AXORW: + p.As = i386.AXORL + + case i386.ASHLB, + i386.ASHLW: + p.As = i386.ASHLL + } + } else { + // explicit zero extension + switch p.As { + case i386.AMOVB: + p.As = i386.AMOVBLZX + + case i386.AMOVW: + p.As = i386.AMOVWLZX + } + } + } + } +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R0 + * ADD b, R0 / no use of R1 + * MOV R0, R1 + * would be converted to + * MOV a, R1 + * ADD b, R1 + * MOV R1, R0 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + */ +func subprop(r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + var r *gc.Flow + var t int + var info gc.ProgInfo + + p = r0.Prog + v1 = &p.From + if !regtyp(v1) { + return false + } + v2 = &p.To + if !regtyp(v2) { + return false + } + for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("\t? %v\n", r.Prog) + } + if gc.Uniqs(r) == nil { + break + } + p = r.Prog + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + continue + } + proginfo(&info, p) + if info.Flags&gc.Call != 0 { + return false + } + + if info.Reguse|info.Regset != 0 { + return false + } + + if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg { + goto gotit + } + + if copyau(&p.From, v2) || copyau(&p.To, v2) { + break + } + if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { + break + } + } + + return false + +gotit: + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) + if p.From.Type == v2.Type && p.From.Reg == v2.Reg { + fmt.Printf(" excise") + } + fmt.Printf("\n") + } + + for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { + p = r.Prog + copysub(&p.From, v1, v2, 1) + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("%v\n", r.Prog) + } + } + + t = int(v1.Reg) + v1.Reg = v2.Reg + v2.Reg = int16(t) + if gc.Debug['P'] != 0 { + fmt.Printf("%v last\n", r.Prog) + } + return true +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success + */ +func copyprop(g *gc.Graph, r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + + p = r0.Prog + v1 = &p.From + v2 = &p.To + if copyas(v1, v2) { + return true + } + gactive++ + return copy1(v1, v2, r0.S1, 0) +} + +func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { + var t int + var p *obj.Prog + + if uint32(r.Active) == gactive { + if gc.Debug['P'] != 0 { + fmt.Printf("act set; return 1\n") + } + return true + } + + r.Active = int32(gactive) + if gc.Debug['P'] != 0 { + fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) + } + for ; r != nil; r = r.S1 { + p = r.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("%v", p) + } + if f == 0 && gc.Uniqp(r) == nil { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; merge; f=%d", f) + } + } + + t = copyu(p, v2, nil) + switch t { + case 2: /* rar, can't split */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) + } + return false + + case 3: /* set */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + + case 1, /* used, substitute */ + 4: /* use and set */ + if f != 0 { + if gc.Debug['P'] == 0 { + return false + } + if t == 4 { + fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } else { + fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } + return false + } + + if copyu(p, v2, v1) != 0 { + if gc.Debug['P'] != 0 { + fmt.Printf("; sub fail; return 0\n") + } + return false + } + + if gc.Debug['P'] != 0 { + fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) + } + if t == 4 { + if gc.Debug['P'] != 0 { + fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + } + } + + if f == 0 { + t = copyu(p, v1, nil) + if f == 0 && (t == 2 || t == 3 || t == 4) { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) + } + } + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\n") + } + if r.S2 != nil { + if !copy1(v1, v2, r.S2, f) { + return false + } + } + } + + return true +} + +/* + * return + * 1 if v only used (and substitute), + * 2 if read-alter-rewrite + * 3 if set + * 4 if set and used + * 0 otherwise (not touched) + */ +func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { + var info gc.ProgInfo + + switch p.As { + case obj.AJMP: + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 1 + } + return 0 + + case obj.ARET: + if s != nil { + return 1 + } + return 3 + + case obj.ACALL: + if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset { + return 2 + } + if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG { + return 2 + } + if v.Type == p.From.Type && v.Reg == p.From.Reg { + return 2 + } + + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 4 + } + return 3 + + case obj.ATEXT: + if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG { + return 3 + } + return 0 + } + + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + return 0 + } + proginfo(&info, p) + + if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 { + return 2 + } + + if info.Flags&gc.LeftAddr != 0 { + if copyas(&p.From, v) { + return 2 + } + } + + if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite { + if copyas(&p.To, v) { + return 2 + } + } + + if info.Flags&gc.RightWrite != 0 { + if copyas(&p.To, v) { + if s != nil { + return copysub(&p.From, v, s, 1) + } + if copyau(&p.From, v) { + return 4 + } + return 3 + } + } + + if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 { + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + return copysub(&p.To, v, s, 1) + } + + if copyau(&p.From, v) { + return 1 + } + if copyau(&p.To, v) { + return 1 + } + } + + return 0 +} + +/* + * direct reference, + * could be set/use depending on + * semantics + */ +func copyas(a *obj.Addr, v *obj.Addr) bool { + if i386.REG_AL <= a.Reg && a.Reg <= i386.REG_BL { + gc.Fatal("use of byte register") + } + if i386.REG_AL <= v.Reg && v.Reg <= i386.REG_BL { + gc.Fatal("use of byte register") + } + + if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { + return false + } + if regtyp(v) { + return true + } + if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { + if v.Offset == a.Offset { + return true + } + } + return false +} + +func sameaddr(a *obj.Addr, v *obj.Addr) bool { + if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { + return false + } + if regtyp(v) { + return true + } + if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { + if v.Offset == a.Offset { + return true + } + } + return false +} + +/* + * either direct or indirect + */ +func copyau(a *obj.Addr, v *obj.Addr) bool { + if copyas(a, v) { + return true + } + if regtyp(v) { + if a.Type == obj.TYPE_MEM && a.Reg == v.Reg { + return true + } + if a.Index == v.Reg { + return true + } + } + + return false +} + +/* + * substitute s for v in a + * return failure to substitute + */ +func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { + var reg int + + if copyas(a, v) { + reg = int(s.Reg) + if reg >= i386.REG_AX && reg <= i386.REG_DI || reg >= i386.REG_X0 && reg <= i386.REG_X7 { + if f != 0 { + a.Reg = int16(reg) + } + } + + return 0 + } + + if regtyp(v) { + reg = int(v.Reg) + if a.Type == obj.TYPE_MEM && int(a.Reg) == reg { + if (s.Reg == i386.REG_BP) && a.Index != obj.TYPE_NONE { + return 1 /* can't use BP-base with index */ + } + if f != 0 { + a.Reg = s.Reg + } + } + + // return 0; + if int(a.Index) == reg { + if f != 0 { + a.Index = s.Reg + } + return 0 + } + + return 0 + } + + return 0 +} + +func conprop(r0 *gc.Flow) { + var r *gc.Flow + var p *obj.Prog + var p0 *obj.Prog + var t int + var v0 *obj.Addr + + p0 = r0.Prog + v0 = &p0.To + r = r0 + +loop: + r = gc.Uniqs(r) + if r == nil || r == r0 { + return + } + if gc.Uniqp(r) == nil { + return + } + + p = r.Prog + t = copyu(p, v0, nil) + switch t { + case 0, // miss + 1: // use + goto loop + + case 2, // rar + 4: // use and set + break + + case 3: // set + if p.As == p0.As { + if p.From.Type == p0.From.Type { + if p.From.Reg == p0.From.Reg { + if p.From.Node == p0.From.Node { + if p.From.Offset == p0.From.Offset { + if p.From.Scale == p0.From.Scale { + if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval { + if p.From.Index == p0.From.Index { + excise(r) + goto loop + } + } + } + } + } + } + } + } + } +} + +func smallindir(a *obj.Addr, reg *obj.Addr) bool { + return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == i386.REG_NONE && 0 <= a.Offset && a.Offset < 4096 +} + +func stackaddr(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && a.Reg == i386.REG_SP +} diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c deleted file mode 100644 index e77a026a93..0000000000 --- a/src/cmd/8g/prog.c +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -// Matches real RtoB but can be used in global initializer. -#define RtoB(r) (1<<((r)-REG_AX)) - -enum { - AX = RtoB(REG_AX), - BX = RtoB(REG_BX), - CX = RtoB(REG_CX), - DX = RtoB(REG_DX), - DI = RtoB(REG_DI), - SI = RtoB(REG_SI), - - LeftRdwr = LeftRead | LeftWrite, - RightRdwr = RightRead | RightWrite, -}; - -#undef RtoB - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -static ProgInfo progtable[ALAST] = { - [ATYPE]= {Pseudo | Skip}, - [ATEXT]= {Pseudo}, - [AFUNCDATA]= {Pseudo}, - [APCDATA]= {Pseudo}, - [AUNDEF]= {Break}, - [AUSEFIELD]= {OK}, - [ACHECKNIL]= {LeftRead}, - [AVARDEF]= {Pseudo | RightWrite}, - [AVARKILL]= {Pseudo | RightWrite}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - [ANOP]= {LeftRead | RightWrite}, - - [AADCL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry}, - [AADCW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry}, - - [AADDB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AADDL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AADDW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [AADDSD]= {SizeD | LeftRead | RightRdwr}, - [AADDSS]= {SizeF | LeftRead | RightRdwr}, - - [AANDB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AANDL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AANDW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [ACALL]= {RightAddr | Call | KillCarry}, - - [ACDQ]= {OK, AX, AX | DX}, - [ACWD]= {OK, AX, AX | DX}, - - [ACLD]= {OK}, - [ASTD]= {OK}, - - [ACMPB]= {SizeB | LeftRead | RightRead | SetCarry}, - [ACMPL]= {SizeL | LeftRead | RightRead | SetCarry}, - [ACMPW]= {SizeW | LeftRead | RightRead | SetCarry}, - - [ACOMISD]= {SizeD | LeftRead | RightRead | SetCarry}, - [ACOMISS]= {SizeF | LeftRead | RightRead | SetCarry}, - - [ACVTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTSD2SS]= {SizeF | LeftRead | RightWrite | Conv}, - [ACVTSL2SD]= {SizeD | LeftRead | RightWrite | Conv}, - [ACVTSL2SS]= {SizeF | LeftRead | RightWrite | Conv}, - [ACVTSS2SD]= {SizeD | LeftRead | RightWrite | Conv}, - [ACVTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTTSD2SL]= {SizeL | LeftRead | RightWrite | Conv}, - [ACVTTSS2SL]= {SizeL | LeftRead | RightWrite | Conv}, - - [ADECB]= {SizeB | RightRdwr}, - [ADECL]= {SizeL | RightRdwr}, - [ADECW]= {SizeW | RightRdwr}, - - [ADIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [ADIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, - [ADIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, - - [ADIVSD]= {SizeD | LeftRead | RightRdwr}, - [ADIVSS]= {SizeF | LeftRead | RightRdwr}, - - [AFLDCW]= {SizeW | LeftAddr}, - [AFSTCW]= {SizeW | RightAddr}, - - [AFSTSW]= {SizeW | RightAddr | RightWrite}, - - [AFADDD]= {SizeD | LeftAddr | RightRdwr}, - [AFADDDP]= {SizeD | LeftAddr | RightRdwr}, - [AFADDF]= {SizeF | LeftAddr | RightRdwr}, - - [AFCOMD]= {SizeD | LeftAddr | RightRead}, - [AFCOMDP]= {SizeD | LeftAddr | RightRead}, - [AFCOMDPP]= {SizeD | LeftAddr | RightRead}, - [AFCOMF]= {SizeF | LeftAddr | RightRead}, - [AFCOMFP]= {SizeF | LeftAddr | RightRead}, - [AFUCOMIP]= {SizeF | LeftAddr | RightRead}, - - [AFCHS]= {SizeD | RightRdwr}, // also SizeF - - [AFDIVDP]= {SizeD | LeftAddr | RightRdwr}, - [AFDIVF]= {SizeF | LeftAddr | RightRdwr}, - [AFDIVD]= {SizeD | LeftAddr | RightRdwr}, - - [AFDIVRDP]= {SizeD | LeftAddr | RightRdwr}, - [AFDIVRF]= {SizeF | LeftAddr | RightRdwr}, - [AFDIVRD]= {SizeD | LeftAddr | RightRdwr}, - - [AFXCHD]= {SizeD | LeftRdwr | RightRdwr}, - - [AFSUBD]= {SizeD | LeftAddr | RightRdwr}, - [AFSUBDP]= {SizeD | LeftAddr | RightRdwr}, - [AFSUBF]= {SizeF | LeftAddr | RightRdwr}, - [AFSUBRD]= {SizeD | LeftAddr | RightRdwr}, - [AFSUBRDP]= {SizeD | LeftAddr | RightRdwr}, - [AFSUBRF]= {SizeF | LeftAddr | RightRdwr}, - - [AFMOVD]= {SizeD | LeftAddr | RightWrite}, - [AFMOVF]= {SizeF | LeftAddr | RightWrite}, - [AFMOVL]= {SizeL | LeftAddr | RightWrite}, - [AFMOVW]= {SizeW | LeftAddr | RightWrite}, - [AFMOVV]= {SizeQ | LeftAddr | RightWrite}, - - // These instructions are marked as RightAddr - // so that the register optimizer does not try to replace the - // memory references with integer register references. - // But they do not use the previous value at the address, so - // we also mark them RightWrite. - [AFMOVDP]= {SizeD | LeftRead | RightWrite | RightAddr}, - [AFMOVFP]= {SizeF | LeftRead | RightWrite | RightAddr}, - [AFMOVLP]= {SizeL | LeftRead | RightWrite | RightAddr}, - [AFMOVWP]= {SizeW | LeftRead | RightWrite | RightAddr}, - [AFMOVVP]= {SizeQ | LeftRead | RightWrite | RightAddr}, - - [AFMULD]= {SizeD | LeftAddr | RightRdwr}, - [AFMULDP]= {SizeD | LeftAddr | RightRdwr}, - [AFMULF]= {SizeF | LeftAddr | RightRdwr}, - - [AIDIVB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AIDIVL]= {SizeL | LeftRead | SetCarry, AX|DX, AX|DX}, - [AIDIVW]= {SizeW | LeftRead | SetCarry, AX|DX, AX|DX}, - - [AIMULB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AIMULL]= {SizeL | LeftRead | ImulAXDX | SetCarry}, - [AIMULW]= {SizeW | LeftRead | ImulAXDX | SetCarry}, - - [AINCB]= {SizeB | RightRdwr}, - [AINCL]= {SizeL | RightRdwr}, - [AINCW]= {SizeW | RightRdwr}, - - [AJCC]= {Cjmp | UseCarry}, - [AJCS]= {Cjmp | UseCarry}, - [AJEQ]= {Cjmp | UseCarry}, - [AJGE]= {Cjmp | UseCarry}, - [AJGT]= {Cjmp | UseCarry}, - [AJHI]= {Cjmp | UseCarry}, - [AJLE]= {Cjmp | UseCarry}, - [AJLS]= {Cjmp | UseCarry}, - [AJLT]= {Cjmp | UseCarry}, - [AJMI]= {Cjmp | UseCarry}, - [AJNE]= {Cjmp | UseCarry}, - [AJOC]= {Cjmp | UseCarry}, - [AJOS]= {Cjmp | UseCarry}, - [AJPC]= {Cjmp | UseCarry}, - [AJPL]= {Cjmp | UseCarry}, - [AJPS]= {Cjmp | UseCarry}, - - [AJMP]= {Jump | Break | KillCarry}, - - [ALEAL]= {LeftAddr | RightWrite}, - - [AMOVBLSX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVBLZX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVBWSX]= {SizeW | LeftRead | RightWrite | Conv}, - [AMOVBWZX]= {SizeW | LeftRead | RightWrite | Conv}, - [AMOVWLSX]= {SizeL | LeftRead | RightWrite | Conv}, - [AMOVWLZX]= {SizeL | LeftRead | RightWrite | Conv}, - - [AMOVB]= {SizeB | LeftRead | RightWrite | Move}, - [AMOVL]= {SizeL | LeftRead | RightWrite | Move}, - [AMOVW]= {SizeW | LeftRead | RightWrite | Move}, - - [AMOVSB]= {OK, DI|SI, DI|SI}, - [AMOVSL]= {OK, DI|SI, DI|SI}, - [AMOVSW]= {OK, DI|SI, DI|SI}, - [ADUFFCOPY]= {OK, DI|SI, DI|SI|CX}, - - [AMOVSD]= {SizeD | LeftRead | RightWrite | Move}, - [AMOVSS]= {SizeF | LeftRead | RightWrite | Move}, - - // We use MOVAPD as a faster synonym for MOVSD. - [AMOVAPD]= {SizeD | LeftRead | RightWrite | Move}, - - [AMULB]= {SizeB | LeftRead | SetCarry, AX, AX}, - [AMULL]= {SizeL | LeftRead | SetCarry, AX, AX|DX}, - [AMULW]= {SizeW | LeftRead | SetCarry, AX, AX|DX}, - - [AMULSD]= {SizeD | LeftRead | RightRdwr}, - [AMULSS]= {SizeF | LeftRead | RightRdwr}, - - [ANEGB]= {SizeB | RightRdwr | SetCarry}, - [ANEGL]= {SizeL | RightRdwr | SetCarry}, - [ANEGW]= {SizeW | RightRdwr | SetCarry}, - - [ANOTB]= {SizeB | RightRdwr}, - [ANOTL]= {SizeL | RightRdwr}, - [ANOTW]= {SizeW | RightRdwr}, - - [AORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AORL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AORW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [APOPL]= {SizeL | RightWrite}, - [APUSHL]= {SizeL | LeftRead}, - - [ARCLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - - [ARCRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - [ARCRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry}, - - [AREP]= {OK, CX, CX}, - [AREPN]= {OK, CX, CX}, - - [ARET]= {Break | KillCarry}, - - [AROLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [AROLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [AROLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ARORB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ARORL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ARORW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASAHF]= {OK, AX, AX}, - - [ASALB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASALL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASALW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASARB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASARL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASARW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASBBB]= {SizeB | LeftRead | RightRdwr | SetCarry | UseCarry}, - [ASBBL]= {SizeL | LeftRead | RightRdwr | SetCarry | UseCarry}, - [ASBBW]= {SizeW | LeftRead | RightRdwr | SetCarry | UseCarry}, - - [ASETCC]= {SizeB | RightRdwr | UseCarry}, - [ASETCS]= {SizeB | RightRdwr | UseCarry}, - [ASETEQ]= {SizeB | RightRdwr | UseCarry}, - [ASETGE]= {SizeB | RightRdwr | UseCarry}, - [ASETGT]= {SizeB | RightRdwr | UseCarry}, - [ASETHI]= {SizeB | RightRdwr | UseCarry}, - [ASETLE]= {SizeB | RightRdwr | UseCarry}, - [ASETLS]= {SizeB | RightRdwr | UseCarry}, - [ASETLT]= {SizeB | RightRdwr | UseCarry}, - [ASETMI]= {SizeB | RightRdwr | UseCarry}, - [ASETNE]= {SizeB | RightRdwr | UseCarry}, - [ASETOC]= {SizeB | RightRdwr | UseCarry}, - [ASETOS]= {SizeB | RightRdwr | UseCarry}, - [ASETPC]= {SizeB | RightRdwr | UseCarry}, - [ASETPL]= {SizeB | RightRdwr | UseCarry}, - [ASETPS]= {SizeB | RightRdwr | UseCarry}, - - [ASHLB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHLL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHLW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASHRB]= {SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHRL]= {SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry}, - [ASHRW]= {SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry}, - - [ASTOSB]= {OK, AX|DI, DI}, - [ASTOSL]= {OK, AX|DI, DI}, - [ASTOSW]= {OK, AX|DI, DI}, - [ADUFFZERO]= {OK, AX|DI, DI}, - - [ASUBB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [ASUBL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [ASUBW]= {SizeW | LeftRead | RightRdwr | SetCarry}, - - [ASUBSD]= {SizeD | LeftRead | RightRdwr}, - [ASUBSS]= {SizeF | LeftRead | RightRdwr}, - - [ATESTB]= {SizeB | LeftRead | RightRead | SetCarry}, - [ATESTL]= {SizeL | LeftRead | RightRead | SetCarry}, - [ATESTW]= {SizeW | LeftRead | RightRead | SetCarry}, - - [AUCOMISD]= {SizeD | LeftRead | RightRead}, - [AUCOMISS]= {SizeF | LeftRead | RightRead}, - - [AXCHGB]= {SizeB | LeftRdwr | RightRdwr}, - [AXCHGL]= {SizeL | LeftRdwr | RightRdwr}, - [AXCHGW]= {SizeW | LeftRdwr | RightRdwr}, - - [AXORB]= {SizeB | LeftRead | RightRdwr | SetCarry}, - [AXORL]= {SizeL | LeftRead | RightRdwr | SetCarry}, - [AXORW]= {SizeW | LeftRead | RightRdwr | SetCarry}, -}; - -void -proginfo(ProgInfo *info, Prog *p) -{ - *info = progtable[p->as]; - if(info->flags == 0) - fatal("unknown instruction %P", p); - - if((info->flags & ShiftCX) && p->from.type != TYPE_CONST) - info->reguse |= CX; - - if(info->flags & ImulAXDX) { - if(p->to.type == TYPE_NONE) { - info->reguse |= AX; - info->regset |= AX | DX; - } else { - info->flags |= RightRdwr; - } - } - - // Addressing makes some registers used. - if(p->from.type == TYPE_MEM && p->from.name == NAME_NONE) - info->regindex |= RtoB(p->from.reg); - if(p->from.index != REG_NONE) - info->regindex |= RtoB(p->from.index); - if(p->to.type == TYPE_MEM && p->to.name == NAME_NONE) - info->regindex |= RtoB(p->to.reg); - if(p->to.index != REG_NONE) - info->regindex |= RtoB(p->to.index); -} diff --git a/src/cmd/8g/prog.go b/src/cmd/8g/prog.go new file mode 100644 index 0000000000..d8e46e5108 --- /dev/null +++ b/src/cmd/8g/prog.go @@ -0,0 +1,291 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/i386" +) +import "cmd/internal/gc" + +var ( + AX = RtoB(i386.REG_AX) + BX = RtoB(i386.REG_BX) + CX = RtoB(i386.REG_CX) + DX = RtoB(i386.REG_DX) + DI = RtoB(i386.REG_DI) + SI = RtoB(i386.REG_SI) + LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite + RightRdwr uint32 = gc.RightRead | gc.RightWrite +) + +// This table gives the basic information about instruction +// generated by the compiler and processed in the optimizer. +// See opt.h for bit definitions. +// +// Instructions not generated need not be listed. +// As an exception to that rule, we typically write down all the +// size variants of an operation even if we just use a subset. +// +// The table is formatted for 8-space tabs. +var progtable = [i386.ALAST]gc.ProgInfo{ + obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, + obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, + obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, + obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, + obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, + obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, + + // NOP is an internal no-op that also stands + // for USED and SET annotations, not the Intel opcode. + obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, + i386.AADCL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.AADCW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.AADDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AADDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AADDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AADDSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.AADDSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.AANDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AANDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AANDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + obj.ACALL: gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0}, + i386.ACDQ: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, + i386.ACWD: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, + i386.ACLD: gc.ProgInfo{gc.OK, 0, 0, 0}, + i386.ASTD: gc.ProgInfo{gc.OK, 0, 0, 0}, + i386.ACMPB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ACMPL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ACMPW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ACOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ACOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ACVTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTSD2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTSL2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTSL2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTSS2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.ADECB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + i386.ADECL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + i386.ADECW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + i386.ADIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + i386.ADIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + i386.ADIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + i386.ADIVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.ADIVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.AFLDCW: gc.ProgInfo{gc.SizeW | gc.LeftAddr, 0, 0, 0}, + i386.AFSTCW: gc.ProgInfo{gc.SizeW | gc.RightAddr, 0, 0, 0}, + i386.AFSTSW: gc.ProgInfo{gc.SizeW | gc.RightAddr | gc.RightWrite, 0, 0, 0}, + i386.AFADDD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFADDDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFADDF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFCOMD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFCOMDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFCOMDPP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFCOMF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFCOMFP: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFUCOMIP: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, + i386.AFCHS: gc.ProgInfo{gc.SizeD | RightRdwr, 0, 0, 0}, // also SizeF + + i386.AFDIVDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFDIVF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFDIVD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFDIVRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFDIVRF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFDIVRD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFXCHD: gc.ProgInfo{gc.SizeD | LeftRdwr | RightRdwr, 0, 0, 0}, + i386.AFSUBD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFSUBDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFSUBF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFSUBRD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFSUBRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFSUBRF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFMOVD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + i386.AFMOVF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + i386.AFMOVL: gc.ProgInfo{gc.SizeL | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + i386.AFMOVW: gc.ProgInfo{gc.SizeW | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + i386.AFMOVV: gc.ProgInfo{gc.SizeQ | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + + // These instructions are marked as RightAddr + // so that the register optimizer does not try to replace the + // memory references with integer register references. + // But they do not use the previous value at the address, so + // we also mark them RightWrite. + i386.AFMOVDP: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, + i386.AFMOVFP: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, + i386.AFMOVLP: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, + i386.AFMOVWP: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, + i386.AFMOVVP: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, + i386.AFMULD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFMULDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AFMULF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, + i386.AIDIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + i386.AIDIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + i386.AIDIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, + i386.AIMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + i386.AIMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, + i386.AIMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, + i386.AINCB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + i386.AINCL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + i386.AINCW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + i386.AJCC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJCS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJEQ: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJGE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJGT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJHI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJLE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJLS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJLT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJMI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJNE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJOC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJOS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJPC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJPL: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + i386.AJPS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, + obj.AJMP: gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0}, + i386.ALEAL: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, + i386.AMOVBLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVBLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVBWSX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVBWZX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVWLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVWLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, + i386.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + i386.AMOVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + i386.AMOVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + i386.AMOVSB: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + i386.AMOVSL: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + i386.AMOVSW: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, + obj.ADUFFCOPY: gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0}, + i386.AMOVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + i386.AMOVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + + // We use MOVAPD as a faster synonym for MOVSD. + i386.AMOVAPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, + i386.AMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, + i386.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, + i386.AMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, + i386.AMULSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.AMULSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.ANEGB: gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ANEGL: gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ANEGW: gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ANOTB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, + i386.ANOTL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, + i386.ANOTW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, + i386.AORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.APOPL: gc.ProgInfo{gc.SizeL | gc.RightWrite, 0, 0, 0}, + i386.APUSHL: gc.ProgInfo{gc.SizeL | gc.LeftRead, 0, 0, 0}, + i386.ARCLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ARCLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ARCLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ARCRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ARCRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ARCRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.AREP: gc.ProgInfo{gc.OK, CX, CX, 0}, + i386.AREPN: gc.ProgInfo{gc.OK, CX, CX, 0}, + obj.ARET: gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0}, + i386.AROLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.AROLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.AROLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ARORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ARORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ARORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASAHF: gc.ProgInfo{gc.OK, AX, AX, 0}, + i386.ASALB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASALL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASALW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASARB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASARL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASARW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASBBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ASBBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ASBBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, + i386.ASETCC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETCS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETEQ: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETGE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETGT: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETHI: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETLE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETLS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETLT: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETMI: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETNE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETOC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETOS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETPC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETPL: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASETPS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, + i386.ASHLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASHLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASHLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASHRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASHRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASHRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, + i386.ASTOSB: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + i386.ASTOSL: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + i386.ASTOSW: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, + i386.ASUBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ASUBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ASUBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.ASUBSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.ASUBSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, + i386.ATESTB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ATESTL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.ATESTW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, + i386.AUCOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, + i386.AUCOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, + i386.AXCHGB: gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0}, + i386.AXCHGL: gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0}, + i386.AXCHGW: gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0}, + i386.AXORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AXORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, + i386.AXORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, +} + +func proginfo(info *gc.ProgInfo, p *obj.Prog) { + *info = progtable[p.As] + if info.Flags == 0 { + gc.Fatal("unknown instruction %v", p) + } + + if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST { + info.Reguse |= CX + } + + if info.Flags&gc.ImulAXDX != 0 { + if p.To.Type == obj.TYPE_NONE { + info.Reguse |= AX + info.Regset |= AX | DX + } else { + info.Flags |= RightRdwr + } + } + + // Addressing makes some registers used. + if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE { + info.Regindex |= RtoB(int(p.From.Reg)) + } + if p.From.Index != i386.REG_NONE { + info.Regindex |= RtoB(int(p.From.Index)) + } + if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE { + info.Regindex |= RtoB(int(p.To.Reg)) + } + if p.To.Index != i386.REG_NONE { + info.Regindex |= RtoB(int(p.To.Index)) + } +} diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c deleted file mode 100644 index 0470bdf7b5..0000000000 --- a/src/cmd/8g/reg.c +++ /dev/null @@ -1,112 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -enum { - NREGVAR = 16, /* 8 integer + 8 floating */ -}; - -static char* regname[] = { - ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di", - ".x0", ".x1", ".x2", ".x3", ".x4", ".x5", ".x6", ".x7", -}; - -char** -regnames(int *n) -{ - *n = NREGVAR; - return regname; -} - -uint64 -excludedregs(void) -{ - return RtoB(REG_SP); -} - -uint64 -doregbits(int r) -{ - uint64 b; - - b = 0; - if(r >= REG_AX && r <= REG_DI) - b |= RtoB(r); - else - if(r >= REG_AL && r <= REG_BL) - b |= RtoB(r-REG_AL+REG_AX); - else - if(r >= REG_AH && r <= REG_BH) - b |= RtoB(r-REG_AH+REG_AX); - else - if(r >= REG_X0 && r <= REG_X0+7) - b |= FtoB(r); - return b; -} - -uint64 -RtoB(int r) -{ - - if(r < REG_AX || r > REG_DI) - return 0; - return 1ULL << (r-REG_AX); -} - -int -BtoR(uint64 b) -{ - - b &= 0xffL; - if(b == 0) - return 0; - return bitno(b) + REG_AX; -} - -uint64 -FtoB(int f) -{ - if(f < REG_X0 || f > REG_X7) - return 0; - return 1ULL << (f - REG_X0 + 8); -} - -int -BtoF(uint64 b) -{ - b &= 0xFF00L; - if(b == 0) - return 0; - return bitno(b) - 8 + REG_X0; -} diff --git a/src/cmd/8g/reg.go b/src/cmd/8g/reg.go new file mode 100644 index 0000000000..76bd260f54 --- /dev/null +++ b/src/cmd/8g/reg.go @@ -0,0 +1,112 @@ +// Derived from Inferno utils/6c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import "cmd/internal/obj/i386" +import "cmd/internal/gc" + +const ( + NREGVAR = 16 +) + +var regname = []string{ + ".ax", + ".cx", + ".dx", + ".bx", + ".sp", + ".bp", + ".si", + ".di", + ".x0", + ".x1", + ".x2", + ".x3", + ".x4", + ".x5", + ".x6", + ".x7", +} + +func regnames(n *int) []string { + *n = NREGVAR + return regname +} + +func excludedregs() uint64 { + return RtoB(i386.REG_SP) +} + +func doregbits(r int) uint64 { + var b uint64 + + b = 0 + if r >= i386.REG_AX && r <= i386.REG_DI { + b |= RtoB(r) + } else if r >= i386.REG_AL && r <= i386.REG_BL { + b |= RtoB(r - i386.REG_AL + i386.REG_AX) + } else if r >= i386.REG_AH && r <= i386.REG_BH { + b |= RtoB(r - i386.REG_AH + i386.REG_AX) + } else if r >= i386.REG_X0 && r <= i386.REG_X0+7 { + b |= FtoB(r) + } + return b +} + +func RtoB(r int) uint64 { + if r < i386.REG_AX || r > i386.REG_DI { + return 0 + } + return 1 << uint(r-i386.REG_AX) +} + +func BtoR(b uint64) int { + b &= 0xff + if b == 0 { + return 0 + } + return gc.Bitno(b) + i386.REG_AX +} + +func FtoB(f int) uint64 { + if f < i386.REG_X0 || f > i386.REG_X7 { + return 0 + } + return 1 << uint(f-i386.REG_X0+8) +} + +func BtoF(b uint64) int { + b &= 0xFF00 + if b == 0 { + return 0 + } + return gc.Bitno(b) - 8 + i386.REG_X0 +} diff --git a/src/cmd/8g/util.go b/src/cmd/8g/util.go new file mode 100644 index 0000000000..bb5eedb15a --- /dev/null +++ b/src/cmd/8g/util.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func bool2int(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/9a/Makefile b/src/cmd/9a/Makefile deleted file mode 100644 index 27290ddd71..0000000000 --- a/src/cmd/9a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist - -install: y.tab.h - -y.tab.h: a.y - LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y diff --git a/src/cmd/9a/a.h b/src/cmd/9a/a.h deleted file mode 100644 index d4f2fee119..0000000000 --- a/src/cmd/9a/a.h +++ /dev/null @@ -1,172 +0,0 @@ -// cmd/9a/a.h from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "../9l/9.out.h" - -#ifndef EXTERN -#define EXTERN extern -#endif - -#undef getc -#undef ungetc -#undef BUFSIZ - -#define getc ccgetc -#define ungetc ccungetc - -typedef struct Sym Sym; -typedef struct Io Io; - -#define MAXALIGN 7 -#define FPCHIP 1 -#define NSYMB 8192 -#define BUFSIZ 8192 -#define HISTSZ 20 -#define NINCLUDE 10 -#define NHUNK 10000 -#ifndef EOF -#define EOF (-1) -#endif -#define IGN (-2) -#define GETC() ((--fi.c < 0)? filbuf(): *fi.p++ & 0xff) -#define NHASH 503 -#define STRINGSZ 200 -#define NMACRO 10 - -struct Sym -{ - Sym* link; - char* macro; - vlong value; - ushort type; - char *name; - char* labelname; - char sym; -}; -#define S ((Sym*)0) - -EXTERN struct -{ - char* p; - int c; -} fi; - -struct Io -{ - Io* link; - char b[BUFSIZ]; - char* p; - short c; - short f; -}; -#define I ((Io*)0) - -enum -{ - CLAST, - CMACARG, - CMACRO, - CPREPROC, -}; - -EXTERN int debug[256]; -EXTERN Sym* hash[NHASH]; -EXTERN char** Dlist; -EXTERN int nDlist; -EXTERN int newflag; -EXTERN char* hunk; -EXTERN char** include; -EXTERN Io* iofree; -EXTERN Io* ionext; -EXTERN Io* iostack; -EXTERN int32 lineno; -EXTERN int nerrors; -EXTERN int32 nhunk; -EXTERN int nosched; -EXTERN int ninclude; -EXTERN int32 nsymb; -EXTERN Addr nullgen; -EXTERN char* outfile; -EXTERN int pass; -EXTERN int32 pc; -EXTERN int peekc; -EXTERN int32 stmtline; -EXTERN int sym; -EXTERN char* symb; -EXTERN int thechar; -EXTERN char* thestring; -EXTERN int32 thunk; -EXTERN Biobuf obuf; -EXTERN Link* ctxt; -EXTERN Biobuf bstdout; -EXTERN Prog* lastpc; - -void* alloc(int32); -void* allocn(void*, int32, int32); -void ensuresymb(int32); -void errorexit(void); -void pushio(void); -void newio(void); -void newfile(char*, int); -Sym* slookup(char*); -Sym* lookup(void); -Sym* labellookup(Sym*); -void settext(LSym*); -void syminit(Sym*); -int32 yylex(void); -int getc(void); -int getnsc(void); -void unget(int); -int escchar(int); -void cinit(void); -void pinit(char*); -void cclean(void); -void outcode(int, Addr*, int, Addr*); -void outgcode(int, Addr*, int, Addr*, Addr*); -int filbuf(void); -Sym* getsym(void); -void domacro(void); -void macund(void); -void macdef(void); -void macexpand(Sym*, char*); -void macinc(void); -void macprag(void); -void maclin(void); -void macif(int); -void macend(void); -void dodefine(char*); -void prfile(int32); -void linehist(char*, int); -void gethunk(void); -void yyerror(char*, ...); -int yyparse(void); -void setinclude(char*); -int assemble(char*); diff --git a/src/cmd/9a/a.y b/src/cmd/9a/a.y index ccc3bcc3a6..db733c5987 100644 --- a/src/cmd/9a/a.y +++ b/src/cmd/9a/a.y @@ -28,20 +28,24 @@ // THE SOFTWARE. %{ -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/ppc64" +) %} + %union { - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; + sym *asm.Sym + lval int64 + dval float64 + sval string + addr obj.Addr } + %left '|' %left '^' %left '&' @@ -50,7 +54,7 @@ %left '*' '/' '%' %token LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP %token LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW -%token LNOP LEND LRETT LWORD LTEXT LGLOBL LDATA LRETRN +%token LNOP LEND LRETT LWORD LTEXT LDATA LGLOBL LRETRN %token LCONST LSP LSB LFP LPC LCREG LFLUSH %token LREG LFREG LR LCR LF LFPSCR %token LLR LCTR LSPR LSPREG LSEG LMSR @@ -66,34 +70,36 @@ prog: | prog { - stmtline = lineno; + stmtline = asm.Lineno } line line: LNAME ':' { - $1 = labellookup($1); - if($1->type == LLAB && $1->value != pc) - yyerror("redeclaration of %s", $1->labelname); - $1->type = LLAB; - $1->value = pc; + $1 = asm.LabelLookup($1); + if $1.Type == LLAB && $1.Value != int64(asm.PC) { + yyerror("redeclaration of %s", $1.Labelname) + } + $1.Type = LLAB; + $1.Value = int64(asm.PC); } line | LNAME '=' expr ';' { - $1->type = LVAR; - $1->value = $3; + $1.Type = LVAR; + $1.Value = $3; } | LVAR '=' expr ';' { - if($1->value != $3) - yyerror("redeclaration of %s", $1->name); - $1->value = $3; + if $1.Value != $3 { + yyerror("redeclaration of %s", $1.Name) + } + $1.Value = $3; } | LSCHED ';' { - nosched = $1; + nosched = int($1); } | ';' | inst ';' @@ -105,122 +111,122 @@ inst: */ LMOVW rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW addr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW regaddr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVB rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVB addr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVB regaddr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * load floats */ | LFMOV addr ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFMOV regaddr ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFMOV fimm ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFMOV freg ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFMOV freg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFMOV freg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * store ints and bytes */ | LMOVW rreg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW rreg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVB rreg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVB rreg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * store floats */ | LMOVW freg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW freg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * floating point status */ | LMOVW fpscr ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW freg ',' fpscr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW freg ',' imm ',' fpscr { - outgcode($1, &$2, 0, &$4, &$6); + outgcode(int($1), &$2, 0, &$4, &$6); } | LMOVW fpscr ',' creg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMTFSB imm ',' con { - outcode($1, &$2, $4, &nullgen); + outcode(int($1), &$2, int($4), &nullgen); } /* * field moves (mtcrf) */ | LMOVW rreg ',' imm ',' lcr { - outgcode($1, &$2, 0, &$4, &$6); + outgcode(int($1), &$2, 0, &$4, &$6); } | LMOVW rreg ',' creg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW rreg ',' lcr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * integer operations @@ -230,84 +236,84 @@ inst: */ | LADDW rreg ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } | LADDW imm ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } | LADDW rreg ',' imm ',' rreg { - outgcode($1, &$2, 0, &$4, &$6); + outgcode(int($1), &$2, 0, &$4, &$6); } | LADDW rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LADDW imm ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LLOGW rreg ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } | LLOGW rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LSHW rreg ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } | LSHW rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LSHW imm ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } | LSHW imm ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LABS rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LABS rreg { - outcode($1, &$2, 0, &$2); + outcode(int($1), &$2, 0, &$2); } /* * multiply-accumulate */ | LMA rreg ',' sreg ',' rreg { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } /* * move immediate: macro for cau+or, addi, addis, and other combinations */ | LMOVW imm ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW ximm ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * condition register operations */ | LCROP cbit ',' cbit { - outcode($1, &$2, $4.reg, &$4); + outcode(int($1), &$2, int($4.Reg), &$4); } | LCROP cbit ',' con ',' cbit { - outcode($1, &$2, $4, &$6); + outcode(int($1), &$2, int($4), &$6); } /* * condition register moves @@ -315,35 +321,35 @@ inst: */ | LMOVW creg ',' creg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW psr ',' creg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW lcr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW psr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW xlreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW rreg ',' xlreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW creg ',' psr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVW rreg ',' psr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * branch, branch conditional @@ -352,170 +358,170 @@ inst: */ | LBRA rel { - outcode($1, &nullgen, 0, &$2); + outcode(int($1), &nullgen, 0, &$2); } | LBRA addr { - outcode($1, &nullgen, 0, &$2); + outcode(int($1), &nullgen, 0, &$2); } | LBRA '(' xlreg ')' { - outcode($1, &nullgen, 0, &$3); + outcode(int($1), &nullgen, 0, &$3); } | LBRA ',' rel { - outcode($1, &nullgen, 0, &$3); + outcode(int($1), &nullgen, 0, &$3); } | LBRA ',' addr { - outcode($1, &nullgen, 0, &$3); + outcode(int($1), &nullgen, 0, &$3); } | LBRA ',' '(' xlreg ')' { - outcode($1, &nullgen, 0, &$4); + outcode(int($1), &nullgen, 0, &$4); } | LBRA creg ',' rel { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LBRA creg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LBRA creg ',' '(' xlreg ')' { - outcode($1, &$2, 0, &$5); + outcode(int($1), &$2, 0, &$5); } | LBRA con ',' rel { - outcode($1, &nullgen, $2, &$4); + outcode(int($1), &nullgen, int($2), &$4); } | LBRA con ',' addr { - outcode($1, &nullgen, $2, &$4); + outcode(int($1), &nullgen, int($2), &$4); } | LBRA con ',' '(' xlreg ')' { - outcode($1, &nullgen, $2, &$5); + outcode(int($1), &nullgen, int($2), &$5); } | LBRA con ',' con ',' rel { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = $2; - outcode($1, &g, REG_R0+$4, &$6); + g.Type = obj.TYPE_CONST; + g.Offset = $2; + outcode(int($1), &g, int(REG_R0+$4), &$6); } | LBRA con ',' con ',' addr { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = $2; - outcode($1, &g, REG_R0+$4, &$6); + g.Type = obj.TYPE_CONST; + g.Offset = $2; + outcode(int($1), &g, int(REG_R0+$4), &$6); } | LBRA con ',' con ',' '(' xlreg ')' { - Addr g; + var g obj.Addr g = nullgen; - g.type = TYPE_CONST; - g.offset = $2; - outcode($1, &g, REG_R0+$4, &$7); + g.Type = obj.TYPE_CONST; + g.Offset = $2; + outcode(int($1), &g, int(REG_R0+$4), &$7); } /* * conditional trap */ | LTRAP rreg ',' sreg { - outcode($1, &$2, $4, &nullgen); + outcode(int($1), &$2, int($4), &nullgen); } | LTRAP imm ',' sreg { - outcode($1, &$2, $4, &nullgen); + outcode(int($1), &$2, int($4), &nullgen); } | LTRAP rreg comma { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } | LTRAP comma { - outcode($1, &nullgen, 0, &nullgen); + outcode(int($1), &nullgen, 0, &nullgen); } /* * floating point operate */ | LFCONV freg ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFADD freg ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFADD freg ',' freg ',' freg { - outcode($1, &$2, $4.reg, &$6); + outcode(int($1), &$2, int($4.Reg), &$6); } | LFMA freg ',' freg ',' freg ',' freg { - outgcode($1, &$2, $4.reg, &$6, &$8); + outgcode(int($1), &$2, int($4.Reg), &$6, &$8); } | LFCMP freg ',' freg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LFCMP freg ',' freg ',' creg { - outcode($1, &$2, $6.reg, &$4); + outcode(int($1), &$2, int($6.Reg), &$4); } /* * CMP */ | LCMP rreg ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LCMP rreg ',' imm { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LCMP rreg ',' rreg ',' creg { - outcode($1, &$2, $6.reg, &$4); + outcode(int($1), &$2, int($6.Reg), &$4); } | LCMP rreg ',' imm ',' creg { - outcode($1, &$2, $6.reg, &$4); + outcode(int($1), &$2, int($6.Reg), &$4); } /* * rotate and mask */ | LRLWM imm ',' rreg ',' imm ',' rreg { - outgcode($1, &$2, $4.reg, &$6, &$8); + outgcode(int($1), &$2, int($4.Reg), &$6, &$8); } | LRLWM imm ',' rreg ',' mask ',' rreg { - outgcode($1, &$2, $4.reg, &$6, &$8); + outgcode(int($1), &$2, int($4.Reg), &$6, &$8); } | LRLWM rreg ',' rreg ',' imm ',' rreg { - outgcode($1, &$2, $4.reg, &$6, &$8); + outgcode(int($1), &$2, int($4.Reg), &$6, &$8); } | LRLWM rreg ',' rreg ',' mask ',' rreg { - outgcode($1, &$2, $4.reg, &$6, &$8); + outgcode(int($1), &$2, int($4.Reg), &$6, &$8); } /* * load/store multiple */ | LMOVMW addr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LMOVMW rreg ',' addr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } /* * various indexed load/store @@ -523,112 +529,115 @@ inst: */ | LXLD regaddr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LXLD regaddr ',' imm ',' rreg { - outgcode($1, &$2, 0, &$4, &$6); + outgcode(int($1), &$2, 0, &$4, &$6); } | LXST rreg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LXST rreg ',' imm ',' regaddr { - outgcode($1, &$2, 0, &$4, &$6); + outgcode(int($1), &$2, 0, &$4, &$6); } | LXMV regaddr ',' rreg { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LXMV rreg ',' regaddr { - outcode($1, &$2, 0, &$4); + outcode(int($1), &$2, 0, &$4); } | LXOP regaddr { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } /* * NOP */ | LNOP comma { - outcode($1, &nullgen, 0, &nullgen); + outcode(int($1), &nullgen, 0, &nullgen); } | LNOP rreg comma { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } | LNOP freg comma { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } | LNOP ',' rreg { - outcode($1, &nullgen, 0, &$3); + outcode(int($1), &nullgen, 0, &$3); } | LNOP ',' freg { - outcode($1, &nullgen, 0, &$3); + outcode(int($1), &nullgen, 0, &$3); } | LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */ { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } /* * word */ | LWORD imm comma { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } | LWORD ximm comma { - outcode($1, &$2, 0, &nullgen); + outcode(int($1), &$2, 0, &nullgen); } /* * PCDATA */ | LPCDAT imm ',' imm { - if($2.type != TYPE_CONST || $4.type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); - outcode($1, &$2, 0, &$4); + if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST { + yyerror("arguments to PCDATA must be integer constants") + } + outcode(int($1), &$2, 0, &$4); } /* * FUNCDATA */ | LFUNCDAT imm ',' addr { - if($2.type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if($4.type != NAME_EXTERN && $4.type != NAME_STATIC && $4.type != TYPE_MEM) - yyerror("value for FUNCDATA must be symbol reference"); - outcode($1, &$2, 0, &$4); + if $2.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if $4.Type != obj.TYPE_MEM || ($4.Name != obj.NAME_EXTERN && $4.Name != obj.NAME_STATIC) { + yyerror("value for FUNCDATA must be symbol reference") + } + outcode(int($1), &$2, 0, &$4); } /* * END */ | LEND comma { - outcode($1, &nullgen, 0, &nullgen); + outcode(int($1), &nullgen, 0, &nullgen); } /* * TEXT */ | LTEXT name ',' '$' textsize { - settext($2.sym); - outcode($1, &$2, 0, &$5); + asm.Settext($2.Sym); + outcode(int($1), &$2, 0, &$5); } | LTEXT name ',' con ',' '$' textsize { - settext($2.sym); - outcode($1, &$2, 0, &$7); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym); + outcode(int($1), &$2, int($4), &$7); + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } /* @@ -636,16 +645,16 @@ inst: */ | LGLOBL name ',' imm { - settext($2.sym); - outcode($1, &$2, 0, &$4); + asm.Settext($2.Sym) + outcode(int($1), &$2, 0, &$4) } | LGLOBL name ',' con ',' imm { - settext($2.sym); - outcode($1, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + asm.Settext($2.Sym) + outcode(int($1), &$2, 0, &$6) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } @@ -654,26 +663,26 @@ inst: */ | LDATA name '/' con ',' imm { - outcode($1, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + outcode(int($1), &$2, 0, &$6); + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } | LDATA name '/' con ',' ximm { - outcode($1, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + outcode(int($1), &$2, 0, &$6); + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } | LDATA name '/' con ',' fimm { - outcode($1, &$2, 0, &$6); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = $4; + outcode(int($1), &$2, 0, &$6); + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = $4 } } /* @@ -681,32 +690,33 @@ inst: */ | LRETRN comma { - outcode($1, &nullgen, 0, &nullgen); + outcode(int($1), &nullgen, 0, &nullgen); } rel: con '(' LPC ')' { $$ = nullgen; - $$.type = TYPE_BRANCH; - $$.offset = $1 + pc; + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1 + int64(asm.PC); } | LNAME offset { - $1 = labellookup($1); + $1 = asm.LabelLookup($1); $$ = nullgen; - if(pass == 2 && $1->type != LLAB) - yyerror("undefined label: %s", $1->labelname); - $$.type = TYPE_BRANCH; - $$.offset = $1->value + $2; + if asm.Pass == 2 && $1.Type != LLAB { + yyerror("undefined label: %s", $1.Labelname) + } + $$.Type = obj.TYPE_BRANCH; + $$.Offset = $1.Value + $2; } rreg: sreg { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } xlreg: @@ -717,48 +727,49 @@ lr: LLR { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } lcr: LCR { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; /* whole register */ + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); /* whole register */ } ctr: LCTR { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } msr: LMSR { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1) } psr: LSPREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } | LSPR '(' con ')' { - if($3 < 0 || $3 >= 1024) - yyerror("SPR/DCR out of range"); + if $3 < 0 || $3 >= 1024 { + yyerror("SPR/DCR out of range") + } $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1 + $3; + $$.Type = obj.TYPE_REG + $$.Reg = int16($1 + $3); } | msr @@ -766,137 +777,140 @@ fpscr: LFPSCR { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } freg: LFREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } | LF '(' con ')' { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = REG_F0 + $3; + $$.Type = obj.TYPE_REG; + $$.Reg = int16(REG_F0 + $3); } creg: LCREG { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } | LCR '(' con ')' { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = REG_C0 + $3; + $$.Type = obj.TYPE_REG; + $$.Reg = int16(REG_C0 + $3); } cbit: con { $$ = nullgen; - $$.type = TYPE_REG; - $$.reg = $1; + $$.Type = obj.TYPE_REG; + $$.Reg = int16($1); } mask: con ',' con { - int mb, me; - uint32 v; + var mb, me int + var v uint32 $$ = nullgen; - $$.type = TYPE_CONST; - mb = $1; - me = $3; + $$.Type = obj.TYPE_CONST; + mb = int($1); + me = int($3); if(mb < 0 || mb > 31 || me < 0 || me > 31){ yyerror("illegal mask start/end value(s)"); - mb = me = 0; + mb = 0 + me = 0; + } + if mb <= me { + v = (^uint32(0)>>uint(mb)) & (^uint32(0)<>uint(me+1)) & (^uint32(0)<>mb) & (~0L<<(31-me)); - else - v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1)))); - $$.offset = v; + $$.Offset = int64(v); } textsize: LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = int64($1) + $$.U.Argsize = obj.ArgsSizeUnknown; } | '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = ArgsSizeUnknown; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -int64($2) + $$.U.Argsize = obj.ArgsSizeUnknown; } | LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = $1; - $$.u.argsize = $3; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = int64($1) + $$.U.Argsize = int32($3); } | '-' LCONST '-' LCONST { $$ = nullgen; - $$.type = TYPE_TEXTSIZE; - $$.offset = -$2; - $$.u.argsize = $4; + $$.Type = obj.TYPE_TEXTSIZE; + $$.Offset = -int64($2) + $$.U.Argsize = int32($4); } ximm: '$' addr { $$ = $2; - $$.type = TYPE_ADDR; + $$.Type = obj.TYPE_ADDR; } | '$' LSCONST { $$ = nullgen; - $$.type = TYPE_SCONST; - memcpy($$.u.sval, $2, sizeof($$.u.sval)); + $$.Type = obj.TYPE_SCONST; + $$.U.Sval = $2 } fimm: '$' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = $2; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = $2; } | '$' '-' LFCONST { $$ = nullgen; - $$.type = TYPE_FCONST; - $$.u.dval = -$3; + $$.Type = obj.TYPE_FCONST; + $$.U.Dval = -$3; } imm: '$' con { $$ = nullgen; - $$.type = TYPE_CONST; - $$.offset = $2; + $$.Type = obj.TYPE_CONST; + $$.Offset = $2; } sreg: LREG | LR '(' con ')' { - if($$ < 0 || $$ >= NREG) - print("register value out of range\n"); + if $$ < 0 || $$ >= NREG { + print("register value out of range\n") + } $$ = REG_R0 + $3; } @@ -904,17 +918,17 @@ regaddr: '(' sreg ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; - $$.offset = 0; + $$.Type = obj.TYPE_MEM; + $$.Reg = int16($2); + $$.Offset = 0; } | '(' sreg '+' sreg ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $2; - $$.scale = $4; - $$.offset = 0; + $$.Type = obj.TYPE_MEM; + $$.Reg = int16($2); + $$.Scale = int8($4); + $$.Offset = 0; } addr: @@ -922,35 +936,35 @@ addr: | con '(' sreg ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.reg = $3; - $$.offset = $1; + $$.Type = obj.TYPE_MEM; + $$.Reg = int16($3); + $$.Offset = $1; } name: con '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $3; - $$.sym = nil; - $$.offset = $1; + $$.Type = obj.TYPE_MEM; + $$.Name = int8($3); + $$.Sym = nil; + $$.Offset = $1; } | LNAME offset '(' pointer ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = $4; - $$.sym = linklookup(ctxt, $1->name, 0); - $$.offset = $2; + $$.Type = obj.TYPE_MEM; + $$.Name = int8($4); + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); + $$.Offset = $2; } | LNAME '<' '>' offset '(' LSB ')' { $$ = nullgen; - $$.type = TYPE_MEM; - $$.name = NAME_STATIC; - $$.sym = linklookup(ctxt, $1->name, 1); - $$.offset = $4; + $$.Type = obj.TYPE_MEM; + $$.Name = obj.NAME_STATIC; + $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); + $$.Offset = $4; } comma: @@ -978,7 +992,7 @@ con: LCONST | LVAR { - $$ = $1->value; + $$ = $1.Value; } | '-' con { @@ -990,7 +1004,7 @@ con: } | '~' con { - $$ = ~$2; + $$ = ^$2; } | '(' expr ')' { @@ -1021,11 +1035,11 @@ expr: } | expr '<' '<' expr { - $$ = $1 << $4; + $$ = $1 << uint($4); } | expr '>' '>' expr { - $$ = $1 >> $4; + $$ = $1 >> uint($4); } | expr '&' expr { diff --git a/src/cmd/9a/doc.go b/src/cmd/9a/doc.go deleted file mode 100644 index f6eed6d86e..0000000000 --- a/src/cmd/9a/doc.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -9a is a version of the Plan 9 assembler. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/8a - -Go-specific considerations are documented at - - http://golang.org/doc/asm - -Its target architecture is 64-bit PowerPC and Power Architecture processors, -referred to by these tools as ppc64 (big endian) or ppc64le (little endian). - -*/ -package main diff --git a/src/cmd/9a/lex.c b/src/cmd/9a/lex.c deleted file mode 100644 index ad552370d4..0000000000 --- a/src/cmd/9a/lex.c +++ /dev/null @@ -1,726 +0,0 @@ -// cmd/9a/lex.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define EXTERN -#include -#include -#include "a.h" -#include "y.tab.h" - -enum -{ - Plan9 = 1<<0, - Unix = 1<<1, - Windows = 1<<2, -}; - -int -systemtype(int sys) -{ -#ifdef _WIN32 - return sys&Windows; -#else - return sys&Plan9; -#endif -} - -int -pathchar(void) -{ - return '/'; -} - -int -Lconv(Fmt *fp) -{ - return linklinefmt(ctxt, fp); -} - -void -dodef(char *p) -{ - if(nDlist%8 == 0) - Dlist = allocn(Dlist, nDlist*sizeof(char *), - 8*sizeof(char *)); - Dlist[nDlist++] = p; -} - -LinkArch* thelinkarch = &linkppc64; - -void -usage(void) -{ - print("usage: %ca [options] file.c...\n", thechar); - flagprint(1); - errorexit(); -} - -void -main(int argc, char *argv[]) -{ - char *p; - - thechar = '9'; - thestring = "ppc64"; - - // Allow GOARCH=thestring or GOARCH=thestringsuffix, - // but not other values. - p = getgoarch(); - if(strncmp(p, thestring, strlen(thestring)) != 0) - sysfatal("cannot use %cc with GOARCH=%s", thechar, p); - if(strcmp(p, "ppc64le") == 0) - thelinkarch = &linkppc64le; - - ctxt = linknew(thelinkarch); - ctxt->diag = yyerror; - ctxt->bso = &bstdout; - ctxt->enforce_data_order = 1; - Binit(&bstdout, 1, OWRITE); - listinit9(); - fmtinstall('L', Lconv); - - ensuresymb(NSYMB); - memset(debug, 0, sizeof(debug)); - cinit(); - outfile = 0; - setinclude("."); - - flagfn1("D", "name[=value]: add #define", dodef); - flagfn1("I", "dir: add dir to include path", setinclude); - flagcount("S", "print assembly and machine code", &debug['S']); - flagcount("m", "debug preprocessor macros", &debug['m']); - flagstr("o", "file: set output file", &outfile); - flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - - flagparse(&argc, &argv, usage); - ctxt->debugasm = debug['S']; - - if(argc < 1) - usage(); - if(argc > 1){ - print("can't assemble multiple files\n"); - errorexit(); - } - - if(assemble(argv[0])) - errorexit(); - Bflush(&bstdout); - if(nerrors > 0) - errorexit(); - exits(0); -} - -int -assemble(char *file) -{ - char *ofile, *p; - int i, of; - - ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar) - strcpy(ofile, file); - p = utfrrune(ofile, pathchar()); - if(p) { - include[0] = ofile; - *p++ = 0; - } else - p = ofile; - if(outfile == 0) { - outfile = p; - if(outfile){ - p = utfrrune(outfile, '.'); - if(p) - if(p[1] == 's' && p[2] == 0) - p[0] = 0; - p = utfrune(outfile, 0); - p[0] = '.'; - p[1] = thechar; - p[2] = 0; - } else - outfile = "/dev/null"; - } - - of = create(outfile, OWRITE, 0664); - if(of < 0) { - yyerror("%ca: cannot create %s", thechar, outfile); - errorexit(); - } - Binit(&obuf, of, OWRITE); - Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion()); - Bprint(&obuf, "!\n"); - - for(pass = 1; pass <= 2; pass++) { - nosched = 0; - pinit(file); - for(i=0; itype = itab[i].type; - s->value = itab[i].value; - } -} - -void -syminit(Sym *s) -{ - - s->type = LNAME; - s->value = 0; -} - -void -cclean(void) -{ - - outcode(AEND, &nullgen, 0, &nullgen); -} - -void -outcode(int a, Addr *g1, int reg, Addr *g2) -{ - Prog *p; - Plist *pl; - - if(pass == 1) - goto out; - - if(g1->scale != 0) { - if(reg != 0 || g2->scale != 0) - yyerror("bad addressing modes"); - reg = g1->scale; - } else - if(g2->scale != 0) { - if(reg != 0) - yyerror("bad addressing modes"); - reg = g2->scale; - } - - p = emallocz(sizeof(Prog)); - p->as = a; - p->lineno = stmtline; - if(nosched) - p->mark |= NOSCHED; - p->from = *g1; - p->reg = reg; - p->to = *g2; - p->pc = pc; - - if(lastpc == nil) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastpc->link = p; - lastpc = p; -out: - if(a != AGLOBL && a != ADATA) - pc++; -} - -void -outgcode(int a, Addr *g1, int reg, Addr *g2, Addr *g3) -{ - Prog *p; - Plist *pl; - - if(pass == 1) - goto out; - - p = emallocz(sizeof(Prog)); - p->as = a; - p->lineno = stmtline; - if(nosched) - p->mark |= NOSCHED; - p->from = *g1; - p->reg = reg; - p->from3 = *g2; - p->to = *g3; - p->pc = pc; - - if(lastpc == nil) { - pl = linknewplist(ctxt); - pl->firstpc = p; - } else - lastpc->link = p; - lastpc = p; -out: - if(a != AGLOBL && a != ADATA) - pc++; -} - -#include "../cc/lexbody" -#include "../cc/macbody" diff --git a/src/cmd/9a/lex.go b/src/cmd/9a/lex.go new file mode 100644 index 0000000000..d480e4540e --- /dev/null +++ b/src/cmd/9a/lex.go @@ -0,0 +1,555 @@ +// cmd/9a/lex.c from Vita Nuova. +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +//go:generate go tool yacc a.y + +package main + +import ( + "cmd/internal/asm" + "cmd/internal/obj" + "cmd/internal/obj/ppc64" +) + +var ( + yyerror = asm.Yyerror + nullgen obj.Addr + stmtline int32 +) + +func main() { + cinit() + + asm.LSCONST = LSCONST + asm.LCONST = LCONST + asm.LFCONST = LFCONST + asm.LNAME = LNAME + asm.LVAR = LVAR + asm.LLAB = LLAB + + asm.Lexinit = lexinit + asm.Cclean = cclean + asm.Yyparse = yyparse + + asm.Thechar = '9' + asm.Thestring = "ppc64" + asm.Thelinkarch = &ppc64.Linkppc64 + asm.Arches = map[string]*obj.LinkArch{ + "ppc64le": &ppc64.Linkppc64le, + } + + asm.Main() +} + +type yy struct{} + +func (yy) Lex(v *yySymType) int { + var av asm.Yylval + tok := asm.Yylex(&av) + v.sym = av.Sym + v.lval = av.Lval + v.sval = av.Sval + v.dval = av.Dval + return tok +} + +func (yy) Error(msg string) { + asm.Yyerror("%s", msg) +} + +func yyparse() { + nosched = 0 + yyParse(yy{}) +} + +var lexinit = []asm.Lextab{ + {"SP", LSP, obj.NAME_AUTO}, + {"SB", LSB, obj.NAME_EXTERN}, + {"FP", LFP, obj.NAME_PARAM}, + {"PC", LPC, obj.TYPE_BRANCH}, + {"LR", LLR, ppc64.REG_LR}, + {"CTR", LCTR, ppc64.REG_CTR}, + {"XER", LSPREG, ppc64.REG_XER}, + {"MSR", LMSR, ppc64.REG_MSR}, + {"FPSCR", LFPSCR, ppc64.REG_FPSCR}, + {"SPR", LSPR, ppc64.REG_SPR0}, + {"DCR", LSPR, ppc64.REG_DCR0}, + {"CR", LCR, ppc64.REG_CR}, + {"CR0", LCREG, ppc64.REG_C0}, + {"CR1", LCREG, ppc64.REG_C1}, + {"CR2", LCREG, ppc64.REG_C2}, + {"CR3", LCREG, ppc64.REG_C3}, + {"CR4", LCREG, ppc64.REG_C4}, + {"CR5", LCREG, ppc64.REG_C5}, + {"CR6", LCREG, ppc64.REG_C6}, + {"CR7", LCREG, ppc64.REG_C7}, + {"R", LR, 0}, + {"R0", LREG, ppc64.REG_R0}, + {"R1", LREG, ppc64.REG_R1}, + {"R2", LREG, ppc64.REG_R2}, + {"R3", LREG, ppc64.REG_R3}, + {"R4", LREG, ppc64.REG_R4}, + {"R5", LREG, ppc64.REG_R5}, + {"R6", LREG, ppc64.REG_R6}, + {"R7", LREG, ppc64.REG_R7}, + {"R8", LREG, ppc64.REG_R8}, + {"R9", LREG, ppc64.REG_R9}, + {"R10", LREG, ppc64.REG_R10}, + {"R11", LREG, ppc64.REG_R11}, + {"R12", LREG, ppc64.REG_R12}, + {"R13", LREG, ppc64.REG_R13}, + {"R14", LREG, ppc64.REG_R14}, + {"R15", LREG, ppc64.REG_R15}, + {"R16", LREG, ppc64.REG_R16}, + {"R17", LREG, ppc64.REG_R17}, + {"R18", LREG, ppc64.REG_R18}, + {"R19", LREG, ppc64.REG_R19}, + {"R20", LREG, ppc64.REG_R20}, + {"R21", LREG, ppc64.REG_R21}, + {"R22", LREG, ppc64.REG_R22}, + {"R23", LREG, ppc64.REG_R23}, + {"R24", LREG, ppc64.REG_R24}, + {"R25", LREG, ppc64.REG_R25}, + {"R26", LREG, ppc64.REG_R26}, + {"R27", LREG, ppc64.REG_R27}, + {"R28", LREG, ppc64.REG_R28}, + {"R29", LREG, ppc64.REG_R29}, + {"g", LREG, ppc64.REG_R30}, // avoid unintentionally clobbering g using R30 + {"R31", LREG, ppc64.REG_R31}, + {"F", LF, 0}, + {"F0", LFREG, ppc64.REG_F0}, + {"F1", LFREG, ppc64.REG_F1}, + {"F2", LFREG, ppc64.REG_F2}, + {"F3", LFREG, ppc64.REG_F3}, + {"F4", LFREG, ppc64.REG_F4}, + {"F5", LFREG, ppc64.REG_F5}, + {"F6", LFREG, ppc64.REG_F6}, + {"F7", LFREG, ppc64.REG_F7}, + {"F8", LFREG, ppc64.REG_F8}, + {"F9", LFREG, ppc64.REG_F9}, + {"F10", LFREG, ppc64.REG_F10}, + {"F11", LFREG, ppc64.REG_F11}, + {"F12", LFREG, ppc64.REG_F12}, + {"F13", LFREG, ppc64.REG_F13}, + {"F14", LFREG, ppc64.REG_F14}, + {"F15", LFREG, ppc64.REG_F15}, + {"F16", LFREG, ppc64.REG_F16}, + {"F17", LFREG, ppc64.REG_F17}, + {"F18", LFREG, ppc64.REG_F18}, + {"F19", LFREG, ppc64.REG_F19}, + {"F20", LFREG, ppc64.REG_F20}, + {"F21", LFREG, ppc64.REG_F21}, + {"F22", LFREG, ppc64.REG_F22}, + {"F23", LFREG, ppc64.REG_F23}, + {"F24", LFREG, ppc64.REG_F24}, + {"F25", LFREG, ppc64.REG_F25}, + {"F26", LFREG, ppc64.REG_F26}, + {"F27", LFREG, ppc64.REG_F27}, + {"F28", LFREG, ppc64.REG_F28}, + {"F29", LFREG, ppc64.REG_F29}, + {"F30", LFREG, ppc64.REG_F30}, + {"F31", LFREG, ppc64.REG_F31}, + {"CREQV", LCROP, ppc64.ACREQV}, + {"CRXOR", LCROP, ppc64.ACRXOR}, + {"CRAND", LCROP, ppc64.ACRAND}, + {"CROR", LCROP, ppc64.ACROR}, + {"CRANDN", LCROP, ppc64.ACRANDN}, + {"CRORN", LCROP, ppc64.ACRORN}, + {"CRNAND", LCROP, ppc64.ACRNAND}, + {"CRNOR", LCROP, ppc64.ACRNOR}, + {"ADD", LADDW, ppc64.AADD}, + {"ADDV", LADDW, ppc64.AADDV}, + {"ADDCC", LADDW, ppc64.AADDCC}, + {"ADDVCC", LADDW, ppc64.AADDVCC}, + {"ADDC", LADDW, ppc64.AADDC}, + {"ADDCV", LADDW, ppc64.AADDCV}, + {"ADDCCC", LADDW, ppc64.AADDCCC}, + {"ADDCVCC", LADDW, ppc64.AADDCVCC}, + {"ADDE", LLOGW, ppc64.AADDE}, + {"ADDEV", LLOGW, ppc64.AADDEV}, + {"ADDECC", LLOGW, ppc64.AADDECC}, + {"ADDEVCC", LLOGW, ppc64.AADDEVCC}, + {"ADDME", LABS, ppc64.AADDME}, + {"ADDMEV", LABS, ppc64.AADDMEV}, + {"ADDMECC", LABS, ppc64.AADDMECC}, + {"ADDMEVCC", LABS, ppc64.AADDMEVCC}, + {"ADDZE", LABS, ppc64.AADDZE}, + {"ADDZEV", LABS, ppc64.AADDZEV}, + {"ADDZECC", LABS, ppc64.AADDZECC}, + {"ADDZEVCC", LABS, ppc64.AADDZEVCC}, + {"SUB", LADDW, ppc64.ASUB}, + {"SUBV", LADDW, ppc64.ASUBV}, + {"SUBCC", LADDW, ppc64.ASUBCC}, + {"SUBVCC", LADDW, ppc64.ASUBVCC}, + {"SUBE", LLOGW, ppc64.ASUBE}, + {"SUBECC", LLOGW, ppc64.ASUBECC}, + {"SUBEV", LLOGW, ppc64.ASUBEV}, + {"SUBEVCC", LLOGW, ppc64.ASUBEVCC}, + {"SUBC", LADDW, ppc64.ASUBC}, + {"SUBCCC", LADDW, ppc64.ASUBCCC}, + {"SUBCV", LADDW, ppc64.ASUBCV}, + {"SUBCVCC", LADDW, ppc64.ASUBCVCC}, + {"SUBME", LABS, ppc64.ASUBME}, + {"SUBMEV", LABS, ppc64.ASUBMEV}, + {"SUBMECC", LABS, ppc64.ASUBMECC}, + {"SUBMEVCC", LABS, ppc64.ASUBMEVCC}, + {"SUBZE", LABS, ppc64.ASUBZE}, + {"SUBZEV", LABS, ppc64.ASUBZEV}, + {"SUBZECC", LABS, ppc64.ASUBZECC}, + {"SUBZEVCC", LABS, ppc64.ASUBZEVCC}, + {"AND", LADDW, ppc64.AAND}, + {"ANDCC", LADDW, ppc64.AANDCC}, /* includes andil & andiu */ + {"ANDN", LLOGW, ppc64.AANDN}, + {"ANDNCC", LLOGW, ppc64.AANDNCC}, + {"EQV", LLOGW, ppc64.AEQV}, + {"EQVCC", LLOGW, ppc64.AEQVCC}, + {"NAND", LLOGW, ppc64.ANAND}, + {"NANDCC", LLOGW, ppc64.ANANDCC}, + {"NOR", LLOGW, ppc64.ANOR}, + {"NORCC", LLOGW, ppc64.ANORCC}, + {"OR", LADDW, ppc64.AOR}, /* includes oril & oriu */ + {"ORCC", LADDW, ppc64.AORCC}, + {"ORN", LLOGW, ppc64.AORN}, + {"ORNCC", LLOGW, ppc64.AORNCC}, + {"XOR", LADDW, ppc64.AXOR}, /* includes xoril & xoriu */ + {"XORCC", LLOGW, ppc64.AXORCC}, + {"EXTSB", LABS, ppc64.AEXTSB}, + {"EXTSBCC", LABS, ppc64.AEXTSBCC}, + {"EXTSH", LABS, ppc64.AEXTSH}, + {"EXTSHCC", LABS, ppc64.AEXTSHCC}, + {"CNTLZW", LABS, ppc64.ACNTLZW}, + {"CNTLZWCC", LABS, ppc64.ACNTLZWCC}, + {"RLWMI", LRLWM, ppc64.ARLWMI}, + {"RLWMICC", LRLWM, ppc64.ARLWMICC}, + {"RLWNM", LRLWM, ppc64.ARLWNM}, + {"RLWNMCC", LRLWM, ppc64.ARLWNMCC}, + {"SLW", LSHW, ppc64.ASLW}, + {"SLWCC", LSHW, ppc64.ASLWCC}, + {"SRW", LSHW, ppc64.ASRW}, + {"SRWCC", LSHW, ppc64.ASRWCC}, + {"SRAW", LSHW, ppc64.ASRAW}, + {"SRAWCC", LSHW, ppc64.ASRAWCC}, + {"BR", LBRA, ppc64.ABR}, + {"BC", LBRA, ppc64.ABC}, + {"BCL", LBRA, ppc64.ABC}, + {"BL", LBRA, ppc64.ABL}, + {"BEQ", LBRA, ppc64.ABEQ}, + {"BNE", LBRA, ppc64.ABNE}, + {"BGT", LBRA, ppc64.ABGT}, + {"BGE", LBRA, ppc64.ABGE}, + {"BLT", LBRA, ppc64.ABLT}, + {"BLE", LBRA, ppc64.ABLE}, + {"BVC", LBRA, ppc64.ABVC}, + {"BVS", LBRA, ppc64.ABVS}, + {"CMP", LCMP, ppc64.ACMP}, + {"CMPU", LCMP, ppc64.ACMPU}, + {"CMPW", LCMP, ppc64.ACMPW}, + {"CMPWU", LCMP, ppc64.ACMPWU}, + {"DIVW", LLOGW, ppc64.ADIVW}, + {"DIVWV", LLOGW, ppc64.ADIVWV}, + {"DIVWCC", LLOGW, ppc64.ADIVWCC}, + {"DIVWVCC", LLOGW, ppc64.ADIVWVCC}, + {"DIVWU", LLOGW, ppc64.ADIVWU}, + {"DIVWUV", LLOGW, ppc64.ADIVWUV}, + {"DIVWUCC", LLOGW, ppc64.ADIVWUCC}, + {"DIVWUVCC", LLOGW, ppc64.ADIVWUVCC}, + {"FABS", LFCONV, ppc64.AFABS}, + {"FABSCC", LFCONV, ppc64.AFABSCC}, + {"FNEG", LFCONV, ppc64.AFNEG}, + {"FNEGCC", LFCONV, ppc64.AFNEGCC}, + {"FNABS", LFCONV, ppc64.AFNABS}, + {"FNABSCC", LFCONV, ppc64.AFNABSCC}, + {"FADD", LFADD, ppc64.AFADD}, + {"FADDCC", LFADD, ppc64.AFADDCC}, + {"FSUB", LFADD, ppc64.AFSUB}, + {"FSUBCC", LFADD, ppc64.AFSUBCC}, + {"FMUL", LFADD, ppc64.AFMUL}, + {"FMULCC", LFADD, ppc64.AFMULCC}, + {"FDIV", LFADD, ppc64.AFDIV}, + {"FDIVCC", LFADD, ppc64.AFDIVCC}, + {"FRSP", LFCONV, ppc64.AFRSP}, + {"FRSPCC", LFCONV, ppc64.AFRSPCC}, + {"FCTIW", LFCONV, ppc64.AFCTIW}, + {"FCTIWCC", LFCONV, ppc64.AFCTIWCC}, + {"FCTIWZ", LFCONV, ppc64.AFCTIWZ}, + {"FCTIWZCC", LFCONV, ppc64.AFCTIWZCC}, + {"FMADD", LFMA, ppc64.AFMADD}, + {"FMADDCC", LFMA, ppc64.AFMADDCC}, + {"FMSUB", LFMA, ppc64.AFMSUB}, + {"FMSUBCC", LFMA, ppc64.AFMSUBCC}, + {"FNMADD", LFMA, ppc64.AFNMADD}, + {"FNMADDCC", LFMA, ppc64.AFNMADDCC}, + {"FNMSUB", LFMA, ppc64.AFNMSUB}, + {"FNMSUBCC", LFMA, ppc64.AFNMSUBCC}, + {"FMADDS", LFMA, ppc64.AFMADDS}, + {"FMADDSCC", LFMA, ppc64.AFMADDSCC}, + {"FMSUBS", LFMA, ppc64.AFMSUBS}, + {"FMSUBSCC", LFMA, ppc64.AFMSUBSCC}, + {"FNMADDS", LFMA, ppc64.AFNMADDS}, + {"FNMADDSCC", LFMA, ppc64.AFNMADDSCC}, + {"FNMSUBS", LFMA, ppc64.AFNMSUBS}, + {"FNMSUBSCC", LFMA, ppc64.AFNMSUBSCC}, + {"FCMPU", LFCMP, ppc64.AFCMPU}, + {"FCMPO", LFCMP, ppc64.AFCMPO}, + {"MTFSB0", LMTFSB, ppc64.AMTFSB0}, + {"MTFSB1", LMTFSB, ppc64.AMTFSB1}, + {"FMOVD", LFMOV, ppc64.AFMOVD}, + {"FMOVS", LFMOV, ppc64.AFMOVS}, + {"FMOVDCC", LFCONV, ppc64.AFMOVDCC}, /* fmr. */ + {"GLOBL", LGLOBL, obj.AGLOBL}, + {"MOVB", LMOVB, ppc64.AMOVB}, + {"MOVBZ", LMOVB, ppc64.AMOVBZ}, + {"MOVBU", LMOVB, ppc64.AMOVBU}, + {"MOVBZU", LMOVB, ppc64.AMOVBZU}, + {"MOVH", LMOVB, ppc64.AMOVH}, + {"MOVHZ", LMOVB, ppc64.AMOVHZ}, + {"MOVHU", LMOVB, ppc64.AMOVHU}, + {"MOVHZU", LMOVB, ppc64.AMOVHZU}, + {"MOVHBR", LXMV, ppc64.AMOVHBR}, + {"MOVWBR", LXMV, ppc64.AMOVWBR}, + {"MOVW", LMOVW, ppc64.AMOVW}, + {"MOVWU", LMOVW, ppc64.AMOVWU}, + {"MOVMW", LMOVMW, ppc64.AMOVMW}, + {"MOVFL", LMOVW, ppc64.AMOVFL}, + {"MULLW", LADDW, ppc64.AMULLW}, /* includes multiply immediate 10-139 */ + {"MULLWV", LLOGW, ppc64.AMULLWV}, + {"MULLWCC", LLOGW, ppc64.AMULLWCC}, + {"MULLWVCC", LLOGW, ppc64.AMULLWVCC}, + {"MULHW", LLOGW, ppc64.AMULHW}, + {"MULHWCC", LLOGW, ppc64.AMULHWCC}, + {"MULHWU", LLOGW, ppc64.AMULHWU}, + {"MULHWUCC", LLOGW, ppc64.AMULHWUCC}, + {"NEG", LABS, ppc64.ANEG}, + {"NEGV", LABS, ppc64.ANEGV}, + {"NEGCC", LABS, ppc64.ANEGCC}, + {"NEGVCC", LABS, ppc64.ANEGVCC}, + {"NOP", LNOP, obj.ANOP}, /* ori 0,0,0 */ + {"SYSCALL", LNOP, ppc64.ASYSCALL}, + {"UNDEF", LNOP, obj.AUNDEF}, + {"RET", LRETRN, obj.ARET}, + {"RETURN", LRETRN, obj.ARET}, + {"RFI", LRETRN, ppc64.ARFI}, + {"RFCI", LRETRN, ppc64.ARFCI}, + {"DATA", LDATA, obj.ADATA}, + {"END", LEND, obj.AEND}, + {"TEXT", LTEXT, obj.ATEXT}, + + /* 64-bit instructions */ + {"CNTLZD", LABS, ppc64.ACNTLZD}, + {"CNTLZDCC", LABS, ppc64.ACNTLZDCC}, + {"DIVD", LLOGW, ppc64.ADIVD}, + {"DIVDCC", LLOGW, ppc64.ADIVDCC}, + {"DIVDVCC", LLOGW, ppc64.ADIVDVCC}, + {"DIVDV", LLOGW, ppc64.ADIVDV}, + {"DIVDU", LLOGW, ppc64.ADIVDU}, + {"DIVDUCC", LLOGW, ppc64.ADIVDUCC}, + {"DIVDUVCC", LLOGW, ppc64.ADIVDUVCC}, + {"DIVDUV", LLOGW, ppc64.ADIVDUV}, + {"EXTSW", LABS, ppc64.AEXTSW}, + {"EXTSWCC", LABS, ppc64.AEXTSWCC}, + {"FCTID", LFCONV, ppc64.AFCTID}, + {"FCTIDCC", LFCONV, ppc64.AFCTIDCC}, + {"FCTIDZ", LFCONV, ppc64.AFCTIDZ}, + {"FCTIDZCC", LFCONV, ppc64.AFCTIDZCC}, + {"FCFID", LFCONV, ppc64.AFCFID}, + {"FCFIDCC", LFCONV, ppc64.AFCFIDCC}, + {"LDAR", LXLD, ppc64.ALDAR}, + {"MOVD", LMOVW, ppc64.AMOVD}, + {"MOVDU", LMOVW, ppc64.AMOVDU}, + {"MOVWZ", LMOVW, ppc64.AMOVWZ}, + {"MOVWZU", LMOVW, ppc64.AMOVWZU}, + {"MULHD", LLOGW, ppc64.AMULHD}, + {"MULHDCC", LLOGW, ppc64.AMULHDCC}, + {"MULHDU", LLOGW, ppc64.AMULHDU}, + {"MULHDUCC", LLOGW, ppc64.AMULHDUCC}, + {"MULLD", LADDW, ppc64.AMULLD}, /* includes multiply immediate? */ + {"MULLDCC", LLOGW, ppc64.AMULLDCC}, + {"MULLDVCC", LLOGW, ppc64.AMULLDVCC}, + {"MULLDV", LLOGW, ppc64.AMULLDV}, + {"RFID", LRETRN, ppc64.ARFID}, + {"HRFID", LRETRN, ppc64.AHRFID}, + {"RLDMI", LRLWM, ppc64.ARLDMI}, + {"RLDMICC", LRLWM, ppc64.ARLDMICC}, + {"RLDC", LRLWM, ppc64.ARLDC}, + {"RLDCCC", LRLWM, ppc64.ARLDCCC}, + {"RLDCR", LRLWM, ppc64.ARLDCR}, + {"RLDCRCC", LRLWM, ppc64.ARLDCRCC}, + {"RLDCL", LRLWM, ppc64.ARLDCL}, + {"RLDCLCC", LRLWM, ppc64.ARLDCLCC}, + {"SLBIA", LNOP, ppc64.ASLBIA}, + {"SLBIE", LNOP, ppc64.ASLBIE}, + {"SLBMFEE", LABS, ppc64.ASLBMFEE}, + {"SLBMFEV", LABS, ppc64.ASLBMFEV}, + {"SLBMTE", LABS, ppc64.ASLBMTE}, + {"SLD", LSHW, ppc64.ASLD}, + {"SLDCC", LSHW, ppc64.ASLDCC}, + {"SRD", LSHW, ppc64.ASRD}, + {"SRAD", LSHW, ppc64.ASRAD}, + {"SRADCC", LSHW, ppc64.ASRADCC}, + {"SRDCC", LSHW, ppc64.ASRDCC}, + {"STDCCC", LXST, ppc64.ASTDCCC}, + {"TD", LADDW, ppc64.ATD}, + + /* pseudo instructions */ + {"REM", LLOGW, ppc64.AREM}, + {"REMCC", LLOGW, ppc64.AREMCC}, + {"REMV", LLOGW, ppc64.AREMV}, + {"REMVCC", LLOGW, ppc64.AREMVCC}, + {"REMU", LLOGW, ppc64.AREMU}, + {"REMUCC", LLOGW, ppc64.AREMUCC}, + {"REMUV", LLOGW, ppc64.AREMUV}, + {"REMUVCC", LLOGW, ppc64.AREMUVCC}, + {"REMD", LLOGW, ppc64.AREMD}, + {"REMDCC", LLOGW, ppc64.AREMDCC}, + {"REMDV", LLOGW, ppc64.AREMDV}, + {"REMDVCC", LLOGW, ppc64.AREMDVCC}, + {"REMDU", LLOGW, ppc64.AREMDU}, + {"REMDUCC", LLOGW, ppc64.AREMDUCC}, + {"REMDUV", LLOGW, ppc64.AREMDUV}, + {"REMDUVCC", LLOGW, ppc64.AREMDUVCC}, + + /* special instructions */ + {"DCBF", LXOP, ppc64.ADCBF}, + {"DCBI", LXOP, ppc64.ADCBI}, + {"DCBST", LXOP, ppc64.ADCBST}, + {"DCBT", LXOP, ppc64.ADCBT}, + {"DCBTST", LXOP, ppc64.ADCBTST}, + {"DCBZ", LXOP, ppc64.ADCBZ}, + {"ICBI", LXOP, ppc64.AICBI}, + {"ECIWX", LXLD, ppc64.AECIWX}, + {"ECOWX", LXST, ppc64.AECOWX}, + {"LWAR", LXLD, ppc64.ALWAR}, + {"STWCCC", LXST, ppc64.ASTWCCC}, + {"EIEIO", LRETRN, ppc64.AEIEIO}, + {"TLBIE", LNOP, ppc64.ATLBIE}, + {"TLBIEL", LNOP, ppc64.ATLBIEL}, + {"LSW", LXLD, ppc64.ALSW}, + {"STSW", LXST, ppc64.ASTSW}, + {"ISYNC", LRETRN, ppc64.AISYNC}, + {"SYNC", LRETRN, ppc64.ASYNC}, + {"TLBSYNC", LRETRN, ppc64.ATLBSYNC}, + {"PTESYNC", LRETRN, ppc64.APTESYNC}, + + /* "TW", LADDW, ATW,*/ + {"WORD", LWORD, ppc64.AWORD}, + {"DWORD", LWORD, ppc64.ADWORD}, + {"SCHED", LSCHED, 0}, + {"NOSCHED", LSCHED, 0x80}, + {"PCDATA", LPCDAT, obj.APCDATA}, + {"FUNCDATA", LFUNCDAT, obj.AFUNCDATA}, +} + +func cinit() { +} + +func cclean() { + outcode(obj.AEND, &nullgen, 0, &nullgen) +} + +var lastpc *obj.Prog +var nosched int + +func outcode(a int, g1 *obj.Addr, reg int, g2 *obj.Addr) { + var p *obj.Prog + var pl *obj.Plist + + if asm.Pass == 1 { + goto out + } + + if g1.Scale != 0 { + if reg != 0 || g2.Scale != 0 { + yyerror("bad addressing modes") + } + reg = int(g1.Scale) + } else if g2.Scale != 0 { + if reg != 0 { + yyerror("bad addressing modes") + } + reg = int(g2.Scale) + } + + p = asm.Ctxt.NewProg() + p.As = int16(a) + p.Lineno = stmtline + if nosched != 0 { + p.Mark |= ppc64.NOSCHED + } + p.From = *g1 + p.Reg = int16(reg) + p.To = *g2 + p.Pc = int64(asm.PC) + + if lastpc == nil { + pl = obj.Linknewplist(asm.Ctxt) + pl.Firstpc = p + } else { + lastpc.Link = p + } + lastpc = p + +out: + if a != obj.AGLOBL && a != obj.ADATA { + asm.PC++ + } +} + +func outgcode(a int, g1 *obj.Addr, reg int, g2, g3 *obj.Addr) { + var p *obj.Prog + var pl *obj.Plist + + if asm.Pass == 1 { + goto out + } + + p = asm.Ctxt.NewProg() + p.As = int16(a) + p.Lineno = stmtline + if nosched != 0 { + p.Mark |= ppc64.NOSCHED + } + p.From = *g1 + p.Reg = int16(reg) + p.From3 = *g2 + p.To = *g3 + p.Pc = int64(asm.PC) + + if lastpc == nil { + pl = obj.Linknewplist(asm.Ctxt) + pl.Firstpc = p + } else { + lastpc.Link = p + } + lastpc = p + +out: + if a != obj.AGLOBL && a != obj.ADATA { + asm.PC++ + } +} diff --git a/src/cmd/9a/y.go b/src/cmd/9a/y.go new file mode 100644 index 0000000000..2e42378059 --- /dev/null +++ b/src/cmd/9a/y.go @@ -0,0 +1,1953 @@ +//line a.y:31 +package main + +import __yyfmt__ "fmt" + +//line a.y:31 +import ( + "cmd/internal/asm" + "cmd/internal/obj" + . "cmd/internal/obj/ppc64" +) + +//line a.y:40 +type yySymType struct { + yys int + sym *asm.Sym + lval int64 + dval float64 + sval string + addr obj.Addr +} + +const LMOVW = 57346 +const LMOVB = 57347 +const LABS = 57348 +const LLOGW = 57349 +const LSHW = 57350 +const LADDW = 57351 +const LCMP = 57352 +const LCROP = 57353 +const LBRA = 57354 +const LFMOV = 57355 +const LFCONV = 57356 +const LFCMP = 57357 +const LFADD = 57358 +const LFMA = 57359 +const LTRAP = 57360 +const LXORW = 57361 +const LNOP = 57362 +const LEND = 57363 +const LRETT = 57364 +const LWORD = 57365 +const LTEXT = 57366 +const LDATA = 57367 +const LGLOBL = 57368 +const LRETRN = 57369 +const LCONST = 57370 +const LSP = 57371 +const LSB = 57372 +const LFP = 57373 +const LPC = 57374 +const LCREG = 57375 +const LFLUSH = 57376 +const LREG = 57377 +const LFREG = 57378 +const LR = 57379 +const LCR = 57380 +const LF = 57381 +const LFPSCR = 57382 +const LLR = 57383 +const LCTR = 57384 +const LSPR = 57385 +const LSPREG = 57386 +const LSEG = 57387 +const LMSR = 57388 +const LPCDAT = 57389 +const LFUNCDAT = 57390 +const LSCHED = 57391 +const LXLD = 57392 +const LXST = 57393 +const LXOP = 57394 +const LXMV = 57395 +const LRLWM = 57396 +const LMOVMW = 57397 +const LMOVEM = 57398 +const LMOVFL = 57399 +const LMTFSB = 57400 +const LMA = 57401 +const LFCONST = 57402 +const LSCONST = 57403 +const LNAME = 57404 +const LLAB = 57405 +const LVAR = 57406 + +var yyToknames = []string{ + "'|'", + "'^'", + "'&'", + "'<'", + "'>'", + "'+'", + "'-'", + "'*'", + "'/'", + "'%'", + "LMOVW", + "LMOVB", + "LABS", + "LLOGW", + "LSHW", + "LADDW", + "LCMP", + "LCROP", + "LBRA", + "LFMOV", + "LFCONV", + "LFCMP", + "LFADD", + "LFMA", + "LTRAP", + "LXORW", + "LNOP", + "LEND", + "LRETT", + "LWORD", + "LTEXT", + "LDATA", + "LGLOBL", + "LRETRN", + "LCONST", + "LSP", + "LSB", + "LFP", + "LPC", + "LCREG", + "LFLUSH", + "LREG", + "LFREG", + "LR", + "LCR", + "LF", + "LFPSCR", + "LLR", + "LCTR", + "LSPR", + "LSPREG", + "LSEG", + "LMSR", + "LPCDAT", + "LFUNCDAT", + "LSCHED", + "LXLD", + "LXST", + "LXOP", + "LXMV", + "LRLWM", + "LMOVMW", + "LMOVEM", + "LMOVFL", + "LMTFSB", + "LMA", + "LFCONST", + "LSCONST", + "LNAME", + "LLAB", + "LVAR", +} +var yyStatenames = []string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyMaxDepth = 200 + +//line yacctab:1 +var yyExca = []int{ + -1, 1, + 1, -1, + -2, 2, +} + +const yyNprod = 187 +const yyPrivate = 57344 + +var yyTokenNames []string +var yyStates []string + +const yyLast = 900 + +var yyAct = []int{ + + 48, 394, 54, 90, 427, 273, 440, 58, 52, 102, + 80, 79, 85, 172, 94, 95, 97, 98, 100, 101, + 51, 57, 113, 3, 80, 79, 56, 121, 123, 125, + 435, 128, 130, 91, 133, 53, 278, 138, 74, 77, + 75, 66, 164, 117, 118, 119, 120, 454, 453, 93, + 96, 65, 99, 77, 134, 417, 127, 114, 94, 74, + 416, 75, 74, 122, 75, 406, 83, 84, 105, 136, + 137, 139, 140, 76, 94, 78, 80, 79, 405, 384, + 62, 127, 94, 81, 383, 205, 148, 150, 149, 78, + 50, 380, 116, 369, 104, 94, 127, 81, 368, 61, + 61, 61, 87, 89, 367, 77, 366, 277, 103, 110, + 364, 363, 316, 63, 407, 198, 64, 61, 284, 55, + 126, 205, 129, 131, 162, 206, 232, 143, 143, 143, + 169, 74, 63, 75, 171, 64, 225, 204, 205, 76, + 109, 78, 170, 165, 448, 47, 62, 447, 92, 81, + 446, 445, 248, 256, 257, 168, 226, 264, 265, 254, + 269, 270, 271, 260, 135, 444, 443, 94, 176, 177, + 178, 235, 399, 253, 398, 397, 262, 199, 255, 393, + 288, 291, 292, 189, 392, 267, 391, 251, 390, 389, + 261, 303, 305, 307, 309, 311, 312, 202, 388, 387, + 166, 386, 385, 293, 294, 295, 296, 314, 379, 317, + 115, 49, 86, 88, 378, 332, 334, 335, 336, 377, + 338, 106, 342, 376, 375, 374, 302, 373, 372, 124, + 362, 328, 329, 330, 331, 361, 233, 231, 230, 229, + 61, 116, 250, 61, 132, 259, 222, 221, 141, 220, + 333, 219, 146, 218, 280, 339, 341, 217, 281, 282, + 283, 216, 215, 286, 287, 344, 214, 213, 61, 348, + 290, 252, 318, 321, 61, 263, 298, 300, 266, 268, + 351, 352, 353, 354, 355, 212, 315, 358, 359, 360, + 370, 211, 202, 324, 59, 210, 80, 79, 209, 371, + 207, 203, 197, 196, 195, 194, 193, 61, 192, 200, + 191, 340, 190, 343, 188, 185, 184, 80, 79, 61, + 347, 183, 349, 350, 208, 77, 182, 181, 381, 180, + 67, 382, 74, 63, 75, 68, 64, 65, 83, 84, + 70, 69, 179, 82, 223, 224, 77, 161, 227, 228, + 160, 159, 249, 158, 157, 258, 156, 163, 155, 76, + 154, 78, 153, 152, 151, 46, 62, 45, 66, 81, + 44, 404, 187, 408, 409, 410, 411, 412, 413, 414, + 289, 299, 78, 402, 42, 43, 297, 104, 63, 415, + 81, 64, 67, 431, 65, 63, 430, 112, 64, 400, + 401, 403, 438, 439, 319, 322, 421, 422, 246, 245, + 244, 242, 243, 237, 238, 239, 240, 241, 67, 337, + 441, 461, 163, 112, 449, 434, 426, 429, 442, 234, + 450, 345, 186, 433, 436, 437, 357, 451, 74, 63, + 75, 74, 64, 75, 285, 456, 457, 356, 459, 460, + 67, 8, 418, 60, 67, 112, 74, 272, 75, 112, + 70, 69, 396, 82, 455, 275, 274, 276, 103, 174, + 175, 74, 202, 75, 275, 274, 276, 80, 452, 428, + 428, 247, 147, 2, 432, 301, 304, 306, 308, 310, + 395, 313, 142, 144, 145, 275, 274, 276, 325, 9, + 272, 74, 326, 75, 327, 1, 77, 423, 424, 425, + 71, 10, 11, 17, 15, 16, 14, 26, 19, 20, + 12, 22, 25, 23, 24, 21, 73, 33, 37, 168, + 34, 38, 40, 39, 41, 458, 72, 0, 186, 167, + 76, 176, 78, 80, 79, 0, 173, 104, 174, 175, + 81, 239, 240, 241, 35, 36, 6, 29, 30, 32, + 31, 27, 28, 80, 79, 13, 18, 0, 0, 4, + 0, 5, 77, 365, 7, 0, 0, 67, 0, 74, + 0, 75, 68, 0, 419, 83, 84, 70, 69, 0, + 82, 0, 77, 0, 80, 79, 0, 67, 0, 0, + 80, 79, 112, 0, 0, 0, 76, 0, 78, 80, + 79, 0, 0, 62, 0, 94, 81, 237, 238, 239, + 240, 241, 0, 77, 0, 0, 111, 0, 78, 77, + 0, 63, 108, 107, 64, 0, 81, 0, 77, 80, + 79, 0, 0, 0, 0, 74, 0, 75, 245, 244, + 242, 243, 237, 238, 239, 240, 241, 76, 0, 78, + 0, 0, 167, 76, 62, 78, 0, 81, 77, 0, + 104, 0, 76, 81, 78, 74, 0, 75, 0, 62, + 0, 0, 81, 246, 245, 244, 242, 243, 237, 238, + 239, 240, 241, 80, 79, 80, 79, 80, 79, 0, + 0, 0, 76, 0, 78, 0, 80, 79, 0, 104, + 80, 79, 81, 0, 0, 0, 0, 0, 0, 80, + 79, 0, 77, 0, 77, 0, 77, 0, 0, 74, + 0, 75, 80, 79, 0, 77, 0, 0, 0, 77, + 0, 0, 0, 80, 79, 0, 0, 0, 77, 0, + 0, 0, 80, 79, 0, 0, 299, 0, 78, 279, + 78, 77, 78, 104, 0, 104, 81, 104, 81, 94, + 81, 78, 77, 111, 0, 78, 104, 0, 346, 81, + 420, 77, 76, 81, 78, 0, 0, 0, 0, 104, + 0, 0, 81, 0, 0, 111, 0, 78, 0, 0, + 0, 0, 323, 0, 0, 81, 111, 0, 78, 0, + 0, 0, 0, 320, 0, 111, 81, 78, 0, 0, + 0, 0, 201, 0, 0, 81, 246, 245, 244, 242, + 243, 237, 238, 239, 240, 241, 244, 242, 243, 237, + 238, 239, 240, 241, 242, 243, 237, 238, 239, 240, + 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, +} +var yyPact = []int{ + + -1000, -1000, 497, -1000, 309, 294, 290, -1000, 288, 68, + 287, 600, 67, -67, -7, 396, -7, 396, 396, 308, + 554, 14, 342, 342, 342, 342, 396, -7, 630, 2, + 396, 17, 2, 86, -40, -67, -67, 163, 710, 710, + 710, 163, -1000, 308, 308, -1000, -1000, -1000, 286, 285, + 284, 282, 280, 278, 276, 275, 273, 272, 269, -1000, + -1000, 45, 684, -1000, 64, -1000, 591, -1000, 51, -1000, + 63, -1000, -1000, -1000, -1000, 55, 539, -1000, -1000, 308, + 308, 308, -1000, -1000, -1000, 264, 251, 249, 248, 243, + 238, 237, 362, 236, 308, 234, 232, 230, 228, 227, + 226, 225, 224, -1000, 308, -1000, -1000, 15, 743, 223, + 59, 539, 51, 222, 220, -1000, -1000, 217, 213, 207, + 189, 188, 184, 183, 179, 175, 173, 396, 171, 169, + 168, -1000, -1000, 163, 163, 393, -1000, 163, 163, 161, + 160, -1000, 159, 47, 158, 417, -1000, 497, 822, -1000, + 404, 534, 396, 396, 1, 349, 396, 396, 407, 411, + 396, 396, 426, 27, 679, 308, -1000, -1000, 45, 308, + 308, 308, 39, 436, 308, 308, -1000, -1000, -1000, 600, + 396, 396, 342, 342, 342, 585, -1000, 311, 308, -1000, + -7, 396, 396, 396, 396, 396, 396, 308, 32, -1000, + -1000, 15, 42, 734, 723, 456, 39, 396, -1000, 396, + 342, 342, 342, 342, -7, 396, 396, 396, 710, -7, + -23, 396, 2, -1000, -1000, -1000, -1000, -1000, -1000, -67, + 710, 697, 435, 688, 308, -1000, -1000, 308, 308, 308, + 308, 308, 440, 428, 308, 308, 308, -1000, -1000, -1000, + -1000, 157, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 152, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 31, 30, -1000, -1000, -1000, -1000, 396, -1000, + 26, 24, 18, 13, 435, 460, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 150, 149, -1000, 147, -1000, 146, -1000, 145, -1000, + 141, -1000, -1000, 136, -1000, 130, -1000, 11, -1000, -1000, + 15, -1000, -1000, 15, 6, -1, -1000, -1000, -1000, 124, + 123, 121, 120, 111, 110, 108, -1000, -1000, -1000, 106, + -1000, 101, -1000, -1000, -1000, -1000, 452, 97, -1000, 96, + 94, 540, 540, -1000, -1000, -1000, 308, 308, 837, 830, + 643, 353, 344, -1000, -1000, -2, -1000, -1000, -1000, -1000, + -15, 35, 396, 396, 396, 396, 396, 396, 396, 308, + -1000, -20, -25, 701, -1000, 342, 342, 375, 375, 375, + 688, 688, 396, 2, -1000, 423, 387, -51, -67, -75, + 608, 608, -1000, -1000, -1000, -1000, -1000, 380, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 15, -1000, 88, -1000, -1000, -1000, 87, 73, 72, 69, + 66, -1000, -1000, 386, 420, 452, -1000, -1000, -1000, -1000, + 468, -32, -33, 342, 396, 396, 308, 396, 396, -1000, + 383, -1000, 686, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, +} +var yyPgo = []int{ + + 0, 88, 42, 5, 13, 294, 200, 0, 90, 453, + 119, 20, 7, 536, 526, 1, 35, 2, 3, 68, + 26, 21, 9, 8, 510, 4, 505, 483, 23, 482, + 451, 210, +} +var yyR1 = []int{ + + 0, 26, 27, 26, 29, 28, 28, 28, 28, 28, + 28, 28, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 19, 19, 7, 12, 12, + 13, 21, 14, 24, 20, 20, 20, 23, 11, 11, + 10, 10, 22, 25, 15, 15, 15, 15, 17, 17, + 18, 18, 16, 5, 5, 8, 8, 6, 6, 9, + 9, 9, 31, 31, 4, 4, 4, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, +} +var yyR2 = []int{ + + 0, 0, 0, 3, 0, 4, 4, 4, 2, 1, + 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 4, 4, 6, 4, 4, 6, 6, + 6, 4, 4, 6, 4, 6, 4, 6, 4, 4, + 2, 6, 4, 4, 4, 6, 4, 4, 4, 4, + 4, 4, 4, 4, 2, 2, 4, 3, 3, 5, + 4, 4, 6, 4, 4, 6, 6, 6, 8, 4, + 4, 3, 2, 4, 4, 6, 8, 4, 6, 4, + 4, 6, 6, 8, 8, 8, 8, 4, 4, 4, + 6, 4, 6, 4, 4, 2, 2, 3, 3, 3, + 3, 2, 3, 3, 4, 4, 2, 5, 7, 4, + 6, 6, 6, 6, 2, 4, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 1, 1, 1, 4, + 1, 4, 1, 3, 1, 2, 3, 4, 2, 2, + 2, 3, 2, 1, 4, 3, 5, 1, 4, 4, + 5, 7, 0, 1, 0, 2, 2, 1, 1, 1, + 1, 1, 2, 2, 2, 3, 1, 3, 3, 3, + 3, 3, 4, 4, 3, 3, 3, +} +var yyChk = []int{ + + -1000, -26, -27, -28, 72, 74, 59, 77, -30, 2, + 14, 15, 23, 68, 19, 17, 18, 16, 69, 21, + 22, 28, 24, 26, 27, 25, 20, 64, 65, 60, + 61, 63, 62, 30, 33, 57, 58, 31, 34, 36, + 35, 37, 75, 76, 76, 77, 77, 77, -7, -6, + -8, -11, -23, -16, -17, -10, -20, -21, -12, -5, + -9, -1, 79, 46, 49, 50, 81, 43, 48, 54, + 53, -24, -13, -14, 45, 47, 72, 38, 74, 10, + 9, 82, 56, 51, 52, -7, -6, -8, -6, -8, + -18, -11, 81, -16, 81, -7, -16, -7, -7, -16, + -7, -7, -22, -1, 79, -19, -6, 79, 78, -10, + -1, 72, 48, -7, -16, -31, 78, -11, -11, -11, + -11, -7, -16, -7, -6, -7, -8, 79, -7, -8, + -7, -8, -31, -7, -11, 78, -16, -16, -17, -16, + -16, -31, -9, -1, -9, -9, -31, -29, -2, -1, + -2, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 79, -5, -2, 79, -6, 71, -1, 79, + 79, 79, -4, 7, 9, 10, -1, -1, -1, 78, + 78, 78, 78, 78, 78, 78, 70, 10, 78, -1, + 78, 78, 78, 78, 78, 78, 78, 78, -12, -19, + -6, 79, -1, 78, 78, 79, -4, 78, -31, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, -31, -31, -7, -11, -31, -31, 78, + 78, 78, 79, 78, 12, -28, 77, 9, 10, 11, + 12, 13, 7, 8, 6, 5, 4, 77, -7, -6, + -8, -16, -10, -21, -12, -20, -7, -7, -6, -8, + -23, -16, -11, -10, -7, -7, -10, -20, -10, -7, + -7, -7, -5, -3, 40, 39, 41, 80, 9, 80, + -1, -1, -1, -1, 79, 8, -1, -1, -7, -6, + -8, -7, -7, -11, -11, -11, -11, -6, -8, 70, + -1, -5, -16, -7, -5, -7, -5, -7, -5, -7, + -5, -7, -7, -5, -22, -1, 80, -12, -19, -6, + 79, -19, -6, 79, -1, 42, -5, -5, -11, -11, + -11, -11, -7, -16, -7, -7, -7, -6, -7, -16, + -8, -16, -7, -8, -16, -6, 81, -1, -16, -1, + -1, -2, -2, -2, -2, -2, 7, 8, -2, -2, + -2, 78, 78, 80, 80, -5, 80, 80, 80, 80, + -3, -4, 78, 78, 78, 78, 78, 78, 78, 78, + 80, -12, -12, 78, 80, 78, 78, 78, 78, 78, + 78, 78, 78, 78, -15, 38, 10, 78, 78, 78, + -2, -2, -21, 48, -23, 80, 80, 79, -7, -7, + -7, -7, -7, -7, -7, -22, 80, 80, -19, -6, + 79, -11, -11, -10, -10, -10, -16, -25, -1, -16, + -25, -7, -8, 10, 38, 81, -16, -16, -17, -18, + 81, 40, -12, 78, 78, 78, 78, 78, 78, 38, + 10, -15, 10, 80, 80, -11, -7, -7, -1, -7, + -7, 38, +} +var yyDef = []int{ + + 1, -2, 0, 3, 0, 0, 0, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 162, 0, 0, 0, 162, 0, 0, + 0, 162, 4, 0, 0, 8, 10, 11, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, + 157, 0, 0, 138, 0, 137, 0, 140, 131, 134, + 0, 136, 128, 129, 153, 0, 164, 170, 171, 0, + 0, 0, 133, 130, 132, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 50, 0, 0, 142, 0, 64, 65, 0, 0, 0, + 0, 164, 0, 162, 0, 82, 163, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 105, 106, 162, 162, 163, 111, 162, 162, 0, + 0, 116, 0, 0, 0, 0, 124, 0, 0, 176, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 148, 149, 152, 0, + 0, 0, 0, 0, 0, 0, 172, 173, 174, 0, + 0, 0, 0, 0, 0, 0, 150, 0, 0, 152, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, + 68, 0, 0, 0, 0, 0, 126, 163, 81, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 107, 108, 109, 110, 112, 113, 0, + 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 12, 24, + 25, 0, 36, 37, 61, 63, 13, 14, 28, 29, + 31, 0, 30, 33, 52, 53, 56, 62, 57, 59, + 58, 60, 0, 0, 167, 168, 169, 155, 0, 175, + 0, 0, 0, 0, 0, 164, 165, 166, 15, 26, + 27, 16, 17, 18, 19, 20, 21, 22, 23, 151, + 34, 127, 0, 41, 127, 42, 127, 44, 127, 46, + 127, 48, 49, 0, 54, 142, 66, 0, 70, 71, + 0, 73, 74, 0, 0, 0, 79, 80, 83, 84, + 0, 87, 89, 90, 0, 0, 97, 98, 99, 0, + 101, 0, 103, 104, 114, 115, 0, 0, 119, 0, + 0, 177, 178, 179, 180, 181, 0, 0, 184, 185, + 186, 0, 0, 158, 159, 0, 139, 141, 135, 154, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 69, 0, 0, 0, 125, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 117, 144, 0, 0, 0, 0, + 182, 183, 35, 131, 32, 156, 160, 0, 38, 40, + 39, 43, 45, 47, 51, 55, 72, 75, 76, 77, + 0, 85, 0, 88, 91, 92, 0, 0, 0, 0, + 0, 100, 102, 0, 145, 0, 120, 121, 122, 123, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, + 0, 118, 0, 161, 78, 86, 93, 94, 143, 95, + 96, 147, +} +var yyTok1 = []int{ + + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 81, 13, 6, 3, + 79, 80, 11, 9, 78, 10, 3, 12, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 75, 77, + 7, 76, 8, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 4, 3, 82, +} +var yyTok2 = []int{ + + 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, +} +var yyTok3 = []int{ + 0, +} + +//line yaccpar:1 + +/* parser for yacc output */ + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +type yyParser interface { + Parse(yyLexer) int + Lookahead() int +} + +type yyParserImpl struct { + lookahead func() int +} + +func (p *yyParserImpl) Lookahead() int { + return p.lookahead() +} + +func yyNewParser() yyParser { + p := &yyParserImpl{ + lookahead: func() int { return -1 }, + } + return p +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + // 4 is TOKSTART above + if c >= 4 && c-4 < len(yyToknames) { + if yyToknames[c-4] != "" { + return yyToknames[c-4] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yylex1(lex yyLexer, lval *yySymType) (char, token int) { + token = 0 + char = lex.Lex(lval) + if char <= 0 { + token = yyTok1[0] + goto out + } + if char < len(yyTok1) { + token = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + token = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + token = yyTok3[i+0] + if token == char { + token = yyTok3[i+1] + goto out + } + } + +out: + if token == 0 { + token = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) + } + return char, token +} + +func yyParse(yylex yyLexer) int { + return yyNewParser().Parse(yylex) +} + +func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { + var yyn int + var yylval yySymType + var yyVAL yySymType + var yyDollar []yySymType + yyS := make([]yySymType, yyMaxDepth) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yychar := -1 + yytoken := -1 // yychar translated into internal numbering + yyrcvr.lookahead = func() int { return yychar } + defer func() { + // Make sure we report no lookahead when not parsing. + yychar = -1 + yytoken = -1 + }() + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yychar < 0 { + yychar, yytoken = yylex1(yylex, &yylval) + } + yyn += yytoken + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yytoken { /* valid shift */ + yychar = -1 + yytoken = -1 + yyVAL = yylval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yychar < 0 { + yychar, yytoken = yylex1(yylex, &yylval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yytoken { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error("syntax error") + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) + } + if yytoken == yyEofCode { + goto ret1 + } + yychar = -1 + yytoken = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 2: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:72 + { + stmtline = asm.Lineno + } + case 4: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:79 + { + yyDollar[1].sym = asm.LabelLookup(yyDollar[1].sym) + if yyDollar[1].sym.Type == LLAB && yyDollar[1].sym.Value != int64(asm.PC) { + yyerror("redeclaration of %s", yyDollar[1].sym.Labelname) + } + yyDollar[1].sym.Type = LLAB + yyDollar[1].sym.Value = int64(asm.PC) + } + case 6: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:89 + { + yyDollar[1].sym.Type = LVAR + yyDollar[1].sym.Value = yyDollar[3].lval + } + case 7: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:94 + { + if yyDollar[1].sym.Value != yyDollar[3].lval { + yyerror("redeclaration of %s", yyDollar[1].sym.Name) + } + yyDollar[1].sym.Value = yyDollar[3].lval + } + case 8: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:101 + { + nosched = int(yyDollar[1].lval) + } + case 12: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:113 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 13: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:117 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 14: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:121 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 15: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:125 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 16: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:129 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 17: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:133 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 18: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:140 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 19: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:144 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 20: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:148 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 21: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:152 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 22: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:156 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 23: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:160 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 24: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:167 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 25: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:171 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 26: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:175 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 27: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:179 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 28: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:186 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 29: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:190 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 30: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:197 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 31: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:201 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 32: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:205 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) + } + case 33: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:209 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 34: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:213 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) + } + case 35: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:220 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) + } + case 36: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:224 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 37: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:228 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 38: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:238 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 39: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:242 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 40: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:246 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) + } + case 41: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:250 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 42: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:254 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 43: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:258 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 44: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:262 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 45: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:266 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 46: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:270 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 47: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:274 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 48: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:278 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 49: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:282 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 50: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:286 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[2].addr) + } + case 51: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:293 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 52: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:300 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 53: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:304 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 54: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:311 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[4].addr) + } + case 55: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:315 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) + } + case 56: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:323 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 57: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:327 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 58: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:331 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 59: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:335 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 60: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:339 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 61: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:343 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 62: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:347 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 63: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:351 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 64: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:360 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[2].addr) + } + case 65: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:364 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[2].addr) + } + case 66: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:368 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) + } + case 67: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:372 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) + } + case 68: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:376 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) + } + case 69: + yyDollar = yyS[yypt-5 : yypt+1] + //line a.y:380 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[4].addr) + } + case 70: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:384 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 71: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:388 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 72: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:392 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[5].addr) + } + case 73: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:396 + { + outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[4].addr) + } + case 74: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:400 + { + outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[4].addr) + } + case 75: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:404 + { + outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[5].addr) + } + case 76: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:408 + { + var g obj.Addr + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = yyDollar[2].lval + outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[6].addr) + } + case 77: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:416 + { + var g obj.Addr + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = yyDollar[2].lval + outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[6].addr) + } + case 78: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:424 + { + var g obj.Addr + g = nullgen + g.Type = obj.TYPE_CONST + g.Offset = yyDollar[2].lval + outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[7].addr) + } + case 79: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:435 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) + } + case 80: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:439 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) + } + case 81: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:443 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 82: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:447 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) + } + case 83: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:454 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 84: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:458 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 85: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:462 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr) + } + case 86: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:466 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) + } + case 87: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:470 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 88: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:474 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) + } + case 89: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:481 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 90: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:485 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 91: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:489 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) + } + case 92: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:493 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) + } + case 93: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:500 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) + } + case 94: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:504 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) + } + case 95: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:508 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) + } + case 96: + yyDollar = yyS[yypt-8 : yypt+1] + //line a.y:512 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) + } + case 97: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:519 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 98: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:523 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 99: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:531 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 100: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:535 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) + } + case 101: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:539 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 102: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:543 + { + outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) + } + case 103: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:547 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 104: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:551 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 105: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:555 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 106: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:562 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) + } + case 107: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:566 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 108: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:570 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 109: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:574 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) + } + case 110: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:578 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) + } + case 111: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:582 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 112: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:589 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 113: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:593 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) + } + case 114: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:600 + { + if yyDollar[2].addr.Type != obj.TYPE_CONST || yyDollar[4].addr.Type != obj.TYPE_CONST { + yyerror("arguments to PCDATA must be integer constants") + } + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 115: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:610 + { + if yyDollar[2].addr.Type != obj.TYPE_CONST { + yyerror("index for FUNCDATA must be integer constant") + } + if yyDollar[4].addr.Type != obj.TYPE_MEM || (yyDollar[4].addr.Name != obj.NAME_EXTERN && yyDollar[4].addr.Name != obj.NAME_STATIC) { + yyerror("value for FUNCDATA must be symbol reference") + } + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 116: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:623 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) + } + case 117: + yyDollar = yyS[yypt-5 : yypt+1] + //line a.y:630 + { + asm.Settext(yyDollar[2].addr.Sym) + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[5].addr) + } + case 118: + yyDollar = yyS[yypt-7 : yypt+1] + //line a.y:635 + { + asm.Settext(yyDollar[2].addr.Sym) + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[7].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyDollar[4].lval + } + } + case 119: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:647 + { + asm.Settext(yyDollar[2].addr.Sym) + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) + } + case 120: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:652 + { + asm.Settext(yyDollar[2].addr.Sym) + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyDollar[4].lval + } + } + case 121: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:665 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyDollar[4].lval + } + } + case 122: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:673 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyDollar[4].lval + } + } + case 123: + yyDollar = yyS[yypt-6 : yypt+1] + //line a.y:681 + { + outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) + if asm.Pass > 1 { + lastpc.From3.Type = obj.TYPE_CONST + lastpc.From3.Offset = yyDollar[4].lval + } + } + case 124: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:692 + { + outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) + } + case 125: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:698 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyDollar[1].lval + int64(asm.PC) + } + case 126: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:704 + { + yyDollar[1].sym = asm.LabelLookup(yyDollar[1].sym) + yyVAL.addr = nullgen + if asm.Pass == 2 && yyDollar[1].sym.Type != LLAB { + yyerror("undefined label: %s", yyDollar[1].sym.Labelname) + } + yyVAL.addr.Type = obj.TYPE_BRANCH + yyVAL.addr.Offset = yyDollar[1].sym.Value + yyDollar[2].lval + } + case 127: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:716 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 128: + yyVAL.addr = yyS[yypt-0].addr + case 129: + yyVAL.addr = yyS[yypt-0].addr + case 130: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:728 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 131: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:736 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) /* whole register */ + } + case 132: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:743 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 133: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:751 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 134: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:759 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 135: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:765 + { + if yyDollar[3].lval < 0 || yyDollar[3].lval >= 1024 { + yyerror("SPR/DCR out of range") + } + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval + yyDollar[3].lval) + } + case 136: + yyVAL.addr = yyS[yypt-0].addr + case 137: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:777 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 138: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:785 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 139: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:791 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(REG_F0 + yyDollar[3].lval) + } + case 140: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:799 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 141: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:805 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(REG_C0 + yyDollar[3].lval) + } + case 142: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:813 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_REG + yyVAL.addr.Reg = int16(yyDollar[1].lval) + } + case 143: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:821 + { + var mb, me int + var v uint32 + + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + mb = int(yyDollar[1].lval) + me = int(yyDollar[3].lval) + if mb < 0 || mb > 31 || me < 0 || me > 31 { + yyerror("illegal mask start/end value(s)") + mb = 0 + me = 0 + } + if mb <= me { + v = (^uint32(0) >> uint(mb)) & (^uint32(0) << uint(31-me)) + } else { + v = (^uint32(0) >> uint(me+1)) & (^uint32(0) << uint(31-(mb-1))) + } + yyVAL.addr.Offset = int64(v) + } + case 144: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:844 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = int64(yyDollar[1].lval) + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 145: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:851 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -int64(yyDollar[2].lval) + yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown + } + case 146: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:858 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = int64(yyDollar[1].lval) + yyVAL.addr.U.Argsize = int32(yyDollar[3].lval) + } + case 147: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:865 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_TEXTSIZE + yyVAL.addr.Offset = -int64(yyDollar[2].lval) + yyVAL.addr.U.Argsize = int32(yyDollar[4].lval) + } + case 148: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:874 + { + yyVAL.addr = yyDollar[2].addr + yyVAL.addr.Type = obj.TYPE_ADDR + } + case 149: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:879 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_SCONST + yyVAL.addr.U.Sval = yyDollar[2].sval + } + case 150: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:887 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = yyDollar[2].dval + } + case 151: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:893 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_FCONST + yyVAL.addr.U.Dval = -yyDollar[3].dval + } + case 152: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:900 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_CONST + yyVAL.addr.Offset = yyDollar[2].lval + } + case 153: + yyVAL.lval = yyS[yypt-0].lval + case 154: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:909 + { + if yyVAL.lval < 0 || yyVAL.lval >= NREG { + print("register value out of range\n") + } + yyVAL.lval = REG_R0 + yyDollar[3].lval + } + case 155: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:918 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyDollar[2].lval) + yyVAL.addr.Offset = 0 + } + case 156: + yyDollar = yyS[yypt-5 : yypt+1] + //line a.y:925 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyDollar[2].lval) + yyVAL.addr.Scale = int8(yyDollar[4].lval) + yyVAL.addr.Offset = 0 + } + case 157: + yyVAL.addr = yyS[yypt-0].addr + case 158: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:936 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Reg = int16(yyDollar[3].lval) + yyVAL.addr.Offset = yyDollar[1].lval + } + case 159: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:945 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyDollar[3].lval) + yyVAL.addr.Sym = nil + yyVAL.addr.Offset = yyDollar[1].lval + } + case 160: + yyDollar = yyS[yypt-5 : yypt+1] + //line a.y:953 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = int8(yyDollar[4].lval) + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyDollar[1].sym.Name, 0) + yyVAL.addr.Offset = yyDollar[2].lval + } + case 161: + yyDollar = yyS[yypt-7 : yypt+1] + //line a.y:961 + { + yyVAL.addr = nullgen + yyVAL.addr.Type = obj.TYPE_MEM + yyVAL.addr.Name = obj.NAME_STATIC + yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyDollar[1].sym.Name, 1) + yyVAL.addr.Offset = yyDollar[4].lval + } + case 164: + yyDollar = yyS[yypt-0 : yypt+1] + //line a.y:973 + { + yyVAL.lval = 0 + } + case 165: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:977 + { + yyVAL.lval = yyDollar[2].lval + } + case 166: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:981 + { + yyVAL.lval = -yyDollar[2].lval + } + case 167: + yyVAL.lval = yyS[yypt-0].lval + case 168: + yyVAL.lval = yyS[yypt-0].lval + case 169: + yyVAL.lval = yyS[yypt-0].lval + case 170: + yyVAL.lval = yyS[yypt-0].lval + case 171: + yyDollar = yyS[yypt-1 : yypt+1] + //line a.y:993 + { + yyVAL.lval = yyDollar[1].sym.Value + } + case 172: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:997 + { + yyVAL.lval = -yyDollar[2].lval + } + case 173: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:1001 + { + yyVAL.lval = yyDollar[2].lval + } + case 174: + yyDollar = yyS[yypt-2 : yypt+1] + //line a.y:1005 + { + yyVAL.lval = ^yyDollar[2].lval + } + case 175: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1009 + { + yyVAL.lval = yyDollar[2].lval + } + case 176: + yyVAL.lval = yyS[yypt-0].lval + case 177: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1016 + { + yyVAL.lval = yyDollar[1].lval + yyDollar[3].lval + } + case 178: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1020 + { + yyVAL.lval = yyDollar[1].lval - yyDollar[3].lval + } + case 179: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1024 + { + yyVAL.lval = yyDollar[1].lval * yyDollar[3].lval + } + case 180: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1028 + { + yyVAL.lval = yyDollar[1].lval / yyDollar[3].lval + } + case 181: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1032 + { + yyVAL.lval = yyDollar[1].lval % yyDollar[3].lval + } + case 182: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:1036 + { + yyVAL.lval = yyDollar[1].lval << uint(yyDollar[4].lval) + } + case 183: + yyDollar = yyS[yypt-4 : yypt+1] + //line a.y:1040 + { + yyVAL.lval = yyDollar[1].lval >> uint(yyDollar[4].lval) + } + case 184: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1044 + { + yyVAL.lval = yyDollar[1].lval & yyDollar[3].lval + } + case 185: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1048 + { + yyVAL.lval = yyDollar[1].lval ^ yyDollar[3].lval + } + case 186: + yyDollar = yyS[yypt-3 : yypt+1] + //line a.y:1052 + { + yyVAL.lval = yyDollar[1].lval | yyDollar[3].lval + } + } + goto yystack /* stack new state and value */ +} diff --git a/src/cmd/9a/y.tab.c b/src/cmd/9a/y.tab.c deleted file mode 100644 index 829f4d5de2..0000000000 --- a/src/cmd/9a/y.tab.c +++ /dev/null @@ -1,3466 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.3" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LMOVW = 258, - LMOVB = 259, - LABS = 260, - LLOGW = 261, - LSHW = 262, - LADDW = 263, - LCMP = 264, - LCROP = 265, - LBRA = 266, - LFMOV = 267, - LFCONV = 268, - LFCMP = 269, - LFADD = 270, - LFMA = 271, - LTRAP = 272, - LXORW = 273, - LNOP = 274, - LEND = 275, - LRETT = 276, - LWORD = 277, - LTEXT = 278, - LGLOBL = 279, - LDATA = 280, - LRETRN = 281, - LCONST = 282, - LSP = 283, - LSB = 284, - LFP = 285, - LPC = 286, - LCREG = 287, - LFLUSH = 288, - LREG = 289, - LFREG = 290, - LR = 291, - LCR = 292, - LF = 293, - LFPSCR = 294, - LLR = 295, - LCTR = 296, - LSPR = 297, - LSPREG = 298, - LSEG = 299, - LMSR = 300, - LPCDAT = 301, - LFUNCDAT = 302, - LSCHED = 303, - LXLD = 304, - LXST = 305, - LXOP = 306, - LXMV = 307, - LRLWM = 308, - LMOVMW = 309, - LMOVEM = 310, - LMOVFL = 311, - LMTFSB = 312, - LMA = 313, - LFCONST = 314, - LSCONST = 315, - LNAME = 316, - LLAB = 317, - LVAR = 318 - }; -#endif -/* Tokens. */ -#define LMOVW 258 -#define LMOVB 259 -#define LABS 260 -#define LLOGW 261 -#define LSHW 262 -#define LADDW 263 -#define LCMP 264 -#define LCROP 265 -#define LBRA 266 -#define LFMOV 267 -#define LFCONV 268 -#define LFCMP 269 -#define LFADD 270 -#define LFMA 271 -#define LTRAP 272 -#define LXORW 273 -#define LNOP 274 -#define LEND 275 -#define LRETT 276 -#define LWORD 277 -#define LTEXT 278 -#define LGLOBL 279 -#define LDATA 280 -#define LRETRN 281 -#define LCONST 282 -#define LSP 283 -#define LSB 284 -#define LFP 285 -#define LPC 286 -#define LCREG 287 -#define LFLUSH 288 -#define LREG 289 -#define LFREG 290 -#define LR 291 -#define LCR 292 -#define LF 293 -#define LFPSCR 294 -#define LLR 295 -#define LCTR 296 -#define LSPR 297 -#define LSPREG 298 -#define LSEG 299 -#define LMSR 300 -#define LPCDAT 301 -#define LFUNCDAT 302 -#define LSCHED 303 -#define LXLD 304 -#define LXST 305 -#define LXOP 306 -#define LXMV 307 -#define LRLWM 308 -#define LMOVMW 309 -#define LMOVEM 310 -#define LMOVFL 311 -#define LMTFSB 312 -#define LMA 313 -#define LFCONST 314 -#define LSCONST 315 -#define LNAME 316 -#define LLAB 317 -#define LVAR 318 - - - - -/* Copy the first part of user declarations. */ -#line 30 "a.y" - -#include -#include /* if we don't, bison will, and a.h re-#defines getc */ -#include -#include "a.h" -#include "../../runtime/funcdata.h" - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; -} -/* Line 193 of yacc.c. */ -#line 238 "y.tab.c" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 216 of yacc.c. */ -#line 251 "y.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int i) -#else -static int -YYID (i) - int i; -#endif -{ - return i; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 2 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 880 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 82 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 32 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 187 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 463 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 318 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 80, 12, 5, 2, - 78, 79, 10, 8, 77, 9, 2, 11, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 74, 76, - 6, 75, 7, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 81, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 4, 5, 9, 10, 15, 20, 25, - 28, 30, 33, 36, 41, 46, 51, 56, 61, 66, - 71, 76, 81, 86, 91, 96, 101, 106, 111, 116, - 121, 126, 131, 136, 143, 148, 153, 160, 165, 170, - 177, 184, 191, 196, 201, 208, 213, 220, 225, 232, - 237, 242, 245, 252, 257, 262, 267, 274, 279, 284, - 289, 294, 299, 304, 309, 314, 317, 320, 325, 329, - 333, 339, 344, 349, 356, 361, 366, 373, 380, 387, - 396, 401, 406, 410, 413, 418, 423, 430, 439, 444, - 451, 456, 461, 468, 475, 484, 493, 502, 511, 516, - 521, 526, 533, 538, 545, 550, 555, 558, 561, 565, - 569, 573, 577, 580, 584, 588, 593, 598, 601, 607, - 615, 620, 627, 634, 641, 648, 651, 656, 659, 661, - 663, 665, 667, 669, 671, 673, 675, 680, 682, 684, - 686, 691, 693, 698, 700, 704, 706, 709, 713, 718, - 721, 724, 727, 731, 734, 736, 741, 745, 751, 753, - 758, 763, 769, 777, 778, 780, 781, 784, 787, 789, - 791, 793, 795, 797, 800, 803, 806, 810, 812, 816, - 820, 824, 828, 832, 837, 842, 846, 850 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 83, 0, -1, -1, -1, 83, 84, 85, -1, -1, - 71, 74, 86, 85, -1, 71, 75, 113, 76, -1, - 73, 75, 113, 76, -1, 58, 76, -1, 76, -1, - 87, 76, -1, 1, 76, -1, 13, 89, 77, 89, - -1, 13, 107, 77, 89, -1, 13, 106, 77, 89, - -1, 14, 89, 77, 89, -1, 14, 107, 77, 89, - -1, 14, 106, 77, 89, -1, 22, 107, 77, 97, - -1, 22, 106, 77, 97, -1, 22, 103, 77, 97, - -1, 22, 97, 77, 97, -1, 22, 97, 77, 107, - -1, 22, 97, 77, 106, -1, 13, 89, 77, 107, - -1, 13, 89, 77, 106, -1, 14, 89, 77, 107, - -1, 14, 89, 77, 106, -1, 13, 97, 77, 107, - -1, 13, 97, 77, 106, -1, 13, 96, 77, 97, - -1, 13, 97, 77, 96, -1, 13, 97, 77, 104, - 77, 96, -1, 13, 96, 77, 98, -1, 67, 104, - 77, 112, -1, 13, 89, 77, 104, 77, 92, -1, - 13, 89, 77, 98, -1, 13, 89, 77, 92, -1, - 18, 89, 77, 105, 77, 89, -1, 18, 104, 77, - 105, 77, 89, -1, 18, 89, 77, 104, 77, 89, - -1, 18, 89, 77, 89, -1, 18, 104, 77, 89, - -1, 16, 89, 77, 105, 77, 89, -1, 16, 89, - 77, 89, -1, 17, 89, 77, 105, 77, 89, -1, - 17, 89, 77, 89, -1, 17, 104, 77, 105, 77, - 89, -1, 17, 104, 77, 89, -1, 15, 89, 77, - 89, -1, 15, 89, -1, 68, 89, 77, 105, 77, - 89, -1, 13, 104, 77, 89, -1, 13, 102, 77, - 89, -1, 20, 99, 77, 99, -1, 20, 99, 77, - 112, 77, 99, -1, 13, 98, 77, 98, -1, 13, - 95, 77, 98, -1, 13, 92, 77, 89, -1, 13, - 95, 77, 89, -1, 13, 90, 77, 89, -1, 13, - 89, 77, 90, -1, 13, 98, 77, 95, -1, 13, - 89, 77, 95, -1, 21, 88, -1, 21, 107, -1, - 21, 78, 90, 79, -1, 21, 77, 88, -1, 21, - 77, 107, -1, 21, 77, 78, 90, 79, -1, 21, - 98, 77, 88, -1, 21, 98, 77, 107, -1, 21, - 98, 77, 78, 90, 79, -1, 21, 112, 77, 88, - -1, 21, 112, 77, 107, -1, 21, 112, 77, 78, - 90, 79, -1, 21, 112, 77, 112, 77, 88, -1, - 21, 112, 77, 112, 77, 107, -1, 21, 112, 77, - 112, 77, 78, 90, 79, -1, 27, 89, 77, 105, - -1, 27, 104, 77, 105, -1, 27, 89, 109, -1, - 27, 109, -1, 23, 97, 77, 97, -1, 25, 97, - 77, 97, -1, 25, 97, 77, 97, 77, 97, -1, - 26, 97, 77, 97, 77, 97, 77, 97, -1, 24, - 97, 77, 97, -1, 24, 97, 77, 97, 77, 98, - -1, 19, 89, 77, 89, -1, 19, 89, 77, 104, - -1, 19, 89, 77, 89, 77, 98, -1, 19, 89, - 77, 104, 77, 98, -1, 63, 104, 77, 89, 77, - 104, 77, 89, -1, 63, 104, 77, 89, 77, 100, - 77, 89, -1, 63, 89, 77, 89, 77, 104, 77, - 89, -1, 63, 89, 77, 89, 77, 100, 77, 89, - -1, 64, 107, 77, 89, -1, 64, 89, 77, 107, - -1, 59, 106, 77, 89, -1, 59, 106, 77, 104, - 77, 89, -1, 60, 89, 77, 106, -1, 60, 89, - 77, 104, 77, 106, -1, 62, 106, 77, 89, -1, - 62, 89, 77, 106, -1, 61, 106, -1, 29, 109, - -1, 29, 89, 109, -1, 29, 97, 109, -1, 29, - 77, 89, -1, 29, 77, 97, -1, 29, 104, -1, - 32, 104, 109, -1, 32, 102, 109, -1, 56, 104, - 77, 104, -1, 57, 104, 77, 107, -1, 30, 109, - -1, 33, 108, 77, 80, 101, -1, 33, 108, 77, - 112, 77, 80, 101, -1, 34, 108, 77, 104, -1, - 34, 108, 77, 112, 77, 104, -1, 35, 108, 11, - 112, 77, 104, -1, 35, 108, 11, 112, 77, 102, - -1, 35, 108, 11, 112, 77, 103, -1, 36, 109, - -1, 112, 78, 41, 79, -1, 71, 110, -1, 105, - -1, 91, -1, 93, -1, 50, -1, 47, -1, 51, - -1, 55, -1, 53, -1, 52, 78, 112, 79, -1, - 94, -1, 49, -1, 45, -1, 48, 78, 112, 79, - -1, 42, -1, 47, 78, 112, 79, -1, 112, -1, - 112, 77, 112, -1, 37, -1, 9, 37, -1, 37, - 9, 37, -1, 9, 37, 9, 37, -1, 80, 107, - -1, 80, 70, -1, 80, 69, -1, 80, 9, 69, - -1, 80, 112, -1, 44, -1, 46, 78, 112, 79, - -1, 78, 105, 79, -1, 78, 105, 8, 105, 79, - -1, 108, -1, 112, 78, 105, 79, -1, 112, 78, - 111, 79, -1, 71, 110, 78, 111, 79, -1, 71, - 6, 7, 110, 78, 39, 79, -1, -1, 77, -1, - -1, 8, 112, -1, 9, 112, -1, 39, -1, 38, - -1, 40, -1, 37, -1, 73, -1, 9, 112, -1, - 8, 112, -1, 81, 112, -1, 78, 113, 79, -1, - 112, -1, 113, 8, 113, -1, 113, 9, 113, -1, - 113, 10, 113, -1, 113, 11, 113, -1, 113, 12, - 113, -1, 113, 6, 6, 113, -1, 113, 7, 7, - 113, -1, 113, 5, 113, -1, 113, 4, 113, -1, - 113, 3, 113, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 66, 66, 68, 67, 75, 74, 83, 88, 94, - 98, 99, 100, 106, 110, 114, 118, 122, 126, 133, - 137, 141, 145, 149, 153, 160, 164, 168, 172, 179, - 183, 190, 194, 198, 202, 206, 213, 217, 221, 231, - 235, 239, 243, 247, 251, 255, 259, 263, 267, 271, - 275, 279, 286, 293, 297, 304, 308, 316, 320, 324, - 328, 332, 336, 340, 344, 353, 357, 361, 365, 369, - 373, 377, 381, 385, 389, 393, 397, 401, 409, 417, - 428, 432, 436, 440, 447, 451, 455, 459, 463, 467, - 474, 478, 482, 486, 493, 497, 501, 505, 512, 516, - 524, 528, 532, 536, 540, 544, 548, 555, 559, 563, - 567, 571, 575, 582, 586, 593, 602, 613, 620, 625, - 637, 642, 655, 663, 671, 682, 688, 694, 705, 713, - 714, 717, 725, 733, 741, 749, 755, 763, 766, 774, - 780, 788, 794, 802, 810, 831, 838, 845, 852, 861, - 866, 874, 880, 887, 895, 896, 904, 911, 921, 922, - 931, 939, 947, 956, 957, 960, 963, 967, 973, 974, - 975, 978, 979, 983, 987, 991, 995, 1001, 1002, 1006, - 1010, 1014, 1018, 1022, 1026, 1030, 1034, 1038 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'", - "'-'", "'*'", "'/'", "'%'", "LMOVW", "LMOVB", "LABS", "LLOGW", "LSHW", - "LADDW", "LCMP", "LCROP", "LBRA", "LFMOV", "LFCONV", "LFCMP", "LFADD", - "LFMA", "LTRAP", "LXORW", "LNOP", "LEND", "LRETT", "LWORD", "LTEXT", - "LGLOBL", "LDATA", "LRETRN", "LCONST", "LSP", "LSB", "LFP", "LPC", - "LCREG", "LFLUSH", "LREG", "LFREG", "LR", "LCR", "LF", "LFPSCR", "LLR", - "LCTR", "LSPR", "LSPREG", "LSEG", "LMSR", "LPCDAT", "LFUNCDAT", "LSCHED", - "LXLD", "LXST", "LXOP", "LXMV", "LRLWM", "LMOVMW", "LMOVEM", "LMOVFL", - "LMTFSB", "LMA", "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", - "'='", "';'", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1", - "line", "@2", "inst", "rel", "rreg", "xlreg", "lr", "lcr", "ctr", "msr", - "psr", "fpscr", "freg", "creg", "cbit", "mask", "textsize", "ximm", - "fimm", "imm", "sreg", "regaddr", "addr", "name", "comma", "offset", - "pointer", "con", "expr", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 124, 94, 38, 60, 62, 43, 45, - 42, 47, 37, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 58, 61, 59, 44, 40, 41, - 36, 126 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 82, 83, 84, 83, 86, 85, 85, 85, 85, - 85, 85, 85, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 88, 88, 89, 90, - 90, 91, 92, 93, 94, 95, 95, 95, 96, 97, - 97, 98, 98, 99, 100, 101, 101, 101, 101, 102, - 102, 103, 103, 104, 105, 105, 106, 106, 107, 107, - 108, 108, 108, 109, 109, 110, 110, 110, 111, 111, - 111, 112, 112, 112, 112, 112, 112, 113, 113, 113, - 113, 113, 113, 113, 113, 113, 113, 113 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 0, 0, 3, 0, 4, 4, 4, 2, - 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 6, 4, 4, 6, 4, 4, 6, - 6, 6, 4, 4, 6, 4, 6, 4, 6, 4, - 4, 2, 6, 4, 4, 4, 6, 4, 4, 4, - 4, 4, 4, 4, 4, 2, 2, 4, 3, 3, - 5, 4, 4, 6, 4, 4, 6, 6, 6, 8, - 4, 4, 3, 2, 4, 4, 6, 8, 4, 6, - 4, 4, 6, 6, 8, 8, 8, 8, 4, 4, - 4, 6, 4, 6, 4, 4, 2, 2, 3, 3, - 3, 3, 2, 3, 3, 4, 4, 2, 5, 7, - 4, 6, 6, 6, 6, 2, 4, 2, 1, 1, - 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, - 4, 1, 4, 1, 3, 1, 2, 3, 4, 2, - 2, 2, 3, 2, 1, 4, 3, 5, 1, 4, - 4, 5, 7, 0, 1, 0, 2, 2, 1, 1, - 1, 1, 1, 2, 2, 2, 3, 1, 3, 3, - 3, 3, 3, 4, 4, 3, 3, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 2, 3, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 163, - 163, 163, 0, 0, 0, 0, 163, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 10, 4, 0, 12, 0, 0, 171, 141, 154, 139, - 0, 132, 0, 138, 131, 133, 0, 135, 134, 165, - 172, 0, 0, 0, 0, 0, 129, 0, 130, 137, - 0, 0, 0, 0, 0, 0, 128, 0, 0, 158, - 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 143, 0, 165, 0, 0, 65, - 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 164, 163, 0, 83, 164, 163, 163, 112, - 107, 117, 163, 163, 0, 0, 0, 0, 125, 0, - 0, 9, 0, 0, 0, 106, 0, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 0, 11, 174, 173, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, - 0, 150, 149, 153, 175, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 153, 0, 0, 0, 0, 0, 0, 127, - 0, 68, 69, 0, 0, 0, 0, 0, 0, 151, - 0, 0, 0, 0, 0, 0, 0, 0, 164, 82, - 0, 110, 111, 108, 109, 114, 113, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 165, 166, 167, 0, 0, 156, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 176, 13, 62, 38, - 64, 37, 0, 26, 25, 61, 59, 60, 58, 31, - 34, 32, 0, 30, 29, 63, 57, 54, 53, 15, - 14, 169, 168, 170, 0, 0, 16, 28, 27, 18, - 17, 50, 45, 128, 47, 128, 49, 128, 42, 0, - 128, 43, 128, 90, 91, 55, 143, 0, 67, 0, - 71, 72, 0, 74, 75, 0, 0, 152, 22, 24, - 23, 21, 20, 19, 84, 88, 85, 0, 80, 81, - 0, 0, 120, 0, 0, 115, 116, 100, 0, 0, - 102, 105, 104, 0, 0, 99, 98, 35, 0, 6, - 7, 8, 155, 142, 140, 136, 0, 0, 0, 187, - 186, 185, 0, 0, 178, 179, 180, 181, 182, 0, - 0, 159, 160, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 70, 0, 0, 0, 126, 0, 0, 0, - 0, 145, 118, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 161, 157, 183, 184, 132, 36, 33, 44, - 46, 48, 41, 39, 40, 92, 93, 56, 73, 76, - 0, 77, 78, 89, 86, 0, 146, 0, 0, 121, - 0, 123, 124, 122, 101, 103, 0, 0, 0, 0, - 0, 52, 0, 0, 0, 0, 147, 119, 0, 0, - 0, 0, 0, 0, 162, 79, 87, 148, 97, 96, - 144, 95, 94 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 3, 41, 233, 42, 99, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 93, 436, 392, - 74, 105, 75, 76, 77, 162, 79, 115, 157, 285, - 159, 160 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -180 -static const yytype_int16 yypact[] = -{ - -180, 12, -180, 484, -53, 517, 619, 28, 28, -24, - -24, 28, 799, 577, 596, -29, -29, -29, -29, 19, - -11, -51, -38, 701, 701, 701, -51, -19, -19, -8, - -7, 28, -7, -14, -24, 643, -19, 28, -36, 6, - -180, -180, 26, -180, 799, 799, -180, -180, -180, -180, - 7, 27, 51, -180, -180, -180, 61, -180, -180, 188, - -180, 662, 674, 799, 79, 93, -180, 99, -180, -180, - 112, 116, 126, 136, 138, 157, -180, 168, 176, -180, - 80, 179, 182, 184, 186, 194, 799, 196, 198, 200, - 201, 202, 799, 203, -180, 27, 188, 714, 676, -180, - 206, -180, 49, 8, 215, 216, 217, 219, 220, 221, - 223, 224, -180, 225, 226, -180, 181, -51, -51, -180, - -180, -180, -51, -51, 227, 158, 231, 296, -180, 232, - 233, -180, 28, 234, 236, -180, 237, 238, 242, 245, - 246, 248, 249, 250, -180, 799, 799, -180, -180, -180, - 799, 799, 799, 799, 321, 799, 799, 251, 3, -180, - 377, -180, -180, 80, -180, 565, 28, 28, 172, 162, - 623, 31, 28, 28, 28, 28, 230, 619, 28, 28, - 28, 28, -180, 28, 28, -24, 28, -24, 799, 251, - 676, -180, -180, 254, 257, 723, 753, 111, 268, -180, - 67, -29, -29, -29, -29, -29, -29, -29, 28, -180, - 28, -180, -180, -180, -180, -180, -180, 733, 96, 760, - 799, -19, 701, -24, 40, -7, 28, 28, 28, 701, - 28, 799, 28, 484, 463, 524, 265, 266, 267, 270, - 135, -180, -180, 96, 28, -180, 799, 799, 799, 341, - 347, 799, 799, 799, 799, 799, -180, -180, -180, -180, - -180, -180, 278, -180, -180, -180, -180, -180, -180, -180, - -180, -180, 279, -180, -180, -180, -180, -180, -180, -180, - -180, -180, -180, -180, 281, 282, -180, -180, -180, -180, - -180, -180, -180, 280, -180, 285, -180, 286, -180, 288, - 289, -180, 297, 299, 301, -180, 319, 294, -180, 676, - -180, -180, 676, -180, -180, 171, 318, -180, -180, -180, - -180, -180, -180, -180, -180, 324, 325, 327, -180, -180, - 9, 328, -180, 329, 330, -180, -180, -180, 331, 335, - -180, -180, -180, 336, 337, -180, -180, -180, 338, -180, - -180, -180, -180, -180, -180, -180, 320, 339, 340, 571, - 430, 82, 799, 799, 153, 153, -180, -180, -180, 374, - 373, -180, -180, 28, 28, 28, 28, 28, 28, 20, - 20, 799, -180, 344, 345, 772, -180, 20, -29, -29, - 390, 419, -180, 349, -19, 350, 28, -7, 760, 760, - 28, 392, -180, -180, 277, 277, -180, -180, -180, -180, - -180, -180, -180, -180, -180, -180, -180, -180, -180, -180, - 676, -180, -180, -180, -180, 355, 436, 411, 9, -180, - 322, -180, -180, -180, -180, -180, 375, 376, 378, 380, - 381, -180, 372, 382, -29, 417, -180, -180, 790, 28, - 28, 799, 28, 28, -180, -180, -180, -180, -180, -180, - -180, -180, -180 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -180, -180, -180, 229, -180, -180, -73, -6, -62, -180, - -158, -180, -180, -150, -162, 37, 30, -179, 60, 32, - -16, 68, 97, 167, 81, 95, 159, 24, -86, 239, - 35, 87 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -1 -static const yytype_uint16 yytable[] = -{ - 81, 84, 85, 87, 89, 91, 122, 259, 271, 305, - 189, 244, 2, 113, 117, 260, 49, 198, 390, 52, - 48, 275, 50, 43, 191, 134, 112, 136, 138, 140, - 48, 143, 50, 48, 49, 50, 194, 52, 144, 145, - 80, 80, 62, 100, 120, 121, 391, 94, 102, 80, - 128, 104, 108, 109, 110, 111, 86, 118, 125, 125, - 125, 86, 47, 48, 132, 50, 116, 95, 131, 86, - 80, 132, 48, 47, 50, 44, 45, 199, 95, 148, - 149, 146, 245, 56, 57, 150, 58, 82, 249, 250, - 251, 252, 253, 254, 255, 106, 112, 163, 164, 86, - 78, 83, 147, 258, 46, 151, 88, 90, 101, 107, - 211, 133, 49, 135, 137, 52, 114, 119, 132, 123, - 86, 182, 310, 313, 129, 130, 196, 197, 307, 152, - 141, 139, 193, 142, 281, 282, 283, 209, 59, 153, - 60, 213, 214, 155, 156, 61, 215, 216, 63, 281, - 282, 283, 316, 212, 356, 48, 165, 50, 176, 257, - 265, 266, 267, 253, 254, 255, 277, 278, 279, 280, - 166, 286, 289, 290, 291, 292, 167, 294, 296, 298, - 301, 303, 124, 126, 127, 236, 237, 238, 239, 168, - 241, 242, 192, 169, 154, 261, 155, 156, 268, 270, - 80, 276, 417, 170, 47, 80, 269, 49, 408, 95, - 52, 407, 80, 171, 47, 172, 48, 337, 50, 95, - 342, 343, 344, 306, 346, 48, 49, 50, 158, 52, - 193, 315, 234, 235, 173, 80, 218, 318, 321, 322, - 323, 324, 325, 326, 327, 174, 263, 383, 385, 197, - 384, 273, 331, 175, 333, 334, 177, 80, 287, 178, - 264, 179, 262, 180, 80, 274, 347, 272, 281, 282, - 283, 181, 288, 183, 48, 184, 50, 185, 186, 187, - 188, 319, 299, 195, 304, 251, 252, 253, 254, 255, - 311, 314, 200, 201, 202, 320, 203, 204, 205, 158, - 206, 207, 208, 210, 217, 340, 341, 220, 219, 221, - 222, 223, 421, 224, 225, 226, 332, 336, 335, 227, - 338, 339, 228, 229, 345, 230, 231, 232, 240, 243, - 44, 448, 197, 359, 360, 361, 308, 317, 364, 365, - 366, 367, 368, 284, 352, 353, 354, 362, 293, 355, - 295, 297, 300, 302, 363, 369, 370, 373, 443, 46, - 371, 372, 374, 375, 284, 376, 377, 409, 410, 411, - 412, 413, 414, 382, 378, 328, 379, 329, 380, 431, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 434, 199, 161, 59, 441, 60, 381, 386, 401, 348, - 92, 387, 388, 63, 389, 393, 394, 395, 396, 415, - 416, 358, 397, 398, 399, 400, 94, 423, 402, 403, - 193, 406, 53, 418, 419, 424, 425, 426, 427, 428, - 430, 442, 444, 438, 438, 248, 249, 250, 251, 252, - 253, 254, 255, 458, 459, 445, 461, 462, 446, 404, - 405, 454, 449, 450, 457, 451, 256, 452, 453, 439, - 447, 455, 349, 432, 0, 163, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 0, 0, 435, 0, - 422, 456, 357, 149, 0, 4, 460, 0, 0, 0, - 0, 429, 433, 0, 0, 437, 440, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 0, 20, 21, 0, 22, 23, 24, 25, - 26, 0, 0, 0, 0, 44, 45, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 0, 0, 350, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, - 0, 36, 37, 0, 46, 38, 0, 39, 0, 47, - 40, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 0, 58, 44, 45, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 0, 44, 45, 0, 59, 0, - 60, 0, 0, 0, 0, 61, 0, 62, 63, 0, - 351, 0, 46, 0, 44, 45, 0, 47, 0, 48, - 0, 50, 51, 0, 46, 54, 55, 56, 57, 47, - 58, 0, 0, 0, 95, 0, 0, 44, 45, 0, - 0, 44, 45, 46, 0, 0, 59, 0, 60, 0, - 0, 49, 0, 61, 52, 86, 63, 0, 96, 0, - 60, 44, 45, 0, 97, 98, 46, 0, 63, 0, - 46, 0, 0, 48, 0, 50, 0, 59, 0, 60, - 44, 45, 53, 0, 61, 0, 103, 63, 0, 0, - 46, 0, 44, 45, 44, 45, 0, 48, 0, 50, - 59, 0, 60, 0, 59, 0, 60, 61, 0, 46, - 63, 61, 0, 86, 63, 0, 48, 0, 50, 44, - 45, 46, 0, 46, 59, 0, 60, 0, 0, 0, - 0, 92, 44, 45, 63, 0, 54, 55, 0, 0, - 0, 44, 45, 0, 0, 60, 0, 0, 46, 0, - 92, 44, 45, 63, 161, 59, 0, 60, 0, 60, - 0, 46, 92, 0, 92, 63, 0, 63, 0, 0, - 46, 44, 45, 0, 0, 0, 0, 0, 44, 45, - 46, 0, 59, 0, 60, 0, 0, 0, 0, 92, - 44, 45, 63, 0, 0, 96, 0, 60, 0, 0, - 46, 0, 190, 0, 96, 63, 60, 46, 44, 45, - 0, 309, 0, 0, 63, 0, 60, 44, 45, 46, - 0, 92, 0, 330, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 96, 0, 60, 46, 0, 0, - 0, 312, 0, 60, 63, 0, 46, 0, 92, 0, - 86, 63, 0, 96, 0, 60, 0, 0, 0, 0, - 420, 0, 0, 63, 0, 0, 0, 0, 0, 317, - 0, 0, 0, 60, 0, 0, 0, 0, 92, 0, - 0, 63, 60, 0, 0, 0, 0, 92, 0, 0, - 63 -}; - -static const yytype_int16 yycheck[] = -{ - 6, 7, 8, 9, 10, 11, 22, 165, 170, 188, - 96, 8, 0, 19, 20, 165, 45, 9, 9, 48, - 44, 171, 46, 76, 97, 31, 77, 33, 34, 35, - 44, 37, 46, 44, 45, 46, 98, 48, 74, 75, - 5, 6, 80, 13, 20, 21, 37, 12, 13, 14, - 26, 14, 15, 16, 17, 18, 80, 20, 23, 24, - 25, 80, 42, 44, 78, 46, 77, 47, 76, 80, - 35, 78, 44, 42, 46, 8, 9, 69, 47, 44, - 45, 75, 79, 52, 53, 78, 55, 6, 6, 7, - 8, 9, 10, 11, 12, 14, 77, 62, 63, 80, - 5, 6, 76, 165, 37, 78, 9, 10, 13, 14, - 116, 30, 45, 32, 33, 48, 19, 20, 78, 22, - 80, 86, 195, 196, 27, 28, 77, 78, 190, 78, - 35, 34, 97, 36, 38, 39, 40, 113, 71, 78, - 73, 117, 118, 8, 9, 78, 122, 123, 81, 38, - 39, 40, 41, 116, 240, 44, 77, 46, 78, 165, - 166, 167, 168, 10, 11, 12, 172, 173, 174, 175, - 77, 177, 178, 179, 180, 181, 77, 183, 184, 185, - 186, 187, 23, 24, 25, 150, 151, 152, 153, 77, - 155, 156, 97, 77, 6, 165, 8, 9, 168, 169, - 165, 171, 381, 77, 42, 170, 169, 45, 370, 47, - 48, 369, 177, 77, 42, 77, 44, 223, 46, 47, - 226, 227, 228, 188, 230, 44, 45, 46, 61, 48, - 195, 196, 145, 146, 77, 200, 78, 200, 201, 202, - 203, 204, 205, 206, 207, 77, 165, 309, 77, 78, - 312, 170, 217, 77, 219, 220, 77, 222, 177, 77, - 165, 77, 165, 77, 229, 170, 231, 170, 38, 39, - 40, 77, 177, 77, 44, 77, 46, 77, 77, 77, - 77, 200, 185, 77, 187, 8, 9, 10, 11, 12, - 195, 196, 77, 77, 77, 200, 77, 77, 77, 132, - 77, 77, 77, 77, 77, 224, 225, 11, 77, 77, - 77, 77, 385, 77, 77, 77, 219, 222, 221, 77, - 223, 224, 77, 77, 229, 77, 77, 77, 7, 78, - 8, 9, 78, 246, 247, 248, 79, 69, 251, 252, - 253, 254, 255, 176, 79, 79, 79, 6, 181, 79, - 183, 184, 185, 186, 7, 77, 77, 77, 420, 37, - 79, 79, 77, 77, 197, 77, 77, 373, 374, 375, - 376, 377, 378, 79, 77, 208, 77, 210, 77, 395, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 396, 69, 70, 71, 400, 73, 77, 79, 78, 232, - 78, 77, 77, 81, 77, 77, 77, 77, 77, 379, - 380, 244, 77, 77, 77, 77, 381, 387, 79, 79, - 385, 47, 49, 79, 79, 388, 389, 37, 9, 80, - 80, 39, 77, 398, 399, 5, 6, 7, 8, 9, - 10, 11, 12, 449, 450, 9, 452, 453, 37, 362, - 363, 79, 77, 77, 37, 77, 79, 77, 77, 399, - 428, 79, 233, 395, -1, 430, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, -1, -1, 397, -1, - 385, 444, 243, 448, -1, 1, 451, -1, -1, -1, - -1, 394, 395, -1, -1, 398, 399, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, -1, 29, 30, -1, 32, 33, 34, 35, - 36, -1, -1, -1, -1, 8, 9, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, -1, -1, 76, - 56, 57, 58, 59, 60, 61, 62, 63, 64, -1, - -1, 67, 68, -1, 37, 71, -1, 73, -1, 42, - 76, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, -1, 55, 8, 9, 4, 5, 6, 7, 8, - 9, 10, 11, 12, -1, 8, 9, -1, 71, -1, - 73, -1, -1, -1, -1, 78, -1, 80, 81, -1, - 76, -1, 37, -1, 8, 9, -1, 42, -1, 44, - -1, 46, 47, -1, 37, 50, 51, 52, 53, 42, - 55, -1, -1, -1, 47, -1, -1, 8, 9, -1, - -1, 8, 9, 37, -1, -1, 71, -1, 73, -1, - -1, 45, -1, 78, 48, 80, 81, -1, 71, -1, - 73, 8, 9, -1, 77, 78, 37, -1, 81, -1, - 37, -1, -1, 44, -1, 46, -1, 71, -1, 73, - 8, 9, 49, -1, 78, -1, 80, 81, -1, -1, - 37, -1, 8, 9, 8, 9, -1, 44, -1, 46, - 71, -1, 73, -1, 71, -1, 73, 78, -1, 37, - 81, 78, -1, 80, 81, -1, 44, -1, 46, 8, - 9, 37, -1, 37, 71, -1, 73, -1, -1, -1, - -1, 78, 8, 9, 81, -1, 50, 51, -1, -1, - -1, 8, 9, -1, -1, 73, -1, -1, 37, -1, - 78, 8, 9, 81, 70, 71, -1, 73, -1, 73, - -1, 37, 78, -1, 78, 81, -1, 81, -1, -1, - 37, 8, 9, -1, -1, -1, -1, -1, 8, 9, - 37, -1, 71, -1, 73, -1, -1, -1, -1, 78, - 8, 9, 81, -1, -1, 71, -1, 73, -1, -1, - 37, -1, 78, -1, 71, 81, 73, 37, 8, 9, - -1, 78, -1, -1, 81, -1, 73, 8, 9, 37, - -1, 78, -1, 80, 81, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 71, -1, 73, 37, -1, -1, - -1, 78, -1, 73, 81, -1, 37, -1, 78, -1, - 80, 81, -1, 71, -1, 73, -1, -1, -1, -1, - 78, -1, -1, 81, -1, -1, -1, -1, -1, 69, - -1, -1, -1, 73, -1, -1, -1, -1, 78, -1, - -1, 81, 73, -1, -1, -1, -1, 78, -1, -1, - 81 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 83, 0, 84, 1, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 29, 30, 32, 33, 34, 35, 36, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 67, 68, 71, 73, - 76, 85, 87, 76, 8, 9, 37, 42, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 55, 71, - 73, 78, 80, 81, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 102, 104, 105, 106, 107, 108, - 112, 89, 106, 107, 89, 89, 80, 89, 104, 89, - 104, 89, 78, 99, 112, 47, 71, 77, 78, 88, - 98, 107, 112, 80, 97, 103, 106, 107, 97, 97, - 97, 97, 77, 89, 104, 109, 77, 89, 97, 104, - 109, 109, 102, 104, 108, 112, 108, 108, 109, 104, - 104, 76, 78, 106, 89, 106, 89, 106, 89, 104, - 89, 107, 104, 89, 74, 75, 75, 76, 112, 112, - 78, 78, 78, 78, 6, 8, 9, 110, 105, 112, - 113, 70, 107, 112, 112, 77, 77, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 78, 77, 77, 77, - 77, 77, 112, 77, 77, 77, 77, 77, 77, 110, - 78, 88, 107, 112, 90, 77, 77, 78, 9, 69, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 109, - 77, 89, 97, 109, 109, 109, 109, 77, 78, 77, - 11, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 77, 86, 113, 113, 112, 112, 112, 112, - 7, 112, 112, 78, 8, 79, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 79, 89, 90, 92, - 95, 98, 104, 106, 107, 89, 89, 89, 98, 97, - 98, 96, 104, 106, 107, 95, 98, 89, 89, 89, - 89, 38, 39, 40, 105, 111, 89, 106, 107, 89, - 89, 89, 89, 105, 89, 105, 89, 105, 89, 104, - 105, 89, 105, 89, 104, 99, 112, 90, 79, 78, - 88, 107, 78, 88, 107, 112, 41, 69, 97, 106, - 107, 97, 97, 97, 97, 97, 97, 97, 105, 105, - 80, 112, 104, 112, 112, 104, 107, 89, 104, 104, - 106, 106, 89, 89, 89, 107, 89, 112, 105, 85, - 76, 76, 79, 79, 79, 79, 110, 111, 105, 113, - 113, 113, 6, 7, 113, 113, 113, 113, 113, 77, - 77, 79, 79, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 79, 90, 90, 77, 79, 77, 77, 77, - 9, 37, 101, 77, 77, 77, 77, 77, 77, 77, - 77, 78, 79, 79, 113, 113, 47, 92, 96, 89, - 89, 89, 89, 89, 89, 98, 98, 99, 79, 79, - 78, 88, 107, 98, 97, 97, 37, 9, 80, 104, - 80, 102, 103, 104, 89, 106, 100, 104, 112, 100, - 104, 89, 39, 90, 77, 9, 37, 101, 9, 77, - 77, 77, 77, 77, 79, 79, 97, 37, 89, 89, - 112, 89, 89 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) -#else -static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - fprintf (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - fprintf (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The look-ahead symbol. */ -int yychar; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - int yystate; - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to look-ahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a look-ahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the look-ahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 3: -#line 68 "a.y" - { - stmtline = lineno; - } - break; - - case 5: -#line 75 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - if((yyvsp[(1) - (2)].sym)->type == LLAB && (yyvsp[(1) - (2)].sym)->value != pc) - yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyvsp[(1) - (2)].sym)->type = LLAB; - (yyvsp[(1) - (2)].sym)->value = pc; - } - break; - - case 7: -#line 84 "a.y" - { - (yyvsp[(1) - (4)].sym)->type = LVAR; - (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval); - } - break; - - case 8: -#line 89 "a.y" - { - if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval)) - yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name); - (yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval); - } - break; - - case 9: -#line 95 "a.y" - { - nosched = (yyvsp[(1) - (2)].lval); - } - break; - - case 13: -#line 107 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 14: -#line 111 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 15: -#line 115 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 16: -#line 119 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 17: -#line 123 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 18: -#line 127 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 19: -#line 134 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 20: -#line 138 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 21: -#line 142 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 22: -#line 146 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 23: -#line 150 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 24: -#line 154 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 25: -#line 161 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 26: -#line 165 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 27: -#line 169 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 28: -#line 173 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 29: -#line 180 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 30: -#line 184 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 31: -#line 191 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 32: -#line 195 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 33: -#line 199 "a.y" - { - outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 34: -#line 203 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 35: -#line 207 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen); - } - break; - - case 36: -#line 214 "a.y" - { - outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 37: -#line 218 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 38: -#line 222 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 39: -#line 232 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 40: -#line 236 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 41: -#line 240 "a.y" - { - outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 42: -#line 244 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 43: -#line 248 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 44: -#line 252 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 45: -#line 256 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 46: -#line 260 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 47: -#line 264 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 48: -#line 268 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 49: -#line 272 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 50: -#line 276 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 51: -#line 280 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &(yyvsp[(2) - (2)].addr)); - } - break; - - case 52: -#line 287 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 53: -#line 294 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 54: -#line 298 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 55: -#line 305 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].addr).reg, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 56: -#line 309 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 57: -#line 317 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 58: -#line 321 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 59: -#line 325 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 60: -#line 329 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 61: -#line 333 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 62: -#line 337 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 63: -#line 341 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 64: -#line 345 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 65: -#line 354 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr)); - } - break; - - case 66: -#line 358 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &(yyvsp[(2) - (2)].addr)); - } - break; - - case 67: -#line 362 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &nullgen, 0, &(yyvsp[(3) - (4)].addr)); - } - break; - - case 68: -#line 366 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 69: -#line 370 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 70: -#line 374 "a.y" - { - outcode((yyvsp[(1) - (5)].lval), &nullgen, 0, &(yyvsp[(4) - (5)].addr)); - } - break; - - case 71: -#line 378 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 72: -#line 382 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 73: -#line 386 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(5) - (6)].addr)); - } - break; - - case 74: -#line 390 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr)); - } - break; - - case 75: -#line 394 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &nullgen, (yyvsp[(2) - (4)].lval), &(yyvsp[(4) - (4)].addr)); - } - break; - - case 76: -#line 398 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &nullgen, (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr)); - } - break; - - case 77: -#line 402 "a.y" - { - Addr g; - g = nullgen; - g.type = TYPE_CONST; - g.offset = (yyvsp[(2) - (6)].lval); - outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 78: -#line 410 "a.y" - { - Addr g; - g = nullgen; - g.type = TYPE_CONST; - g.offset = (yyvsp[(2) - (6)].lval); - outcode((yyvsp[(1) - (6)].lval), &g, REG_R0+(yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 79: -#line 418 "a.y" - { - Addr g; - g = nullgen; - g.type = TYPE_CONST; - g.offset = (yyvsp[(2) - (8)].lval); - outcode((yyvsp[(1) - (8)].lval), &g, REG_R0+(yyvsp[(4) - (8)].lval), &(yyvsp[(7) - (8)].addr)); - } - break; - - case 80: -#line 429 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen); - } - break; - - case 81: -#line 433 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), (yyvsp[(4) - (4)].lval), &nullgen); - } - break; - - case 82: -#line 437 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen); - } - break; - - case 83: -#line 441 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen); - } - break; - - case 84: -#line 448 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 85: -#line 452 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 86: -#line 456 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr)); - } - break; - - case 87: -#line 460 "a.y" - { - outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr)); - } - break; - - case 88: -#line 464 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 89: -#line 468 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr)); - } - break; - - case 90: -#line 475 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 91: -#line 479 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 92: -#line 483 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr)); - } - break; - - case 93: -#line 487 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(4) - (6)].addr)); - } - break; - - case 94: -#line 494 "a.y" - { - outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr)); - } - break; - - case 95: -#line 498 "a.y" - { - outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr)); - } - break; - - case 96: -#line 502 "a.y" - { - outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr)); - } - break; - - case 97: -#line 506 "a.y" - { - outgcode((yyvsp[(1) - (8)].lval), &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].addr).reg, &(yyvsp[(6) - (8)].addr), &(yyvsp[(8) - (8)].addr)); - } - break; - - case 98: -#line 513 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 99: -#line 517 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 100: -#line 525 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 101: -#line 529 "a.y" - { - outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 102: -#line 533 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 103: -#line 537 "a.y" - { - outgcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(4) - (6)].addr), &(yyvsp[(6) - (6)].addr)); - } - break; - - case 104: -#line 541 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 105: -#line 545 "a.y" - { - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 106: -#line 549 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen); - } - break; - - case 107: -#line 556 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen); - } - break; - - case 108: -#line 560 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen); - } - break; - - case 109: -#line 564 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen); - } - break; - - case 110: -#line 568 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 111: -#line 572 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &nullgen, 0, &(yyvsp[(3) - (3)].addr)); - } - break; - - case 112: -#line 576 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr), 0, &nullgen); - } - break; - - case 113: -#line 583 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen); - } - break; - - case 114: -#line 587 "a.y" - { - outcode((yyvsp[(1) - (3)].lval), &(yyvsp[(2) - (3)].addr), 0, &nullgen); - } - break; - - case 115: -#line 594 "a.y" - { - if((yyvsp[(2) - (4)].addr).type != TYPE_CONST || (yyvsp[(4) - (4)].addr).type != TYPE_CONST) - yyerror("arguments to PCDATA must be integer constants"); - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 116: -#line 603 "a.y" - { - if((yyvsp[(2) - (4)].addr).type != TYPE_CONST) - yyerror("index for FUNCDATA must be integer constant"); - if((yyvsp[(4) - (4)].addr).type != NAME_EXTERN && (yyvsp[(4) - (4)].addr).type != NAME_STATIC && (yyvsp[(4) - (4)].addr).type != TYPE_MEM) - yyerror("value for FUNCDATA must be symbol reference"); - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 117: -#line 614 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen); - } - break; - - case 118: -#line 621 "a.y" - { - settext((yyvsp[(2) - (5)].addr).sym); - outcode((yyvsp[(1) - (5)].lval), &(yyvsp[(2) - (5)].addr), 0, &(yyvsp[(5) - (5)].addr)); - } - break; - - case 119: -#line 626 "a.y" - { - settext((yyvsp[(2) - (7)].addr).sym); - outcode((yyvsp[(1) - (7)].lval), &(yyvsp[(2) - (7)].addr), 0, &(yyvsp[(7) - (7)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (7)].lval); - } - } - break; - - case 120: -#line 638 "a.y" - { - settext((yyvsp[(2) - (4)].addr).sym); - outcode((yyvsp[(1) - (4)].lval), &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr)); - } - break; - - case 121: -#line 643 "a.y" - { - settext((yyvsp[(2) - (6)].addr).sym); - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 122: -#line 656 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 123: -#line 664 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 124: -#line 672 "a.y" - { - outcode((yyvsp[(1) - (6)].lval), &(yyvsp[(2) - (6)].addr), 0, &(yyvsp[(6) - (6)].addr)); - if(pass > 1) { - lastpc->from3.type = TYPE_CONST; - lastpc->from3.offset = (yyvsp[(4) - (6)].lval); - } - } - break; - - case 125: -#line 683 "a.y" - { - outcode((yyvsp[(1) - (2)].lval), &nullgen, 0, &nullgen); - } - break; - - case 126: -#line 689 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc; - } - break; - - case 127: -#line 695 "a.y" - { - (yyvsp[(1) - (2)].sym) = labellookup((yyvsp[(1) - (2)].sym)); - (yyval.addr) = nullgen; - if(pass == 2 && (yyvsp[(1) - (2)].sym)->type != LLAB) - yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->labelname); - (yyval.addr).type = TYPE_BRANCH; - (yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval); - } - break; - - case 128: -#line 706 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 131: -#line 718 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 132: -#line 726 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); /* whole register */ - } - break; - - case 133: -#line 734 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 134: -#line 742 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 135: -#line 750 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 136: -#line 756 "a.y" - { - if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= 1024) - yyerror("SPR/DCR out of range"); - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (4)].lval) + (yyvsp[(3) - (4)].lval); - } - break; - - case 138: -#line 767 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 139: -#line 775 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 140: -#line 781 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = REG_F0 + (yyvsp[(3) - (4)].lval); - } - break; - - case 141: -#line 789 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 142: -#line 795 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = REG_C0 + (yyvsp[(3) - (4)].lval); - } - break; - - case 143: -#line 803 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_REG; - (yyval.addr).reg = (yyvsp[(1) - (1)].lval); - } - break; - - case 144: -#line 811 "a.y" - { - int mb, me; - uint32 v; - - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - mb = (yyvsp[(1) - (3)].lval); - me = (yyvsp[(3) - (3)].lval); - if(mb < 0 || mb > 31 || me < 0 || me > 31){ - yyerror("illegal mask start/end value(s)"); - mb = me = 0; - } - if(mb <= me) - v = ((uint32)~0L>>mb) & (~0L<<(31-me)); - else - v = ~(((uint32)~0L>>(me+1)) & (~0L<<(31-(mb-1)))); - (yyval.addr).offset = v; - } - break; - - case 145: -#line 832 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (1)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 146: -#line 839 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (2)].lval); - (yyval.addr).u.argsize = ArgsSizeUnknown; - } - break; - - case 147: -#line 846 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = (yyvsp[(1) - (3)].lval); - (yyval.addr).u.argsize = (yyvsp[(3) - (3)].lval); - } - break; - - case 148: -#line 853 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_TEXTSIZE; - (yyval.addr).offset = -(yyvsp[(2) - (4)].lval); - (yyval.addr).u.argsize = (yyvsp[(4) - (4)].lval); - } - break; - - case 149: -#line 862 "a.y" - { - (yyval.addr) = (yyvsp[(2) - (2)].addr); - (yyval.addr).type = TYPE_ADDR; - } - break; - - case 150: -#line 867 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_SCONST; - memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval)); - } - break; - - case 151: -#line 875 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = (yyvsp[(2) - (2)].dval); - } - break; - - case 152: -#line 881 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_FCONST; - (yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval); - } - break; - - case 153: -#line 888 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_CONST; - (yyval.addr).offset = (yyvsp[(2) - (2)].lval); - } - break; - - case 155: -#line 897 "a.y" - { - if((yyval.lval) < 0 || (yyval.lval) >= NREG) - print("register value out of range\n"); - (yyval.lval) = REG_R0 + (yyvsp[(3) - (4)].lval); - } - break; - - case 156: -#line 905 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (3)].lval); - (yyval.addr).offset = 0; - } - break; - - case 157: -#line 912 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(2) - (5)].lval); - (yyval.addr).scale = (yyvsp[(4) - (5)].lval); - (yyval.addr).offset = 0; - } - break; - - case 159: -#line 923 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).reg = (yyvsp[(3) - (4)].lval); - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 160: -#line 932 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(3) - (4)].lval); - (yyval.addr).sym = nil; - (yyval.addr).offset = (yyvsp[(1) - (4)].lval); - } - break; - - case 161: -#line 940 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = (yyvsp[(4) - (5)].lval); - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0); - (yyval.addr).offset = (yyvsp[(2) - (5)].lval); - } - break; - - case 162: -#line 948 "a.y" - { - (yyval.addr) = nullgen; - (yyval.addr).type = TYPE_MEM; - (yyval.addr).name = NAME_STATIC; - (yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1); - (yyval.addr).offset = (yyvsp[(4) - (7)].lval); - } - break; - - case 165: -#line 960 "a.y" - { - (yyval.lval) = 0; - } - break; - - case 166: -#line 964 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 167: -#line 968 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 172: -#line 980 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (1)].sym)->value; - } - break; - - case 173: -#line 984 "a.y" - { - (yyval.lval) = -(yyvsp[(2) - (2)].lval); - } - break; - - case 174: -#line 988 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (2)].lval); - } - break; - - case 175: -#line 992 "a.y" - { - (yyval.lval) = ~(yyvsp[(2) - (2)].lval); - } - break; - - case 176: -#line 996 "a.y" - { - (yyval.lval) = (yyvsp[(2) - (3)].lval); - } - break; - - case 178: -#line 1003 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval); - } - break; - - case 179: -#line 1007 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval); - } - break; - - case 180: -#line 1011 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval); - } - break; - - case 181: -#line 1015 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval); - } - break; - - case 182: -#line 1019 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval); - } - break; - - case 183: -#line 1023 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval); - } - break; - - case 184: -#line 1027 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval); - } - break; - - case 185: -#line 1031 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval); - } - break; - - case 186: -#line 1035 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval); - } - break; - - case 187: -#line 1039 "a.y" - { - (yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval); - } - break; - - -/* Line 1267 of yacc.c. */ -#line 3253 "y.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse look-ahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse look-ahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - diff --git a/src/cmd/9a/y.tab.h b/src/cmd/9a/y.tab.h deleted file mode 100644 index e7b00330fa..0000000000 --- a/src/cmd/9a/y.tab.h +++ /dev/null @@ -1,190 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LMOVW = 258, - LMOVB = 259, - LABS = 260, - LLOGW = 261, - LSHW = 262, - LADDW = 263, - LCMP = 264, - LCROP = 265, - LBRA = 266, - LFMOV = 267, - LFCONV = 268, - LFCMP = 269, - LFADD = 270, - LFMA = 271, - LTRAP = 272, - LXORW = 273, - LNOP = 274, - LEND = 275, - LRETT = 276, - LWORD = 277, - LTEXT = 278, - LGLOBL = 279, - LDATA = 280, - LRETRN = 281, - LCONST = 282, - LSP = 283, - LSB = 284, - LFP = 285, - LPC = 286, - LCREG = 287, - LFLUSH = 288, - LREG = 289, - LFREG = 290, - LR = 291, - LCR = 292, - LF = 293, - LFPSCR = 294, - LLR = 295, - LCTR = 296, - LSPR = 297, - LSPREG = 298, - LSEG = 299, - LMSR = 300, - LPCDAT = 301, - LFUNCDAT = 302, - LSCHED = 303, - LXLD = 304, - LXST = 305, - LXOP = 306, - LXMV = 307, - LRLWM = 308, - LMOVMW = 309, - LMOVEM = 310, - LMOVFL = 311, - LMTFSB = 312, - LMA = 313, - LFCONST = 314, - LSCONST = 315, - LNAME = 316, - LLAB = 317, - LVAR = 318 - }; -#endif -/* Tokens. */ -#define LMOVW 258 -#define LMOVB 259 -#define LABS 260 -#define LLOGW 261 -#define LSHW 262 -#define LADDW 263 -#define LCMP 264 -#define LCROP 265 -#define LBRA 266 -#define LFMOV 267 -#define LFCONV 268 -#define LFCMP 269 -#define LFADD 270 -#define LFMA 271 -#define LTRAP 272 -#define LXORW 273 -#define LNOP 274 -#define LEND 275 -#define LRETT 276 -#define LWORD 277 -#define LTEXT 278 -#define LGLOBL 279 -#define LDATA 280 -#define LRETRN 281 -#define LCONST 282 -#define LSP 283 -#define LSB 284 -#define LFP 285 -#define LPC 286 -#define LCREG 287 -#define LFLUSH 288 -#define LREG 289 -#define LFREG 290 -#define LR 291 -#define LCR 292 -#define LF 293 -#define LFPSCR 294 -#define LLR 295 -#define LCTR 296 -#define LSPR 297 -#define LSPREG 298 -#define LSEG 299 -#define LMSR 300 -#define LPCDAT 301 -#define LFUNCDAT 302 -#define LSCHED 303 -#define LXLD 304 -#define LXST 305 -#define LXOP 306 -#define LXMV 307 -#define LRLWM 308 -#define LMOVMW 309 -#define LMOVEM 310 -#define LMOVFL 311 -#define LMTFSB 312 -#define LMA 313 -#define LFCONST 314 -#define LSCONST 315 -#define LNAME 316 -#define LLAB 317 -#define LVAR 318 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 38 "a.y" -{ - Sym *sym; - vlong lval; - double dval; - char sval[8]; - Addr addr; -} -/* Line 1529 of yacc.c. */ -#line 183 "y.tab.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/src/cmd/9g/cgen.c b/src/cmd/9g/cgen.c deleted file mode 100644 index 009ea1ed7a..0000000000 --- a/src/cmd/9g/cgen.c +++ /dev/null @@ -1,1758 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -void -cgen(Node *n, Node *res) -{ - Node *nl, *nr, *r; - Node n1, n2; - int a, f; - Prog *p1, *p2, *p3; - Addr addr; - -//print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable); - if(debug['g']) { - dump("\ncgen-n", n); - dump("cgen-res", res); - } - if(n == N || n->type == T) - goto ret; - - if(res == N || res->type == T) - fatal("cgen: res nil"); - - while(n->op == OCONVNOP) - n = n->left; - - switch(n->op) { - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_slice(n, &n1); - cgen(&n1, res); - } else - cgen_slice(n, res); - goto ret; - case OEFACE: - if (res->op != ONAME || !res->addable) { - tempname(&n1, n->type); - cgen_eface(n, &n1); - cgen(&n1, res); - } else - cgen_eface(n, res); - goto ret; - } - - if(n->ullman >= UINF) { - if(n->op == OINDREG) - fatal("cgen: this is going to misscompile"); - if(res->ullman >= UINF) { - tempname(&n1, n->type); - cgen(n, &n1); - cgen(&n1, res); - goto ret; - } - } - - if(isfat(n->type)) { - if(n->type->width < 0) - fatal("forgot to compute width for %T", n->type); - sgen(n, res, n->type->width); - goto ret; - } - - if(!res->addable) { - if(n->ullman > res->ullman) { - regalloc(&n1, n->type, res); - cgen(n, &n1); - if(n1.ullman > res->ullman) { - dump("n1", &n1); - dump("res", res); - fatal("loop in cgen"); - } - cgen(&n1, res); - regfree(&n1); - goto ret; - } - - if(res->ullman >= UINF) - goto gen; - - if(complexop(n, res)) { - complexgen(n, res); - goto ret; - } - - f = 1; // gen thru register - switch(n->op) { - case OLITERAL: - if(smallintconst(n)) - f = 0; - break; - case OREGISTER: - f = 0; - break; - } - - if(!iscomplex[n->type->etype]) { - a = optoas(OAS, res->type); - if(sudoaddable(a, res, &addr)) { - if(f) { - regalloc(&n2, res->type, N); - cgen(n, &n2); - p1 = gins(a, &n2, N); - regfree(&n2); - } else - p1 = gins(a, n, N); - p1->to = addr; - if(debug['g']) - print("%P [ignore previous line]\n", p1); - sudoclean(); - goto ret; - } - } - - gen: - igen(res, &n1, N); - cgen(n, &n1); - regfree(&n1); - goto ret; - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch(n->op) { - case OSPTR: - case OLEN: - if(isslice(n->left->type) || istype(n->left->type, TSTRING)) - n->addable = n->left->addable; - break; - case OCAP: - if(isslice(n->left->type)) - n->addable = n->left->addable; - break; - case OITAB: - n->addable = n->left->addable; - break; - } - - if(complexop(n, res)) { - complexgen(n, res); - goto ret; - } - - // if both are addressable, move - if(n->addable) { - if(n->op == OREGISTER || res->op == OREGISTER) { - gmove(n, res); - } else { - regalloc(&n1, n->type, N); - gmove(n, &n1); - cgen(&n1, res); - regfree(&n1); - } - goto ret; - } - - nl = n->left; - nr = n->right; - - if(nl != N && nl->ullman >= UINF) - if(nr != N && nr->ullman >= UINF) { - tempname(&n1, nl->type); - cgen(nl, &n1); - n2 = *n; - n2.left = &n1; - cgen(&n2, res); - goto ret; - } - - if(!iscomplex[n->type->etype]) { - a = optoas(OAS, n->type); - if(sudoaddable(a, n, &addr)) { - if(res->op == OREGISTER) { - p1 = gins(a, N, res); - p1->from = addr; - } else { - regalloc(&n2, n->type, N); - p1 = gins(a, N, &n2); - p1->from = addr; - gins(a, &n2, res); - regfree(&n2); - } - sudoclean(); - goto ret; - } - } - - // TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize - // OGE, OLE, and ONE ourselves. - // if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt; - - switch(n->op) { - default: - dump("cgen", n); - fatal("cgen: unknown op %+hN", n); - break; - - // these call bgen to get a bool value - case OOROR: - case OANDAND: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case ONOT: - p1 = gbranch(ABR, T, 0); - p2 = pc; - gmove(nodbool(1), res); - p3 = gbranch(ABR, T, 0); - patch(p1, pc); - bgen(n, 1, 0, p2); - gmove(nodbool(0), res); - patch(p3, pc); - goto ret; - - case OPLUS: - cgen(nl, res); - goto ret; - - // unary - case OCOM: - a = optoas(OXOR, nl->type); - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - nodconst(&n2, nl->type, -1); - gins(a, &n2, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - - case OMINUS: - if(isfloat[nl->type->etype]) { - nr = nodintconst(-1); - convlit(&nr, n->type); - a = optoas(OMUL, nl->type); - goto sbop; - } - a = optoas(n->op, nl->type); - goto uop; - - // symmetric binary - case OAND: - case OOR: - case OXOR: - case OADD: - case OMUL: - a = optoas(n->op, nl->type); - goto sbop; - - // asymmetric binary - case OSUB: - a = optoas(n->op, nl->type); - goto abop; - - case OHMUL: - cgen_hmul(nl, nr, res); - break; - - case OCONV: - if(n->type->width > nl->type->width) { - // If loading from memory, do conversion during load, - // so as to avoid use of 8-bit register in, say, int(*byteptr). - switch(nl->op) { - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: - igen(nl, &n1, res); - regalloc(&n2, n->type, res); - gmove(&n1, &n2); - gmove(&n2, res); - regfree(&n2); - regfree(&n1); - goto ret; - } - } - - regalloc(&n1, nl->type, res); - regalloc(&n2, n->type, &n1); - cgen(nl, &n1); - - // if we do the conversion n1 -> n2 here - // reusing the register, then gmove won't - // have to allocate its own register. - gmove(&n1, &n2); - gmove(&n2, res); - regfree(&n2); - regfree(&n1); - break; - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case OITAB: - // interface table is first word of interface value - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OSPTR: - // pointer is the first word of string or slice. - if(isconst(nl, CTSTR)) { - regalloc(&n1, types[tptr], res); - p1 = gins(AMOVD, N, &n1); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - gmove(&n1, res); - regfree(&n1); - break; - } - igen(nl, &n1, res); - n1.type = n->type; - gmove(&n1, res); - regfree(&n1); - break; - - case OLEN: - if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) { - // map and chan have len in the first int-sized word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); - - n2 = n1; - n2.op = OINDREG; - n2.type = types[simtype[TINT]]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(istype(nl->type, TSTRING) || isslice(nl->type)) { - // both slice and string have len one pointer into the struct. - // a zero pointer means zero length - igen(nl, &n1, res); - n1.type = types[simtype[TUINT]]; - n1.xoffset += Array_nel; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OLEN: unknown type %lT", nl->type); - break; - - case OCAP: - if(istype(nl->type, TCHAN)) { - // chan has cap in the second int-sized word. - // a zero pointer means zero length - regalloc(&n1, types[tptr], res); - cgen(nl, &n1); - - nodconst(&n2, types[tptr], 0); - gins(optoas(OCMP, types[tptr]), &n1, &n2); - p1 = gbranch(optoas(OEQ, types[tptr]), T, 0); - - n2 = n1; - n2.op = OINDREG; - n2.xoffset = widthint; - n2.type = types[simtype[TINT]]; - gmove(&n2, &n1); - - patch(p1, pc); - - gmove(&n1, res); - regfree(&n1); - break; - } - if(isslice(nl->type)) { - igen(nl, &n1, res); - n1.type = types[simtype[TUINT]]; - n1.xoffset += Array_cap; - gmove(&n1, res); - regfree(&n1); - break; - } - fatal("cgen: OCAP: unknown type %lT", nl->type); - break; - - case OADDR: - if(n->bounded) // let race detector avoid nil checks - disable_checknil++; - agen(nl, res); - if(n->bounded) - disable_checknil--; - break; - - case OCALLMETH: - cgen_callmeth(n, 0); - cgen_callret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_callret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_callret(n, res); - break; - - case OMOD: - case ODIV: - if(isfloat[n->type->etype]) { - a = optoas(n->op, nl->type); - goto abop; - } - - if(nl->ullman >= nr->ullman) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - cgen_div(n->op, &n1, nr, res); - regfree(&n1); - } else { - if(!smallintconst(nr)) { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - } else { - n2 = *nr; - } - cgen_div(n->op, nl, &n2, res); - if(n2.op != OLITERAL) - regfree(&n2); - } - break; - - case OLSH: - case ORSH: - case OLROT: - cgen_shift(n->op, n->bounded, nl, nr, res); - break; - } - goto ret; - -sbop: // symmetric binary - /* - * put simplest on right - we'll generate into left - * and then adjust it using the computation of right. - * constants and variables have the same ullman - * count, so look for constants specially. - * - * an integer constant we can use as an immediate - * is simpler than a variable - we can use the immediate - * in the adjustment instruction directly - so it goes - * on the right. - * - * other constants, like big integers or floating point - * constants, require a mov into a register, so those - * might as well go on the left, so we can reuse that - * register for the computation. - */ - if(nl->ullman < nr->ullman || - (nl->ullman == nr->ullman && - (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) { - r = nl; - nl = nr; - nr = r; - } - -abop: // asymmetric binary - if(nl->ullman >= nr->ullman) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - /* - * This generates smaller code - it avoids a MOV - but it's - * easily 10% slower due to not being able to - * optimize/manipulate the move. - * To see, run: go test -bench . crypto/md5 - * with and without. - * - if(sudoaddable(a, nr, &addr)) { - p1 = gins(a, N, &n1); - p1->from = addr; - gmove(&n1, res); - sudoclean(); - regfree(&n1); - goto ret; - } - * - */ - // TODO(minux): enable using constants directly in certain instructions. - //if(smallintconst(nr)) - // n2 = *nr; - //else { - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - //} - } else { - //if(smallintconst(nr)) - // n2 = *nr; - //else { - regalloc(&n2, nr->type, res); - cgen(nr, &n2); - //} - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - } - gins(a, &n2, &n1); - // Normalize result for types smaller than word. - if(n->type->width < widthreg) { - switch(n->op) { - case OADD: - case OSUB: - case OMUL: - case OLSH: - gins(optoas(OAS, n->type), &n1, &n1); - break; - } - } - gmove(&n1, res); - regfree(&n1); - if(n2.op != OLITERAL) - regfree(&n2); - goto ret; - -uop: // unary - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - gins(a, N, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - -ret: - ; -} - -/* - * allocate a register (reusing res if possible) and generate - * a = n - * The caller must call regfree(a). - */ -void -cgenr(Node *n, Node *a, Node *res) -{ - Node n1; - - if(debug['g']) - dump("cgenr-n", n); - - if(isfat(n->type)) - fatal("cgenr on fat node"); - - if(n->addable) { - regalloc(a, n->type, res); - gmove(n, a); - return; - } - - switch(n->op) { - case ONAME: - case ODOT: - case ODOTPTR: - case OINDEX: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - gmove(&n1, a); - regfree(&n1); - break; - default: - regalloc(a, n->type, res); - cgen(n, a); - break; - } -} - -/* - * allocate a register (reusing res if possible) and generate - * a = &n - * The caller must call regfree(a). - * The generated code checks that the result is not nil. - */ -void -agenr(Node *n, Node *a, Node *res) -{ - Node *nl, *nr; - Node n1, n2, n3, n4, tmp; - Prog *p1, *p2; - uint32 w; - uint64 v; - - if(debug['g']) - dump("agenr-n", n); - - nl = n->left; - nr = n->right; - - switch(n->op) { - case ODOT: - case ODOTPTR: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - igen(n, &n1, res); - regalloc(a, types[tptr], &n1); - agen(&n1, a); - regfree(&n1); - break; - - case OIND: - cgenr(n->left, a, res); - cgen_checknil(a); - break; - - case OINDEX: - p2 = nil; // to be patched to panicindex. - w = n->type->width; - //bounded = debug['B'] || n->bounded; - if(nr->addable) { - if(!isconst(nr, CTINT)) - tempname(&tmp, types[TINT64]); - if(!isconst(nl, CTSTR)) - agenr(nl, &n3, res); - if(!isconst(nr, CTINT)) { - cgen(nr, &tmp); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - } else if(nl->addable) { - if(!isconst(nr, CTINT)) { - tempname(&tmp, types[TINT64]); - cgen(nr, &tmp); - regalloc(&n1, tmp.type, N); - gmove(&tmp, &n1); - } - if(!isconst(nl, CTSTR)) { - agenr(nl, &n3, res); - } - } else { - tempname(&tmp, types[TINT64]); - cgen(nr, &tmp); - nr = &tmp; - if(!isconst(nl, CTSTR)) - agenr(nl, &n3, res); - regalloc(&n1, tmp.type, N); - gins(optoas(OAS, tmp.type), &tmp, &n1); - } - - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // w is width - - // constant index - if(isconst(nr, CTINT)) { - if(isconst(nl, CTSTR)) - fatal("constant string constant index"); - v = mpgetfix(nr->val.u.xval); - if(isslice(nl->type) || nl->type->etype == TSTRING) { - if(!debug['B'] && !n->bounded) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - regalloc(&n4, n1.type, N); - gmove(&n1, &n4); - ginscon2(optoas(OCMP, types[TUINT64]), &n4, v); - regfree(&n4); - p1 = gbranch(optoas(OGT, types[TUINT64]), T, +1); - ginscall(panicindex, 0); - patch(p1, pc); - } - - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, &n3); - } - - if (v*w != 0) { - ginscon(optoas(OADD, types[tptr]), v*w, &n3); - } - *a = n3; - break; - } - - regalloc(&n2, types[TINT64], &n1); // i - gmove(&n1, &n2); - regfree(&n1); - - if(!debug['B'] && !n->bounded) { - // check bounds - if(isconst(nl, CTSTR)) { - nodconst(&n4, types[TUINT64], nl->val.u.sval->len); - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_nel; - regalloc(&n4, types[TUINT64], N); - gmove(&n1, &n4); - } else { - if(nl->type->bound < (1<<15)-1) - nodconst(&n4, types[TUINT64], nl->type->bound); - else { - regalloc(&n4, types[TUINT64], N); - p1 = gins(AMOVD, N, &n4); - p1->from.type = TYPE_CONST; - p1->from.offset = nl->type->bound; - } - } - gins(optoas(OCMP, types[TUINT64]), &n2, &n4); - if(n4.op == OREGISTER) - regfree(&n4); - p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); - if(p2) - patch(p2, pc); - ginscall(panicindex, 0); - patch(p1, pc); - } - - if(isconst(nl, CTSTR)) { - regalloc(&n3, types[tptr], res); - p1 = gins(AMOVD, N, &n3); - datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from); - p1->from.type = TYPE_ADDR; - } else if(isslice(nl->type) || nl->type->etype == TSTRING) { - n1 = n3; - n1.op = OINDREG; - n1.type = types[tptr]; - n1.xoffset = Array_array; - gmove(&n1, &n3); - } - - if(w == 0) { - // nothing to do - } else if(w == 1) { - /* w already scaled */ - gins(optoas(OADD, types[tptr]), &n2, &n3); - } /* else if(w == 2 || w == 4 || w == 8) { - // TODO(minux): scale using shift - } */ else { - regalloc(&n4, types[TUINT64], N); - nodconst(&n1, types[TUINT64], w); - gmove(&n1, &n4); - gins(optoas(OMUL, types[TUINT64]), &n4, &n2); - gins(optoas(OADD, types[tptr]), &n2, &n3); - regfree(&n4); - } - - *a = n3; - regfree(&n2); - break; - - default: - regalloc(a, types[tptr], res); - agen(n, a); - break; - } -} - -static void -ginsadd(int as, vlong off, Node *dst) -{ - Node n1; - - regalloc(&n1, types[tptr], dst); - gmove(dst, &n1); - ginscon(as, off, &n1); - gmove(&n1, dst); - regfree(&n1); -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -void -agen(Node *n, Node *res) -{ - Node *nl; - Node n1, n2, n3; - - if(debug['g']) { - dump("\nagen-res", res); - dump("agen-r", n); - } - if(n == N || n->type == T) - return; - - while(n->op == OCONVNOP) - n = n->left; - - if(isconst(n, CTNIL) && n->type->width > widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - tempname(&n1, n->type); - gvardef(&n1); - clearfat(&n1); - regalloc(&n2, types[tptr], res); - memset(&n3, 0, sizeof n3); - n3.op = OADDR; - n3.left = &n1; - gins(AMOVD, &n3, &n2); - gmove(&n2, res); - regfree(&n2); - goto ret; - } - - if(n->addable) { - memset(&n1, 0, sizeof n1); - n1.op = OADDR; - n1.left = n; - regalloc(&n2, types[tptr], res); - gins(AMOVD, &n1, &n2); - gmove(&n2, res); - regfree(&n2); - goto ret; - } - - nl = n->left; - - switch(n->op) { - default: - fatal("agen: unknown op %+hN", n); - break; - - case OCALLMETH: - // TODO(minux): 5g has this: Release res so that it is available for cgen_call. - // Pick it up again after the call for OCALLMETH and OCALLFUNC. - cgen_callmeth(n, 0); - cgen_aret(n, res); - break; - - case OCALLINTER: - cgen_callinter(n, res, 0); - cgen_aret(n, res); - break; - - case OCALLFUNC: - cgen_call(n, 0); - cgen_aret(n, res); - break; - - case OSLICE: - case OSLICEARR: - case OSLICESTR: - case OSLICE3: - case OSLICE3ARR: - tempname(&n1, n->type); - cgen_slice(n, &n1); - agen(&n1, res); - break; - - case OEFACE: - tempname(&n1, n->type); - cgen_eface(n, &n1); - agen(&n1, res); - break; - - case OINDEX: - agenr(n, &n1, res); - gmove(&n1, res); - regfree(&n1); - break; - - case ONAME: - // should only get here with names in this func. - if(n->funcdepth > 0 && n->funcdepth != funcdepth) { - dump("bad agen", n); - fatal("agen: bad ONAME funcdepth %d != %d", - n->funcdepth, funcdepth); - } - - // should only get here for heap vars or paramref - if(!(n->class & PHEAP) && n->class != PPARAMREF) { - dump("bad agen", n); - fatal("agen: bad ONAME class %#x", n->class); - } - cgen(n->heapaddr, res); - if(n->xoffset != 0) { - ginsadd(optoas(OADD, types[tptr]), n->xoffset, res); - } - break; - - case OIND: - cgen(nl, res); - cgen_checknil(res); - break; - - case ODOT: - agen(nl, res); - if(n->xoffset != 0) { - ginsadd(optoas(OADD, types[tptr]), n->xoffset, res); - } - break; - - case ODOTPTR: - cgen(nl, res); - cgen_checknil(res); - if(n->xoffset != 0) { - ginsadd(optoas(OADD, types[tptr]), n->xoffset, res); - } - break; - } - -ret: - ; -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -void -igen(Node *n, Node *a, Node *res) -{ - Type *fp; - Iter flist; - Node n1; - - if(debug['g']) { - dump("\nigen-n", n); - } - switch(n->op) { - case ONAME: - if((n->class&PHEAP) || n->class == PPARAMREF) - break; - *a = *n; - return; - - case OINDREG: - // Increase the refcount of the register so that igen's caller - // has to call regfree. - if(n->val.u.reg != REGSP) - reg[n->val.u.reg]++; - *a = *n; - return; - - case ODOT: - igen(n->left, a, res); - a->xoffset += n->xoffset; - a->type = n->type; - fixlargeoffset(a); - return; - - case ODOTPTR: - cgenr(n->left, a, res); - cgen_checknil(a); - a->op = OINDREG; - a->xoffset += n->xoffset; - a->type = n->type; - fixlargeoffset(a); - return; - - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - switch(n->op) { - case OCALLFUNC: - cgen_call(n, 0); - break; - case OCALLMETH: - cgen_callmeth(n, 0); - break; - case OCALLINTER: - cgen_callinter(n, N, 0); - break; - } - fp = structfirst(&flist, getoutarg(n->left->type)); - memset(a, 0, sizeof *a); - a->op = OINDREG; - a->val.u.reg = REGSP; - a->addable = 1; - a->xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP) - a->type = n->type; - return; - - case OINDEX: - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - if(isfixedarray(n->left->type) || - (isptr[n->left->type->etype] && isfixedarray(n->left->left->type))) - if(isconst(n->right, CTINT)) { - // Compute &a. - if(!isptr[n->left->type->etype]) - igen(n->left, a, res); - else { - igen(n->left, &n1, res); - cgen_checknil(&n1); - regalloc(a, types[tptr], res); - gmove(&n1, a); - regfree(&n1); - a->op = OINDREG; - } - - // Compute &a[i] as &a + i*width. - a->type = n->type; - a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width; - fixlargeoffset(a); - return; - } - break; - } - - agenr(n, a, res); - a->op = OINDREG; - a->type = n->type; -} - -/* - * generate: - * if(n == true) goto to; - */ -void -bgen(Node *n, int true, int likely, Prog *to) -{ - int et, a; - Node *nl, *nr, *l, *r; - Node n1, n2, tmp; - NodeList *ll; - Prog *p1, *p2; - - if(debug['g']) { - dump("\nbgen", n); - } - - if(n == N) - n = nodbool(1); - - if(n->ninit != nil) - genlist(n->ninit); - - if(n->type == T) { - convlit(&n, types[TBOOL]); - if(n->type == T) - goto ret; - } - - et = n->type->etype; - if(et != TBOOL) { - yyerror("cgen: bad type %T for %O", n->type, n->op); - patch(gins(AEND, N, N), to); - goto ret; - } - nr = N; - - while(n->op == OCONVNOP) { - n = n->left; - if(n->ninit != nil) - genlist(n->ninit); - } - - switch(n->op) { - default: - regalloc(&n1, n->type, N); - cgen(n, &n1); - nodconst(&n2, n->type, 0); - gins(optoas(OCMP, n->type), &n1, &n2); - a = ABNE; - if(!true) - a = ABEQ; - patch(gbranch(a, n->type, likely), to); - regfree(&n1); - goto ret; - - case OLITERAL: - // need to ask if it is bool? - if(!true == !n->val.u.bval) - patch(gbranch(ABR, T, likely), to); - goto ret; - - case OANDAND: - case OOROR: - if((n->op == OANDAND) == true) { - p1 = gbranch(AJMP, T, 0); - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - bgen(n->left, !true, -likely, p2); - bgen(n->right, !true, -likely, p2); - p1 = gbranch(AJMP, T, 0); - patch(p1, to); - patch(p2, pc); - } else { - bgen(n->left, true, likely, to); - bgen(n->right, true, likely, to); - } - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - nr = n->right; - if(nr == N || nr->type == T) - goto ret; - - case ONOT: // unary - nl = n->left; - if(nl == N || nl->type == T) - goto ret; - break; - } - - switch(n->op) { - - case ONOT: - bgen(nl, !true, likely, to); - goto ret; - - case OEQ: - case ONE: - case OLT: - case OGT: - case OLE: - case OGE: - a = n->op; - if(!true) { - if(isfloat[nr->type->etype]) { - // brcom is not valid on floats when NaN is involved. - p1 = gbranch(ABR, T, 0); - p2 = gbranch(ABR, T, 0); - patch(p1, pc); - ll = n->ninit; // avoid re-genning ninit - n->ninit = nil; - bgen(n, 1, -likely, p2); - n->ninit = ll; - patch(gbranch(ABR, T, 0), to); - patch(p2, pc); - goto ret; - } - a = brcom(a); - true = !true; - } - - // make simplest on right - if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) { - a = brrev(a); - r = nl; - nl = nr; - nr = r; - } - - if(isslice(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal slice comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.xoffset += Array_array; - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - regalloc(&n2, types[tptr], &n1); - gmove(&n1, &n2); - gins(optoas(OCMP, types[tptr]), &n2, &tmp); - regfree(&n2); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - - if(isinter(nl->type)) { - // front end should only leave cmp to literal nil - if((a != OEQ && a != ONE) || nr->op != OLITERAL) { - yyerror("illegal interface comparison"); - break; - } - a = optoas(a, types[tptr]); - igen(nl, &n1, N); - n1.type = types[tptr]; - nodconst(&tmp, types[tptr], 0); - regalloc(&n2, types[tptr], &n1); - gmove(&n1, &n2); - gins(optoas(OCMP, types[tptr]), &n2, &tmp); - regfree(&n2); - patch(gbranch(a, types[tptr], likely), to); - regfree(&n1); - break; - } - if(iscomplex[nl->type->etype]) { - complexbool(a, nl, nr, true, likely, to); - break; - } - - if(nr->ullman >= UINF) { - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - - tempname(&tmp, nl->type); - gmove(&n1, &tmp); - regfree(&n1); - - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - - regalloc(&n1, nl->type, N); - cgen(&tmp, &n1); - - goto cmp; - } - - regalloc(&n1, nl->type, N); - cgen(nl, &n1); - - // TODO(minux): cmpi does accept 16-bit signed immediate as p->to. - // and cmpli accepts 16-bit unsigned immediate. - //if(smallintconst(nr)) { - // gins(optoas(OCMP, nr->type), &n1, nr); - // patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - // regfree(&n1); - // break; - //} - - regalloc(&n2, nr->type, N); - cgen(nr, &n2); - cmp: - l = &n1; - r = &n2; - gins(optoas(OCMP, nr->type), l, r); - if(isfloat[nr->type->etype] && (a == OLE || a == OGE)) { - // To get NaN right, must rewrite x <= y into separate x < y or x = y. - switch(a) { - case OLE: - a = OLT; - break; - case OGE: - a = OGT; - break; - } - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - patch(gbranch(optoas(OEQ, nr->type), nr->type, likely), to); - } else { - patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - } - regfree(&n1); - regfree(&n2); - break; - } - goto ret; - -ret: - ; -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -int64 -stkof(Node *n) -{ - Type *t; - Iter flist; - int64 off; - - switch(n->op) { - case OINDREG: - return n->xoffset; - - case ODOT: - t = n->left->type; - if(isptr[t->etype]) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - return off + n->xoffset; - - case OINDEX: - t = n->left->type; - if(!isfixedarray(t)) - break; - off = stkof(n->left); - if(off == -1000 || off == 1000) - return off; - if(isconst(n->right, CTINT)) - return off + t->type->width * mpgetfix(n->right->val.u.xval); - return 1000; - - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - t = structfirst(&flist, getoutarg(t)); - if(t != T) - return t->width + widthptr; // +widthptr: correct for saved LR - break; - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000; -} - -/* - * block copy: - * memmove(&ns, &n, w); - */ -void -sgen(Node *n, Node *ns, int64 w) -{ - Node dst, src, tmp, nend; - int32 c, odst, osrc; - int dir, align, op; - Prog *p, *ploop; - NodeList *l; - Node *res = ns; - - if(debug['g']) { - print("\nsgen w=%lld\n", w); - dump("r", n); - dump("res", ns); - } - - if(n->ullman >= UINF && ns->ullman >= UINF) - fatal("sgen UINF"); - - if(w < 0) - fatal("sgen copy %lld", w); - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0) - for(l = curfn->dcl; l != nil; l = l->next) - if(l->n->class == PPARAMOUT) - gvardef(l->n); - - // Avoid taking the address for simple enough types. - //if(componentgen(n, ns)) - // return; - - if(w == 0) { - // evaluate side effects only. - regalloc(&dst, types[tptr], N); - agen(res, &dst); - agen(n, &dst); - regfree(&dst); - return; - } - - // determine alignment. - // want to avoid unaligned access, so have to use - // smaller operations for less aligned types. - // for example moving [4]byte must use 4 MOVB not 1 MOVW. - align = n->type->align; - switch(align) { - default: - fatal("sgen: invalid alignment %d for %T", align, n->type); - case 1: - op = AMOVBU; - break; - case 2: - op = AMOVHU; - break; - case 4: - op = AMOVWZU; // there is no lwau, only lwaux - break; - case 8: - op = AMOVDU; - break; - } - if(w%align) - fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type); - c = w / align; - - // offset on the stack - osrc = stkof(n); - odst = stkof(res); - if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - tempname(&tmp, n->type); - sgen(n, &tmp, w); - sgen(&tmp, res, w); - return; - } - if(osrc%align != 0 || odst%align != 0) - fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align); - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - dir = align; - if(osrc < odst && odst < osrc+w) - dir = -dir; - - if(n->ullman >= res->ullman) { - agenr(n, &dst, res); // temporarily use dst - regalloc(&src, types[tptr], N); - gins(AMOVD, &dst, &src); - if(res->op == ONAME) - gvardef(res); - agen(res, &dst); - } else { - if(res->op == ONAME) - gvardef(res); - agenr(res, &dst, res); - agenr(n, &src, N); - } - - regalloc(&tmp, types[tptr], N); - - // set up end marker - memset(&nend, 0, sizeof nend); - - // move src and dest to the end of block if necessary - if(dir < 0) { - if(c >= 4) { - regalloc(&nend, types[tptr], N); - p = gins(AMOVD, &src, &nend); - } - - p = gins(AADD, N, &src); - p->from.type = TYPE_CONST; - p->from.offset = w; - - p = gins(AADD, N, &dst); - p->from.type = TYPE_CONST; - p->from.offset = w; - } else { - p = gins(AADD, N, &src); - p->from.type = TYPE_CONST; - p->from.offset = -dir; - - p = gins(AADD, N, &dst); - p->from.type = TYPE_CONST; - p->from.offset = -dir; - - if(c >= 4) { - regalloc(&nend, types[tptr], N); - p = gins(AMOVD, &src, &nend); - p->from.type = TYPE_ADDR; - p->from.offset = w; - } - } - - - // move - // TODO: enable duffcopy for larger copies. - if(c >= 4) { - p = gins(op, &src, &tmp); - p->from.type = TYPE_MEM; - p->from.offset = dir; - ploop = p; - - p = gins(op, &tmp, &dst); - p->to.type = TYPE_MEM; - p->to.offset = dir; - - p = gins(ACMP, &src, &nend); - - patch(gbranch(ABNE, T, 0), ploop); - regfree(&nend); - } else { - // TODO(austin): Instead of generating ADD $-8,R8; ADD - // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just - // generate the offsets directly and eliminate the - // ADDs. That will produce shorter, more - // pipeline-able code. - while(c-- > 0) { - p = gins(op, &src, &tmp); - p->from.type = TYPE_MEM; - p->from.offset = dir; - - p = gins(op, &tmp, &dst); - p->to.type = TYPE_MEM; - p->to.offset = dir; - } - } - - regfree(&dst); - regfree(&src); - regfree(&tmp); -} - -static int -cadable(Node *n) -{ - if(!n->addable) { - // dont know how it happens, - // but it does - return 0; - } - - switch(n->op) { - case ONAME: - return 1; - } - return 0; -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -int -componentgen(Node *nr, Node *nl) -{ - Node nodl, nodr, tmp; - Type *t; - int freel, freer; - vlong fldcount; - vlong loffset, roffset; - - freel = 0; - freer = 0; - - switch(nl->type->etype) { - default: - goto no; - - case TARRAY: - t = nl->type; - - // Slices are ok. - if(isslice(t)) - break; - // Small arrays are ok. - if(t->bound > 0 && t->bound <= 3 && !isfat(t->type)) - break; - - goto no; - - case TSTRUCT: - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - fldcount = 0; - for(t=nl->type->type; t; t=t->down) { - if(isfat(t->type)) - goto no; - if(t->etype != TFIELD) - fatal("componentgen: not a TFIELD: %lT", t); - fldcount++; - } - if(fldcount == 0 || fldcount > 4) - goto no; - - break; - - case TSTRING: - case TINTER: - break; - } - - nodl = *nl; - if(!cadable(nl)) { - if(nr != N && !cadable(nr)) - goto no; - igen(nl, &nodl, N); - freel = 1; - } - - if(nr != N) { - nodr = *nr; - if(!cadable(nr)) { - igen(nr, &nodr, N); - freer = 1; - } - } else { - // When zeroing, prepare a register containing zero. - nodconst(&tmp, nl->type, 0); - regalloc(&nodr, types[TUINT], N); - gmove(&tmp, &nodr); - freer = 1; - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr) - goto yes; - - switch(nl->type->etype) { - case TARRAY: - // componentgen for arrays. - if(nl->op == ONAME) - gvardef(nl); - t = nl->type; - if(!isslice(t)) { - nodl.type = t->type; - nodr.type = nodl.type; - for(fldcount=0; fldcount < t->bound; fldcount++) { - if(nr == N) - clearslim(&nodl); - else - gmove(&nodr, &nodl); - nodl.xoffset += t->type->width; - nodr.xoffset += t->type->width; - } - goto yes; - } - - // componentgen for slices. - nodl.xoffset += Array_array; - nodl.type = ptrto(nl->type->type); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_cap-Array_nel; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_cap-Array_nel; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRING: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = types[simtype[TUINT]]; - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TINTER: - if(nl->op == ONAME) - gvardef(nl); - nodl.xoffset += Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - nodl.xoffset += Array_nel-Array_array; - nodl.type = ptrto(types[TUINT8]); - - if(nr != N) { - nodr.xoffset += Array_nel-Array_array; - nodr.type = nodl.type; - } - gmove(&nodr, &nodl); - - goto yes; - - case TSTRUCT: - if(nl->op == ONAME) - gvardef(nl); - loffset = nodl.xoffset; - roffset = nodr.xoffset; - // funarg structs may not begin at offset zero. - if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type) - loffset -= nl->type->type->width; - if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type) - roffset -= nr->type->type->width; - - for(t=nl->type->type; t; t=t->down) { - nodl.xoffset = loffset + t->width; - nodl.type = t->type; - - if(nr == N) - clearslim(&nodl); - else { - nodr.xoffset = roffset + t->width; - nodr.type = nodl.type; - gmove(&nodr, &nodl); - } - } - goto yes; - } - -no: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 0; - -yes: - if(freer) - regfree(&nodr); - if(freel) - regfree(&nodl); - return 1; -} diff --git a/src/cmd/9g/cgen.go b/src/cmd/9g/cgen.go new file mode 100644 index 0000000000..7a1e967267 --- /dev/null +++ b/src/cmd/9g/cgen.go @@ -0,0 +1,1888 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" + "fmt" +) +import "cmd/internal/gc" + +/* + * peep.c + */ +/* + * generate: + * res = n; + * simplifies and calls gmove. + */ +func cgen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var a int + var f int + var p1 *obj.Prog + var p2 *obj.Prog + var p3 *obj.Prog + var addr obj.Addr + + //print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable); + if gc.Debug['g'] != 0 { + gc.Dump("\ncgen-n", n) + gc.Dump("cgen-res", res) + } + + if n == nil || n.Type == nil { + goto ret + } + + if res == nil || res.Type == nil { + gc.Fatal("cgen: res nil") + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + switch n.Op { + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_slice(n, res) + } + goto ret + + case gc.OEFACE: + if res.Op != gc.ONAME || res.Addable == 0 { + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + cgen(&n1, res) + } else { + gc.Cgen_eface(n, res) + } + goto ret + } + + if n.Ullman >= gc.UINF { + if n.Op == gc.OINDREG { + gc.Fatal("cgen: this is going to misscompile") + } + if res.Ullman >= gc.UINF { + gc.Tempname(&n1, n.Type) + cgen(n, &n1) + cgen(&n1, res) + goto ret + } + } + + if gc.Isfat(n.Type) { + if n.Type.Width < 0 { + gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) + } + sgen(n, res, n.Type.Width) + goto ret + } + + if res.Addable == 0 { + if n.Ullman > res.Ullman { + regalloc(&n1, n.Type, res) + cgen(n, &n1) + if n1.Ullman > res.Ullman { + gc.Dump("n1", &n1) + gc.Dump("res", res) + gc.Fatal("loop in cgen") + } + + cgen(&n1, res) + regfree(&n1) + goto ret + } + + if res.Ullman >= gc.UINF { + goto gen + } + + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + goto ret + } + + f = 1 // gen thru register + switch n.Op { + case gc.OLITERAL: + if gc.Smallintconst(n) { + f = 0 + } + + case gc.OREGISTER: + f = 0 + } + + if gc.Iscomplex[n.Type.Etype] == 0 { + a = optoas(gc.OAS, res.Type) + if sudoaddable(a, res, &addr) { + if f != 0 { + regalloc(&n2, res.Type, nil) + cgen(n, &n2) + p1 = gins(a, &n2, nil) + regfree(&n2) + } else { + p1 = gins(a, n, nil) + } + p1.To = addr + if gc.Debug['g'] != 0 { + fmt.Printf("%v [ignore previous line]\n", p1) + } + sudoclean() + goto ret + } + } + + gen: + igen(res, &n1, nil) + cgen(n, &n1) + regfree(&n1) + goto ret + } + + // update addressability for string, slice + // can't do in walk because n->left->addable + // changes if n->left is an escaping local variable. + switch n.Op { + case gc.OSPTR, + gc.OLEN: + if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { + n.Addable = n.Left.Addable + } + + case gc.OCAP: + if gc.Isslice(n.Left.Type) { + n.Addable = n.Left.Addable + } + + case gc.OITAB: + n.Addable = n.Left.Addable + } + + if gc.Complexop(n, res) { + gc.Complexgen(n, res) + goto ret + } + + // if both are addressable, move + if n.Addable != 0 { + if n.Op == gc.OREGISTER || res.Op == gc.OREGISTER { + gmove(n, res) + } else { + regalloc(&n1, n.Type, nil) + gmove(n, &n1) + cgen(&n1, res) + regfree(&n1) + } + + goto ret + } + + nl = n.Left + nr = n.Right + + if nl != nil && nl.Ullman >= gc.UINF { + if nr != nil && nr.Ullman >= gc.UINF { + gc.Tempname(&n1, nl.Type) + cgen(nl, &n1) + n2 = *n + n2.Left = &n1 + cgen(&n2, res) + goto ret + } + } + + if gc.Iscomplex[n.Type.Etype] == 0 { + a = optoas(gc.OAS, n.Type) + if sudoaddable(a, n, &addr) { + if res.Op == gc.OREGISTER { + p1 = gins(a, nil, res) + p1.From = addr + } else { + regalloc(&n2, n.Type, nil) + p1 = gins(a, nil, &n2) + p1.From = addr + gins(a, &n2, res) + regfree(&n2) + } + + sudoclean() + goto ret + } + } + + // TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize + // OGE, OLE, and ONE ourselves. + // if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt; + + switch n.Op { + default: + gc.Dump("cgen", n) + gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + // these call bgen to get a bool value + case gc.OOROR, + gc.OANDAND, + gc.OEQ, + gc.ONE, + gc.OLT, + gc.OLE, + gc.OGE, + gc.OGT, + gc.ONOT: + p1 = gc.Gbranch(ppc64.ABR, nil, 0) + + p2 = gc.Pc + gmove(gc.Nodbool(true), res) + p3 = gc.Gbranch(ppc64.ABR, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n, true, 0, p2) + gmove(gc.Nodbool(false), res) + gc.Patch(p3, gc.Pc) + goto ret + + case gc.OPLUS: + cgen(nl, res) + goto ret + + // unary + case gc.OCOM: + a = optoas(gc.OXOR, nl.Type) + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + gc.Nodconst(&n2, nl.Type, -1) + gins(a, &n2, &n1) + gmove(&n1, res) + regfree(&n1) + goto ret + + case gc.OMINUS: + if gc.Isfloat[nl.Type.Etype] != 0 { + nr = gc.Nodintconst(-1) + gc.Convlit(&nr, n.Type) + a = optoas(gc.OMUL, nl.Type) + goto sbop + } + + a = optoas(int(n.Op), nl.Type) + goto uop + + // symmetric binary + case gc.OAND, + gc.OOR, + gc.OXOR, + gc.OADD, + gc.OMUL: + a = optoas(int(n.Op), nl.Type) + + goto sbop + + // asymmetric binary + case gc.OSUB: + a = optoas(int(n.Op), nl.Type) + + goto abop + + case gc.OHMUL: + cgen_hmul(nl, nr, res) + + case gc.OCONV: + if n.Type.Width > nl.Type.Width { + // If loading from memory, do conversion during load, + // so as to avoid use of 8-bit register in, say, int(*byteptr). + switch nl.Op { + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: + igen(nl, &n1, res) + regalloc(&n2, n.Type, res) + gmove(&n1, &n2) + gmove(&n2, res) + regfree(&n2) + regfree(&n1) + goto ret + } + } + + regalloc(&n1, nl.Type, res) + regalloc(&n2, n.Type, &n1) + cgen(nl, &n1) + + // if we do the conversion n1 -> n2 here + // reusing the register, then gmove won't + // have to allocate its own register. + gmove(&n1, &n2) + + gmove(&n2, res) + regfree(&n2) + regfree(&n1) + + case gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OIND, + gc.ONAME: // PHEAP or PPARAMREF var + igen(n, &n1, res) + + gmove(&n1, res) + regfree(&n1) + + // interface table is first word of interface value + case gc.OITAB: + igen(nl, &n1, res) + + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + // pointer is the first word of string or slice. + case gc.OSPTR: + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n1, gc.Types[gc.Tptr], res) + p1 = gins(ppc64.AMOVD, nil, &n1) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + gmove(&n1, res) + regfree(&n1) + break + } + + igen(nl, &n1, res) + n1.Type = n.Type + gmove(&n1, res) + regfree(&n1) + + case gc.OLEN: + if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { + // map and chan have len in the first int-sized word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Type = gc.Types[gc.Simtype[gc.TINT]] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { + // both slice and string have len one pointer into the struct. + // a zero pointer means zero length + igen(nl, &n1, res) + + n1.Type = gc.Types[gc.Simtype[gc.TUINT]] + n1.Xoffset += int64(gc.Array_nel) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OCAP: + if gc.Istype(nl.Type, gc.TCHAN) { + // chan has cap in the second int-sized word. + // a zero pointer means zero length + regalloc(&n1, gc.Types[gc.Tptr], res) + + cgen(nl, &n1) + + gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) + p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) + + n2 = n1 + n2.Op = gc.OINDREG + n2.Xoffset = int64(gc.Widthint) + n2.Type = gc.Types[gc.Simtype[gc.TINT]] + gmove(&n2, &n1) + + gc.Patch(p1, gc.Pc) + + gmove(&n1, res) + regfree(&n1) + break + } + + if gc.Isslice(nl.Type) { + igen(nl, &n1, res) + n1.Type = gc.Types[gc.Simtype[gc.TUINT]] + n1.Xoffset += int64(gc.Array_cap) + gmove(&n1, res) + regfree(&n1) + break + } + + gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) + + case gc.OADDR: + if n.Bounded { // let race detector avoid nil checks + gc.Disable_checknil++ + } + agen(nl, res) + if n.Bounded { + gc.Disable_checknil-- + } + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + cgen_callret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_callret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_callret(n, res) + + case gc.OMOD, + gc.ODIV: + if gc.Isfloat[n.Type.Etype] != 0 { + a = optoas(int(n.Op), nl.Type) + goto abop + } + + if nl.Ullman >= nr.Ullman { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + cgen_div(int(n.Op), &n1, nr, res) + regfree(&n1) + } else { + if !gc.Smallintconst(nr) { + regalloc(&n2, nr.Type, res) + cgen(nr, &n2) + } else { + n2 = *nr + } + + cgen_div(int(n.Op), nl, &n2, res) + if n2.Op != gc.OLITERAL { + regfree(&n2) + } + } + + case gc.OLSH, + gc.ORSH, + gc.OLROT: + cgen_shift(int(n.Op), n.Bounded, nl, nr, res) + } + + goto ret + + /* + * put simplest on right - we'll generate into left + * and then adjust it using the computation of right. + * constants and variables have the same ullman + * count, so look for constants specially. + * + * an integer constant we can use as an immediate + * is simpler than a variable - we can use the immediate + * in the adjustment instruction directly - so it goes + * on the right. + * + * other constants, like big integers or floating point + * constants, require a mov into a register, so those + * might as well go on the left, so we can reuse that + * register for the computation. + */ +sbop: // symmetric binary + if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) { + r = nl + nl = nr + nr = r + } + +abop: // asymmetric binary + if nl.Ullman >= nr.Ullman { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + + /* + * This generates smaller code - it avoids a MOV - but it's + * easily 10% slower due to not being able to + * optimize/manipulate the move. + * To see, run: go test -bench . crypto/md5 + * with and without. + * + if(sudoaddable(a, nr, &addr)) { + p1 = gins(a, N, &n1); + p1->from = addr; + gmove(&n1, res); + sudoclean(); + regfree(&n1); + goto ret; + } + * + */ + // TODO(minux): enable using constants directly in certain instructions. + //if(smallintconst(nr)) + // n2 = *nr; + //else { + regalloc(&n2, nr.Type, nil) + + cgen(nr, &n2) + } else //} + { + //if(smallintconst(nr)) + // n2 = *nr; + //else { + regalloc(&n2, nr.Type, res) + + cgen(nr, &n2) + + //} + regalloc(&n1, nl.Type, nil) + + cgen(nl, &n1) + } + + gins(a, &n2, &n1) + + // Normalize result for types smaller than word. + if n.Type.Width < int64(gc.Widthreg) { + switch n.Op { + case gc.OADD, + gc.OSUB, + gc.OMUL, + gc.OLSH: + gins(optoas(gc.OAS, n.Type), &n1, &n1) + } + } + + gmove(&n1, res) + regfree(&n1) + if n2.Op != gc.OLITERAL { + regfree(&n2) + } + goto ret + +uop: // unary + regalloc(&n1, nl.Type, res) + + cgen(nl, &n1) + gins(a, nil, &n1) + gmove(&n1, res) + regfree(&n1) + goto ret + +ret: +} + +/* + * allocate a register (reusing res if possible) and generate + * a = n + * The caller must call regfree(a). + */ +func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("cgenr-n", n) + } + + if gc.Isfat(n.Type) { + gc.Fatal("cgenr on fat node") + } + + if n.Addable != 0 { + regalloc(a, n.Type, res) + gmove(n, a) + return + } + + switch n.Op { + case gc.ONAME, + gc.ODOT, + gc.ODOTPTR, + gc.OINDEX, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + gmove(&n1, a) + regfree(&n1) + + default: + regalloc(a, n.Type, res) + cgen(n, a) + } +} + +/* + * allocate a register (reusing res if possible) and generate + * a = &n + * The caller must call regfree(a). + * The generated code checks that the result is not nil. + */ +func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { + var nl *gc.Node + var nr *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var tmp gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + var w uint32 + var v uint64 + + if gc.Debug['g'] != 0 { + gc.Dump("agenr-n", n) + } + + nl = n.Left + nr = n.Right + + switch n.Op { + case gc.ODOT, + gc.ODOTPTR, + gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + igen(n, &n1, res) + regalloc(a, gc.Types[gc.Tptr], &n1) + agen(&n1, a) + regfree(&n1) + + case gc.OIND: + cgenr(n.Left, a, res) + gc.Cgen_checknil(a) + + case gc.OINDEX: + p2 = nil // to be patched to panicindex. + w = uint32(n.Type.Width) + + //bounded = debug['B'] || n->bounded; + if nr.Addable != 0 { + if !gc.Isconst(nr, gc.CTINT) { + gc.Tempname(&tmp, gc.Types[gc.TINT64]) + } + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + if !gc.Isconst(nr, gc.CTINT) { + cgen(nr, &tmp) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + } else if nl.Addable != 0 { + if !gc.Isconst(nr, gc.CTINT) { + gc.Tempname(&tmp, gc.Types[gc.TINT64]) + cgen(nr, &tmp) + regalloc(&n1, tmp.Type, nil) + gmove(&tmp, &n1) + } + + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + } else { + gc.Tempname(&tmp, gc.Types[gc.TINT64]) + cgen(nr, &tmp) + nr = &tmp + if !gc.Isconst(nl, gc.CTSTR) { + agenr(nl, &n3, res) + } + regalloc(&n1, tmp.Type, nil) + gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) + } + + // &a is in &n3 (allocated in res) + // i is in &n1 (if not constant) + // w is width + + // constant index + if gc.Isconst(nr, gc.CTINT) { + if gc.Isconst(nl, gc.CTSTR) { + gc.Fatal("constant string constant index") + } + v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + if gc.Debug['B'] == 0 && !n.Bounded { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + regalloc(&n4, n1.Type, nil) + gmove(&n1, &n4) + ginscon2(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n4, int64(v)) + regfree(&n4) + p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT64]), nil, +1) + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, &n3) + } + + if v*uint64(w) != 0 { + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*uint64(w)), &n3) + } + + *a = n3 + break + } + + regalloc(&n2, gc.Types[gc.TINT64], &n1) // i + gmove(&n1, &n2) + regfree(&n1) + + if gc.Debug['B'] == 0 && !n.Bounded { + // check bounds + if gc.Isconst(nl, gc.CTSTR) { + gc.Nodconst(&n4, gc.Types[gc.TUINT64], int64(len(nl.Val.U.Sval.S))) + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_nel) + regalloc(&n4, gc.Types[gc.TUINT64], nil) + gmove(&n1, &n4) + } else { + if nl.Type.Bound < (1<<15)-1 { + gc.Nodconst(&n4, gc.Types[gc.TUINT64], nl.Type.Bound) + } else { + regalloc(&n4, gc.Types[gc.TUINT64], nil) + p1 = gins(ppc64.AMOVD, nil, &n4) + p1.From.Type = obj.TYPE_CONST + p1.From.Offset = nl.Type.Bound + } + } + + gins(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n2, &n4) + if n4.Op == gc.OREGISTER { + regfree(&n4) + } + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) + if p2 != nil { + gc.Patch(p2, gc.Pc) + } + ginscall(gc.Panicindex, 0) + gc.Patch(p1, gc.Pc) + } + + if gc.Isconst(nl, gc.CTSTR) { + regalloc(&n3, gc.Types[gc.Tptr], res) + p1 = gins(ppc64.AMOVD, nil, &n3) + gc.Datastring(nl.Val.U.Sval.S, &p1.From) + p1.From.Type = obj.TYPE_ADDR + } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { + n1 = n3 + n1.Op = gc.OINDREG + n1.Type = gc.Types[gc.Tptr] + n1.Xoffset = int64(gc.Array_array) + gmove(&n1, &n3) + } + + if w == 0 { + } else // nothing to do + if w == 1 { + /* w already scaled */ + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + /* else if(w == 2 || w == 4 || w == 8) { + // TODO(minux): scale using shift + } */ + } else { + regalloc(&n4, gc.Types[gc.TUINT64], nil) + gc.Nodconst(&n1, gc.Types[gc.TUINT64], int64(w)) + gmove(&n1, &n4) + gins(optoas(gc.OMUL, gc.Types[gc.TUINT64]), &n4, &n2) + gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) + regfree(&n4) + } + + *a = n3 + regfree(&n2) + + default: + regalloc(a, gc.Types[gc.Tptr], res) + agen(n, a) + } +} + +func ginsadd(as int, off int64, dst *gc.Node) { + var n1 gc.Node + + regalloc(&n1, gc.Types[gc.Tptr], dst) + gmove(dst, &n1) + ginscon(as, off, &n1) + gmove(&n1, dst) + regfree(&n1) +} + +/* + * generate: + * res = &n; + * The generated code checks that the result is not nil. + */ +func agen(n *gc.Node, res *gc.Node) { + var nl *gc.Node + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("\nagen-res", res) + gc.Dump("agen-r", n) + } + + if n == nil || n.Type == nil { + return + } + + for n.Op == gc.OCONVNOP { + n = n.Left + } + + if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { + // Use of a nil interface or nil slice. + // Create a temporary we can take the address of and read. + // The generated code is just going to panic, so it need not + // be terribly efficient. See issue 3670. + gc.Tempname(&n1, n.Type) + + gc.Gvardef(&n1) + clearfat(&n1) + regalloc(&n2, gc.Types[gc.Tptr], res) + n3 = gc.Node{} + n3.Op = gc.OADDR + n3.Left = &n1 + gins(ppc64.AMOVD, &n3, &n2) + gmove(&n2, res) + regfree(&n2) + goto ret + } + + if n.Addable != 0 { + n1 = gc.Node{} + n1.Op = gc.OADDR + n1.Left = n + regalloc(&n2, gc.Types[gc.Tptr], res) + gins(ppc64.AMOVD, &n1, &n2) + gmove(&n2, res) + regfree(&n2) + goto ret + } + + nl = n.Left + + switch n.Op { + default: + gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) + + // TODO(minux): 5g has this: Release res so that it is available for cgen_call. + // Pick it up again after the call for OCALLMETH and OCALLFUNC. + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + + cgen_aret(n, res) + + case gc.OCALLINTER: + cgen_callinter(n, res, 0) + cgen_aret(n, res) + + case gc.OCALLFUNC: + cgen_call(n, 0) + cgen_aret(n, res) + + case gc.OSLICE, + gc.OSLICEARR, + gc.OSLICESTR, + gc.OSLICE3, + gc.OSLICE3ARR: + gc.Tempname(&n1, n.Type) + gc.Cgen_slice(n, &n1) + agen(&n1, res) + + case gc.OEFACE: + gc.Tempname(&n1, n.Type) + gc.Cgen_eface(n, &n1) + agen(&n1, res) + + case gc.OINDEX: + agenr(n, &n1, res) + gmove(&n1, res) + regfree(&n1) + + // should only get here with names in this func. + case gc.ONAME: + if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) + } + + // should only get here for heap vars or paramref + if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { + gc.Dump("bad agen", n) + gc.Fatal("agen: bad ONAME class %#x", n.Class) + } + + cgen(n.Heapaddr, res) + if n.Xoffset != 0 { + ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + + case gc.OIND: + cgen(nl, res) + gc.Cgen_checknil(res) + + case gc.ODOT: + agen(nl, res) + if n.Xoffset != 0 { + ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + + case gc.ODOTPTR: + cgen(nl, res) + gc.Cgen_checknil(res) + if n.Xoffset != 0 { + ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) + } + } + +ret: +} + +/* + * generate: + * newreg = &n; + * res = newreg + * + * on exit, a has been changed to be *newreg. + * caller must regfree(a). + * The generated code checks that the result is not *nil. + */ +func igen(n *gc.Node, a *gc.Node, res *gc.Node) { + var fp *gc.Type + var flist gc.Iter + var n1 gc.Node + + if gc.Debug['g'] != 0 { + gc.Dump("\nigen-n", n) + } + + switch n.Op { + case gc.ONAME: + if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { + break + } + *a = *n + return + + // Increase the refcount of the register so that igen's caller + // has to call regfree. + case gc.OINDREG: + if n.Val.U.Reg != ppc64.REGSP { + reg[n.Val.U.Reg]++ + } + *a = *n + return + + case gc.ODOT: + igen(n.Left, a, res) + a.Xoffset += n.Xoffset + a.Type = n.Type + fixlargeoffset(a) + return + + case gc.ODOTPTR: + cgenr(n.Left, a, res) + gc.Cgen_checknil(a) + a.Op = gc.OINDREG + a.Xoffset += n.Xoffset + a.Type = n.Type + fixlargeoffset(a) + return + + case gc.OCALLFUNC, + gc.OCALLMETH, + gc.OCALLINTER: + switch n.Op { + case gc.OCALLFUNC: + cgen_call(n, 0) + + case gc.OCALLMETH: + gc.Cgen_callmeth(n, 0) + + case gc.OCALLINTER: + cgen_callinter(n, nil, 0) + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) + *a = gc.Node{} + a.Op = gc.OINDREG + a.Val.U.Reg = ppc64.REGSP + a.Addable = 1 + a.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) + a.Type = n.Type + return + + // Index of fixed-size array by constant can + // put the offset in the addressing. + // Could do the same for slice except that we need + // to use the real index for the bounds checking. + case gc.OINDEX: + if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { + if gc.Isconst(n.Right, gc.CTINT) { + // Compute &a. + if gc.Isptr[n.Left.Type.Etype] == 0 { + igen(n.Left, a, res) + } else { + igen(n.Left, &n1, res) + gc.Cgen_checknil(&n1) + regalloc(a, gc.Types[gc.Tptr], res) + gmove(&n1, a) + regfree(&n1) + a.Op = gc.OINDREG + } + + // Compute &a[i] as &a + i*width. + a.Type = n.Type + + a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width + fixlargeoffset(a) + return + } + } + } + + agenr(n, a, res) + a.Op = gc.OINDREG + a.Type = n.Type +} + +/* + * generate: + * if(n == true) goto to; + */ +func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { + var et int + var a int + var nl *gc.Node + var nr *gc.Node + var l *gc.Node + var r *gc.Node + var n1 gc.Node + var n2 gc.Node + var tmp gc.Node + var ll *gc.NodeList + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['g'] != 0 { + gc.Dump("\nbgen", n) + } + + if n == nil { + n = gc.Nodbool(true) + } + + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + + if n.Type == nil { + gc.Convlit(&n, gc.Types[gc.TBOOL]) + if n.Type == nil { + goto ret + } + } + + et = int(n.Type.Etype) + if et != gc.TBOOL { + gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) + gc.Patch(gins(obj.AEND, nil, nil), to) + goto ret + } + + nr = nil + + for n.Op == gc.OCONVNOP { + n = n.Left + if n.Ninit != nil { + gc.Genlist(n.Ninit) + } + } + + switch n.Op { + default: + regalloc(&n1, n.Type, nil) + cgen(n, &n1) + gc.Nodconst(&n2, n.Type, 0) + gins(optoas(gc.OCMP, n.Type), &n1, &n2) + a = ppc64.ABNE + if !true_ { + a = ppc64.ABEQ + } + gc.Patch(gc.Gbranch(a, n.Type, likely), to) + regfree(&n1) + goto ret + + // need to ask if it is bool? + case gc.OLITERAL: + if !true_ == (n.Val.U.Bval == 0) { + gc.Patch(gc.Gbranch(ppc64.ABR, nil, likely), to) + } + goto ret + + case gc.OANDAND, + gc.OOROR: + if (n.Op == gc.OANDAND) == true_ { + p1 = gc.Gbranch(obj.AJMP, nil, 0) + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + bgen(n.Left, !true_, -likely, p2) + bgen(n.Right, !true_, -likely, p2) + p1 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, to) + gc.Patch(p2, gc.Pc) + } else { + bgen(n.Left, true_, likely, to) + bgen(n.Right, true_, likely, to) + } + + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + nr = n.Right + if nr == nil || nr.Type == nil { + goto ret + } + fallthrough + + case gc.ONOT: // unary + nl = n.Left + + if nl == nil || nl.Type == nil { + goto ret + } + } + + switch n.Op { + case gc.ONOT: + bgen(nl, !true_, likely, to) + goto ret + + case gc.OEQ, + gc.ONE, + gc.OLT, + gc.OGT, + gc.OLE, + gc.OGE: + a = int(n.Op) + if !true_ { + if gc.Isfloat[nr.Type.Etype] != 0 { + // brcom is not valid on floats when NaN is involved. + p1 = gc.Gbranch(ppc64.ABR, nil, 0) + + p2 = gc.Gbranch(ppc64.ABR, nil, 0) + gc.Patch(p1, gc.Pc) + ll = n.Ninit // avoid re-genning ninit + n.Ninit = nil + bgen(n, true, -likely, p2) + n.Ninit = ll + gc.Patch(gc.Gbranch(ppc64.ABR, nil, 0), to) + gc.Patch(p2, gc.Pc) + goto ret + } + + a = gc.Brcom(a) + true_ = !true_ + } + + // make simplest on right + if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { + a = gc.Brrev(a) + r = nl + nl = nr + nr = r + } + + if gc.Isslice(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal slice comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Xoffset += int64(gc.Array_array) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + regalloc(&n2, gc.Types[gc.Tptr], &n1) + gmove(&n1, &n2) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) + regfree(&n2) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Isinter(nl.Type) { + // front end should only leave cmp to literal nil + if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { + gc.Yyerror("illegal interface comparison") + break + } + + a = optoas(a, gc.Types[gc.Tptr]) + igen(nl, &n1, nil) + n1.Type = gc.Types[gc.Tptr] + gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) + regalloc(&n2, gc.Types[gc.Tptr], &n1) + gmove(&n1, &n2) + gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) + regfree(&n2) + gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) + regfree(&n1) + break + } + + if gc.Iscomplex[nl.Type.Etype] != 0 { + gc.Complexbool(a, nl, nr, true_, likely, to) + break + } + + if nr.Ullman >= gc.UINF { + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + + gc.Tempname(&tmp, nl.Type) + gmove(&n1, &tmp) + regfree(&n1) + + regalloc(&n2, nr.Type, nil) + cgen(nr, &n2) + + regalloc(&n1, nl.Type, nil) + cgen(&tmp, &n1) + + goto cmp + } + + regalloc(&n1, nl.Type, nil) + cgen(nl, &n1) + + // TODO(minux): cmpi does accept 16-bit signed immediate as p->to. + // and cmpli accepts 16-bit unsigned immediate. + //if(smallintconst(nr)) { + // gins(optoas(OCMP, nr->type), &n1, nr); + // patch(gbranch(optoas(a, nr->type), nr->type, likely), to); + // regfree(&n1); + // break; + //} + + regalloc(&n2, nr.Type, nil) + + cgen(nr, &n2) + + cmp: + l = &n1 + r = &n2 + gins(optoas(gc.OCMP, nr.Type), l, r) + if gc.Isfloat[nr.Type.Etype] != 0 && (a == gc.OLE || a == gc.OGE) { + // To get NaN right, must rewrite x <= y into separate x < y or x = y. + switch a { + case gc.OLE: + a = gc.OLT + + case gc.OGE: + a = gc.OGT + } + + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + gc.Patch(gc.Gbranch(optoas(gc.OEQ, nr.Type), nr.Type, likely), to) + } else { + gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) + } + + regfree(&n1) + regfree(&n2) + } + + goto ret + +ret: +} + +/* + * n is on stack, either local variable + * or return value from function call. + * return n's offset from SP. + */ +func stkof(n *gc.Node) int64 { + var t *gc.Type + var flist gc.Iter + var off int64 + + switch n.Op { + case gc.OINDREG: + return n.Xoffset + + case gc.ODOT: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + return off + n.Xoffset + + case gc.OINDEX: + t = n.Left.Type + if !gc.Isfixedarray(t) { + break + } + off = stkof(n.Left) + if off == -1000 || off == 1000 { + return off + } + if gc.Isconst(n.Right, gc.CTINT) { + return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval) + } + return 1000 + + case gc.OCALLMETH, + gc.OCALLINTER, + gc.OCALLFUNC: + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + t = gc.Structfirst(&flist, gc.Getoutarg(t)) + if t != nil { + return t.Width + int64(gc.Widthptr) // +widthptr: correct for saved LR + } + } + + // botch - probably failing to recognize address + // arithmetic on the above. eg INDEX and DOT + return -1000 +} + +/* + * block copy: + * memmove(&ns, &n, w); + */ +func sgen(n *gc.Node, ns *gc.Node, w int64) { + var dst gc.Node + var src gc.Node + var tmp gc.Node + var nend gc.Node + var c int32 + var odst int32 + var osrc int32 + var dir int + var align int + var op int + var p *obj.Prog + var ploop *obj.Prog + var l *gc.NodeList + var res *gc.Node = ns + + if gc.Debug['g'] != 0 { + fmt.Printf("\nsgen w=%d\n", w) + gc.Dump("r", n) + gc.Dump("res", ns) + } + + if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF { + gc.Fatal("sgen UINF") + } + + if w < 0 { + gc.Fatal("sgen copy %d", w) + } + + // If copying .args, that's all the results, so record definition sites + // for them for the liveness analysis. + if ns.Op == gc.ONAME && ns.Sym.Name == ".args" { + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + if l.N.Class == gc.PPARAMOUT { + gc.Gvardef(l.N) + } + } + } + + // Avoid taking the address for simple enough types. + //if(componentgen(n, ns)) + // return; + if w == 0 { + // evaluate side effects only. + regalloc(&dst, gc.Types[gc.Tptr], nil) + + agen(res, &dst) + agen(n, &dst) + regfree(&dst) + return + } + + // determine alignment. + // want to avoid unaligned access, so have to use + // smaller operations for less aligned types. + // for example moving [4]byte must use 4 MOVB not 1 MOVW. + align = int(n.Type.Align) + + switch align { + default: + gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0)) + + case 1: + op = ppc64.AMOVBU + + case 2: + op = ppc64.AMOVHU + + case 4: + op = ppc64.AMOVWZU // there is no lwau, only lwaux + + case 8: + op = ppc64.AMOVDU + } + + if w%int64(align) != 0 { + gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0)) + } + c = int32(w / int64(align)) + + // offset on the stack + osrc = int32(stkof(n)) + + odst = int32(stkof(res)) + if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { + // osrc and odst both on stack, and at least one is in + // an unknown position. Could generate code to test + // for forward/backward copy, but instead just copy + // to a temporary location first. + gc.Tempname(&tmp, n.Type) + + sgen(n, &tmp, w) + sgen(&tmp, res, w) + return + } + + if osrc%int32(align) != 0 || odst%int32(align) != 0 { + gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align) + } + + // if we are copying forward on the stack and + // the src and dst overlap, then reverse direction + dir = align + + if osrc < odst && int64(odst) < int64(osrc)+w { + dir = -dir + } + + if n.Ullman >= res.Ullman { + agenr(n, &dst, res) // temporarily use dst + regalloc(&src, gc.Types[gc.Tptr], nil) + gins(ppc64.AMOVD, &dst, &src) + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agen(res, &dst) + } else { + if res.Op == gc.ONAME { + gc.Gvardef(res) + } + agenr(res, &dst, res) + agenr(n, &src, nil) + } + + regalloc(&tmp, gc.Types[gc.Tptr], nil) + + // set up end marker + nend = gc.Node{} + + // move src and dest to the end of block if necessary + if dir < 0 { + if c >= 4 { + regalloc(&nend, gc.Types[gc.Tptr], nil) + p = gins(ppc64.AMOVD, &src, &nend) + } + + p = gins(ppc64.AADD, nil, &src) + p.From.Type = obj.TYPE_CONST + p.From.Offset = w + + p = gins(ppc64.AADD, nil, &dst) + p.From.Type = obj.TYPE_CONST + p.From.Offset = w + } else { + p = gins(ppc64.AADD, nil, &src) + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(-dir) + + p = gins(ppc64.AADD, nil, &dst) + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(-dir) + + if c >= 4 { + regalloc(&nend, gc.Types[gc.Tptr], nil) + p = gins(ppc64.AMOVD, &src, &nend) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = w + } + } + + // move + // TODO: enable duffcopy for larger copies. + if c >= 4 { + p = gins(op, &src, &tmp) + p.From.Type = obj.TYPE_MEM + p.From.Offset = int64(dir) + ploop = p + + p = gins(op, &tmp, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(dir) + + p = gins(ppc64.ACMP, &src, &nend) + + gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), ploop) + regfree(&nend) + } else { + // TODO(austin): Instead of generating ADD $-8,R8; ADD + // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just + // generate the offsets directly and eliminate the + // ADDs. That will produce shorter, more + // pipeline-able code. + for { + tmp14 := c + c-- + if tmp14 <= 0 { + break + } + + p = gins(op, &src, &tmp) + p.From.Type = obj.TYPE_MEM + p.From.Offset = int64(dir) + + p = gins(op, &tmp, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(dir) + } + } + + regfree(&dst) + regfree(&src) + regfree(&tmp) +} + +func cadable(n *gc.Node) bool { + if n.Addable == 0 { + // dont know how it happens, + // but it does + return false + } + + switch n.Op { + case gc.ONAME: + return true + } + + return false +} + +/* + * copy a composite value by moving its individual components. + * Slices, strings and interfaces are supported. + * Small structs or arrays with elements of basic type are + * also supported. + * nr is N when assigning a zero value. + * return 1 if can do, 0 if can't. + */ +func componentgen(nr *gc.Node, nl *gc.Node) bool { + var nodl gc.Node + var nodr gc.Node + var tmp gc.Node + var t *gc.Type + var freel int + var freer int + var fldcount int64 + var loffset int64 + var roffset int64 + + freel = 0 + freer = 0 + + switch nl.Type.Etype { + default: + goto no + + case gc.TARRAY: + t = nl.Type + + // Slices are ok. + if gc.Isslice(t) { + break + } + + // Small arrays are ok. + if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { + break + } + + goto no + + // Small structs with non-fat types are ok. + // Zero-sized structs are treated separately elsewhere. + case gc.TSTRUCT: + fldcount = 0 + + for t = nl.Type.Type; t != nil; t = t.Down { + if gc.Isfat(t.Type) { + goto no + } + if t.Etype != gc.TFIELD { + gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) + } + fldcount++ + } + + if fldcount == 0 || fldcount > 4 { + goto no + } + + case gc.TSTRING, + gc.TINTER: + break + } + + nodl = *nl + if !cadable(nl) { + if nr != nil && !cadable(nr) { + goto no + } + igen(nl, &nodl, nil) + freel = 1 + } + + if nr != nil { + nodr = *nr + if !cadable(nr) { + igen(nr, &nodr, nil) + freer = 1 + } + } else { + // When zeroing, prepare a register containing zero. + gc.Nodconst(&tmp, nl.Type, 0) + + regalloc(&nodr, gc.Types[gc.TUINT], nil) + gmove(&tmp, &nodr) + freer = 1 + } + + // nl and nr are 'cadable' which basically means they are names (variables) now. + // If they are the same variable, don't generate any code, because the + // VARDEF we generate will mark the old value as dead incorrectly. + // (And also the assignments are useless.) + if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { + goto yes + } + + switch nl.Type.Etype { + // componentgen for arrays. + case gc.TARRAY: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + t = nl.Type + if !gc.Isslice(t) { + nodl.Type = t.Type + nodr.Type = nodl.Type + for fldcount = 0; fldcount < t.Bound; fldcount++ { + if nr == nil { + gc.Clearslim(&nodl) + } else { + gmove(&nodr, &nodl) + } + nodl.Xoffset += t.Type.Width + nodr.Xoffset += t.Type.Width + } + + goto yes + } + + // componentgen for slices. + nodl.Xoffset += int64(gc.Array_array) + + nodl.Type = gc.Ptrto(nl.Type.Type) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRING: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TINTER: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + nodl.Xoffset += int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) + + if nr != nil { + nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) + nodr.Type = nodl.Type + } + + gmove(&nodr, &nodl) + + goto yes + + case gc.TSTRUCT: + if nl.Op == gc.ONAME { + gc.Gvardef(nl) + } + loffset = nodl.Xoffset + roffset = nodr.Xoffset + + // funarg structs may not begin at offset zero. + if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { + loffset -= nl.Type.Type.Width + } + if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { + roffset -= nr.Type.Type.Width + } + + for t = nl.Type.Type; t != nil; t = t.Down { + nodl.Xoffset = loffset + t.Width + nodl.Type = t.Type + + if nr == nil { + gc.Clearslim(&nodl) + } else { + nodr.Xoffset = roffset + t.Width + nodr.Type = nodl.Type + gmove(&nodr, &nodl) + } + } + + goto yes + } + +no: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return false + +yes: + if freer != 0 { + regfree(&nodr) + } + if freel != 0 { + regfree(&nodl) + } + return true +} diff --git a/src/cmd/9g/doc.go b/src/cmd/9g/doc.go deleted file mode 100644 index 56bb14344b..0000000000 --- a/src/cmd/9g/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -9g is the version of the gc compiler for 64-bit PowerPC or Power Architecture processors. -The $GOARCH for these tools is ppc64 (big endian) or -ppc64le (little endian). - -It reads .go files and outputs .9 files. The flags are documented in ../gc/doc.go. - -*/ -package main diff --git a/src/cmd/9g/galign.c b/src/cmd/9g/galign.c deleted file mode 100644 index 74856e2af0..0000000000 --- a/src/cmd/9g/galign.c +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" - -int thechar = '9'; -char* thestring = "ppc64"; -LinkArch* thelinkarch; - -void -linkarchinit(void) -{ - thestring = getgoarch(); - thearch.thestring = thestring; - if(strcmp(thestring, "ppc64le") == 0) - thelinkarch = &linkppc64le; - else - thelinkarch = &linkppc64; - thearch.thelinkarch = thelinkarch; -} - -vlong MAXWIDTH = 1LL<<50; - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -Typedef typedefs[] = -{ - {"int", TINT, TINT64}, - {"uint", TUINT, TUINT64}, - {"uintptr", TUINTPTR, TUINT64}, - {0} -}; - -void -betypeinit(void) -{ - widthptr = 8; - widthint = 8; - widthreg = 8; - - listinit9(); -} - -void -main(int argc, char **argv) -{ - thearch.thechar = thechar; - thearch.thestring = thestring; - thearch.thelinkarch = thelinkarch; - thearch.typedefs = typedefs; - thearch.REGSP = REGSP; - thearch.REGCTXT = REGCTXT; - thearch.MAXWIDTH = MAXWIDTH; - thearch.anyregalloc = anyregalloc; - thearch.betypeinit = betypeinit; - thearch.bgen = bgen; - thearch.cgen = cgen; - thearch.cgen_call = cgen_call; - thearch.cgen_callinter = cgen_callinter; - thearch.cgen_ret = cgen_ret; - thearch.clearfat = clearfat; - thearch.defframe = defframe; - thearch.excise = excise; - thearch.expandchecks = expandchecks; - thearch.gclean = gclean; - thearch.ginit = ginit; - thearch.gins = gins; - thearch.ginscall = ginscall; - thearch.igen = igen; - thearch.linkarchinit = linkarchinit; - thearch.peep = peep; - thearch.proginfo = proginfo; - thearch.regalloc = regalloc; - thearch.regfree = regfree; - thearch.regtyp = regtyp; - thearch.sameaddr = sameaddr; - thearch.smallindir = smallindir; - thearch.stackaddr = stackaddr; - thearch.excludedregs = excludedregs; - thearch.RtoB = RtoB; - thearch.FtoB = RtoB; - thearch.BtoR = BtoR; - thearch.BtoF = BtoF; - thearch.optoas = optoas; - thearch.doregbits = doregbits; - thearch.regnames = regnames; - - gcmain(argc, argv); -} diff --git a/src/cmd/9g/galign.go b/src/cmd/9g/galign.go new file mode 100644 index 0000000000..99425c3929 --- /dev/null +++ b/src/cmd/9g/galign.go @@ -0,0 +1,93 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" +) +import "cmd/internal/gc" + +var thechar int = '9' + +var thestring string = "ppc64" + +var thelinkarch *obj.LinkArch + +func linkarchinit() { + thestring = obj.Getgoarch() + gc.Thearch.Thestring = thestring + if thestring == "ppc64le" { + thelinkarch = &ppc64.Linkppc64le + } else { + thelinkarch = &ppc64.Linkppc64 + } + gc.Thearch.Thelinkarch = thelinkarch +} + +var MAXWIDTH int64 = 1 << 50 + +/* + * go declares several platform-specific type aliases: + * int, uint, float, and uintptr + */ +var typedefs = []gc.Typedef{ + gc.Typedef{"int", gc.TINT, gc.TINT64}, + gc.Typedef{"uint", gc.TUINT, gc.TUINT64}, + gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64}, +} + +func betypeinit() { + gc.Widthptr = 8 + gc.Widthint = 8 + gc.Widthreg = 8 + +} + +func main() { + gc.Thearch.Thechar = thechar + gc.Thearch.Thestring = thestring + gc.Thearch.Thelinkarch = thelinkarch + gc.Thearch.Typedefs = typedefs + gc.Thearch.REGSP = ppc64.REGSP + gc.Thearch.REGCTXT = ppc64.REGCTXT + gc.Thearch.MAXWIDTH = MAXWIDTH + gc.Thearch.Anyregalloc = anyregalloc + gc.Thearch.Betypeinit = betypeinit + gc.Thearch.Bgen = bgen + gc.Thearch.Cgen = cgen + gc.Thearch.Cgen_call = cgen_call + gc.Thearch.Cgen_callinter = cgen_callinter + gc.Thearch.Cgen_ret = cgen_ret + gc.Thearch.Clearfat = clearfat + gc.Thearch.Defframe = defframe + gc.Thearch.Excise = excise + gc.Thearch.Expandchecks = expandchecks + gc.Thearch.Gclean = gclean + gc.Thearch.Ginit = ginit + gc.Thearch.Gins = gins + gc.Thearch.Ginscall = ginscall + gc.Thearch.Igen = igen + gc.Thearch.Linkarchinit = linkarchinit + gc.Thearch.Peep = peep + gc.Thearch.Proginfo = proginfo + gc.Thearch.Regalloc = regalloc + gc.Thearch.Regfree = regfree + gc.Thearch.Regtyp = regtyp + gc.Thearch.Sameaddr = sameaddr + gc.Thearch.Smallindir = smallindir + gc.Thearch.Stackaddr = stackaddr + gc.Thearch.Excludedregs = excludedregs + gc.Thearch.RtoB = RtoB + gc.Thearch.FtoB = RtoB + gc.Thearch.BtoR = BtoR + gc.Thearch.BtoF = BtoF + gc.Thearch.Optoas = optoas + gc.Thearch.Doregbits = doregbits + gc.Thearch.Regnames = regnames + + gc.Main() + gc.Exit(0) +} diff --git a/src/cmd/9g/gg.go b/src/cmd/9g/gg.go new file mode 100644 index 0000000000..068d8afe53 --- /dev/null +++ b/src/cmd/9g/gg.go @@ -0,0 +1,28 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "cmd/internal/obj/ppc64" +import "cmd/internal/gc" + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +var reg [ppc64.NREG + ppc64.NFREG]uint8 + +var panicdiv *gc.Node + +/* + * cgen.c + */ + +/* + * list.c + */ + +/* + * reg.c + */ diff --git a/src/cmd/9g/gg.h b/src/cmd/9g/gg.h deleted file mode 100644 index 938675937e..0000000000 --- a/src/cmd/9g/gg.h +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#ifndef EXTERN -#define EXTERN extern -#endif - -#include "../gc/go.h" -#include "../9l/9.out.h" - -EXTERN uchar reg[NREG+NFREG]; -EXTERN Node* panicdiv; -extern vlong unmappedzero; - -/* - * ggen.c - */ -void compile(Node*); -void gen(Node*); -Node* lookdot(Node*, Node*, int); -void cgen_as(Node*, Node*); -void cgen_callmeth(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_proc(Node*, int); -void cgen_callret(Node*, Node*); -void cgen_div(int, Node*, Node*, Node*); -void cgen_hmul(Node*, Node*, Node*); -void cgen_shift(int, int, Node*, Node*, Node*); -void cgen_dcl(Node*); -int needconvert(Type*, Type*); -void genconv(Type*, Type*); -void allocparams(void); -void checklabels(void); -void ginscall(Node*, int); -int gen_as_init(Node*); - -/* - * cgen.c - */ -void agen(Node*, Node*); -void agenr(Node*, Node*, Node*); -void cgenr(Node*, Node*, Node*); -void igen(Node*, Node*, Node*); -vlong fieldoffset(Type*, Node*); -void sgen(Node*, Node*, int64); -void gmove(Node*, Node*); -Prog* gins(int, Node*, Node*); -void naddr(Node*, Addr*, int); -void cgen_aret(Node*, Node*); -int componentgen(Node*, Node*); - -/* - * gsubr.c - */ -void clearp(Prog*); -Prog* gbranch(int, Type*, int); -Prog* prog(int); -void gconv(int, int); -int conv2pt(Type*); -vlong convvtox(vlong, int); -void fnparam(Type*, int, int); -Prog* gop(int, Node*, Node*, Node*); -int optoas(int, Type*); -void ginit(void); -void gclean(void); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -Node* nodarg(Type*, int); -void nodreg(Node*, Type*, int); -void nodindreg(Node*, Type*, int); -void ginscon(int, vlong, Node*); -void ginscon2(int, Node*, vlong); -void buildtxt(void); -Plist* newplist(void); -int isfat(Type*); -void sudoclean(void); -int sudoaddable(int, Node*, Addr*); -void afunclit(Addr*, Node*); -void nodfconst(Node*, Type*, Mpflt*); -void gtrack(Sym*); -void fixlargeoffset(Node *n); - -/* - * cplx.c - */ -int complexop(Node*, Node*); -void complexmove(Node*, Node*); -void complexgen(Node*, Node*); - -/* - * gobj.c - */ -void datastring(char*, int, Addr*); -void datagostring(Strlit*, Addr*); - -/* - * list.c - */ -void listinit(void); - -void zaddr(Biobuf*, Addr*, int, int); - -void afunclit(Addr*, Node*); -int anyregalloc(void); -void betypeinit(void); -void bgen(Node*, int, int, Prog*); -void cgen(Node*, Node*); -void cgen_call(Node*, int); -void cgen_callinter(Node*, Node*, int); -void cgen_ret(Node*); -void clearfat(Node*); -void clearp(Prog*); -void defframe(Prog*); -int dgostringptr(Sym*, int, char*); -int dgostrlitptr(Sym*, int, Strlit*); -int dsname(Sym*, int, char*, int); -int dsymptr(Sym*, int, Sym*, int); -void dumpdata(void); -void dumpit(char*, Flow*, int); -void excise(Flow*); -void expandchecks(Prog*); -void fixautoused(Prog*); -void gclean(void); -void gdata(Node*, Node*, int); -void gdatacomplex(Node*, Mpcplx*); -void gdatastring(Node*, Strlit*); -void ggloblnod(Node *nam); -void ggloblsym(Sym *s, int32 width, int8 flags); -void ginit(void); -Prog* gins(int, Node*, Node*); -void ginscall(Node*, int); -Prog* gjmp(Prog*); -void gtrack(Sym*); -void gused(Node*); -void igen(Node*, Node*, Node*); -int isfat(Type*); -void linkarchinit(void); -void markautoused(Prog*); -void naddr(Node*, Addr*, int); -Plist* newplist(void); -Node* nodarg(Type*, int); -void patch(Prog*, Prog*); -void proginfo(ProgInfo*, Prog*); -void regalloc(Node*, Type*, Node*); -void regfree(Node*); -void regopt(Prog*); -int regtyp(Addr*); -int sameaddr(Addr*, Addr*); -int smallindir(Addr*, Addr*); -int stackaddr(Addr*); -Prog* unpatch(Prog*); - - -/* - * reg.c - */ -uint64 excludedregs(void); -uint64 RtoB(int); -uint64 FtoB(int); -int BtoR(uint64); -int BtoF(uint64); -uint64 doregbits(int); -char** regnames(int*); - -/* - * peep.c - */ -void peep(Prog*); diff --git a/src/cmd/9g/ggen.c b/src/cmd/9g/ggen.c deleted file mode 100644 index 7b34282685..0000000000 --- a/src/cmd/9g/ggen.c +++ /dev/null @@ -1,965 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#undef EXTERN -#define EXTERN -#include -#include -#include "gg.h" -#include "../gc/popt.h" - -static Prog *appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset); -static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi); - -void -defframe(Prog *ptxt) -{ - uint32 frame; - Prog *p; - vlong hi, lo; - NodeList *l; - Node *n; - - // fill in argument size, stack size - ptxt->to.type = TYPE_TEXTSIZE; - ptxt->to.u.argsize = rnd(curfn->type->argwid, widthptr); - frame = rnd(stksize+maxarg, widthreg); - ptxt->to.offset = frame; - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt; - lo = hi = 0; - // iterate through declarations - they are sorted in decreasing xoffset order. - for(l=curfn->dcl; l != nil; l = l->next) { - n = l->n; - if(!n->needzero) - continue; - if(n->class != PAUTO) - fatal("needzero class %d", n->class); - if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0) - fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset); - - if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) { - // merge with range we already have - lo = n->xoffset; - continue; - } - // zero old range - p = zerorange(p, frame, lo, hi); - - // set new range - hi = n->xoffset + n->type->width; - lo = n->xoffset; - } - // zero final range - zerorange(p, frame, lo, hi); -} - -static Prog* -zerorange(Prog *p, vlong frame, vlong lo, vlong hi) -{ - vlong cnt, i; - Prog *p1; - Node *f; - - cnt = hi - lo; - if(cnt == 0) - return p; - if(cnt < 4*widthptr) { - for(i = 0; i < cnt; i += widthptr) - p = appendpp(p, AMOVD, TYPE_REG, REGZERO, 0, TYPE_MEM, REGSP, 8+frame+lo+i); - } else if(cnt <= 128*widthptr) { - p = appendpp(p, AADD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGRT1, 0); - p->reg = REGSP; - p = appendpp(p, ADUFFZERO, TYPE_NONE, 0, 0, TYPE_MEM, 0, 0); - f = sysfunc("duffzero"); - naddr(f, &p->to, 1); - afunclit(&p->to, f); - p->to.offset = 4*(128-cnt/widthptr); - } else { - p = appendpp(p, AMOVD, TYPE_CONST, 0, 8+frame+lo-8, TYPE_REG, REGTMP, 0); - p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT1, 0); - p->reg = REGSP; - p = appendpp(p, AMOVD, TYPE_CONST, 0, cnt, TYPE_REG, REGTMP, 0); - p = appendpp(p, AADD, TYPE_REG, REGTMP, 0, TYPE_REG, REGRT2, 0); - p->reg = REGRT1; - p1 = p = appendpp(p, AMOVDU, TYPE_REG, REGZERO, 0, TYPE_MEM, REGRT1, widthptr); - p = appendpp(p, ACMP, TYPE_REG, REGRT1, 0, TYPE_REG, REGRT2, 0); - p = appendpp(p, ABNE, TYPE_NONE, 0, 0, TYPE_BRANCH, 0, 0); - patch(p, p1); - } - return p; -} - -static Prog* -appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int treg, vlong toffset) -{ - Prog *q; - q = mal(sizeof(*q)); - clearp(q); - q->as = as; - q->lineno = p->lineno; - q->from.type = ftype; - q->from.reg = freg; - q->from.offset = foffset; - q->to.type = ttype; - q->to.reg = treg; - q->to.offset = toffset; - q->link = p->link; - p->link = q; - return q; -} - -/* - * generate: BL reg, f - * where both reg and f are registers. - * On power, f must be moved to CTR first. - */ -static void -ginsBL(Node *reg, Node *f) -{ - Prog *p; - p = gins(AMOVD, f, N); - p->to.type = TYPE_REG; - p->to.reg = REG_CTR; - p = gins(ABL, reg, N); - p->to.type = TYPE_REG; - p->to.reg = REG_CTR; -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) - */ -void -ginscall(Node *f, int proc) -{ - Prog *p; - Node reg, con, reg2; - Node r1; - int32 extra; - - if(f->type != T) { - extra = 0; - if(proc == 1 || proc == 2) - extra = 2 * widthptr; - setmaxarg(f->type, extra); - } - - switch(proc) { - default: - fatal("ginscall: bad proc %d", proc); - break; - - case 0: // normal call - case -1: // normal call but no return - if(f->op == ONAME && f->class == PFUNC) { - if(f == deferreturn) { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert a ppc64 NOP that we will have the right line number. - // The ppc64 NOP is really or r0, r0, r0; use that description - // because the NOP pseudo-instruction would be removed by - // the linker. - nodreg(®, types[TINT], REG_R0); - gins(AOR, ®, ®); - } - p = gins(ABL, N, f); - afunclit(&p->to, f); - if(proc == -1 || noreturn(p)) - gins(AUNDEF, N, N); - break; - } - nodreg(®, types[tptr], REGCTXT); - nodreg(&r1, types[tptr], REG_R3); - gmove(f, ®); - reg.op = OINDREG; - gmove(®, &r1); - reg.op = OREGISTER; - ginsBL(®, &r1); - break; - - case 3: // normal call of c function pointer - ginsBL(N, f); - break; - - case 1: // call in new proc (go) - case 2: // deferred call (defer) - nodconst(&con, types[TINT64], argsize(f->type)); - nodreg(®, types[TINT64], REG_R3); - nodreg(®2, types[TINT64], REG_R4); - gmove(f, ®); - - gmove(&con, ®2); - p = gins(AMOVW, ®2, N); - p->to.type = TYPE_MEM; - p->to.reg = REGSP; - p->to.offset = 8; - - p = gins(AMOVD, ®, N); - p->to.type = TYPE_MEM; - p->to.reg = REGSP; - p->to.offset = 16; - - if(proc == 1) - ginscall(newproc, 0); - else { - if(!hasdefer) - fatal("hasdefer=0 but has defer"); - ginscall(deferproc, 0); - } - - if(proc == 2) { - nodreg(®, types[TINT64], REG_R3); - p = gins(ACMP, ®, N); - p->to.type = TYPE_REG; - p->to.reg = REG_R0; - p = gbranch(ABEQ, T, +1); - cgen_ret(N); - patch(p, pc); - } - break; - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -void -cgen_callinter(Node *n, Node *res, int proc) -{ - Node *i, *f; - Node tmpi, nodi, nodo, nodr, nodsp; - Prog *p; - - i = n->left; - if(i->op != ODOTINTER) - fatal("cgen_callinter: not ODOTINTER %O", i->op); - - f = i->right; // field - if(f->op != ONAME) - fatal("cgen_callinter: not ONAME %O", f->op); - - i = i->left; // interface - - if(!i->addable) { - tempname(&tmpi, i->type); - cgen(i, &tmpi); - i = &tmpi; - } - - genlist(n->list); // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res); // REG = &inter - - nodindreg(&nodsp, types[tptr], REGSP); - nodsp.xoffset = widthptr; - if(proc != 0) - nodsp.xoffset += 2 * widthptr; // leave room for size & fn - nodi.type = types[tptr]; - nodi.xoffset += widthptr; - cgen(&nodi, &nodsp); // {8 or 24}(SP) = 8(REG) -- i.data - - regalloc(&nodo, types[tptr], res); - nodi.type = types[tptr]; - nodi.xoffset -= widthptr; - cgen(&nodi, &nodo); // REG = 0(REG) -- i.tab - regfree(&nodi); - - regalloc(&nodr, types[tptr], &nodo); - if(n->left->xoffset == BADWIDTH) - fatal("cgen_callinter: badwidth"); - cgen_checknil(&nodo); // in case offset is huge - nodo.op = OINDREG; - nodo.xoffset = n->left->xoffset + 3*widthptr + 8; - if(proc == 0) { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.tab->fun[f] - proc = 3; - } else { - // go/defer. generate go func value. - p = gins(AMOVD, &nodo, &nodr); // REG = &(32+offset(REG)) -- i.tab->fun[f] - p->from.type = TYPE_ADDR; - } - - nodr.type = n->left->type; - ginscall(&nodr, proc); - - regfree(&nodr); - regfree(&nodo); -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -void -cgen_call(Node *n, int proc) -{ - Type *t; - Node nod, afun; - - if(n == N) - return; - - if(n->left->ullman >= UINF) { - // if name involves a fn call - // precompute the address of the fn - tempname(&afun, types[tptr]); - cgen(n->left, &afun); - } - - genlist(n->list); // assign the args - t = n->left->type; - - // call tempname pointer - if(n->left->ullman >= UINF) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, &afun); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call pointer - if(n->left->op != ONAME || n->left->class != PFUNC) { - regalloc(&nod, types[tptr], N); - cgen_as(&nod, n->left); - nod.type = t; - ginscall(&nod, proc); - regfree(&nod); - return; - } - - // call direct - n->left->method = 1; - ginscall(n->left, proc); -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -void -cgen_callret(Node *n, Node *res) -{ - Node nod; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(t->etype == TPTR32 || t->etype == TPTR64) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_callret: nil"); - - memset(&nod, 0, sizeof(nod)); - nod.op = OINDREG; - nod.val.u.reg = REGSP; - nod.addable = 1; - - nod.xoffset = fp->width + widthptr; // +widthptr: saved LR at 0(R1) - nod.type = fp->type; - cgen_as(res, &nod); -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -void -cgen_aret(Node *n, Node *res) -{ - Node nod1, nod2; - Type *fp, *t; - Iter flist; - - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - - fp = structfirst(&flist, getoutarg(t)); - if(fp == T) - fatal("cgen_aret: nil"); - - memset(&nod1, 0, sizeof(nod1)); - nod1.op = OINDREG; - nod1.val.u.reg = REGSP; - nod1.addable = 1; - - nod1.xoffset = fp->width + widthptr; // +widthptr: saved lr at 0(SP) - nod1.type = fp->type; - - if(res->op != OREGISTER) { - regalloc(&nod2, types[tptr], res); - agen(&nod1, &nod2); - gins(AMOVD, &nod2, res); - regfree(&nod2); - } else - agen(&nod1, res); -} - -/* - * generate return. - * n->left is assignments to return values. - */ -void -cgen_ret(Node *n) -{ - Prog *p; - - if(n != N) - genlist(n->list); // copy out args - if(hasdefer) - ginscall(deferreturn, 0); - genlist(curfn->exit); - p = gins(ARET, N, N); - if(n != N && n->op == ORETJMP) { - p->to.name = NAME_EXTERN; - p->to.type = TYPE_ADDR; - p->to.sym = linksym(n->left->sym); - } -} - -/* - * generate division. - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -void -dodiv(int op, Node *nl, Node *nr, Node *res) -{ - int a, check; - Type *t, *t0; - Node tl, tr, tl2, tr2, nm1, nz, tm; - Prog *p1, *p2; - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will generate undefined result. - // Also need to explicitly trap on division on zero, - // the hardware will silently generate undefined result. - // DIVW will leave unpredicable result in higher 32-bit, - // so always use DIVD/DIVDU. - t = nl->type; - t0 = t; - check = 0; - if(issigned[t->etype]) { - check = 1; - if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1))) - check = 0; - else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1) - check = 0; - } - if(t->width < 8) { - if(issigned[t->etype]) - t = types[TINT64]; - else - t = types[TUINT64]; - check = 0; - } - - a = optoas(ODIV, t); - - regalloc(&tl, t0, N); - regalloc(&tr, t0, N); - if(nl->ullman >= nr->ullman) { - cgen(nl, &tl); - cgen(nr, &tr); - } else { - cgen(nr, &tr); - cgen(nl, &tl); - } - if(t != t0) { - // Convert - tl2 = tl; - tr2 = tr; - tl.type = t; - tr.type = t; - gmove(&tl2, &tl); - gmove(&tr2, &tr); - } - - // Handle divide-by-zero panic. - p1 = gins(optoas(OCMP, t), &tr, N); - p1->to.type = TYPE_REG; - p1->to.reg = REGZERO; - p1 = gbranch(optoas(ONE, t), T, +1); - if(panicdiv == N) - panicdiv = sysfunc("panicdivide"); - ginscall(panicdiv, -1); - patch(p1, pc); - - if(check) { - nodconst(&nm1, t, -1); - gins(optoas(OCMP, t), &tr, &nm1); - p1 = gbranch(optoas(ONE, t), T, +1); - if(op == ODIV) { - // a / (-1) is -a. - gins(optoas(OMINUS, t), N, &tl); - gmove(&tl, res); - } else { - // a % (-1) is 0. - nodconst(&nz, t, 0); - gmove(&nz, res); - } - p2 = gbranch(AJMP, T, 0); - patch(p1, pc); - } - p1 = gins(a, &tr, &tl); - if(op == ODIV) { - regfree(&tr); - gmove(&tl, res); - } else { - // A%B = A-(A/B*B) - regalloc(&tm, t, N); - // patch div to use the 3 register form - // TODO(minux): add gins3? - p1->reg = p1->to.reg; - p1->to.reg = tm.val.u.reg; - gins(optoas(OMUL, t), &tr, &tm); - regfree(&tr); - gins(optoas(OSUB, t), &tm, &tl); - regfree(&tm); - gmove(&tl, res); - } - regfree(&tl); - if(check) - patch(p2, pc); -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -void -cgen_div(int op, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3; - int w, a; - Magic m; - - // TODO(minux): enable division by magic multiply (also need to fix longmod below) - //if(nr->op != OLITERAL) - goto longdiv; - w = nl->type->width*8; - - // Front end handled 32-bit division. We only need to handle 64-bit. - // try to do division by multiply by (2^w)/d - // see hacker's delight chapter 10 - switch(simtype[nl->type->etype]) { - default: - goto longdiv; - - case TUINT64: - m.w = w; - m.ud = mpgetfix(nr->val.u.xval); - umagic(&m); - if(m.bad) - break; - if(op == OMOD) - goto longmod; - - cgenr(nl, &n1, N); - nodconst(&n2, nl->type, m.um); - regalloc(&n3, nl->type, res); - cgen_hmul(&n1, &n2, &n3); - - if(m.ua) { - // need to add numerator accounting for overflow - gins(optoas(OADD, nl->type), &n1, &n3); - nodconst(&n2, nl->type, 1); - gins(optoas(ORROTC, nl->type), &n2, &n3); - nodconst(&n2, nl->type, m.s-1); - gins(optoas(ORSH, nl->type), &n2, &n3); - } else { - nodconst(&n2, nl->type, m.s); - gins(optoas(ORSH, nl->type), &n2, &n3); // shift dx - } - - gmove(&n3, res); - regfree(&n1); - regfree(&n3); - return; - - case TINT64: - m.w = w; - m.sd = mpgetfix(nr->val.u.xval); - smagic(&m); - if(m.bad) - break; - if(op == OMOD) - goto longmod; - - cgenr(nl, &n1, res); - nodconst(&n2, nl->type, m.sm); - regalloc(&n3, nl->type, N); - cgen_hmul(&n1, &n2, &n3); - - if(m.sm < 0) { - // need to add numerator - gins(optoas(OADD, nl->type), &n1, &n3); - } - - nodconst(&n2, nl->type, m.s); - gins(optoas(ORSH, nl->type), &n2, &n3); // shift n3 - - nodconst(&n2, nl->type, w-1); - gins(optoas(ORSH, nl->type), &n2, &n1); // -1 iff num is neg - gins(optoas(OSUB, nl->type), &n1, &n3); // added - - if(m.sd < 0) { - // this could probably be removed - // by factoring it into the multiplier - gins(optoas(OMINUS, nl->type), N, &n3); - } - - gmove(&n3, res); - regfree(&n1); - regfree(&n3); - return; - } - goto longdiv; - -longdiv: - // division and mod using (slow) hardware instruction - dodiv(op, nl, nr, res); - return; - -longmod: - // mod using formula A%B = A-(A/B*B) but - // we know that there is a fast algorithm for A/B - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - regalloc(&n2, nl->type, N); - cgen_div(ODIV, &n1, nr, &n2); - a = optoas(OMUL, nl->type); - if(w == 8) { - // use 2-operand 16-bit multiply - // because there is no 2-operand 8-bit multiply - //a = AIMULW; - } - if(!smallintconst(nr)) { - regalloc(&n3, nl->type, N); - cgen(nr, &n3); - gins(a, &n3, &n2); - regfree(&n3); - } else - gins(a, nr, &n2); - gins(optoas(OSUB, nl->type), &n2, &n1); - gmove(&n1, res); - regfree(&n1); - regfree(&n2); -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -void -cgen_hmul(Node *nl, Node *nr, Node *res) -{ - int w; - Node n1, n2, *tmp; - Type *t; - Prog *p; - - // largest ullman on left. - if(nl->ullman < nr->ullman) { - tmp = nl; - nl = nr; - nr = tmp; - } - t = nl->type; - w = t->width * 8; - cgenr(nl, &n1, res); - cgenr(nr, &n2, N); - switch(simtype[t->etype]) { - case TINT8: - case TINT16: - case TINT32: - gins(optoas(OMUL, t), &n2, &n1); - p = gins(ASRAD, N, &n1); - p->from.type = TYPE_CONST; - p->from.offset = w; - break; - case TUINT8: - case TUINT16: - case TUINT32: - gins(optoas(OMUL, t), &n2, &n1); - p = gins(ASRD, N, &n1); - p->from.type = TYPE_CONST; - p->from.offset = w; - break; - case TINT64: - case TUINT64: - if(issigned[t->etype]) - p = gins(AMULHD, &n2, &n1); - else - p = gins(AMULHDU, &n2, &n1); - break; - default: - fatal("cgen_hmul %T", t); - break; - } - cgen(&n1, res); - regfree(&n1); - regfree(&n2); -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -void -cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3, n4, n5; - int a; - Prog *p1; - uvlong sc; - Type *tcount; - - a = optoas(op, nl->type); - - if(nr->op == OLITERAL) { - regalloc(&n1, nl->type, res); - cgen(nl, &n1); - sc = mpgetfix(nr->val.u.xval); - if(sc >= nl->type->width*8) { - // large shift gets 2 shifts by width-1 - nodconst(&n3, types[TUINT32], nl->type->width*8-1); - gins(a, &n3, &n1); - gins(a, &n3, &n1); - } else - gins(a, nr, &n1); - gmove(&n1, res); - regfree(&n1); - goto ret; - } - - if(nl->ullman >= UINF) { - tempname(&n4, nl->type); - cgen(nl, &n4); - nl = &n4; - } - if(nr->ullman >= UINF) { - tempname(&n5, nr->type); - cgen(nr, &n5); - nr = &n5; - } - - // Allow either uint32 or uint64 as shift type, - // to avoid unnecessary conversion from uint32 to uint64 - // just to do the comparison. - tcount = types[simtype[nr->type->etype]]; - if(tcount->etype < TUINT32) - tcount = types[TUINT32]; - - regalloc(&n1, nr->type, N); // to hold the shift type in CX - regalloc(&n3, tcount, &n1); // to clear high bits of CX - - regalloc(&n2, nl->type, res); - if(nl->ullman >= nr->ullman) { - cgen(nl, &n2); - cgen(nr, &n1); - gmove(&n1, &n3); - } else { - cgen(nr, &n1); - gmove(&n1, &n3); - cgen(nl, &n2); - } - regfree(&n3); - - // test and fix up large shifts - if(!bounded) { - nodconst(&n3, tcount, nl->type->width*8); - gins(optoas(OCMP, tcount), &n1, &n3); - p1 = gbranch(optoas(OLT, tcount), T, +1); - if(op == ORSH && issigned[nl->type->etype]) { - nodconst(&n3, types[TUINT32], nl->type->width*8-1); - gins(a, &n3, &n2); - } else { - nodconst(&n3, nl->type, 0); - gmove(&n3, &n2); - } - patch(p1, pc); - } - - gins(a, &n1, &n2); - - gmove(&n2, res); - - regfree(&n1); - regfree(&n2); - -ret: - ; -} - -void -clearfat(Node *nl) -{ - uint64 w, c, q, t, boff; - Node dst, end, r0, *f; - Prog *p, *pl; - - /* clear a fat object */ - if(debug['g']) { - print("clearfat %N (%T, size: %lld)\n", nl, nl->type, nl->type->width); - } - - w = nl->type->width; - // Avoid taking the address for simple enough types. - //if(componentgen(N, nl)) - // return; - - c = w % 8; // bytes - q = w / 8; // dwords - - if(reg[REGRT1] > 0) - fatal("R%d in use during clearfat", REGRT1); - - nodreg(&r0, types[TUINT64], REG_R0); // r0 is always zero - nodreg(&dst, types[tptr], REGRT1); - reg[REGRT1]++; - agen(nl, &dst); - - if(q > 128) { - p = gins(ASUB, N, &dst); - p->from.type = TYPE_CONST; - p->from.offset = 8; - - regalloc(&end, types[tptr], N); - p = gins(AMOVD, &dst, &end); - p->from.type = TYPE_ADDR; - p->from.offset = q*8; - - p = gins(AMOVDU, &r0, &dst); - p->to.type = TYPE_MEM; - p->to.offset = 8; - pl = p; - - p = gins(ACMP, &dst, &end); - patch(gbranch(ABNE, T, 0), pl); - - regfree(&end); - // The loop leaves R3 on the last zeroed dword - boff = 8; - } else if(q >= 4) { - p = gins(ASUB, N, &dst); - p->from.type = TYPE_CONST; - p->from.offset = 8; - f = sysfunc("duffzero"); - p = gins(ADUFFZERO, N, f); - afunclit(&p->to, f); - // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s - p->to.offset = 4*(128-q); - // duffzero leaves R3 on the last zeroed dword - boff = 8; - } else { - for(t = 0; t < q; t++) { - p = gins(AMOVD, &r0, &dst); - p->to.type = TYPE_MEM; - p->to.offset = 8*t; - } - boff = 8*q; - } - - for(t = 0; t < c; t++) { - p = gins(AMOVB, &r0, &dst); - p->to.type = TYPE_MEM; - p->to.offset = t+boff; - } - reg[REGRT1]--; -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -void -expandchecks(Prog *firstp) -{ - Prog *p, *p1, *p2; - - for(p = firstp; p != P; p = p->link) { - if(debug_checknil && ctxt->debugvlog) - print("expandchecks: %P\n", p); - if(p->as != ACHECKNIL) - continue; - if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers - warnl(p->lineno, "generated nil check"); - if(p->from.type != TYPE_REG) - fatal("invalid nil check %P\n", p); - /* - // check is - // TD $4, R0, arg (R0 is always zero) - // eqv. to: - // tdeq r0, arg - // NOTE: this needs special runtime support to make SIGTRAP recoverable. - reg = p->from.reg; - p->as = ATD; - p->from = p->to = p->from3 = zprog.from; - p->from.type = TYPE_CONST; - p->from.offset = 4; - p->from.reg = 0; - p->reg = REG_R0; - p->to.type = TYPE_REG; - p->to.reg = reg; - */ - // check is - // CMP arg, R0 - // BNE 2(PC) [likely] - // MOVD R0, 0(R0) - p1 = mal(sizeof *p1); - p2 = mal(sizeof *p2); - clearp(p1); - clearp(p2); - p1->link = p2; - p2->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - p2->lineno = p->lineno; - p1->pc = 9999; - p2->pc = 9999; - p->as = ACMP; - p->to.type = TYPE_REG; - p->to.reg = REGZERO; - p1->as = ABNE; - //p1->from.type = TYPE_CONST; - //p1->from.offset = 1; // likely - p1->to.type = TYPE_BRANCH; - p1->to.u.branch = p2->link; - // crash by write to memory address 0. - p2->as = AMOVD; - p2->from.type = TYPE_REG; - p2->from.reg = REG_R0; - p2->to.type = TYPE_MEM; - p2->to.reg = REG_R0; - p2->to.offset = 0; - } -} diff --git a/src/cmd/9g/ggen.go b/src/cmd/9g/ggen.go new file mode 100644 index 0000000000..54bebdda40 --- /dev/null +++ b/src/cmd/9g/ggen.go @@ -0,0 +1,1060 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" + "fmt" +) +import "cmd/internal/gc" + +func defframe(ptxt *obj.Prog) { + var frame uint32 + var p *obj.Prog + var hi int64 + var lo int64 + var l *gc.NodeList + var n *gc.Node + + // fill in argument size, stack size + ptxt.To.Type = obj.TYPE_TEXTSIZE + + ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) + frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) + ptxt.To.Offset = int64(frame) + + // insert code to zero ambiguously live variables + // so that the garbage collector only sees initialized values + // when it looks for pointers. + p = ptxt + + hi = 0 + lo = hi + + // iterate through declarations - they are sorted in decreasing xoffset order. + for l = gc.Curfn.Dcl; l != nil; l = l.Next { + n = l.N + if n.Needzero == 0 { + continue + } + if n.Class != gc.PAUTO { + gc.Fatal("needzero class %d", n.Class) + } + if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { + gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) + } + + if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) { + // merge with range we already have + lo = n.Xoffset + + continue + } + + // zero old range + p = zerorange(p, int64(frame), lo, hi) + + // set new range + hi = n.Xoffset + n.Type.Width + + lo = n.Xoffset + } + + // zero final range + zerorange(p, int64(frame), lo, hi) +} + +func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog { + var cnt int64 + var i int64 + var p1 *obj.Prog + var f *gc.Node + + cnt = hi - lo + if cnt == 0 { + return p + } + if cnt < int64(4*gc.Widthptr) { + for i = 0; i < cnt; i += int64(gc.Widthptr) { + p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i) + } + } else if cnt <= int64(128*gc.Widthptr) { + p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0) + p.Reg = ppc64.REGSP + p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) + f = gc.Sysfunc("duffzero") + gc.Naddr(f, &p.To, 1) + gc.Afunclit(&p.To, f) + p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) + } else { + p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0) + p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0) + p.Reg = ppc64.REGSP + p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0) + p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0) + p.Reg = ppc64.REGRT1 + p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr)) + p1 = p + p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0) + p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0) + gc.Patch(p, p1) + } + + return p +} + +func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { + var q *obj.Prog + q = gc.Ctxt.NewProg() + gc.Clearp(q) + q.As = int16(as) + q.Lineno = p.Lineno + q.From.Type = int16(ftype) + q.From.Reg = int16(freg) + q.From.Offset = foffset + q.To.Type = int16(ttype) + q.To.Reg = int16(treg) + q.To.Offset = toffset + q.Link = p.Link + p.Link = q + return q +} + +/* + * generate: BL reg, f + * where both reg and f are registers. + * On power, f must be moved to CTR first. + */ +func ginsBL(reg *gc.Node, f *gc.Node) { + var p *obj.Prog + p = gins(ppc64.AMOVD, f, nil) + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REG_CTR + p = gins(ppc64.ABL, reg, nil) + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REG_CTR +} + +/* + * generate: + * call f + * proc=-1 normal call but no return + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + * proc=3 normal call to C pointer (not Go func value) +*/ +func ginscall(f *gc.Node, proc int) { + var p *obj.Prog + var reg gc.Node + var con gc.Node + var reg2 gc.Node + var r1 gc.Node + var extra int32 + + if f.Type != nil { + extra = 0 + if proc == 1 || proc == 2 { + extra = 2 * int32(gc.Widthptr) + } + gc.Setmaxarg(f.Type, extra) + } + + switch proc { + default: + gc.Fatal("ginscall: bad proc %d", proc) + + case 0, // normal call + -1: // normal call but no return + if f.Op == gc.ONAME && f.Class == gc.PFUNC { + if f == gc.Deferreturn { + // Deferred calls will appear to be returning to + // the CALL deferreturn(SB) that we are about to emit. + // However, the stack trace code will show the line + // of the instruction byte before the return PC. + // To avoid that being an unrelated instruction, + // insert a ppc64 NOP that we will have the right line number. + // The ppc64 NOP is really or r0, r0, r0; use that description + // because the NOP pseudo-instruction would be removed by + // the linker. + gc.Nodreg(®, gc.Types[gc.TINT], ppc64.REG_R0) + + gins(ppc64.AOR, ®, ®) + } + + p = gins(ppc64.ABL, nil, f) + gc.Afunclit(&p.To, f) + if proc == -1 || gc.Noreturn(p) { + gins(obj.AUNDEF, nil, nil) + } + break + } + + gc.Nodreg(®, gc.Types[gc.Tptr], ppc64.REGCTXT) + gc.Nodreg(&r1, gc.Types[gc.Tptr], ppc64.REG_R3) + gmove(f, ®) + reg.Op = gc.OINDREG + gmove(®, &r1) + reg.Op = gc.OREGISTER + ginsBL(®, &r1) + + case 3: // normal call of c function pointer + ginsBL(nil, f) + + case 1, // call in new proc (go) + 2: // deferred call (defer) + gc.Nodconst(&con, gc.Types[gc.TINT64], int64(gc.Argsize(f.Type))) + + gc.Nodreg(®, gc.Types[gc.TINT64], ppc64.REG_R3) + gc.Nodreg(®2, gc.Types[gc.TINT64], ppc64.REG_R4) + gmove(f, ®) + + gmove(&con, ®2) + p = gins(ppc64.AMOVW, ®2, nil) + p.To.Type = obj.TYPE_MEM + p.To.Reg = ppc64.REGSP + p.To.Offset = 8 + + p = gins(ppc64.AMOVD, ®, nil) + p.To.Type = obj.TYPE_MEM + p.To.Reg = ppc64.REGSP + p.To.Offset = 16 + + if proc == 1 { + ginscall(gc.Newproc, 0) + } else { + if gc.Hasdefer == 0 { + gc.Fatal("hasdefer=0 but has defer") + } + ginscall(gc.Deferproc, 0) + } + + if proc == 2 { + gc.Nodreg(®, gc.Types[gc.TINT64], ppc64.REG_R3) + p = gins(ppc64.ACMP, ®, nil) + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REG_R0 + p = gc.Gbranch(ppc64.ABEQ, nil, +1) + cgen_ret(nil) + gc.Patch(p, gc.Pc) + } + } +} + +/* + * n is call to interface method. + * generate res = n. + */ +func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { + var i *gc.Node + var f *gc.Node + var tmpi gc.Node + var nodi gc.Node + var nodo gc.Node + var nodr gc.Node + var nodsp gc.Node + var p *obj.Prog + + i = n.Left + if i.Op != gc.ODOTINTER { + gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) + } + + f = i.Right // field + if f.Op != gc.ONAME { + gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) + } + + i = i.Left // interface + + if i.Addable == 0 { + gc.Tempname(&tmpi, i.Type) + cgen(i, &tmpi) + i = &tmpi + } + + gc.Genlist(n.List) // assign the args + + // i is now addable, prepare an indirected + // register to hold its address. + igen(i, &nodi, res) // REG = &inter + + gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], ppc64.REGSP) + + nodsp.Xoffset = int64(gc.Widthptr) + if proc != 0 { + nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn + } + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset += int64(gc.Widthptr) + cgen(&nodi, &nodsp) // {8 or 24}(SP) = 8(REG) -- i.data + + regalloc(&nodo, gc.Types[gc.Tptr], res) + + nodi.Type = gc.Types[gc.Tptr] + nodi.Xoffset -= int64(gc.Widthptr) + cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab + regfree(&nodi) + + regalloc(&nodr, gc.Types[gc.Tptr], &nodo) + if n.Left.Xoffset == gc.BADWIDTH { + gc.Fatal("cgen_callinter: badwidth") + } + gc.Cgen_checknil(&nodo) // in case offset is huge + nodo.Op = gc.OINDREG + nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 + if proc == 0 { + // plain call: use direct c function pointer - more efficient + cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] + proc = 3 + } else { + // go/defer. generate go func value. + p = gins(ppc64.AMOVD, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] + p.From.Type = obj.TYPE_ADDR + } + + nodr.Type = n.Left.Type + ginscall(&nodr, proc) + + regfree(&nodr) + regfree(&nodo) +} + +/* + * generate function call; + * proc=0 normal call + * proc=1 goroutine run in new proc + * proc=2 defer call save away stack + */ +func cgen_call(n *gc.Node, proc int) { + var t *gc.Type + var nod gc.Node + var afun gc.Node + + if n == nil { + return + } + + if n.Left.Ullman >= gc.UINF { + // if name involves a fn call + // precompute the address of the fn + gc.Tempname(&afun, gc.Types[gc.Tptr]) + + cgen(n.Left, &afun) + } + + gc.Genlist(n.List) // assign the args + t = n.Left.Type + + // call tempname pointer + if n.Left.Ullman >= gc.UINF { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, &afun) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call pointer + if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { + regalloc(&nod, gc.Types[gc.Tptr], nil) + gc.Cgen_as(&nod, n.Left) + nod.Type = t + ginscall(&nod, proc) + regfree(&nod) + return + } + + // call direct + n.Left.Method = 1 + + ginscall(n.Left, proc) +} + +/* + * call to n has already been generated. + * generate: + * res = return value from call. + */ +func cgen_callret(n *gc.Node, res *gc.Node) { + var nod gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_callret: nil") + } + + nod = gc.Node{} + nod.Op = gc.OINDREG + nod.Val.U.Reg = ppc64.REGSP + nod.Addable = 1 + + nod.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved LR at 0(R1) + nod.Type = fp.Type + gc.Cgen_as(res, &nod) +} + +/* + * call to n has already been generated. + * generate: + * res = &return value from call. + */ +func cgen_aret(n *gc.Node, res *gc.Node) { + var nod1 gc.Node + var nod2 gc.Node + var fp *gc.Type + var t *gc.Type + var flist gc.Iter + + t = n.Left.Type + if gc.Isptr[t.Etype] != 0 { + t = t.Type + } + + fp = gc.Structfirst(&flist, gc.Getoutarg(t)) + if fp == nil { + gc.Fatal("cgen_aret: nil") + } + + nod1 = gc.Node{} + nod1.Op = gc.OINDREG + nod1.Val.U.Reg = ppc64.REGSP + nod1.Addable = 1 + + nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) + nod1.Type = fp.Type + + if res.Op != gc.OREGISTER { + regalloc(&nod2, gc.Types[gc.Tptr], res) + agen(&nod1, &nod2) + gins(ppc64.AMOVD, &nod2, res) + regfree(&nod2) + } else { + agen(&nod1, res) + } +} + +/* + * generate return. + * n->left is assignments to return values. + */ +func cgen_ret(n *gc.Node) { + var p *obj.Prog + + if n != nil { + gc.Genlist(n.List) // copy out args + } + if gc.Hasdefer != 0 { + ginscall(gc.Deferreturn, 0) + } + gc.Genlist(gc.Curfn.Exit) + p = gins(obj.ARET, nil, nil) + if n != nil && n.Op == gc.ORETJMP { + p.To.Name = obj.NAME_EXTERN + p.To.Type = obj.TYPE_ADDR + p.To.Sym = gc.Linksym(n.Left.Sym) + } +} + +/* + * generate division. + * generates one of: + * res = nl / nr + * res = nl % nr + * according to op. + */ +func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var a int + var check int + var t *gc.Type + var t0 *gc.Type + var tl gc.Node + var tr gc.Node + var tl2 gc.Node + var tr2 gc.Node + var nm1 gc.Node + var nz gc.Node + var tm gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + // Have to be careful about handling + // most negative int divided by -1 correctly. + // The hardware will generate undefined result. + // Also need to explicitly trap on division on zero, + // the hardware will silently generate undefined result. + // DIVW will leave unpredicable result in higher 32-bit, + // so always use DIVD/DIVDU. + t = nl.Type + + t0 = t + check = 0 + if gc.Issigned[t.Etype] != 0 { + check = 1 + if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= nr.Ullman { + cgen(nl, &tl) + cgen(nr, &tr) + } else { + cgen(nr, &tr) + cgen(nl, &tl) + } + + if t != t0 { + // Convert + tl2 = tl + + tr2 = tr + tl.Type = t + tr.Type = t + gmove(&tl2, &tl) + gmove(&tr2, &tr) + } + + // Handle divide-by-zero panic. + p1 = gins(optoas(gc.OCMP, t), &tr, nil) + + p1.To.Type = obj.TYPE_REG + p1.To.Reg = ppc64.REGZERO + p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) + if panicdiv == nil { + panicdiv = gc.Sysfunc("panicdivide") + } + ginscall(panicdiv, -1) + gc.Patch(p1, gc.Pc) + + if check != 0 { + gc.Nodconst(&nm1, t, -1) + gins(optoas(gc.OCMP, t), &tr, &nm1) + p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) + if op == gc.ODIV { + // a / (-1) is -a. + gins(optoas(gc.OMINUS, t), nil, &tl) + + gmove(&tl, res) + } else { + // a % (-1) is 0. + gc.Nodconst(&nz, t, 0) + + gmove(&nz, res) + } + + p2 = gc.Gbranch(obj.AJMP, nil, 0) + gc.Patch(p1, gc.Pc) + } + + p1 = gins(a, &tr, &tl) + if op == gc.ODIV { + regfree(&tr) + gmove(&tl, res) + } else { + // A%B = A-(A/B*B) + regalloc(&tm, t, nil) + + // patch div to use the 3 register form + // TODO(minux): add gins3? + p1.Reg = p1.To.Reg + + p1.To.Reg = tm.Val.U.Reg + gins(optoas(gc.OMUL, t), &tr, &tm) + regfree(&tr) + gins(optoas(gc.OSUB, t), &tm, &tl) + regfree(&tm) + gmove(&tl, res) + } + + regfree(&tl) + if check != 0 { + gc.Patch(p2, gc.Pc) + } +} + +/* + * generate division according to op, one of: + * res = nl / nr + * res = nl % nr + */ +func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var w int + var a int + var m gc.Magic + + // TODO(minux): enable division by magic multiply (also need to fix longmod below) + //if(nr->op != OLITERAL) + goto longdiv + + w = int(nl.Type.Width * 8) + + // Front end handled 32-bit division. We only need to handle 64-bit. + // try to do division by multiply by (2^w)/d + // see hacker's delight chapter 10 + switch gc.Simtype[nl.Type.Etype] { + default: + goto longdiv + + case gc.TUINT64: + m.W = w + m.Ud = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + gc.Umagic(&m) + if m.Bad != 0 { + break + } + if op == gc.OMOD { + goto longmod + } + + cgenr(nl, &n1, nil) + gc.Nodconst(&n2, nl.Type, int64(m.Um)) + regalloc(&n3, nl.Type, res) + cgen_hmul(&n1, &n2, &n3) + + if m.Ua != 0 { + // need to add numerator accounting for overflow + gins(optoas(gc.OADD, nl.Type), &n1, &n3) + + gc.Nodconst(&n2, nl.Type, 1) + gins(optoas(gc.ORROTC, nl.Type), &n2, &n3) + gc.Nodconst(&n2, nl.Type, int64(m.S)-1) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) + } else { + gc.Nodconst(&n2, nl.Type, int64(m.S)) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift dx + } + + gmove(&n3, res) + regfree(&n1) + regfree(&n3) + return + + case gc.TINT64: + m.W = w + m.Sd = gc.Mpgetfix(nr.Val.U.Xval) + gc.Smagic(&m) + if m.Bad != 0 { + break + } + if op == gc.OMOD { + goto longmod + } + + cgenr(nl, &n1, res) + gc.Nodconst(&n2, nl.Type, m.Sm) + regalloc(&n3, nl.Type, nil) + cgen_hmul(&n1, &n2, &n3) + + if m.Sm < 0 { + // need to add numerator + gins(optoas(gc.OADD, nl.Type), &n1, &n3) + } + + gc.Nodconst(&n2, nl.Type, int64(m.S)) + gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift n3 + + gc.Nodconst(&n2, nl.Type, int64(w)-1) + + gins(optoas(gc.ORSH, nl.Type), &n2, &n1) // -1 iff num is neg + gins(optoas(gc.OSUB, nl.Type), &n1, &n3) // added + + if m.Sd < 0 { + // this could probably be removed + // by factoring it into the multiplier + gins(optoas(gc.OMINUS, nl.Type), nil, &n3) + } + + gmove(&n3, res) + regfree(&n1) + regfree(&n3) + return + } + + goto longdiv + + // division and mod using (slow) hardware instruction +longdiv: + dodiv(op, nl, nr, res) + + return + + // mod using formula A%B = A-(A/B*B) but + // we know that there is a fast algorithm for A/B +longmod: + regalloc(&n1, nl.Type, res) + + cgen(nl, &n1) + regalloc(&n2, nl.Type, nil) + cgen_div(gc.ODIV, &n1, nr, &n2) + a = optoas(gc.OMUL, nl.Type) + if w == 8 { + } + // use 2-operand 16-bit multiply + // because there is no 2-operand 8-bit multiply + //a = AIMULW; + if !gc.Smallintconst(nr) { + regalloc(&n3, nl.Type, nil) + cgen(nr, &n3) + gins(a, &n3, &n2) + regfree(&n3) + } else { + gins(a, nr, &n2) + } + gins(optoas(gc.OSUB, nl.Type), &n2, &n1) + gmove(&n1, res) + regfree(&n1) + regfree(&n2) +} + +/* + * generate high multiply: + * res = (nl*nr) >> width + */ +func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { + var w int + var n1 gc.Node + var n2 gc.Node + var tmp *gc.Node + var t *gc.Type + var p *obj.Prog + + // largest ullman on left. + if nl.Ullman < nr.Ullman { + tmp = nl + nl = nr + nr = tmp + } + + t = nl.Type + w = int(t.Width * 8) + cgenr(nl, &n1, res) + cgenr(nr, &n2, nil) + switch gc.Simtype[t.Etype] { + case gc.TINT8, + gc.TINT16, + gc.TINT32: + gins(optoas(gc.OMUL, t), &n2, &n1) + p = gins(ppc64.ASRAD, nil, &n1) + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(w) + + case gc.TUINT8, + gc.TUINT16, + gc.TUINT32: + gins(optoas(gc.OMUL, t), &n2, &n1) + p = gins(ppc64.ASRD, nil, &n1) + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(w) + + case gc.TINT64, + gc.TUINT64: + if gc.Issigned[t.Etype] != 0 { + p = gins(ppc64.AMULHD, &n2, &n1) + } else { + p = gins(ppc64.AMULHDU, &n2, &n1) + } + + default: + gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0)) + } + + cgen(&n1, res) + regfree(&n1) + regfree(&n2) +} + +/* + * generate shift according to op, one of: + * res = nl << nr + * res = nl >> nr + */ +func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { + var n1 gc.Node + var n2 gc.Node + var n3 gc.Node + var n4 gc.Node + var n5 gc.Node + var a int + var p1 *obj.Prog + var sc uint64 + var tcount *gc.Type + + a = optoas(op, nl.Type) + + if nr.Op == gc.OLITERAL { + regalloc(&n1, nl.Type, res) + cgen(nl, &n1) + sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) + if sc >= uint64(nl.Type.Width*8) { + // large shift gets 2 shifts by width-1 + gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) + + gins(a, &n3, &n1) + gins(a, &n3, &n1) + } else { + gins(a, nr, &n1) + } + gmove(&n1, res) + regfree(&n1) + goto ret + } + + if nl.Ullman >= gc.UINF { + gc.Tempname(&n4, nl.Type) + cgen(nl, &n4) + nl = &n4 + } + + if nr.Ullman >= gc.UINF { + gc.Tempname(&n5, nr.Type) + cgen(nr, &n5) + nr = &n5 + } + + // Allow either uint32 or uint64 as shift type, + // to avoid unnecessary conversion from uint32 to uint64 + // just to do the comparison. + tcount = gc.Types[gc.Simtype[nr.Type.Etype]] + + if tcount.Etype < gc.TUINT32 { + tcount = gc.Types[gc.TUINT32] + } + + regalloc(&n1, nr.Type, nil) // to hold the shift type in CX + regalloc(&n3, tcount, &n1) // to clear high bits of CX + + regalloc(&n2, nl.Type, res) + + if nl.Ullman >= nr.Ullman { + cgen(nl, &n2) + cgen(nr, &n1) + gmove(&n1, &n3) + } else { + cgen(nr, &n1) + gmove(&n1, &n3) + cgen(nl, &n2) + } + + regfree(&n3) + + // test and fix up large shifts + if !bounded { + gc.Nodconst(&n3, tcount, nl.Type.Width*8) + gins(optoas(gc.OCMP, tcount), &n1, &n3) + p1 = gc.Gbranch(optoas(gc.OLT, tcount), nil, +1) + if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { + gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) + gins(a, &n3, &n2) + } else { + gc.Nodconst(&n3, nl.Type, 0) + gmove(&n3, &n2) + } + + gc.Patch(p1, gc.Pc) + } + + gins(a, &n1, &n2) + + gmove(&n2, res) + + regfree(&n1) + regfree(&n2) + +ret: +} + +func clearfat(nl *gc.Node) { + var w uint64 + var c uint64 + var q uint64 + var t uint64 + var boff uint64 + var dst gc.Node + var end gc.Node + var r0 gc.Node + var f *gc.Node + var p *obj.Prog + var pl *obj.Prog + + /* clear a fat object */ + if gc.Debug['g'] != 0 { + fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width) + } + + w = uint64(nl.Type.Width) + + // Avoid taking the address for simple enough types. + //if(componentgen(N, nl)) + // return; + + c = w % 8 // bytes + q = w / 8 // dwords + + if reg[ppc64.REGRT1] > 0 { + gc.Fatal("R%d in use during clearfat", ppc64.REGRT1) + } + + gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REG_R0) // r0 is always zero + gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1) + reg[ppc64.REGRT1]++ + agen(nl, &dst) + + if q > 128 { + p = gins(ppc64.ASUB, nil, &dst) + p.From.Type = obj.TYPE_CONST + p.From.Offset = 8 + + regalloc(&end, gc.Types[gc.Tptr], nil) + p = gins(ppc64.AMOVD, &dst, &end) + p.From.Type = obj.TYPE_ADDR + p.From.Offset = int64(q * 8) + + p = gins(ppc64.AMOVDU, &r0, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = 8 + pl = p + + p = gins(ppc64.ACMP, &dst, &end) + gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl) + + regfree(&end) + + // The loop leaves R3 on the last zeroed dword + boff = 8 + } else if q >= 4 { + p = gins(ppc64.ASUB, nil, &dst) + p.From.Type = obj.TYPE_CONST + p.From.Offset = 8 + f = gc.Sysfunc("duffzero") + p = gins(obj.ADUFFZERO, nil, f) + gc.Afunclit(&p.To, f) + + // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s + p.To.Offset = int64(4 * (128 - q)) + + // duffzero leaves R3 on the last zeroed dword + boff = 8 + } else { + for t = 0; t < q; t++ { + p = gins(ppc64.AMOVD, &r0, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(8 * t) + } + + boff = 8 * q + } + + for t = 0; t < c; t++ { + p = gins(ppc64.AMOVB, &r0, &dst) + p.To.Type = obj.TYPE_MEM + p.To.Offset = int64(t + boff) + } + + reg[ppc64.REGRT1]-- +} + +// Called after regopt and peep have run. +// Expand CHECKNIL pseudo-op into actual nil pointer check. +func expandchecks(firstp *obj.Prog) { + var p *obj.Prog + var p1 *obj.Prog + var p2 *obj.Prog + + for p = firstp; p != nil; p = p.Link { + if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 { + fmt.Printf("expandchecks: %v\n", p) + } + if p.As != obj.ACHECKNIL { + continue + } + if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers + gc.Warnl(int(p.Lineno), "generated nil check") + } + if p.From.Type != obj.TYPE_REG { + gc.Fatal("invalid nil check %v\n", p) + } + + /* + // check is + // TD $4, R0, arg (R0 is always zero) + // eqv. to: + // tdeq r0, arg + // NOTE: this needs special runtime support to make SIGTRAP recoverable. + reg = p->from.reg; + p->as = ATD; + p->from = p->to = p->from3 = zprog.from; + p->from.type = TYPE_CONST; + p->from.offset = 4; + p->from.reg = 0; + p->reg = REG_R0; + p->to.type = TYPE_REG; + p->to.reg = reg; + */ + // check is + // CMP arg, R0 + // BNE 2(PC) [likely] + // MOVD R0, 0(R0) + p1 = gc.Ctxt.NewProg() + + p2 = gc.Ctxt.NewProg() + gc.Clearp(p1) + gc.Clearp(p2) + p1.Link = p2 + p2.Link = p.Link + p.Link = p1 + p1.Lineno = p.Lineno + p2.Lineno = p.Lineno + p1.Pc = 9999 + p2.Pc = 9999 + p.As = ppc64.ACMP + p.To.Type = obj.TYPE_REG + p.To.Reg = ppc64.REGZERO + p1.As = ppc64.ABNE + + //p1->from.type = TYPE_CONST; + //p1->from.offset = 1; // likely + p1.To.Type = obj.TYPE_BRANCH + + p1.To.U.Branch = p2.Link + + // crash by write to memory address 0. + p2.As = ppc64.AMOVD + + p2.From.Type = obj.TYPE_REG + p2.From.Reg = ppc64.REG_R0 + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = ppc64.REG_R0 + p2.To.Offset = 0 + } +} diff --git a/src/cmd/9g/gsubr.c b/src/cmd/9g/gsubr.c deleted file mode 100644 index 1fb1511361..0000000000 --- a/src/cmd/9g/gsubr.c +++ /dev/null @@ -1,1158 +0,0 @@ -// Derived from Inferno utils/6c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../../runtime/funcdata.h" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 6l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -vlong unmappedzero = 4096; - -static int resvd[] = -{ - REGZERO, - REGSP, // reserved for SP - // We need to preserve the C ABI TLS pointer because sigtramp - // may happen during C code and needs to access the g. C - // clobbers REGG, so if Go were to clobber REGTLS, sigtramp - // won't know which convention to use. By preserving REGTLS, - // we can just retrieve g from TLS when we aren't sure. - REGTLS, - // TODO(austin): Consolidate REGTLS and REGG? - REGG, - REGTMP, // REGTMP - FREGCVI, - FREGZERO, - FREGHALF, - FREGONE, - FREGTWO, -}; - -void -ginit(void) -{ - int i; - - for(i=0; ietype]; - - if(debug['r']) { - fixfree = 0; - fltfree = 0; - for(i = REG_R0; i < REG_F31; i++) - if(reg[i - REG_R0] == 0) { - if(i < REG_F0) - fixfree++; - else - fltfree++; - } - print("regalloc fix %d flt %d free\n", fixfree, fltfree); - } - - switch(et) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TPTR32: - case TPTR64: - case TBOOL: - if(o != N && o->op == OREGISTER) { - i = o->val.u.reg; - if(i >= REGMIN && i <= REGMAX) - goto out; - } - for(i=REGMIN; i<=REGMAX; i++) - if(reg[i - REG_R0] == 0) { - regpc[i - REG_R0] = (uintptr)getcallerpc(&n); - goto out; - } - flusherrors(); - for(i=REG_R0; iop == OREGISTER) { - i = o->val.u.reg; - if(i >= FREGMIN && i <= FREGMAX) - goto out; - } - for(i=FREGMIN; i<=FREGMAX; i++) - if(reg[i - REG_R0] == 0) { - regpc[i - REG_R0] = (uintptr)getcallerpc(&n); - goto out; - } - flusherrors(); - for(i=REG_F0; iop == ONAME) - return; - if(n->op != OREGISTER && n->op != OINDREG) - fatal("regfree: not a register"); - i = n->val.u.reg - REG_R0; - if(i == REGSP - REG_R0) - return; - if(i < 0 || i >= nelem(reg)) - fatal("regfree: reg out of range"); - if(reg[i] <= 0) - fatal("regfree: reg not allocated"); - reg[i]--; - if(reg[i] == 0) - regpc[i] = 0; -} - -/* - * generate - * as $c, n - */ -void -ginscon(int as, vlong c, Node *n2) -{ - Node n1, ntmp; - - nodconst(&n1, types[TINT64], c); - - if(as != AMOVD && (c < -BIG || c > BIG)) { - // cannot have more than 16-bit of immediate in ADD, etc. - // instead, MOV into register first. - regalloc(&ntmp, types[TINT64], N); - gins(AMOVD, &n1, &ntmp); - gins(as, &ntmp, n2); - regfree(&ntmp); - return; - } - gins(as, &n1, n2); -} - -/* - * generate - * as n, $c (CMP/CMPU) - */ -void -ginscon2(int as, Node *n2, vlong c) -{ - Node n1, ntmp; - - nodconst(&n1, types[TINT64], c); - - switch(as) { - default: - fatal("ginscon2"); - case ACMP: - if(-BIG <= c && c <= BIG) { - gins(as, n2, &n1); - return; - } - break; - case ACMPU: - if(0 <= c && c <= 2*BIG) { - gins(as, n2, &n1); - return; - } - break; - } - // MOV n1 into register first - regalloc(&ntmp, types[TINT64], N); - gins(AMOVD, &n1, &ntmp); - gins(as, n2, &ntmp); - regfree(&ntmp); -} - -#define CASE(a,b) (((a)<<16)|((b)<<0)) -/*c2go int CASE(int, int); */ - -/* - * set up nodes representing 2^63 - */ -Node bigi; -Node bigf; - -void -bignodes(void) -{ - static int did; - - if(did) - return; - did = 1; - - nodconst(&bigi, types[TUINT64], 1); - mpshiftfix(bigi.val.u.xval, 63); - - bigf = bigi; - bigf.type = types[TFLOAT64]; - bigf.val.ctype = CTFLT; - bigf.val.u.fval = mal(sizeof *bigf.val.u.fval); - mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval); -} - -/* - * generate move: - * t = f - * hard part is conversions. - */ -void -gmove(Node *f, Node *t) -{ - int a, ft, tt; - Type *cvt; - Node r1, r2, r3, con; - Prog *p1, *p2; - - if(debug['M']) - print("gmove %lN -> %lN\n", f, t); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - cvt = t->type; - - if(iscomplex[ft] || iscomplex[tt]) { - complexmove(f, t); - return; - } - - // cannot have two memory operands - if(ismem(f) && ismem(t)) - goto hard; - - // convert constant to desired type - if(f->op == OLITERAL) { - switch(tt) { - default: - convconst(&con, t->type, &f->val); - break; - - case TINT32: - case TINT16: - case TINT8: - convconst(&con, types[TINT64], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVD, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - - case TUINT32: - case TUINT16: - case TUINT8: - convconst(&con, types[TUINT64], &f->val); - regalloc(&r1, con.type, t); - gins(AMOVD, &con, &r1); - gmove(&r1, t); - regfree(&r1); - return; - } - - f = &con; - ft = tt; // so big switch will choose a simple mov - - // constants can't move directly to memory. - if(ismem(t)) { - goto hard; - // float constants come from memory. - //if(isfloat[tt]) - // goto hard; - - // 64-bit immediates are also from memory. - //if(isint[tt]) - // goto hard; - //// 64-bit immediates are really 32-bit sign-extended - //// unless moving into a register. - //if(isint[tt]) { - // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) - // goto hard; - // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) - // goto hard; - //} - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch(CASE(ft, tt)) { - default: - fatal("gmove %lT -> %lT", f->type, t->type); - - /* - * integer copy and truncate - */ - case CASE(TINT8, TINT8): // same size - case CASE(TUINT8, TINT8): - case CASE(TINT16, TINT8): // truncate - case CASE(TUINT16, TINT8): - case CASE(TINT32, TINT8): - case CASE(TUINT32, TINT8): - case CASE(TINT64, TINT8): - case CASE(TUINT64, TINT8): - a = AMOVB; - break; - - case CASE(TINT8, TUINT8): // same size - case CASE(TUINT8, TUINT8): - case CASE(TINT16, TUINT8): // truncate - case CASE(TUINT16, TUINT8): - case CASE(TINT32, TUINT8): - case CASE(TUINT32, TUINT8): - case CASE(TINT64, TUINT8): - case CASE(TUINT64, TUINT8): - a = AMOVBZ; - break; - - case CASE(TINT16, TINT16): // same size - case CASE(TUINT16, TINT16): - case CASE(TINT32, TINT16): // truncate - case CASE(TUINT32, TINT16): - case CASE(TINT64, TINT16): - case CASE(TUINT64, TINT16): - a = AMOVH; - break; - - case CASE(TINT16, TUINT16): // same size - case CASE(TUINT16, TUINT16): - case CASE(TINT32, TUINT16): // truncate - case CASE(TUINT32, TUINT16): - case CASE(TINT64, TUINT16): - case CASE(TUINT64, TUINT16): - a = AMOVHZ; - break; - - case CASE(TINT32, TINT32): // same size - case CASE(TUINT32, TINT32): - case CASE(TINT64, TINT32): // truncate - case CASE(TUINT64, TINT32): - a = AMOVW; - break; - - case CASE(TINT32, TUINT32): // same size - case CASE(TUINT32, TUINT32): - case CASE(TINT64, TUINT32): - case CASE(TUINT64, TUINT32): - a = AMOVWZ; - break; - - case CASE(TINT64, TINT64): // same size - case CASE(TINT64, TUINT64): - case CASE(TUINT64, TINT64): - case CASE(TUINT64, TUINT64): - a = AMOVD; - break; - - /* - * integer up-conversions - */ - case CASE(TINT8, TINT16): // sign extend int8 - case CASE(TINT8, TUINT16): - case CASE(TINT8, TINT32): - case CASE(TINT8, TUINT32): - case CASE(TINT8, TINT64): - case CASE(TINT8, TUINT64): - a = AMOVB; - goto rdst; - - case CASE(TUINT8, TINT16): // zero extend uint8 - case CASE(TUINT8, TUINT16): - case CASE(TUINT8, TINT32): - case CASE(TUINT8, TUINT32): - case CASE(TUINT8, TINT64): - case CASE(TUINT8, TUINT64): - a = AMOVBZ; - goto rdst; - - case CASE(TINT16, TINT32): // sign extend int16 - case CASE(TINT16, TUINT32): - case CASE(TINT16, TINT64): - case CASE(TINT16, TUINT64): - a = AMOVH; - goto rdst; - - case CASE(TUINT16, TINT32): // zero extend uint16 - case CASE(TUINT16, TUINT32): - case CASE(TUINT16, TINT64): - case CASE(TUINT16, TUINT64): - a = AMOVHZ; - goto rdst; - - case CASE(TINT32, TINT64): // sign extend int32 - case CASE(TINT32, TUINT64): - a = AMOVW; - goto rdst; - - case CASE(TUINT32, TINT64): // zero extend uint32 - case CASE(TUINT32, TUINT64): - a = AMOVWZ; - goto rdst; - - /* - * float to integer - */ - case CASE(TFLOAT32, TINT32): - case CASE(TFLOAT64, TINT32): - case CASE(TFLOAT32, TINT64): - case CASE(TFLOAT64, TINT64): - case CASE(TFLOAT32, TINT16): - case CASE(TFLOAT32, TINT8): - case CASE(TFLOAT32, TUINT16): - case CASE(TFLOAT32, TUINT8): - case CASE(TFLOAT64, TINT16): - case CASE(TFLOAT64, TINT8): - case CASE(TFLOAT64, TUINT16): - case CASE(TFLOAT64, TUINT8): - case CASE(TFLOAT32, TUINT32): - case CASE(TFLOAT64, TUINT32): - case CASE(TFLOAT32, TUINT64): - case CASE(TFLOAT64, TUINT64): - //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t); - //return; - // algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - bignodes(); - regalloc(&r1, types[ft], f); - gmove(f, &r1); - if(tt == TUINT64) { - regalloc(&r2, types[TFLOAT64], N); - gmove(&bigf, &r2); - gins(AFCMPU, &r1, &r2); - p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1); - gins(AFSUB, &r2, &r1); - patch(p1, pc); - regfree(&r2); - } - regalloc(&r2, types[TFLOAT64], N); - regalloc(&r3, types[TINT64], t); - gins(AFCTIDZ, &r1, &r2); - p1 = gins(AFMOVD, &r2, N); - p1->to.type = TYPE_MEM; - p1->to.reg = REGSP; - p1->to.offset = -8; - p1 = gins(AMOVD, N, &r3); - p1->from.type = TYPE_MEM; - p1->from.reg = REGSP; - p1->from.offset = -8; - regfree(&r2); - regfree(&r1); - if(tt == TUINT64) { - p1 = gbranch(optoas(OLT, types[TFLOAT64]), T, +1); // use CR0 here again - nodreg(&r1, types[TINT64], REGTMP); - gins(AMOVD, &bigi, &r1); - gins(AADD, &r1, &r3); - patch(p1, pc); - } - gmove(&r3, t); - regfree(&r3); - return; - - /* - * integer to float - */ - case CASE(TINT32, TFLOAT32): - case CASE(TINT32, TFLOAT64): - case CASE(TINT64, TFLOAT32): - case CASE(TINT64, TFLOAT64): - case CASE(TINT16, TFLOAT32): - case CASE(TINT16, TFLOAT64): - case CASE(TINT8, TFLOAT32): - case CASE(TINT8, TFLOAT64): - case CASE(TUINT16, TFLOAT32): - case CASE(TUINT16, TFLOAT64): - case CASE(TUINT8, TFLOAT32): - case CASE(TUINT8, TFLOAT64): - case CASE(TUINT32, TFLOAT32): - case CASE(TUINT32, TFLOAT64): - case CASE(TUINT64, TFLOAT32): - case CASE(TUINT64, TFLOAT64): - //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t); - //return; - // algorithm is: - // if small enough, use native int64 -> uint64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - bignodes(); - regalloc(&r1, types[TINT64], N); - gmove(f, &r1); - if(ft == TUINT64) { - nodreg(&r2, types[TUINT64], REGTMP); - gmove(&bigi, &r2); - gins(ACMPU, &r1, &r2); - p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); - p2 = gins(ASRD, N, &r1); - p2->from.type = TYPE_CONST; - p2->from.offset = 1; - patch(p1, pc); - } - regalloc(&r2, types[TFLOAT64], t); - p1 = gins(AMOVD, &r1, N); - p1->to.type = TYPE_MEM; - p1->to.reg = REGSP; - p1->to.offset = -8; - p1 = gins(AFMOVD, N, &r2); - p1->from.type = TYPE_MEM; - p1->from.reg = REGSP; - p1->from.offset = -8; - gins(AFCFID, &r2, &r2); - regfree(&r1); - if(ft == TUINT64) { - p1 = gbranch(optoas(OLT, types[TUINT64]), T, +1); // use CR0 here again - nodreg(&r1, types[TFLOAT64], FREGTWO); - gins(AFMUL, &r1, &r2); - patch(p1, pc); - } - gmove(&r2, t); - regfree(&r2); - return; - - /* - * float to float - */ - case CASE(TFLOAT32, TFLOAT32): - a = AFMOVS; - break; - - case CASE(TFLOAT64, TFLOAT64): - a = AFMOVD; - break; - - case CASE(TFLOAT32, TFLOAT64): - a = AFMOVS; - goto rdst; - - case CASE(TFLOAT64, TFLOAT32): - a = AFRSP; - goto rdst; - } - - gins(a, f, t); - return; - -rdst: - // requires register destination - regalloc(&r1, t->type, t); - gins(a, f, &r1); - gmove(&r1, t); - regfree(&r1); - return; - -hard: - // requires register intermediate - regalloc(&r1, cvt, t); - gmove(f, &r1); - gmove(&r1, t); - regfree(&r1); - return; -} - -/* - * generate one instruction: - * as f, t - */ -Prog* -gins(int as, Node *f, Node *t) -{ - int32 w; - Prog *p; - Addr af, at; - - // TODO(austin): Add self-move test like in 6g (but be careful - // of truncation moves) - - memset(&af, 0, sizeof af); - memset(&at, 0, sizeof at); - if(f != N) - naddr(f, &af, 1); - if(t != N) - naddr(t, &at, 1); - p = prog(as); - if(f != N) - p->from = af; - if(t != N) - p->to = at; - if(debug['g']) - print("%P\n", p); - - w = 0; - switch(as) { - case AMOVB: - case AMOVBU: - case AMOVBZ: - case AMOVBZU: - w = 1; - break; - case AMOVH: - case AMOVHU: - case AMOVHZ: - case AMOVHZU: - w = 2; - break; - case AMOVW: - case AMOVWU: - case AMOVWZ: - case AMOVWZU: - w = 4; - break; - case AMOVD: - case AMOVDU: - if(af.type == TYPE_CONST || af.type == TYPE_ADDR) - break; - w = 8; - break; - } - if(w != 0 && ((f != N && af.width < w) || (t != N && at.type != TYPE_REG && at.width > w))) { - dump("f", f); - dump("t", t); - fatal("bad width: %P (%d, %d)\n", p, af.width, at.width); - } - - return p; -} - -void -fixlargeoffset(Node *n) -{ - Node a; - - if(n == N) - return; - if(n->op != OINDREG) - return; - if(n->val.u.reg == REGSP) // stack offset cannot be large - return; - if(n->xoffset != (int32)n->xoffset) { - // TODO(minux): offset too large, move into R31 and add to R31 instead. - // this is used only in test/fixedbugs/issue6036.go. - fatal("offset too large: %N", n); - a = *n; - a.op = OREGISTER; - a.type = types[tptr]; - a.xoffset = 0; - cgen_checknil(&a); - ginscon(optoas(OADD, types[tptr]), n->xoffset, &a); - n->xoffset = 0; - } -} - -/* - * return Axxx for Oxxx on type t. - */ -int -optoas(int op, Type *t) -{ - int a; - - if(t == T) - fatal("optoas: t is nil"); - - a = AXXX; - switch(CASE(op, simtype[t->etype])) { - default: - fatal("optoas: no entry for op=%O type=%T", op, t); - break; - - case CASE(OEQ, TBOOL): - case CASE(OEQ, TINT8): - case CASE(OEQ, TUINT8): - case CASE(OEQ, TINT16): - case CASE(OEQ, TUINT16): - case CASE(OEQ, TINT32): - case CASE(OEQ, TUINT32): - case CASE(OEQ, TINT64): - case CASE(OEQ, TUINT64): - case CASE(OEQ, TPTR32): - case CASE(OEQ, TPTR64): - case CASE(OEQ, TFLOAT32): - case CASE(OEQ, TFLOAT64): - a = ABEQ; - break; - - case CASE(ONE, TBOOL): - case CASE(ONE, TINT8): - case CASE(ONE, TUINT8): - case CASE(ONE, TINT16): - case CASE(ONE, TUINT16): - case CASE(ONE, TINT32): - case CASE(ONE, TUINT32): - case CASE(ONE, TINT64): - case CASE(ONE, TUINT64): - case CASE(ONE, TPTR32): - case CASE(ONE, TPTR64): - case CASE(ONE, TFLOAT32): - case CASE(ONE, TFLOAT64): - a = ABNE; - break; - - case CASE(OLT, TINT8): // ACMP - case CASE(OLT, TINT16): - case CASE(OLT, TINT32): - case CASE(OLT, TINT64): - case CASE(OLT, TUINT8): // ACMPU - case CASE(OLT, TUINT16): - case CASE(OLT, TUINT32): - case CASE(OLT, TUINT64): - case CASE(OLT, TFLOAT32): // AFCMPU - case CASE(OLT, TFLOAT64): - a = ABLT; - break; - - case CASE(OLE, TINT8): // ACMP - case CASE(OLE, TINT16): - case CASE(OLE, TINT32): - case CASE(OLE, TINT64): - case CASE(OLE, TUINT8): // ACMPU - case CASE(OLE, TUINT16): - case CASE(OLE, TUINT32): - case CASE(OLE, TUINT64): - case CASE(OLE, TFLOAT32): // AFCMPU - case CASE(OLE, TFLOAT64): - a = ABLE; - break; - - case CASE(OGT, TINT8): - case CASE(OGT, TINT16): - case CASE(OGT, TINT32): - case CASE(OGT, TINT64): - case CASE(OGT, TUINT8): - case CASE(OGT, TUINT16): - case CASE(OGT, TUINT32): - case CASE(OGT, TUINT64): - case CASE(OGT, TFLOAT32): - case CASE(OGT, TFLOAT64): - a = ABGT; - break; - - case CASE(OGE, TINT8): - case CASE(OGE, TINT16): - case CASE(OGE, TINT32): - case CASE(OGE, TINT64): - case CASE(OGE, TUINT8): - case CASE(OGE, TUINT16): - case CASE(OGE, TUINT32): - case CASE(OGE, TUINT64): - case CASE(OGE, TFLOAT32): - case CASE(OGE, TFLOAT64): - a = ABGE; - break; - - case CASE(OCMP, TBOOL): - case CASE(OCMP, TINT8): - case CASE(OCMP, TINT16): - case CASE(OCMP, TINT32): - case CASE(OCMP, TPTR32): - case CASE(OCMP, TINT64): - a = ACMP; - break; - - case CASE(OCMP, TUINT8): - case CASE(OCMP, TUINT16): - case CASE(OCMP, TUINT32): - case CASE(OCMP, TUINT64): - case CASE(OCMP, TPTR64): - a = ACMPU; - break; - - case CASE(OCMP, TFLOAT32): - case CASE(OCMP, TFLOAT64): - a = AFCMPU; - break; - - case CASE(OAS, TBOOL): - case CASE(OAS, TINT8): - a = AMOVB; - break; - - case CASE(OAS, TUINT8): - a = AMOVBZ; - break; - - case CASE(OAS, TINT16): - a = AMOVH; - break; - - case CASE(OAS, TUINT16): - a = AMOVHZ; - break; - - case CASE(OAS, TINT32): - a = AMOVW; - break; - - case CASE(OAS, TUINT32): - case CASE(OAS, TPTR32): - a = AMOVWZ; - break; - - case CASE(OAS, TINT64): - case CASE(OAS, TUINT64): - case CASE(OAS, TPTR64): - a = AMOVD; - break; - - case CASE(OAS, TFLOAT32): - a = AFMOVS; - break; - - case CASE(OAS, TFLOAT64): - a = AFMOVD; - break; - - case CASE(OADD, TINT8): - case CASE(OADD, TUINT8): - case CASE(OADD, TINT16): - case CASE(OADD, TUINT16): - case CASE(OADD, TINT32): - case CASE(OADD, TUINT32): - case CASE(OADD, TPTR32): - case CASE(OADD, TINT64): - case CASE(OADD, TUINT64): - case CASE(OADD, TPTR64): - a = AADD; - break; - - case CASE(OADD, TFLOAT32): - a = AFADDS; - break; - - case CASE(OADD, TFLOAT64): - a = AFADD; - break; - - case CASE(OSUB, TINT8): - case CASE(OSUB, TUINT8): - case CASE(OSUB, TINT16): - case CASE(OSUB, TUINT16): - case CASE(OSUB, TINT32): - case CASE(OSUB, TUINT32): - case CASE(OSUB, TPTR32): - case CASE(OSUB, TINT64): - case CASE(OSUB, TUINT64): - case CASE(OSUB, TPTR64): - a = ASUB; - break; - - case CASE(OSUB, TFLOAT32): - a = AFSUBS; - break; - - case CASE(OSUB, TFLOAT64): - a = AFSUB; - break; - - case CASE(OMINUS, TINT8): - case CASE(OMINUS, TUINT8): - case CASE(OMINUS, TINT16): - case CASE(OMINUS, TUINT16): - case CASE(OMINUS, TINT32): - case CASE(OMINUS, TUINT32): - case CASE(OMINUS, TPTR32): - case CASE(OMINUS, TINT64): - case CASE(OMINUS, TUINT64): - case CASE(OMINUS, TPTR64): - a = ANEG; - break; - - case CASE(OAND, TINT8): - case CASE(OAND, TUINT8): - case CASE(OAND, TINT16): - case CASE(OAND, TUINT16): - case CASE(OAND, TINT32): - case CASE(OAND, TUINT32): - case CASE(OAND, TPTR32): - case CASE(OAND, TINT64): - case CASE(OAND, TUINT64): - case CASE(OAND, TPTR64): - a = AAND; - break; - - case CASE(OOR, TINT8): - case CASE(OOR, TUINT8): - case CASE(OOR, TINT16): - case CASE(OOR, TUINT16): - case CASE(OOR, TINT32): - case CASE(OOR, TUINT32): - case CASE(OOR, TPTR32): - case CASE(OOR, TINT64): - case CASE(OOR, TUINT64): - case CASE(OOR, TPTR64): - a = AOR; - break; - - case CASE(OXOR, TINT8): - case CASE(OXOR, TUINT8): - case CASE(OXOR, TINT16): - case CASE(OXOR, TUINT16): - case CASE(OXOR, TINT32): - case CASE(OXOR, TUINT32): - case CASE(OXOR, TPTR32): - case CASE(OXOR, TINT64): - case CASE(OXOR, TUINT64): - case CASE(OXOR, TPTR64): - a = AXOR; - break; - - // TODO(minux): handle rotates - //case CASE(OLROT, TINT8): - //case CASE(OLROT, TUINT8): - //case CASE(OLROT, TINT16): - //case CASE(OLROT, TUINT16): - //case CASE(OLROT, TINT32): - //case CASE(OLROT, TUINT32): - //case CASE(OLROT, TPTR32): - //case CASE(OLROT, TINT64): - //case CASE(OLROT, TUINT64): - //case CASE(OLROT, TPTR64): - // a = 0//???; RLDC? - // break; - - case CASE(OLSH, TINT8): - case CASE(OLSH, TUINT8): - case CASE(OLSH, TINT16): - case CASE(OLSH, TUINT16): - case CASE(OLSH, TINT32): - case CASE(OLSH, TUINT32): - case CASE(OLSH, TPTR32): - case CASE(OLSH, TINT64): - case CASE(OLSH, TUINT64): - case CASE(OLSH, TPTR64): - a = ASLD; - break; - - case CASE(ORSH, TUINT8): - case CASE(ORSH, TUINT16): - case CASE(ORSH, TUINT32): - case CASE(ORSH, TPTR32): - case CASE(ORSH, TUINT64): - case CASE(ORSH, TPTR64): - a = ASRD; - break; - - case CASE(ORSH, TINT8): - case CASE(ORSH, TINT16): - case CASE(ORSH, TINT32): - case CASE(ORSH, TINT64): - a = ASRAD; - break; - - // TODO(minux): handle rotates - //case CASE(ORROTC, TINT8): - //case CASE(ORROTC, TUINT8): - //case CASE(ORROTC, TINT16): - //case CASE(ORROTC, TUINT16): - //case CASE(ORROTC, TINT32): - //case CASE(ORROTC, TUINT32): - //case CASE(ORROTC, TINT64): - //case CASE(ORROTC, TUINT64): - // a = 0//??? RLDC?? - // break; - - case CASE(OHMUL, TINT64): - a = AMULHD; - break; - case CASE(OHMUL, TUINT64): - case CASE(OHMUL, TPTR64): - a = AMULHDU; - break; - - case CASE(OMUL, TINT8): - case CASE(OMUL, TINT16): - case CASE(OMUL, TINT32): - case CASE(OMUL, TINT64): - a = AMULLD; - break; - - case CASE(OMUL, TUINT8): - case CASE(OMUL, TUINT16): - case CASE(OMUL, TUINT32): - case CASE(OMUL, TPTR32): - // don't use word multiply, the high 32-bit are undefined. - // fallthrough - case CASE(OMUL, TUINT64): - case CASE(OMUL, TPTR64): - a = AMULLD; // for 64-bit multiplies, signedness doesn't matter. - break; - - case CASE(OMUL, TFLOAT32): - a = AFMULS; - break; - - case CASE(OMUL, TFLOAT64): - a = AFMUL; - break; - - case CASE(ODIV, TINT8): - case CASE(ODIV, TINT16): - case CASE(ODIV, TINT32): - case CASE(ODIV, TINT64): - a = ADIVD; - break; - - case CASE(ODIV, TUINT8): - case CASE(ODIV, TUINT16): - case CASE(ODIV, TUINT32): - case CASE(ODIV, TPTR32): - case CASE(ODIV, TUINT64): - case CASE(ODIV, TPTR64): - a = ADIVDU; - break; - - case CASE(ODIV, TFLOAT32): - a = AFDIVS; - break; - - case CASE(ODIV, TFLOAT64): - a = AFDIV; - break; - - } - return a; -} - -enum -{ - ODynam = 1<<0, - OAddable = 1<<1, -}; - -int -xgen(Node *n, Node *a, int o) -{ - // TODO(minux) - USED(n); USED(a); USED(o); - return -1; -} - -void -sudoclean(void) -{ - return; -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -int -sudoaddable(int as, Node *n, Addr *a) -{ - // TODO(minux) - USED(as); USED(n); - memset(a, 0, sizeof *a); - return 0; -} diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go new file mode 100644 index 0000000000..91e87ff015 --- /dev/null +++ b/src/cmd/9g/gsubr.go @@ -0,0 +1,1165 @@ +// Derived from Inferno utils/6c/txt.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" + "fmt" +) +import "cmd/internal/gc" + +// TODO(rsc): Can make this bigger if we move +// the text segment up higher in 6l for all GOOS. +// At the same time, can raise StackBig in ../../runtime/stack.h. +var unmappedzero int64 = 4096 + +var resvd = []int{ + ppc64.REGZERO, + ppc64.REGSP, // reserved for SP + // We need to preserve the C ABI TLS pointer because sigtramp + // may happen during C code and needs to access the g. C + // clobbers REGG, so if Go were to clobber REGTLS, sigtramp + // won't know which convention to use. By preserving REGTLS, + // we can just retrieve g from TLS when we aren't sure. + ppc64.REGTLS, + + // TODO(austin): Consolidate REGTLS and REGG? + ppc64.REGG, + ppc64.REGTMP, // REGTMP + ppc64.FREGCVI, + ppc64.FREGZERO, + ppc64.FREGHALF, + ppc64.FREGONE, + ppc64.FREGTWO, +} + +func ginit() { + var i int + + for i = 0; i < len(reg); i++ { + reg[i] = 1 + } + for i = 0; i < ppc64.NREG+ppc64.NFREG; i++ { + reg[i] = 0 + } + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]-ppc64.REG_R0]++ + } +} + +var regpc [len(reg)]uint32 + +func gclean() { + var i int + + for i = 0; i < len(resvd); i++ { + reg[resvd[i]-ppc64.REG_R0]-- + } + + for i = 0; i < len(reg); i++ { + if reg[i] != 0 { + gc.Yyerror("reg %v left allocated, %p\n", gc.Ctxt.Rconv(i+ppc64.REG_R0), regpc[i]) + } + } +} + +func anyregalloc() bool { + var i int + var j int + + for i = 0; i < len(reg); i++ { + if reg[i] == 0 { + goto ok + } + for j = 0; j < len(resvd); j++ { + if resvd[j] == i { + goto ok + } + } + return true + ok: + } + + return false +} + +/* + * allocate register of type t, leave in n. + * if o != N, o is desired fixed register. + * caller must regfree(n). + */ +func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { + var i int + var et int + var fixfree int + var fltfree int + + if t == nil { + gc.Fatal("regalloc: t nil") + } + et = int(gc.Simtype[t.Etype]) + + if gc.Debug['r'] != 0 { + fixfree = 0 + fltfree = 0 + for i = ppc64.REG_R0; i < ppc64.REG_F31; i++ { + if reg[i-ppc64.REG_R0] == 0 { + if i < ppc64.REG_F0 { + fixfree++ + } else { + fltfree++ + } + } + } + + fmt.Printf("regalloc fix %d flt %d free\n", fixfree, fltfree) + } + + switch et { + case gc.TINT8, + gc.TUINT8, + gc.TINT16, + gc.TUINT16, + gc.TINT32, + gc.TUINT32, + gc.TINT64, + gc.TUINT64, + gc.TPTR32, + gc.TPTR64, + gc.TBOOL: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= ppc64.REGMIN && i <= ppc64.REGMAX { + goto out + } + } + + for i = ppc64.REGMIN; i <= ppc64.REGMAX; i++ { + if reg[i-ppc64.REG_R0] == 0 { + regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n)) + goto out + } + } + + gc.Flusherrors() + for i = ppc64.REG_R0; i < ppc64.REG_R0+ppc64.NREG; i++ { + fmt.Printf("R%d %p\n", i, regpc[i-ppc64.REG_R0]) + } + gc.Fatal("out of fixed registers") + + case gc.TFLOAT32, + gc.TFLOAT64: + if o != nil && o.Op == gc.OREGISTER { + i = int(o.Val.U.Reg) + if i >= ppc64.FREGMIN && i <= ppc64.FREGMAX { + goto out + } + } + + for i = ppc64.FREGMIN; i <= ppc64.FREGMAX; i++ { + if reg[i-ppc64.REG_R0] == 0 { + regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n)) + goto out + } + } + + gc.Flusherrors() + for i = ppc64.REG_F0; i < ppc64.REG_F0+ppc64.NREG; i++ { + fmt.Printf("F%d %p\n", i, regpc[i-ppc64.REG_R0]) + } + gc.Fatal("out of floating registers") + + case gc.TCOMPLEX64, + gc.TCOMPLEX128: + gc.Tempname(n, t) + return + } + + gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0)) + return + +out: + reg[i-ppc64.REG_R0]++ + gc.Nodreg(n, t, i) +} + +func regfree(n *gc.Node) { + var i int + + if n.Op == gc.ONAME { + return + } + if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { + gc.Fatal("regfree: not a register") + } + i = int(n.Val.U.Reg) - ppc64.REG_R0 + if i == ppc64.REGSP-ppc64.REG_R0 { + return + } + if i < 0 || i >= len(reg) { + gc.Fatal("regfree: reg out of range") + } + if reg[i] <= 0 { + gc.Fatal("regfree: reg not allocated") + } + reg[i]-- + if reg[i] == 0 { + regpc[i] = 0 + } +} + +/* + * generate + * as $c, n + */ +func ginscon(as int, c int64, n2 *gc.Node) { + var n1 gc.Node + var ntmp gc.Node + + gc.Nodconst(&n1, gc.Types[gc.TINT64], c) + + if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) { + // cannot have more than 16-bit of immediate in ADD, etc. + // instead, MOV into register first. + regalloc(&ntmp, gc.Types[gc.TINT64], nil) + + gins(ppc64.AMOVD, &n1, &ntmp) + gins(as, &ntmp, n2) + regfree(&ntmp) + return + } + + gins(as, &n1, n2) +} + +/* + * generate + * as n, $c (CMP/CMPU) + */ +func ginscon2(as int, n2 *gc.Node, c int64) { + var n1 gc.Node + var ntmp gc.Node + + gc.Nodconst(&n1, gc.Types[gc.TINT64], c) + + switch as { + default: + gc.Fatal("ginscon2") + + case ppc64.ACMP: + if -ppc64.BIG <= c && c <= ppc64.BIG { + gins(as, n2, &n1) + return + } + + case ppc64.ACMPU: + if 0 <= c && c <= 2*ppc64.BIG { + gins(as, n2, &n1) + return + } + } + + // MOV n1 into register first + regalloc(&ntmp, gc.Types[gc.TINT64], nil) + + gins(ppc64.AMOVD, &n1, &ntmp) + gins(as, n2, &ntmp) + regfree(&ntmp) +} + +/* + * set up nodes representing 2^63 + */ +var bigi gc.Node + +var bigf gc.Node + +var bignodes_did int + +func bignodes() { + if bignodes_did != 0 { + return + } + bignodes_did = 1 + + gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) + gc.Mpshiftfix(bigi.Val.U.Xval, 63) + + bigf = bigi + bigf.Type = gc.Types[gc.TFLOAT64] + bigf.Val.Ctype = gc.CTFLT + bigf.Val.U.Fval = new(gc.Mpflt) + gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) +} + +/* + * generate move: + * t = f + * hard part is conversions. + */ +func gmove(f *gc.Node, t *gc.Node) { + var a int + var ft int + var tt int + var cvt *gc.Type + var r1 gc.Node + var r2 gc.Node + var r3 gc.Node + var con gc.Node + var p1 *obj.Prog + var p2 *obj.Prog + + if gc.Debug['M'] != 0 { + fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) + } + + ft = gc.Simsimtype(f.Type) + tt = gc.Simsimtype(t.Type) + cvt = t.Type + + if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { + gc.Complexmove(f, t) + return + } + + // cannot have two memory operands + if gc.Ismem(f) && gc.Ismem(t) { + goto hard + } + + // convert constant to desired type + if f.Op == gc.OLITERAL { + switch tt { + default: + gc.Convconst(&con, t.Type, &f.Val) + + case gc.TINT32, + gc.TINT16, + gc.TINT8: + gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) + regalloc(&r1, con.Type, t) + gins(ppc64.AMOVD, &con, &r1) + gmove(&r1, t) + regfree(&r1) + return + + case gc.TUINT32, + gc.TUINT16, + gc.TUINT8: + gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) + regalloc(&r1, con.Type, t) + gins(ppc64.AMOVD, &con, &r1) + gmove(&r1, t) + regfree(&r1) + return + } + + f = &con + ft = tt // so big switch will choose a simple mov + + // constants can't move directly to memory. + if gc.Ismem(t) { + goto hard + } + } + + // float constants come from memory. + //if(isfloat[tt]) + // goto hard; + + // 64-bit immediates are also from memory. + //if(isint[tt]) + // goto hard; + //// 64-bit immediates are really 32-bit sign-extended + //// unless moving into a register. + //if(isint[tt]) { + // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) + // goto hard; + // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) + // goto hard; + //} + + // value -> value copy, only one memory operand. + // figure out the instruction to use. + // break out of switch for one-instruction gins. + // goto rdst for "destination must be register". + // goto hard for "convert to cvt type first". + // otherwise handle and return. + + switch uint32(ft)<<16 | uint32(tt) { + default: + gc.Fatal("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong)) + + /* + * integer copy and truncate + */ + case gc.TINT8<<16 | gc.TINT8, // same size + gc.TUINT8<<16 | gc.TINT8, + gc.TINT16<<16 | gc.TINT8, + // truncate + gc.TUINT16<<16 | gc.TINT8, + gc.TINT32<<16 | gc.TINT8, + gc.TUINT32<<16 | gc.TINT8, + gc.TINT64<<16 | gc.TINT8, + gc.TUINT64<<16 | gc.TINT8: + a = ppc64.AMOVB + + case gc.TINT8<<16 | gc.TUINT8, // same size + gc.TUINT8<<16 | gc.TUINT8, + gc.TINT16<<16 | gc.TUINT8, + // truncate + gc.TUINT16<<16 | gc.TUINT8, + gc.TINT32<<16 | gc.TUINT8, + gc.TUINT32<<16 | gc.TUINT8, + gc.TINT64<<16 | gc.TUINT8, + gc.TUINT64<<16 | gc.TUINT8: + a = ppc64.AMOVBZ + + case gc.TINT16<<16 | gc.TINT16, // same size + gc.TUINT16<<16 | gc.TINT16, + gc.TINT32<<16 | gc.TINT16, + // truncate + gc.TUINT32<<16 | gc.TINT16, + gc.TINT64<<16 | gc.TINT16, + gc.TUINT64<<16 | gc.TINT16: + a = ppc64.AMOVH + + case gc.TINT16<<16 | gc.TUINT16, // same size + gc.TUINT16<<16 | gc.TUINT16, + gc.TINT32<<16 | gc.TUINT16, + // truncate + gc.TUINT32<<16 | gc.TUINT16, + gc.TINT64<<16 | gc.TUINT16, + gc.TUINT64<<16 | gc.TUINT16: + a = ppc64.AMOVHZ + + case gc.TINT32<<16 | gc.TINT32, // same size + gc.TUINT32<<16 | gc.TINT32, + gc.TINT64<<16 | gc.TINT32, + // truncate + gc.TUINT64<<16 | gc.TINT32: + a = ppc64.AMOVW + + case gc.TINT32<<16 | gc.TUINT32, // same size + gc.TUINT32<<16 | gc.TUINT32, + gc.TINT64<<16 | gc.TUINT32, + gc.TUINT64<<16 | gc.TUINT32: + a = ppc64.AMOVWZ + + case gc.TINT64<<16 | gc.TINT64, // same size + gc.TINT64<<16 | gc.TUINT64, + gc.TUINT64<<16 | gc.TINT64, + gc.TUINT64<<16 | gc.TUINT64: + a = ppc64.AMOVD + + /* + * integer up-conversions + */ + case gc.TINT8<<16 | gc.TINT16, // sign extend int8 + gc.TINT8<<16 | gc.TUINT16, + gc.TINT8<<16 | gc.TINT32, + gc.TINT8<<16 | gc.TUINT32, + gc.TINT8<<16 | gc.TINT64, + gc.TINT8<<16 | gc.TUINT64: + a = ppc64.AMOVB + + goto rdst + + case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 + gc.TUINT8<<16 | gc.TUINT16, + gc.TUINT8<<16 | gc.TINT32, + gc.TUINT8<<16 | gc.TUINT32, + gc.TUINT8<<16 | gc.TINT64, + gc.TUINT8<<16 | gc.TUINT64: + a = ppc64.AMOVBZ + + goto rdst + + case gc.TINT16<<16 | gc.TINT32, // sign extend int16 + gc.TINT16<<16 | gc.TUINT32, + gc.TINT16<<16 | gc.TINT64, + gc.TINT16<<16 | gc.TUINT64: + a = ppc64.AMOVH + + goto rdst + + case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 + gc.TUINT16<<16 | gc.TUINT32, + gc.TUINT16<<16 | gc.TINT64, + gc.TUINT16<<16 | gc.TUINT64: + a = ppc64.AMOVHZ + + goto rdst + + case gc.TINT32<<16 | gc.TINT64, // sign extend int32 + gc.TINT32<<16 | gc.TUINT64: + a = ppc64.AMOVW + + goto rdst + + case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 + gc.TUINT32<<16 | gc.TUINT64: + a = ppc64.AMOVWZ + + goto rdst + + //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t); + //return; + // algorithm is: + // if small enough, use native float64 -> int64 conversion. + // otherwise, subtract 2^63, convert, and add it back. + /* + * float to integer + */ + case gc.TFLOAT32<<16 | gc.TINT32, + gc.TFLOAT64<<16 | gc.TINT32, + gc.TFLOAT32<<16 | gc.TINT64, + gc.TFLOAT64<<16 | gc.TINT64, + gc.TFLOAT32<<16 | gc.TINT16, + gc.TFLOAT32<<16 | gc.TINT8, + gc.TFLOAT32<<16 | gc.TUINT16, + gc.TFLOAT32<<16 | gc.TUINT8, + gc.TFLOAT64<<16 | gc.TINT16, + gc.TFLOAT64<<16 | gc.TINT8, + gc.TFLOAT64<<16 | gc.TUINT16, + gc.TFLOAT64<<16 | gc.TUINT8, + gc.TFLOAT32<<16 | gc.TUINT32, + gc.TFLOAT64<<16 | gc.TUINT32, + gc.TFLOAT32<<16 | gc.TUINT64, + gc.TFLOAT64<<16 | gc.TUINT64: + bignodes() + + regalloc(&r1, gc.Types[ft], f) + gmove(f, &r1) + if tt == gc.TUINT64 { + regalloc(&r2, gc.Types[gc.TFLOAT64], nil) + gmove(&bigf, &r2) + gins(ppc64.AFCMPU, &r1, &r2) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) + gins(ppc64.AFSUB, &r2, &r1) + gc.Patch(p1, gc.Pc) + regfree(&r2) + } + + regalloc(&r2, gc.Types[gc.TFLOAT64], nil) + regalloc(&r3, gc.Types[gc.TINT64], t) + gins(ppc64.AFCTIDZ, &r1, &r2) + p1 = gins(ppc64.AFMOVD, &r2, nil) + p1.To.Type = obj.TYPE_MEM + p1.To.Reg = ppc64.REGSP + p1.To.Offset = -8 + p1 = gins(ppc64.AMOVD, nil, &r3) + p1.From.Type = obj.TYPE_MEM + p1.From.Reg = ppc64.REGSP + p1.From.Offset = -8 + regfree(&r2) + regfree(&r1) + if tt == gc.TUINT64 { + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) // use CR0 here again + gc.Nodreg(&r1, gc.Types[gc.TINT64], ppc64.REGTMP) + gins(ppc64.AMOVD, &bigi, &r1) + gins(ppc64.AADD, &r1, &r3) + gc.Patch(p1, gc.Pc) + } + + gmove(&r3, t) + regfree(&r3) + return + + //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t); + //return; + // algorithm is: + // if small enough, use native int64 -> uint64 conversion. + // otherwise, halve (rounding to odd?), convert, and double. + /* + * integer to float + */ + case gc.TINT32<<16 | gc.TFLOAT32, + gc.TINT32<<16 | gc.TFLOAT64, + gc.TINT64<<16 | gc.TFLOAT32, + gc.TINT64<<16 | gc.TFLOAT64, + gc.TINT16<<16 | gc.TFLOAT32, + gc.TINT16<<16 | gc.TFLOAT64, + gc.TINT8<<16 | gc.TFLOAT32, + gc.TINT8<<16 | gc.TFLOAT64, + gc.TUINT16<<16 | gc.TFLOAT32, + gc.TUINT16<<16 | gc.TFLOAT64, + gc.TUINT8<<16 | gc.TFLOAT32, + gc.TUINT8<<16 | gc.TFLOAT64, + gc.TUINT32<<16 | gc.TFLOAT32, + gc.TUINT32<<16 | gc.TFLOAT64, + gc.TUINT64<<16 | gc.TFLOAT32, + gc.TUINT64<<16 | gc.TFLOAT64: + bignodes() + + regalloc(&r1, gc.Types[gc.TINT64], nil) + gmove(f, &r1) + if ft == gc.TUINT64 { + gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP) + gmove(&bigi, &r2) + gins(ppc64.ACMPU, &r1, &r2) + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) + p2 = gins(ppc64.ASRD, nil, &r1) + p2.From.Type = obj.TYPE_CONST + p2.From.Offset = 1 + gc.Patch(p1, gc.Pc) + } + + regalloc(&r2, gc.Types[gc.TFLOAT64], t) + p1 = gins(ppc64.AMOVD, &r1, nil) + p1.To.Type = obj.TYPE_MEM + p1.To.Reg = ppc64.REGSP + p1.To.Offset = -8 + p1 = gins(ppc64.AFMOVD, nil, &r2) + p1.From.Type = obj.TYPE_MEM + p1.From.Reg = ppc64.REGSP + p1.From.Offset = -8 + gins(ppc64.AFCFID, &r2, &r2) + regfree(&r1) + if ft == gc.TUINT64 { + p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again + gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO) + gins(ppc64.AFMUL, &r1, &r2) + gc.Patch(p1, gc.Pc) + } + + gmove(&r2, t) + regfree(&r2) + return + + /* + * float to float + */ + case gc.TFLOAT32<<16 | gc.TFLOAT32: + a = ppc64.AFMOVS + + case gc.TFLOAT64<<16 | gc.TFLOAT64: + a = ppc64.AFMOVD + + case gc.TFLOAT32<<16 | gc.TFLOAT64: + a = ppc64.AFMOVS + goto rdst + + case gc.TFLOAT64<<16 | gc.TFLOAT32: + a = ppc64.AFRSP + goto rdst + } + + gins(a, f, t) + return + + // requires register destination +rdst: + regalloc(&r1, t.Type, t) + + gins(a, f, &r1) + gmove(&r1, t) + regfree(&r1) + return + + // requires register intermediate +hard: + regalloc(&r1, cvt, t) + + gmove(f, &r1) + gmove(&r1, t) + regfree(&r1) + return +} + +/* + * generate one instruction: + * as f, t + */ +func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { + var w int32 + var p *obj.Prog + var af obj.Addr + var at obj.Addr + + // TODO(austin): Add self-move test like in 6g (but be careful + // of truncation moves) + + af = obj.Addr{} + + at = obj.Addr{} + if f != nil { + gc.Naddr(f, &af, 1) + } + if t != nil { + gc.Naddr(t, &at, 1) + } + p = gc.Prog(as) + if f != nil { + p.From = af + } + if t != nil { + p.To = at + } + if gc.Debug['g'] != 0 { + fmt.Printf("%v\n", p) + } + + w = 0 + switch as { + case ppc64.AMOVB, + ppc64.AMOVBU, + ppc64.AMOVBZ, + ppc64.AMOVBZU: + w = 1 + + case ppc64.AMOVH, + ppc64.AMOVHU, + ppc64.AMOVHZ, + ppc64.AMOVHZU: + w = 2 + + case ppc64.AMOVW, + ppc64.AMOVWU, + ppc64.AMOVWZ, + ppc64.AMOVWZU: + w = 4 + + case ppc64.AMOVD, + ppc64.AMOVDU: + if af.Type == obj.TYPE_CONST || af.Type == obj.TYPE_ADDR { + break + } + w = 8 + } + + if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Type != obj.TYPE_REG && at.Width > int64(w))) { + gc.Dump("f", f) + gc.Dump("t", t) + gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) + } + + return p +} + +func fixlargeoffset(n *gc.Node) { + var a gc.Node + + if n == nil { + return + } + if n.Op != gc.OINDREG { + return + } + if n.Val.U.Reg == ppc64.REGSP { // stack offset cannot be large + return + } + if n.Xoffset != int64(int32(n.Xoffset)) { + // TODO(minux): offset too large, move into R31 and add to R31 instead. + // this is used only in test/fixedbugs/issue6036.go. + gc.Fatal("offset too large: %v", gc.Nconv(n, 0)) + + a = *n + a.Op = gc.OREGISTER + a.Type = gc.Types[gc.Tptr] + a.Xoffset = 0 + gc.Cgen_checknil(&a) + ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a) + n.Xoffset = 0 + } +} + +/* + * return Axxx for Oxxx on type t. + */ +func optoas(op int, t *gc.Type) int { + var a int + + if t == nil { + gc.Fatal("optoas: t is nil") + } + + a = obj.AXXX + switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { + default: + gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) + + case gc.OEQ<<16 | gc.TBOOL, + gc.OEQ<<16 | gc.TINT8, + gc.OEQ<<16 | gc.TUINT8, + gc.OEQ<<16 | gc.TINT16, + gc.OEQ<<16 | gc.TUINT16, + gc.OEQ<<16 | gc.TINT32, + gc.OEQ<<16 | gc.TUINT32, + gc.OEQ<<16 | gc.TINT64, + gc.OEQ<<16 | gc.TUINT64, + gc.OEQ<<16 | gc.TPTR32, + gc.OEQ<<16 | gc.TPTR64, + gc.OEQ<<16 | gc.TFLOAT32, + gc.OEQ<<16 | gc.TFLOAT64: + a = ppc64.ABEQ + + case gc.ONE<<16 | gc.TBOOL, + gc.ONE<<16 | gc.TINT8, + gc.ONE<<16 | gc.TUINT8, + gc.ONE<<16 | gc.TINT16, + gc.ONE<<16 | gc.TUINT16, + gc.ONE<<16 | gc.TINT32, + gc.ONE<<16 | gc.TUINT32, + gc.ONE<<16 | gc.TINT64, + gc.ONE<<16 | gc.TUINT64, + gc.ONE<<16 | gc.TPTR32, + gc.ONE<<16 | gc.TPTR64, + gc.ONE<<16 | gc.TFLOAT32, + gc.ONE<<16 | gc.TFLOAT64: + a = ppc64.ABNE + + case gc.OLT<<16 | gc.TINT8, // ACMP + gc.OLT<<16 | gc.TINT16, + gc.OLT<<16 | gc.TINT32, + gc.OLT<<16 | gc.TINT64, + gc.OLT<<16 | gc.TUINT8, + // ACMPU + gc.OLT<<16 | gc.TUINT16, + gc.OLT<<16 | gc.TUINT32, + gc.OLT<<16 | gc.TUINT64, + gc.OLT<<16 | gc.TFLOAT32, + // AFCMPU + gc.OLT<<16 | gc.TFLOAT64: + a = ppc64.ABLT + + case gc.OLE<<16 | gc.TINT8, // ACMP + gc.OLE<<16 | gc.TINT16, + gc.OLE<<16 | gc.TINT32, + gc.OLE<<16 | gc.TINT64, + gc.OLE<<16 | gc.TUINT8, + // ACMPU + gc.OLE<<16 | gc.TUINT16, + gc.OLE<<16 | gc.TUINT32, + gc.OLE<<16 | gc.TUINT64, + gc.OLE<<16 | gc.TFLOAT32, + // AFCMPU + gc.OLE<<16 | gc.TFLOAT64: + a = ppc64.ABLE + + case gc.OGT<<16 | gc.TINT8, + gc.OGT<<16 | gc.TINT16, + gc.OGT<<16 | gc.TINT32, + gc.OGT<<16 | gc.TINT64, + gc.OGT<<16 | gc.TUINT8, + gc.OGT<<16 | gc.TUINT16, + gc.OGT<<16 | gc.TUINT32, + gc.OGT<<16 | gc.TUINT64, + gc.OGT<<16 | gc.TFLOAT32, + gc.OGT<<16 | gc.TFLOAT64: + a = ppc64.ABGT + + case gc.OGE<<16 | gc.TINT8, + gc.OGE<<16 | gc.TINT16, + gc.OGE<<16 | gc.TINT32, + gc.OGE<<16 | gc.TINT64, + gc.OGE<<16 | gc.TUINT8, + gc.OGE<<16 | gc.TUINT16, + gc.OGE<<16 | gc.TUINT32, + gc.OGE<<16 | gc.TUINT64, + gc.OGE<<16 | gc.TFLOAT32, + gc.OGE<<16 | gc.TFLOAT64: + a = ppc64.ABGE + + case gc.OCMP<<16 | gc.TBOOL, + gc.OCMP<<16 | gc.TINT8, + gc.OCMP<<16 | gc.TINT16, + gc.OCMP<<16 | gc.TINT32, + gc.OCMP<<16 | gc.TPTR32, + gc.OCMP<<16 | gc.TINT64: + a = ppc64.ACMP + + case gc.OCMP<<16 | gc.TUINT8, + gc.OCMP<<16 | gc.TUINT16, + gc.OCMP<<16 | gc.TUINT32, + gc.OCMP<<16 | gc.TUINT64, + gc.OCMP<<16 | gc.TPTR64: + a = ppc64.ACMPU + + case gc.OCMP<<16 | gc.TFLOAT32, + gc.OCMP<<16 | gc.TFLOAT64: + a = ppc64.AFCMPU + + case gc.OAS<<16 | gc.TBOOL, + gc.OAS<<16 | gc.TINT8: + a = ppc64.AMOVB + + case gc.OAS<<16 | gc.TUINT8: + a = ppc64.AMOVBZ + + case gc.OAS<<16 | gc.TINT16: + a = ppc64.AMOVH + + case gc.OAS<<16 | gc.TUINT16: + a = ppc64.AMOVHZ + + case gc.OAS<<16 | gc.TINT32: + a = ppc64.AMOVW + + case gc.OAS<<16 | gc.TUINT32, + gc.OAS<<16 | gc.TPTR32: + a = ppc64.AMOVWZ + + case gc.OAS<<16 | gc.TINT64, + gc.OAS<<16 | gc.TUINT64, + gc.OAS<<16 | gc.TPTR64: + a = ppc64.AMOVD + + case gc.OAS<<16 | gc.TFLOAT32: + a = ppc64.AFMOVS + + case gc.OAS<<16 | gc.TFLOAT64: + a = ppc64.AFMOVD + + case gc.OADD<<16 | gc.TINT8, + gc.OADD<<16 | gc.TUINT8, + gc.OADD<<16 | gc.TINT16, + gc.OADD<<16 | gc.TUINT16, + gc.OADD<<16 | gc.TINT32, + gc.OADD<<16 | gc.TUINT32, + gc.OADD<<16 | gc.TPTR32, + gc.OADD<<16 | gc.TINT64, + gc.OADD<<16 | gc.TUINT64, + gc.OADD<<16 | gc.TPTR64: + a = ppc64.AADD + + case gc.OADD<<16 | gc.TFLOAT32: + a = ppc64.AFADDS + + case gc.OADD<<16 | gc.TFLOAT64: + a = ppc64.AFADD + + case gc.OSUB<<16 | gc.TINT8, + gc.OSUB<<16 | gc.TUINT8, + gc.OSUB<<16 | gc.TINT16, + gc.OSUB<<16 | gc.TUINT16, + gc.OSUB<<16 | gc.TINT32, + gc.OSUB<<16 | gc.TUINT32, + gc.OSUB<<16 | gc.TPTR32, + gc.OSUB<<16 | gc.TINT64, + gc.OSUB<<16 | gc.TUINT64, + gc.OSUB<<16 | gc.TPTR64: + a = ppc64.ASUB + + case gc.OSUB<<16 | gc.TFLOAT32: + a = ppc64.AFSUBS + + case gc.OSUB<<16 | gc.TFLOAT64: + a = ppc64.AFSUB + + case gc.OMINUS<<16 | gc.TINT8, + gc.OMINUS<<16 | gc.TUINT8, + gc.OMINUS<<16 | gc.TINT16, + gc.OMINUS<<16 | gc.TUINT16, + gc.OMINUS<<16 | gc.TINT32, + gc.OMINUS<<16 | gc.TUINT32, + gc.OMINUS<<16 | gc.TPTR32, + gc.OMINUS<<16 | gc.TINT64, + gc.OMINUS<<16 | gc.TUINT64, + gc.OMINUS<<16 | gc.TPTR64: + a = ppc64.ANEG + + case gc.OAND<<16 | gc.TINT8, + gc.OAND<<16 | gc.TUINT8, + gc.OAND<<16 | gc.TINT16, + gc.OAND<<16 | gc.TUINT16, + gc.OAND<<16 | gc.TINT32, + gc.OAND<<16 | gc.TUINT32, + gc.OAND<<16 | gc.TPTR32, + gc.OAND<<16 | gc.TINT64, + gc.OAND<<16 | gc.TUINT64, + gc.OAND<<16 | gc.TPTR64: + a = ppc64.AAND + + case gc.OOR<<16 | gc.TINT8, + gc.OOR<<16 | gc.TUINT8, + gc.OOR<<16 | gc.TINT16, + gc.OOR<<16 | gc.TUINT16, + gc.OOR<<16 | gc.TINT32, + gc.OOR<<16 | gc.TUINT32, + gc.OOR<<16 | gc.TPTR32, + gc.OOR<<16 | gc.TINT64, + gc.OOR<<16 | gc.TUINT64, + gc.OOR<<16 | gc.TPTR64: + a = ppc64.AOR + + case gc.OXOR<<16 | gc.TINT8, + gc.OXOR<<16 | gc.TUINT8, + gc.OXOR<<16 | gc.TINT16, + gc.OXOR<<16 | gc.TUINT16, + gc.OXOR<<16 | gc.TINT32, + gc.OXOR<<16 | gc.TUINT32, + gc.OXOR<<16 | gc.TPTR32, + gc.OXOR<<16 | gc.TINT64, + gc.OXOR<<16 | gc.TUINT64, + gc.OXOR<<16 | gc.TPTR64: + a = ppc64.AXOR + + // TODO(minux): handle rotates + //case CASE(OLROT, TINT8): + //case CASE(OLROT, TUINT8): + //case CASE(OLROT, TINT16): + //case CASE(OLROT, TUINT16): + //case CASE(OLROT, TINT32): + //case CASE(OLROT, TUINT32): + //case CASE(OLROT, TPTR32): + //case CASE(OLROT, TINT64): + //case CASE(OLROT, TUINT64): + //case CASE(OLROT, TPTR64): + // a = 0//???; RLDC? + // break; + + case gc.OLSH<<16 | gc.TINT8, + gc.OLSH<<16 | gc.TUINT8, + gc.OLSH<<16 | gc.TINT16, + gc.OLSH<<16 | gc.TUINT16, + gc.OLSH<<16 | gc.TINT32, + gc.OLSH<<16 | gc.TUINT32, + gc.OLSH<<16 | gc.TPTR32, + gc.OLSH<<16 | gc.TINT64, + gc.OLSH<<16 | gc.TUINT64, + gc.OLSH<<16 | gc.TPTR64: + a = ppc64.ASLD + + case gc.ORSH<<16 | gc.TUINT8, + gc.ORSH<<16 | gc.TUINT16, + gc.ORSH<<16 | gc.TUINT32, + gc.ORSH<<16 | gc.TPTR32, + gc.ORSH<<16 | gc.TUINT64, + gc.ORSH<<16 | gc.TPTR64: + a = ppc64.ASRD + + case gc.ORSH<<16 | gc.TINT8, + gc.ORSH<<16 | gc.TINT16, + gc.ORSH<<16 | gc.TINT32, + gc.ORSH<<16 | gc.TINT64: + a = ppc64.ASRAD + + // TODO(minux): handle rotates + //case CASE(ORROTC, TINT8): + //case CASE(ORROTC, TUINT8): + //case CASE(ORROTC, TINT16): + //case CASE(ORROTC, TUINT16): + //case CASE(ORROTC, TINT32): + //case CASE(ORROTC, TUINT32): + //case CASE(ORROTC, TINT64): + //case CASE(ORROTC, TUINT64): + // a = 0//??? RLDC?? + // break; + + case gc.OHMUL<<16 | gc.TINT64: + a = ppc64.AMULHD + + case gc.OHMUL<<16 | gc.TUINT64, + gc.OHMUL<<16 | gc.TPTR64: + a = ppc64.AMULHDU + + case gc.OMUL<<16 | gc.TINT8, + gc.OMUL<<16 | gc.TINT16, + gc.OMUL<<16 | gc.TINT32, + gc.OMUL<<16 | gc.TINT64: + a = ppc64.AMULLD + + case gc.OMUL<<16 | gc.TUINT8, + gc.OMUL<<16 | gc.TUINT16, + gc.OMUL<<16 | gc.TUINT32, + gc.OMUL<<16 | gc.TPTR32, + // don't use word multiply, the high 32-bit are undefined. + // fallthrough + gc.OMUL<<16 | gc.TUINT64, + gc.OMUL<<16 | gc.TPTR64: + a = ppc64.AMULLD + // for 64-bit multiplies, signedness doesn't matter. + + case gc.OMUL<<16 | gc.TFLOAT32: + a = ppc64.AFMULS + + case gc.OMUL<<16 | gc.TFLOAT64: + a = ppc64.AFMUL + + case gc.ODIV<<16 | gc.TINT8, + gc.ODIV<<16 | gc.TINT16, + gc.ODIV<<16 | gc.TINT32, + gc.ODIV<<16 | gc.TINT64: + a = ppc64.ADIVD + + case gc.ODIV<<16 | gc.TUINT8, + gc.ODIV<<16 | gc.TUINT16, + gc.ODIV<<16 | gc.TUINT32, + gc.ODIV<<16 | gc.TPTR32, + gc.ODIV<<16 | gc.TUINT64, + gc.ODIV<<16 | gc.TPTR64: + a = ppc64.ADIVDU + + case gc.ODIV<<16 | gc.TFLOAT32: + a = ppc64.AFDIVS + + case gc.ODIV<<16 | gc.TFLOAT64: + a = ppc64.AFDIV + } + + return a +} + +const ( + ODynam = 1 << 0 + OAddable = 1 << 1 +) + +func xgen(n *gc.Node, a *gc.Node, o int) bool { + // TODO(minux) + + return -1 != 0 /*TypeKind(100016)*/ +} + +func sudoclean() { + return +} + +/* + * generate code to compute address of n, + * a reference to a (perhaps nested) field inside + * an array or struct. + * return 0 on failure, 1 on success. + * on success, leaves usable address in a. + * + * caller is responsible for calling sudoclean + * after successful sudoaddable, + * to release the register used for a. + */ +func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { + // TODO(minux) + + *a = obj.Addr{} + return false +} diff --git a/src/cmd/9g/opt.go b/src/cmd/9g/opt.go new file mode 100644 index 0000000000..a0294209aa --- /dev/null +++ b/src/cmd/9g/opt.go @@ -0,0 +1,42 @@ +// Derived from Inferno utils/6c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Many Power ISA arithmetic and logical instructions come in four +// standard variants. These bits let us map between variants. +const ( + V_CC = 1 << 0 + V_V = 1 << 1 +) diff --git a/src/cmd/9g/opt.h b/src/cmd/9g/opt.h deleted file mode 100644 index 79a34fb1f0..0000000000 --- a/src/cmd/9g/opt.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Many Power ISA arithmetic and logical instructions come in four -// standard variants. These bits let us map between variants. -enum { - V_CC = 1<<0, // xCC (affect CR field 0 flags) - V_V = 1<<1, // xV (affect SO and OV flags) -}; - -int as2variant(int); -int variant2as(int, int); diff --git a/src/cmd/9g/peep.c b/src/cmd/9g/peep.c deleted file mode 100644 index cf96d5dcda..0000000000 --- a/src/cmd/9g/peep.c +++ /dev/null @@ -1,959 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" -#include "opt.h" - -static int regzer(Addr *a); -static int subprop(Flow*); -static int copyprop(Flow*); -static int copy1(Addr*, Addr*, Flow*, int); -static int copyas(Addr*, Addr*); -static int copyau(Addr*, Addr*); -static int copysub(Addr*, Addr*, Addr*, int); -static int copysub1(Prog*, Addr*, Addr*, int); -static int copyau1(Prog *p, Addr *v); -static int copyu(Prog *p, Addr *v, Addr *s); - -static uint32 gactive; - -void -peep(Prog *firstp) -{ - Graph *g; - Flow *r, *r1; - Prog *p, *p1; - int t; - - g = flowstart(firstp, 0); - if(g == nil) - return; - gactive = 0; - -loop1: - if(debug['P'] && debug['v']) - dumpit("loop1", g->start, 0); - - t = 0; - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - // TODO(austin) Handle smaller moves. arm and amd64 - // distinguish between moves that moves that *must* - // sign/zero extend and moves that don't care so they - // can eliminate moves that don't care without - // breaking moves that do care. This might let us - // simplify or remove the next peep loop, too. - if(p->as == AMOVD || p->as == AFMOVD) - if(regtyp(&p->to)) { - // Try to eliminate reg->reg moves - if(regtyp(&p->from)) - if(p->from.type == p->to.type) { - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - // Convert uses to $0 to uses of R0 and - // propagate R0 - if(regzer(&p->from)) - if(p->to.type == TYPE_REG) { - p->from.type = TYPE_REG; - p->from.reg = REGZERO; - if(copyprop(r)) { - excise(r); - t++; - } else - if(subprop(r) && copyprop(r)) { - excise(r); - t++; - } - } - } - } - if(t) - goto loop1; - - /* - * look for MOVB x,R; MOVB R,R (for small MOVs not handled above) - */ - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - default: - continue; - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - if(p->to.type != TYPE_REG) - continue; - break; - } - r1 = r->link; - if(r1 == nil) - continue; - p1 = r1->prog; - if(p1->as != p->as) - continue; - if(p1->from.type != TYPE_REG || p1->from.reg != p->to.reg) - continue; - if(p1->to.type != TYPE_REG || p1->to.reg != p->to.reg) - continue; - excise(r1); - } - - if(debug['D'] > 1) - goto ret; /* allow following code improvement to be suppressed */ - - /* - * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R - * when OP can set condition codes correctly - */ - for(r=g->start; r!=nil; r=r->link) { - p = r->prog; - switch(p->as) { - case ACMP: - case ACMPW: /* always safe? */ - if(!regzer(&p->to)) - continue; - r1 = r->s1; - if(r1 == nil) - continue; - switch(r1->prog->as) { - default: - continue; - case ABCL: - case ABC: - /* the conditions can be complex and these are currently little used */ - continue; - case ABEQ: - case ABGE: - case ABGT: - case ABLE: - case ABLT: - case ABNE: - case ABVC: - case ABVS: - break; - } - r1 = r; - do - r1 = uniqp(r1); - while (r1 != nil && r1->prog->as == ANOP); - if(r1 == nil) - continue; - p1 = r1->prog; - if(p1->to.type != TYPE_REG || p1->to.reg != p->from.reg) - continue; - switch(p1->as) { - case ASUB: - case AADD: - case AXOR: - case AOR: - /* irregular instructions */ - if(p1->from.type == TYPE_CONST || p1->from.type == TYPE_ADDR) - continue; - break; - } - switch(p1->as) { - default: - continue; - case AMOVW: - case AMOVD: - if(p1->from.type != TYPE_REG) - continue; - continue; - case AANDCC: - case AANDNCC: - case AORCC: - case AORNCC: - case AXORCC: - case ASUBCC: - case ASUBECC: - case ASUBMECC: - case ASUBZECC: - case AADDCC: - case AADDCCC: - case AADDECC: - case AADDMECC: - case AADDZECC: - case ARLWMICC: - case ARLWNMCC: - /* don't deal with floating point instructions for now */ -/* - case AFABS: - case AFADD: - case AFADDS: - case AFCTIW: - case AFCTIWZ: - case AFDIV: - case AFDIVS: - case AFMADD: - case AFMADDS: - case AFMOVD: - case AFMSUB: - case AFMSUBS: - case AFMUL: - case AFMULS: - case AFNABS: - case AFNEG: - case AFNMADD: - case AFNMADDS: - case AFNMSUB: - case AFNMSUBS: - case AFRSP: - case AFSUB: - case AFSUBS: - case ACNTLZW: - case AMTFSB0: - case AMTFSB1: -*/ - case AADD: - case AADDV: - case AADDC: - case AADDCV: - case AADDME: - case AADDMEV: - case AADDE: - case AADDEV: - case AADDZE: - case AADDZEV: - case AAND: - case AANDN: - case ADIVW: - case ADIVWV: - case ADIVWU: - case ADIVWUV: - case ADIVD: - case ADIVDV: - case ADIVDU: - case ADIVDUV: - case AEQV: - case AEXTSB: - case AEXTSH: - case AEXTSW: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLWV: - case AMULHD: - case AMULHDU: - case AMULLD: - case AMULLDV: - case ANAND: - case ANEG: - case ANEGV: - case ANOR: - case AOR: - case AORN: - case AREM: - case AREMV: - case AREMU: - case AREMUV: - case AREMD: - case AREMDV: - case AREMDU: - case AREMDUV: - case ARLWMI: - case ARLWNM: - case ASLW: - case ASRAW: - case ASRW: - case ASLD: - case ASRAD: - case ASRD: - case ASUB: - case ASUBV: - case ASUBC: - case ASUBCV: - case ASUBME: - case ASUBMEV: - case ASUBE: - case ASUBEV: - case ASUBZE: - case ASUBZEV: - case AXOR: - t = variant2as(p1->as, as2variant(p1->as) | V_CC); - break; - } - if(debug['D']) - print("cmp %P; %P -> ", p1, p); - p1->as = t; - if(debug['D']) - print("%P\n", p1); - excise(r); - continue; - } - } - -ret: - flowend(g); -} - -void -excise(Flow *r) -{ - Prog *p; - - p = r->prog; - if(debug['P'] && debug['v']) - print("%P ===delete===\n", p); - nopout(p); - ostats.ndelmov++; -} - -/* - * regzer returns 1 if a's value is 0 (a is R0 or $0) - */ -static int -regzer(Addr *a) -{ - if(a->type == TYPE_CONST || a->type == TYPE_ADDR) - if(a->sym == nil && a->reg == 0) - if(a->offset == 0) - return 1; - if(a->type == TYPE_REG) - if(a->reg == REGZERO) - return 1; - return 0; -} - -int -regtyp(Adr *a) -{ - // TODO(rsc): Floating point register exclusions? - return a->type == TYPE_REG && REG_R0 <= a->reg && a->reg <= REG_F31 && a->reg != REGZERO; -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R1 - * ADD b, R1 / no use of R2 - * MOV R1, R2 - * would be converted to - * MOV a, R2 - * ADD b, R2 - * MOV R2, R1 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - * - * r0 (the argument, not the register) is the MOV at the end of the - * above sequences. This returns 1 if it modified any instructions. - */ -static int -subprop(Flow *r0) -{ - Prog *p; - Addr *v1, *v2; - Flow *r; - int t; - ProgInfo info; - - p = r0->prog; - v1 = &p->from; - if(!regtyp(v1)) - return 0; - v2 = &p->to; - if(!regtyp(v2)) - return 0; - for(r=uniqp(r0); r!=nil; r=uniqp(r)) { - if(uniqs(r) == nil) - break; - p = r->prog; - if(p->as == AVARDEF || p->as == AVARKILL) - continue; - proginfo(&info, p); - if(info.flags & Call) - return 0; - - if((info.flags & (RightRead|RightWrite)) == RightWrite) { - if(p->to.type == v1->type) - if(p->to.reg == v1->reg) - goto gotit; - } - - if(copyau(&p->from, v2) || - copyau1(p, v2) || - copyau(&p->to, v2)) - break; - if(copysub(&p->from, v1, v2, 0) || - copysub1(p, v1, v2, 0) || - copysub(&p->to, v1, v2, 0)) - break; - } - return 0; - -gotit: - copysub(&p->to, v1, v2, 1); - if(debug['P']) { - print("gotit: %D->%D\n%P", v1, v2, r->prog); - if(p->from.type == v2->type) - print(" excise"); - print("\n"); - } - for(r=uniqs(r); r!=r0; r=uniqs(r)) { - p = r->prog; - copysub(&p->from, v1, v2, 1); - copysub1(p, v1, v2, 1); - copysub(&p->to, v1, v2, 1); - if(debug['P']) - print("%P\n", r->prog); - } - t = v1->reg; - v1->reg = v2->reg; - v2->reg = t; - if(debug['P']) - print("%P last\n", r->prog); - return 1; -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail (v1->v2 move must remain) - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success (caller can remove v1->v2 move) - */ -static int -copyprop(Flow *r0) -{ - Prog *p; - Addr *v1, *v2; - - p = r0->prog; - v1 = &p->from; - v2 = &p->to; - if(copyas(v1, v2)) { - if(debug['P']) - print("eliminating self-move\n", r0->prog); - return 1; - } - gactive++; - if(debug['P']) - print("trying to eliminate %D->%D move from:\n%P\n", v1, v2, r0->prog); - return copy1(v1, v2, r0->s1, 0); -} - -// copy1 replaces uses of v2 with v1 starting at r and returns 1 if -// all uses were rewritten. -static int -copy1(Addr *v1, Addr *v2, Flow *r, int f) -{ - int t; - Prog *p; - - if(r->active == gactive) { - if(debug['P']) - print("act set; return 1\n"); - return 1; - } - r->active = gactive; - if(debug['P']) - print("copy1 replace %D with %D f=%d\n", v2, v1, f); - for(; r != nil; r = r->s1) { - p = r->prog; - if(debug['P']) - print("%P", p); - if(!f && uniqp(r) == nil) { - // Multiple predecessors; conservatively - // assume v1 was set on other path - f = 1; - if(debug['P']) - print("; merge; f=%d", f); - } - t = copyu(p, v2, nil); - switch(t) { - case 2: /* rar, can't split */ - if(debug['P']) - print("; %D rar; return 0\n", v2); - return 0; - - case 3: /* set */ - if(debug['P']) - print("; %D set; return 1\n", v2); - return 1; - - case 1: /* used, substitute */ - case 4: /* use and set */ - if(f) { - if(!debug['P']) - return 0; - if(t == 4) - print("; %D used+set and f=%d; return 0\n", v2, f); - else - print("; %D used and f=%d; return 0\n", v2, f); - return 0; - } - if(copyu(p, v2, v1)) { - if(debug['P']) - print("; sub fail; return 0\n"); - return 0; - } - if(debug['P']) - print("; sub %D->%D\n => %P", v2, v1, p); - if(t == 4) { - if(debug['P']) - print("; %D used+set; return 1\n", v2); - return 1; - } - break; - } - if(!f) { - t = copyu(p, v1, nil); - if(!f && (t == 2 || t == 3 || t == 4)) { - f = 1; - if(debug['P']) - print("; %D set and !f; f=%d", v1, f); - } - } - if(debug['P']) - print("\n"); - if(r->s2) - if(!copy1(v1, v2, r->s2, f)) - return 0; - } - return 1; -} - -// If s==nil, copyu returns the set/use of v in p; otherwise, it -// modifies p to replace reads of v with reads of s and returns 0 for -// success or non-zero for failure. -// -// If s==nil, copy returns one of the following values: -// 1 if v only used -// 2 if v is set and used in one address (read-alter-rewrite; -// can't substitute) -// 3 if v is only set -// 4 if v is set in one address and used in another (so addresses -// can be rewritten independently) -// 0 otherwise (not touched) -static int -copyu(Prog *p, Addr *v, Addr *s) -{ - if(p->from3.type != TYPE_NONE) - // 9g never generates a from3 - print("copyu: from3 (%D) not implemented\n", &p->from3); - - switch(p->as) { - - default: - print("copyu: can't find %A\n", p->as); - return 2; - - case ANOP: /* read p->from, write p->to */ - case AMOVH: - case AMOVHZ: - case AMOVB: - case AMOVBZ: - case AMOVW: - case AMOVWZ: - case AMOVD: - - case ANEG: - case ANEGCC: - case AADDME: - case AADDMECC: - case AADDZE: - case AADDZECC: - case ASUBME: - case ASUBMECC: - case ASUBZE: - case ASUBZECC: - - case AFCTIW: - case AFCTIWZ: - case AFCTID: - case AFCTIDZ: - case AFCFID: - case AFCFIDCC: - case AFMOVS: - case AFMOVD: - case AFRSP: - case AFNEG: - case AFNEGCC: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - // Update only indirect uses of v in p->to - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - // Fix up implicit from - if(p->from.type == TYPE_NONE) - p->from = p->to; - if(copyau(&p->from, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - // p->to only indirectly uses v - return 1; - return 0; - - case AMOVBU: /* rar p->from, write p->to or read p->from, rar p->to */ - case AMOVBZU: - case AMOVHU: - case AMOVHZU: - case AMOVWZU: - case AMOVDU: - if(p->from.type == TYPE_MEM) { - if(copyas(&p->from, v)) - // No s!=nil check; need to fail - // anyway in that case - return 2; - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) - return 3; - } else if (p->to.type == TYPE_MEM) { - if(copyas(&p->to, v)) - return 2; - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->from, v)) - return 1; - } else { - print("copyu: bad %P\n", p); - } - return 0; - - case ARLWMI: /* read p->from, read p->reg, rar p->to */ - case ARLWMICC: - if(copyas(&p->to, v)) - return 2; - /* fall through */ - - case AADD: /* read p->from, read p->reg, write p->to */ - case AADDC: - case AADDE: - case ASUB: - case ASLW: - case ASRW: - case ASRAW: - case ASLD: - case ASRD: - case ASRAD: - case AOR: - case AORCC: - case AORN: - case AORNCC: - case AAND: - case AANDCC: - case AANDN: - case AANDNCC: - case ANAND: - case ANANDCC: - case ANOR: - case ANORCC: - case AXOR: - case AMULHW: - case AMULHWU: - case AMULLW: - case AMULLD: - case ADIVW: - case ADIVD: - case ADIVWU: - case ADIVDU: - case AREM: - case AREMU: - case AREMD: - case AREMDU: - case ARLWNM: - case ARLWNMCC: - - case AFADDS: - case AFADD: - case AFSUBS: - case AFSUB: - case AFMULS: - case AFMUL: - case AFDIVS: - case AFDIV: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - if(copysub1(p, v, s, 1)) - return 1; - // Update only indirect uses of v in p->to - if(!copyas(&p->to, v)) - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyas(&p->to, v)) { - if(p->reg == 0) - // Fix up implicit reg (e.g., ADD - // R3,R4 -> ADD R3,R4,R4) so we can - // update reg and to separately. - p->reg = p->to.reg; - if(copyau(&p->from, v)) - return 4; - if(copyau1(p, v)) - return 4; - return 3; - } - if(copyau(&p->from, v)) - return 1; - if(copyau1(p, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ABEQ: - case ABGT: - case ABGE: - case ABLT: - case ABLE: - case ABNE: - case ABVC: - case ABVS: - return 0; - - case ACHECKNIL: /* read p->from */ - case ACMP: /* read p->from, read p->to */ - case ACMPU: - case ACMPW: - case ACMPWU: - case AFCMPO: - case AFCMPU: - if(s != nil) { - if(copysub(&p->from, v, s, 1)) - return 1; - return copysub(&p->to, v, s, 1); - } - if(copyau(&p->from, v)) - return 1; - if(copyau(&p->to, v)) - return 1; - return 0; - - case ABR: /* read p->to */ - // 9g never generates a branch to a GPR (this isn't - // even a normal instruction; liblink turns it in to a - // mov and a branch). - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 1; - return 0; - - case ARETURN: /* funny */ - if(s != nil) - return 0; - // All registers die at this point, so claim - // everything is set (and not used). - return 3; - - case ABL: /* funny */ - if(v->type == TYPE_REG) { - // TODO(rsc): REG_R0 and REG_F0 used to be - // (when register numbers started at 0) exregoffset and exfregoffset, - // which are unset entirely. - // It's strange that this handles R0 and F0 differently from the other - // registers. Possible failure to optimize? - if(REG_R0 < v->reg && v->reg <= REGEXT) - return 2; - if(v->reg == REGARG) - return 2; - if(REG_F0 < v->reg && v->reg <= FREGEXT) - return 2; - } - if(p->from.type == TYPE_REG && v->type == TYPE_REG && p->from.reg == v->reg) - return 2; - - if(s != nil) { - if(copysub(&p->to, v, s, 1)) - return 1; - return 0; - } - if(copyau(&p->to, v)) - return 4; - return 3; - - case ADUFFZERO: - // R0 is zero, used by DUFFZERO, cannot be substituted. - // R3 is ptr to memory, used and set, cannot be substituted. - if(v->type == TYPE_REG) { - if(v->reg == 0) - return 1; - if(v->reg == 3) - return 2; - } - return 0; - - case ADUFFCOPY: - // R3, R4 are ptr to src, dst, used and set, cannot be substituted. - // R5 is scratch, set by DUFFCOPY, cannot be substituted. - if(v->type == TYPE_REG) { - if(v->reg == 3 || v->reg == 4) - return 2; - if(v->reg == 5) - return 3; - } - return 0; - - case ATEXT: /* funny */ - if(v->type == TYPE_REG) - if(v->reg == REGARG) - return 3; - return 0; - - case APCDATA: - case AFUNCDATA: - case AVARDEF: - case AVARKILL: - return 0; - } -} - -// copyas returns 1 if a and v address the same register. -// -// If a is the from operand, this means this operation reads the -// register in v. If a is the to operand, this means this operation -// writes the register in v. -static int -copyas(Addr *a, Addr *v) -{ - if(regtyp(v)) - if(a->type == v->type) - if(a->reg == v->reg) - return 1; - return 0; -} - -// copyau returns 1 if a either directly or indirectly addresses the -// same register as v. -// -// If a is the from operand, this means this operation reads the -// register in v. If a is the to operand, this means the operation -// either reads or writes the register in v (if !copyas(a, v), then -// the operation reads the register in v). -static int -copyau(Addr *a, Addr *v) -{ - if(copyas(a, v)) - return 1; - if(v->type == TYPE_REG) - if(a->type == TYPE_MEM || (a->type == TYPE_ADDR && a->reg != 0)) - if(v->reg == a->reg) - return 1; - return 0; -} - -// copyau1 returns 1 if p->reg references the same register as v and v -// is a direct reference. -static int -copyau1(Prog *p, Addr *v) -{ - if(regtyp(v) && v->reg != 0) - if(p->reg == v->reg) - return 1; - return 0; -} - -// copysub replaces v with s in a if f!=0 or indicates it if could if f==0. -// Returns 1 on failure to substitute (it always succeeds on ppc64). -static int -copysub(Addr *a, Addr *v, Addr *s, int f) -{ - if(f) - if(copyau(a, v)) - a->reg = s->reg; - return 0; -} - -// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0. -// Returns 1 on failure to substitute (it always succeeds on ppc64). -static int -copysub1(Prog *p1, Addr *v, Addr *s, int f) -{ - if(f) - if(copyau1(p1, v)) - p1->reg = s->reg; - return 0; -} - -int -sameaddr(Addr *a, Addr *v) -{ - if(a->type != v->type) - return 0; - if(regtyp(v) && a->reg == v->reg) - return 1; - if(v->type == NAME_AUTO || v->type == NAME_PARAM) - if(v->offset == a->offset) - return 1; - return 0; -} - -int -smallindir(Addr *a, Addr *reg) -{ - return reg->type == TYPE_REG && a->type == TYPE_MEM && - a->reg == reg->reg && - 0 <= a->offset && a->offset < 4096; -} - -int -stackaddr(Addr *a) -{ - return a->type == TYPE_REG && a->reg == REGSP; -} diff --git a/src/cmd/9g/peep.go b/src/cmd/9g/peep.go new file mode 100644 index 0000000000..486b316dcf --- /dev/null +++ b/src/cmd/9g/peep.go @@ -0,0 +1,1071 @@ +// Derived from Inferno utils/6c/peep.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import ( + "cmd/internal/obj" + "cmd/internal/obj/ppc64" + "fmt" +) +import "cmd/internal/gc" + +var gactive uint32 + +func peep(firstp *obj.Prog) { + var g *gc.Graph + var r *gc.Flow + var r1 *gc.Flow + var p *obj.Prog + var p1 *obj.Prog + var t int + + g = gc.Flowstart(firstp, nil) + if g == nil { + return + } + gactive = 0 + +loop1: + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + gc.Dumpit("loop1", g.Start, 0) + } + + t = 0 + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + + // TODO(austin) Handle smaller moves. arm and amd64 + // distinguish between moves that moves that *must* + // sign/zero extend and moves that don't care so they + // can eliminate moves that don't care without + // breaking moves that do care. This might let us + // simplify or remove the next peep loop, too. + if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD { + if regtyp(&p.To) { + // Try to eliminate reg->reg moves + if regtyp(&p.From) { + if p.From.Type == p.To.Type { + if copyprop(r) { + excise(r) + t++ + } else if subprop(r) && copyprop(r) { + excise(r) + t++ + } + } + } + + // Convert uses to $0 to uses of R0 and + // propagate R0 + if regzer(&p.From) != 0 { + if p.To.Type == obj.TYPE_REG { + p.From.Type = obj.TYPE_REG + p.From.Reg = ppc64.REGZERO + if copyprop(r) { + excise(r) + t++ + } else if subprop(r) && copyprop(r) { + excise(r) + t++ + } + } + } + } + } + } + + if t != 0 { + goto loop1 + } + + /* + * look for MOVB x,R; MOVB R,R (for small MOVs not handled above) + */ + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + default: + continue + + case ppc64.AMOVH, + ppc64.AMOVHZ, + ppc64.AMOVB, + ppc64.AMOVBZ, + ppc64.AMOVW, + ppc64.AMOVWZ: + if p.To.Type != obj.TYPE_REG { + continue + } + } + + r1 = r.Link + if r1 == nil { + continue + } + p1 = r1.Prog + if p1.As != p.As { + continue + } + if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg { + continue + } + if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg { + continue + } + excise(r1) + } + + if gc.Debug['D'] > 1 { + goto ret /* allow following code improvement to be suppressed */ + } + + /* + * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R + * when OP can set condition codes correctly + */ + for r = g.Start; r != nil; r = r.Link { + p = r.Prog + switch p.As { + case ppc64.ACMP, + ppc64.ACMPW: /* always safe? */ + if regzer(&p.To) == 0 { + continue + } + r1 = r.S1 + if r1 == nil { + continue + } + switch r1.Prog.As { + default: + continue + + /* the conditions can be complex and these are currently little used */ + case ppc64.ABCL, + ppc64.ABC: + continue + + case ppc64.ABEQ, + ppc64.ABGE, + ppc64.ABGT, + ppc64.ABLE, + ppc64.ABLT, + ppc64.ABNE, + ppc64.ABVC, + ppc64.ABVS: + break + } + + r1 = r + for { + r1 = gc.Uniqp(r1) + if r1 == nil || r1.Prog.As != obj.ANOP { + break + } + } + + if r1 == nil { + continue + } + p1 = r1.Prog + if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg { + continue + } + switch p1.As { + /* irregular instructions */ + case ppc64.ASUB, + ppc64.AADD, + ppc64.AXOR, + ppc64.AOR: + if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR { + continue + } + } + + switch p1.As { + default: + continue + + case ppc64.AMOVW, + ppc64.AMOVD: + if p1.From.Type != obj.TYPE_REG { + continue + } + continue + + case ppc64.AANDCC, + ppc64.AANDNCC, + ppc64.AORCC, + ppc64.AORNCC, + ppc64.AXORCC, + ppc64.ASUBCC, + ppc64.ASUBECC, + ppc64.ASUBMECC, + ppc64.ASUBZECC, + ppc64.AADDCC, + ppc64.AADDCCC, + ppc64.AADDECC, + ppc64.AADDMECC, + ppc64.AADDZECC, + ppc64.ARLWMICC, + ppc64.ARLWNMCC, + /* don't deal with floating point instructions for now */ + /* + case AFABS: + case AFADD: + case AFADDS: + case AFCTIW: + case AFCTIWZ: + case AFDIV: + case AFDIVS: + case AFMADD: + case AFMADDS: + case AFMOVD: + case AFMSUB: + case AFMSUBS: + case AFMUL: + case AFMULS: + case AFNABS: + case AFNEG: + case AFNMADD: + case AFNMADDS: + case AFNMSUB: + case AFNMSUBS: + case AFRSP: + case AFSUB: + case AFSUBS: + case ACNTLZW: + case AMTFSB0: + case AMTFSB1: + */ + ppc64.AADD, + ppc64.AADDV, + ppc64.AADDC, + ppc64.AADDCV, + ppc64.AADDME, + ppc64.AADDMEV, + ppc64.AADDE, + ppc64.AADDEV, + ppc64.AADDZE, + ppc64.AADDZEV, + ppc64.AAND, + ppc64.AANDN, + ppc64.ADIVW, + ppc64.ADIVWV, + ppc64.ADIVWU, + ppc64.ADIVWUV, + ppc64.ADIVD, + ppc64.ADIVDV, + ppc64.ADIVDU, + ppc64.ADIVDUV, + ppc64.AEQV, + ppc64.AEXTSB, + ppc64.AEXTSH, + ppc64.AEXTSW, + ppc64.AMULHW, + ppc64.AMULHWU, + ppc64.AMULLW, + ppc64.AMULLWV, + ppc64.AMULHD, + ppc64.AMULHDU, + ppc64.AMULLD, + ppc64.AMULLDV, + ppc64.ANAND, + ppc64.ANEG, + ppc64.ANEGV, + ppc64.ANOR, + ppc64.AOR, + ppc64.AORN, + ppc64.AREM, + ppc64.AREMV, + ppc64.AREMU, + ppc64.AREMUV, + ppc64.AREMD, + ppc64.AREMDV, + ppc64.AREMDU, + ppc64.AREMDUV, + ppc64.ARLWMI, + ppc64.ARLWNM, + ppc64.ASLW, + ppc64.ASRAW, + ppc64.ASRW, + ppc64.ASLD, + ppc64.ASRAD, + ppc64.ASRD, + ppc64.ASUB, + ppc64.ASUBV, + ppc64.ASUBC, + ppc64.ASUBCV, + ppc64.ASUBME, + ppc64.ASUBMEV, + ppc64.ASUBE, + ppc64.ASUBEV, + ppc64.ASUBZE, + ppc64.ASUBZEV, + ppc64.AXOR: + t = variant2as(int(p1.As), as2variant(int(p1.As))|V_CC) + } + + if gc.Debug['D'] != 0 { + fmt.Printf("cmp %v; %v -> ", p1, p) + } + p1.As = int16(t) + if gc.Debug['D'] != 0 { + fmt.Printf("%v\n", p1) + } + excise(r) + continue + } + } + +ret: + gc.Flowend(g) +} + +func excise(r *gc.Flow) { + var p *obj.Prog + + p = r.Prog + if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { + fmt.Printf("%v ===delete===\n", p) + } + obj.Nopout(p) + gc.Ostats.Ndelmov++ +} + +/* + * regzer returns 1 if a's value is 0 (a is R0 or $0) + */ +func regzer(a *obj.Addr) int { + if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR { + if a.Sym == nil && a.Reg == 0 { + if a.Offset == 0 { + return 1 + } + } + } + if a.Type == obj.TYPE_REG { + if a.Reg == ppc64.REGZERO { + return 1 + } + } + return 0 +} + +func regtyp(a *obj.Addr) bool { + // TODO(rsc): Floating point register exclusions? + return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO +} + +/* + * the idea is to substitute + * one register for another + * from one MOV to another + * MOV a, R1 + * ADD b, R1 / no use of R2 + * MOV R1, R2 + * would be converted to + * MOV a, R2 + * ADD b, R2 + * MOV R2, R1 + * hopefully, then the former or latter MOV + * will be eliminated by copy propagation. + * + * r0 (the argument, not the register) is the MOV at the end of the + * above sequences. This returns 1 if it modified any instructions. + */ +func subprop(r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + var r *gc.Flow + var t int + var info gc.ProgInfo + + p = r0.Prog + v1 = &p.From + if !regtyp(v1) { + return false + } + v2 = &p.To + if !regtyp(v2) { + return false + } + for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { + if gc.Uniqs(r) == nil { + break + } + p = r.Prog + if p.As == obj.AVARDEF || p.As == obj.AVARKILL { + continue + } + proginfo(&info, p) + if info.Flags&gc.Call != 0 { + return false + } + + if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite { + if p.To.Type == v1.Type { + if p.To.Reg == v1.Reg { + goto gotit + } + } + } + + if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) { + break + } + if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { + break + } + } + + return false + +gotit: + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) + if p.From.Type == v2.Type { + fmt.Printf(" excise") + } + fmt.Printf("\n") + } + + for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { + p = r.Prog + copysub(&p.From, v1, v2, 1) + copysub1(p, v1, v2, 1) + copysub(&p.To, v1, v2, 1) + if gc.Debug['P'] != 0 { + fmt.Printf("%v\n", r.Prog) + } + } + + t = int(v1.Reg) + v1.Reg = v2.Reg + v2.Reg = int16(t) + if gc.Debug['P'] != 0 { + fmt.Printf("%v last\n", r.Prog) + } + return true +} + +/* + * The idea is to remove redundant copies. + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * use v2 return fail (v1->v2 move must remain) + * ----------------- + * v1->v2 F=0 + * (use v2 s/v2/v1/)* + * set v1 F=1 + * set v2 return success (caller can remove v1->v2 move) + */ +func copyprop(r0 *gc.Flow) bool { + var p *obj.Prog + var v1 *obj.Addr + var v2 *obj.Addr + + p = r0.Prog + v1 = &p.From + v2 = &p.To + if copyas(v1, v2) { + if gc.Debug['P'] != 0 { + fmt.Printf("eliminating self-move\n", r0.Prog) + } + return true + } + + gactive++ + if gc.Debug['P'] != 0 { + fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog) + } + return copy1(v1, v2, r0.S1, 0) +} + +// copy1 replaces uses of v2 with v1 starting at r and returns 1 if +// all uses were rewritten. +func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { + var t int + var p *obj.Prog + + if uint32(r.Active) == gactive { + if gc.Debug['P'] != 0 { + fmt.Printf("act set; return 1\n") + } + return true + } + + r.Active = int32(gactive) + if gc.Debug['P'] != 0 { + fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f) + } + for ; r != nil; r = r.S1 { + p = r.Prog + if gc.Debug['P'] != 0 { + fmt.Printf("%v", p) + } + if f == 0 && gc.Uniqp(r) == nil { + // Multiple predecessors; conservatively + // assume v1 was set on other path + f = 1 + + if gc.Debug['P'] != 0 { + fmt.Printf("; merge; f=%d", f) + } + } + + t = copyu(p, v2, nil) + switch t { + case 2: /* rar, can't split */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) + } + return false + + case 3: /* set */ + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + + case 1, /* used, substitute */ + 4: /* use and set */ + if f != 0 { + if gc.Debug['P'] == 0 { + return false + } + if t == 4 { + fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } else { + fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) + } + return false + } + + if copyu(p, v2, v1) != 0 { + if gc.Debug['P'] != 0 { + fmt.Printf("; sub fail; return 0\n") + } + return false + } + + if gc.Debug['P'] != 0 { + fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p) + } + if t == 4 { + if gc.Debug['P'] != 0 { + fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) + } + return true + } + } + + if f == 0 { + t = copyu(p, v1, nil) + if f == 0 && (t == 2 || t == 3 || t == 4) { + f = 1 + if gc.Debug['P'] != 0 { + fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) + } + } + } + + if gc.Debug['P'] != 0 { + fmt.Printf("\n") + } + if r.S2 != nil { + if !copy1(v1, v2, r.S2, f) { + return false + } + } + } + + return true +} + +// If s==nil, copyu returns the set/use of v in p; otherwise, it +// modifies p to replace reads of v with reads of s and returns 0 for +// success or non-zero for failure. +// +// If s==nil, copy returns one of the following values: +// 1 if v only used +// 2 if v is set and used in one address (read-alter-rewrite; +// can't substitute) +// 3 if v is only set +// 4 if v is set in one address and used in another (so addresses +// can be rewritten independently) +// 0 otherwise (not touched) +func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { + if p.From3.Type != obj.TYPE_NONE { + // 9g never generates a from3 + fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(&p.From3)) + } + + switch p.As { + default: + fmt.Printf("copyu: can't find %v\n", ppc64.Aconv(int(p.As))) + return 2 + + case obj.ANOP, /* read p->from, write p->to */ + ppc64.AMOVH, + ppc64.AMOVHZ, + ppc64.AMOVB, + ppc64.AMOVBZ, + ppc64.AMOVW, + ppc64.AMOVWZ, + ppc64.AMOVD, + ppc64.ANEG, + ppc64.ANEGCC, + ppc64.AADDME, + ppc64.AADDMECC, + ppc64.AADDZE, + ppc64.AADDZECC, + ppc64.ASUBME, + ppc64.ASUBMECC, + ppc64.ASUBZE, + ppc64.ASUBZECC, + ppc64.AFCTIW, + ppc64.AFCTIWZ, + ppc64.AFCTID, + ppc64.AFCTIDZ, + ppc64.AFCFID, + ppc64.AFCFIDCC, + ppc64.AFMOVS, + ppc64.AFMOVD, + ppc64.AFRSP, + ppc64.AFNEG, + ppc64.AFNEGCC: + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + + // Update only indirect uses of v in p->to + if !copyas(&p.To, v) { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + } + return 0 + } + + if copyas(&p.To, v) { + // Fix up implicit from + if p.From.Type == obj.TYPE_NONE { + p.From = p.To + } + if copyau(&p.From, v) { + return 4 + } + return 3 + } + + if copyau(&p.From, v) { + return 1 + } + if copyau(&p.To, v) { + // p->to only indirectly uses v + return 1 + } + + return 0 + + case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */ + ppc64.AMOVBZU, + ppc64.AMOVHU, + ppc64.AMOVHZU, + ppc64.AMOVWZU, + ppc64.AMOVDU: + if p.From.Type == obj.TYPE_MEM { + if copyas(&p.From, v) { + // No s!=nil check; need to fail + // anyway in that case + return 2 + } + + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyas(&p.To, v) { + return 3 + } + } else if p.To.Type == obj.TYPE_MEM { + if copyas(&p.To, v) { + return 2 + } + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.From, v) { + return 1 + } + } else { + fmt.Printf("copyu: bad %v\n", p) + } + + return 0 + + case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */ + ppc64.ARLWMICC: + if copyas(&p.To, v) { + return 2 + } + fallthrough + + /* fall through */ + case ppc64.AADD, + /* read p->from, read p->reg, write p->to */ + ppc64.AADDC, + ppc64.AADDE, + ppc64.ASUB, + ppc64.ASLW, + ppc64.ASRW, + ppc64.ASRAW, + ppc64.ASLD, + ppc64.ASRD, + ppc64.ASRAD, + ppc64.AOR, + ppc64.AORCC, + ppc64.AORN, + ppc64.AORNCC, + ppc64.AAND, + ppc64.AANDCC, + ppc64.AANDN, + ppc64.AANDNCC, + ppc64.ANAND, + ppc64.ANANDCC, + ppc64.ANOR, + ppc64.ANORCC, + ppc64.AXOR, + ppc64.AMULHW, + ppc64.AMULHWU, + ppc64.AMULLW, + ppc64.AMULLD, + ppc64.ADIVW, + ppc64.ADIVD, + ppc64.ADIVWU, + ppc64.ADIVDU, + ppc64.AREM, + ppc64.AREMU, + ppc64.AREMD, + ppc64.AREMDU, + ppc64.ARLWNM, + ppc64.ARLWNMCC, + ppc64.AFADDS, + ppc64.AFADD, + ppc64.AFSUBS, + ppc64.AFSUB, + ppc64.AFMULS, + ppc64.AFMUL, + ppc64.AFDIVS, + ppc64.AFDIV: + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + if copysub1(p, v, s, 1) != 0 { + return 1 + } + + // Update only indirect uses of v in p->to + if !copyas(&p.To, v) { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + } + return 0 + } + + if copyas(&p.To, v) { + if p.Reg == 0 { + // Fix up implicit reg (e.g., ADD + // R3,R4 -> ADD R3,R4,R4) so we can + // update reg and to separately. + p.Reg = p.To.Reg + } + + if copyau(&p.From, v) { + return 4 + } + if copyau1(p, v) { + return 4 + } + return 3 + } + + if copyau(&p.From, v) { + return 1 + } + if copyau1(p, v) { + return 1 + } + if copyau(&p.To, v) { + return 1 + } + return 0 + + case ppc64.ABEQ, + ppc64.ABGT, + ppc64.ABGE, + ppc64.ABLT, + ppc64.ABLE, + ppc64.ABNE, + ppc64.ABVC, + ppc64.ABVS: + return 0 + + case obj.ACHECKNIL, /* read p->from */ + ppc64.ACMP, /* read p->from, read p->to */ + ppc64.ACMPU, + ppc64.ACMPW, + ppc64.ACMPWU, + ppc64.AFCMPO, + ppc64.AFCMPU: + if s != nil { + if copysub(&p.From, v, s, 1) != 0 { + return 1 + } + return copysub(&p.To, v, s, 1) + } + + if copyau(&p.From, v) { + return 1 + } + if copyau(&p.To, v) { + return 1 + } + return 0 + + // 9g never generates a branch to a GPR (this isn't + // even a normal instruction; liblink turns it in to a + // mov and a branch). + case ppc64.ABR: /* read p->to */ + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 1 + } + return 0 + + case ppc64.ARETURN: /* funny */ + if s != nil { + return 0 + } + + // All registers die at this point, so claim + // everything is set (and not used). + return 3 + + case ppc64.ABL: /* funny */ + if v.Type == obj.TYPE_REG { + // TODO(rsc): REG_R0 and REG_F0 used to be + // (when register numbers started at 0) exregoffset and exfregoffset, + // which are unset entirely. + // It's strange that this handles R0 and F0 differently from the other + // registers. Possible failure to optimize? + if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT { + return 2 + } + if v.Reg == ppc64.REGARG { + return 2 + } + if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT { + return 2 + } + } + + if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg { + return 2 + } + + if s != nil { + if copysub(&p.To, v, s, 1) != 0 { + return 1 + } + return 0 + } + + if copyau(&p.To, v) { + return 4 + } + return 3 + + // R0 is zero, used by DUFFZERO, cannot be substituted. + // R3 is ptr to memory, used and set, cannot be substituted. + case obj.ADUFFZERO: + if v.Type == obj.TYPE_REG { + if v.Reg == 0 { + return 1 + } + if v.Reg == 3 { + return 2 + } + } + + return 0 + + // R3, R4 are ptr to src, dst, used and set, cannot be substituted. + // R5 is scratch, set by DUFFCOPY, cannot be substituted. + case obj.ADUFFCOPY: + if v.Type == obj.TYPE_REG { + if v.Reg == 3 || v.Reg == 4 { + return 2 + } + if v.Reg == 5 { + return 3 + } + } + + return 0 + + case obj.ATEXT: /* funny */ + if v.Type == obj.TYPE_REG { + if v.Reg == ppc64.REGARG { + return 3 + } + } + return 0 + + case obj.APCDATA, + obj.AFUNCDATA, + obj.AVARDEF, + obj.AVARKILL: + return 0 + } +} + +// copyas returns 1 if a and v address the same register. +// +// If a is the from operand, this means this operation reads the +// register in v. If a is the to operand, this means this operation +// writes the register in v. +func copyas(a *obj.Addr, v *obj.Addr) bool { + if regtyp(v) { + if a.Type == v.Type { + if a.Reg == v.Reg { + return true + } + } + } + return false +} + +// copyau returns 1 if a either directly or indirectly addresses the +// same register as v. +// +// If a is the from operand, this means this operation reads the +// register in v. If a is the to operand, this means the operation +// either reads or writes the register in v (if !copyas(a, v), then +// the operation reads the register in v). +func copyau(a *obj.Addr, v *obj.Addr) bool { + if copyas(a, v) { + return true + } + if v.Type == obj.TYPE_REG { + if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) { + if v.Reg == a.Reg { + return true + } + } + } + return false +} + +// copyau1 returns 1 if p->reg references the same register as v and v +// is a direct reference. +func copyau1(p *obj.Prog, v *obj.Addr) bool { + if regtyp(v) && v.Reg != 0 { + if p.Reg == v.Reg { + return true + } + } + return false +} + +// copysub replaces v with s in a if f!=0 or indicates it if could if f==0. +// Returns 1 on failure to substitute (it always succeeds on ppc64). +func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { + if f != 0 { + if copyau(a, v) { + a.Reg = s.Reg + } + } + return 0 +} + +// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0. +// Returns 1 on failure to substitute (it always succeeds on ppc64). +func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int { + if f != 0 { + if copyau1(p1, v) { + p1.Reg = s.Reg + } + } + return 0 +} + +func sameaddr(a *obj.Addr, v *obj.Addr) bool { + if a.Type != v.Type { + return false + } + if regtyp(v) && a.Reg == v.Reg { + return true + } + if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM { + if v.Offset == a.Offset { + return true + } + } + return false +} + +func smallindir(a *obj.Addr, reg *obj.Addr) bool { + return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096 +} + +func stackaddr(a *obj.Addr) bool { + return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGSP +} diff --git a/src/cmd/9g/prog.c b/src/cmd/9g/prog.c deleted file mode 100644 index 561249c358..0000000000 --- a/src/cmd/9g/prog.c +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "gg.h" -#include "../gc/popt.h" -#include "opt.h" - -enum { - LeftRdwr = LeftRead | LeftWrite, - RightRdwr = RightRead | RightWrite, -}; - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -static ProgInfo progtable[ALAST] = { - [ATYPE]= {Pseudo | Skip}, - [ATEXT]= {Pseudo}, - [AFUNCDATA]= {Pseudo}, - [APCDATA]= {Pseudo}, - [AUNDEF]= {Break}, - [AUSEFIELD]= {OK}, - [ACHECKNIL]= {LeftRead}, - [AVARDEF]= {Pseudo | RightWrite}, - [AVARKILL]= {Pseudo | RightWrite}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Power opcode. - [ANOP]= {LeftRead | RightWrite}, - - // Integer - [AADD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ASUB]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ANEG]= {SizeQ | LeftRead | RegRead | RightWrite}, - [AAND]= {SizeQ | LeftRead | RegRead | RightWrite}, - [AOR]= {SizeQ | LeftRead | RegRead | RightWrite}, - [AXOR]= {SizeQ | LeftRead | RegRead | RightWrite}, - [AMULLD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [AMULLW]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMULHD]= {SizeL | LeftRead | RegRead | RightWrite}, - [AMULHDU]= {SizeL | LeftRead | RegRead | RightWrite}, - [ADIVD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ADIVDU]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ASLD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ASRD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ASRAD]= {SizeQ | LeftRead | RegRead | RightWrite}, - [ACMP]= {SizeQ | LeftRead | RightRead}, - [ACMPU]= {SizeQ | LeftRead | RightRead}, - [ATD]= {SizeQ | RightRead}, - - // Floating point. - [AFADD]= {SizeD | LeftRead | RegRead | RightWrite}, - [AFADDS]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFSUB]= {SizeD | LeftRead | RegRead | RightWrite}, - [AFSUBS]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFMUL]= {SizeD | LeftRead | RegRead | RightWrite}, - [AFMULS]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFDIV]= {SizeD | LeftRead | RegRead | RightWrite}, - [AFDIVS]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFCTIDZ]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFCFID]= {SizeF | LeftRead | RegRead | RightWrite}, - [AFCMPU]= {SizeD | LeftRead | RightRead}, - [AFRSP]= {SizeD | LeftRead | RightWrite | Conv}, - - // Moves - [AMOVB]= {SizeB | LeftRead | RightWrite | Move | Conv}, - [AMOVBU]= {SizeB | LeftRead | RightWrite | Move | Conv | PostInc}, - [AMOVBZ]= {SizeB | LeftRead | RightWrite | Move | Conv}, - [AMOVH]= {SizeW | LeftRead | RightWrite | Move | Conv}, - [AMOVHU]= {SizeW | LeftRead | RightWrite | Move | Conv | PostInc}, - [AMOVHZ]= {SizeW | LeftRead | RightWrite | Move | Conv}, - [AMOVW]= {SizeL | LeftRead | RightWrite | Move | Conv}, - // there is no AMOVWU. - [AMOVWZU]= {SizeL | LeftRead | RightWrite | Move | Conv | PostInc}, - [AMOVWZ]= {SizeL | LeftRead | RightWrite | Move | Conv}, - [AMOVD]= {SizeQ | LeftRead | RightWrite | Move}, - [AMOVDU]= {SizeQ | LeftRead | RightWrite | Move | PostInc}, - [AFMOVS]= {SizeF | LeftRead | RightWrite | Move | Conv}, - [AFMOVD]= {SizeD | LeftRead | RightWrite | Move}, - - // Jumps - [ABR]= {Jump | Break}, - [ABL]= {Call}, - [ABEQ]= {Cjmp}, - [ABNE]= {Cjmp}, - [ABGE]= {Cjmp}, - [ABLT]= {Cjmp}, - [ABGT]= {Cjmp}, - [ABLE]= {Cjmp}, - [ARETURN]= {Break}, - - [ADUFFZERO]= {Call}, - [ADUFFCOPY]= {Call}, -}; - -static void -initproginfo(void) -{ - static int initialized; - int addvariant[] = {V_CC, V_V, V_CC|V_V}; - int as, as2, i, variant; - - if(initialized) - return; - initialized = 1; - - // Perform one-time expansion of instructions in progtable to - // their CC, V, and VCC variants - for(as=0; asas]; - if(info->flags == 0) { - *info = progtable[AADD]; - fatal("proginfo: unknown instruction %P", p); - } - - if((info->flags & RegRead) && p->reg == 0) { - info->flags &= ~RegRead; - info->flags |= /*CanRegRead |*/ RightRead; - } - - if((p->from.type == TYPE_MEM || p->from.type == TYPE_ADDR) && p->from.reg != 0) { - info->regindex |= RtoB(p->from.reg); - if(info->flags & PostInc) { - info->regset |= RtoB(p->from.reg); - } - } - if((p->to.type == TYPE_MEM || p->to.type == TYPE_ADDR) && p->to.reg != 0) { - info->regindex |= RtoB(p->to.reg); - if(info->flags & PostInc) { - info->regset |= RtoB(p->to.reg); - } - } - - if(p->from.type == TYPE_ADDR && p->from.sym != nil && (info->flags & LeftRead)) { - info->flags &= ~LeftRead; - info->flags |= LeftAddr; - } - - if(p->as == ADUFFZERO) { - info->reguse |= (1<<0) | RtoB(REG_R3); - info->regset |= RtoB(REG_R3); - } - if(p->as == ADUFFCOPY) { - // TODO(austin) Revisit when duffcopy is implemented - info->reguse |= RtoB(REG_R3) | RtoB(REG_R4) | RtoB(REG_R5); - info->regset |= RtoB(REG_R3) | RtoB(REG_R4); - } -} - -// Instruction variants table. Initially this contains entries only -// for the "base" form of each instruction. On the first call to -// as2variant or variant2as, we'll add the variants to the table. -static int varianttable[ALAST][4] = { - [AADD]= {AADD, AADDCC, AADDV, AADDVCC}, - [AADDC]= {AADDC, AADDCCC, AADDCV, AADDCVCC}, - [AADDE]= {AADDE, AADDECC, AADDEV, AADDEVCC}, - [AADDME]= {AADDME, AADDMECC, AADDMEV, AADDMEVCC}, - [AADDZE]= {AADDZE, AADDZECC, AADDZEV, AADDZEVCC}, - [AAND]= {AAND, AANDCC, 0, 0}, - [AANDN]= {AANDN, AANDNCC, 0, 0}, - [ACNTLZD]= {ACNTLZD, ACNTLZDCC, 0, 0}, - [ACNTLZW]= {ACNTLZW, ACNTLZWCC, 0, 0}, - [ADIVD]= {ADIVD, ADIVDCC, ADIVDV, ADIVDVCC}, - [ADIVDU]= {ADIVDU, ADIVDUCC, ADIVDUV, ADIVDUVCC}, - [ADIVW]= {ADIVW, ADIVWCC, ADIVWV, ADIVWVCC}, - [ADIVWU]= {ADIVWU, ADIVWUCC, ADIVWUV, ADIVWUVCC}, - [AEQV]= {AEQV, AEQVCC, 0, 0}, - [AEXTSB]= {AEXTSB, AEXTSBCC, 0, 0}, - [AEXTSH]= {AEXTSH, AEXTSHCC, 0, 0}, - [AEXTSW]= {AEXTSW, AEXTSWCC, 0, 0}, - [AFABS]= {AFABS, AFABSCC, 0, 0}, - [AFADD]= {AFADD, AFADDCC, 0, 0}, - [AFADDS]= {AFADDS, AFADDSCC, 0, 0}, - [AFCFID]= {AFCFID, AFCFIDCC, 0, 0}, - [AFCTID]= {AFCTID, AFCTIDCC, 0, 0}, - [AFCTIDZ]= {AFCTIDZ, AFCTIDZCC, 0, 0}, - [AFCTIW]= {AFCTIW, AFCTIWCC, 0, 0}, - [AFCTIWZ]= {AFCTIWZ, AFCTIWZCC, 0, 0}, - [AFDIV]= {AFDIV, AFDIVCC, 0, 0}, - [AFDIVS]= {AFDIVS, AFDIVSCC, 0, 0}, - [AFMADD]= {AFMADD, AFMADDCC, 0, 0}, - [AFMADDS]= {AFMADDS, AFMADDSCC, 0, 0}, - [AFMOVD]= {AFMOVD, AFMOVDCC, 0, 0}, - [AFMSUB]= {AFMSUB, AFMSUBCC, 0, 0}, - [AFMSUBS]= {AFMSUBS, AFMSUBSCC, 0, 0}, - [AFMUL]= {AFMUL, AFMULCC, 0, 0}, - [AFMULS]= {AFMULS, AFMULSCC, 0, 0}, - [AFNABS]= {AFNABS, AFNABSCC, 0, 0}, - [AFNEG]= {AFNEG, AFNEGCC, 0, 0}, - [AFNMADD]= {AFNMADD, AFNMADDCC, 0, 0}, - [AFNMADDS]= {AFNMADDS, AFNMADDSCC, 0, 0}, - [AFNMSUB]= {AFNMSUB, AFNMSUBCC, 0, 0}, - [AFNMSUBS]= {AFNMSUBS, AFNMSUBSCC, 0, 0}, - [AFRES]= {AFRES, AFRESCC, 0, 0}, - [AFRSP]= {AFRSP, AFRSPCC, 0, 0}, - [AFRSQRTE]= {AFRSQRTE, AFRSQRTECC, 0, 0}, - [AFSEL]= {AFSEL, AFSELCC, 0, 0}, - [AFSQRT]= {AFSQRT, AFSQRTCC, 0, 0}, - [AFSQRTS]= {AFSQRTS, AFSQRTSCC, 0, 0}, - [AFSUB]= {AFSUB, AFSUBCC, 0, 0}, - [AFSUBS]= {AFSUBS, AFSUBSCC, 0, 0}, - [AMTFSB0]= {AMTFSB0, AMTFSB0CC, 0, 0}, - [AMTFSB1]= {AMTFSB1, AMTFSB1CC, 0, 0}, - [AMULHD]= {AMULHD, AMULHDCC, 0, 0}, - [AMULHDU]= {AMULHDU, AMULHDUCC, 0, 0}, - [AMULHW]= {AMULHW, AMULHWCC, 0, 0}, - [AMULHWU]= {AMULHWU, AMULHWUCC, 0, 0}, - [AMULLD]= {AMULLD, AMULLDCC, AMULLDV, AMULLDVCC}, - [AMULLW]= {AMULLW, AMULLWCC, AMULLWV, AMULLWVCC}, - [ANAND]= {ANAND, ANANDCC, 0, 0}, - [ANEG]= {ANEG, ANEGCC, ANEGV, ANEGVCC}, - [ANOR]= {ANOR, ANORCC, 0, 0}, - [AOR]= {AOR, AORCC, 0, 0}, - [AORN]= {AORN, AORNCC, 0, 0}, - [AREM]= {AREM, AREMCC, AREMV, AREMVCC}, - [AREMD]= {AREMD, AREMDCC, AREMDV, AREMDVCC}, - [AREMDU]= {AREMDU, AREMDUCC, AREMDUV, AREMDUVCC}, - [AREMU]= {AREMU, AREMUCC, AREMUV, AREMUVCC}, - [ARLDC]= {ARLDC, ARLDCCC, 0, 0}, - [ARLDCL]= {ARLDCL, ARLDCLCC, 0, 0}, - [ARLDCR]= {ARLDCR, ARLDCRCC, 0, 0}, - [ARLDMI]= {ARLDMI, ARLDMICC, 0, 0}, - [ARLWMI]= {ARLWMI, ARLWMICC, 0, 0}, - [ARLWNM]= {ARLWNM, ARLWNMCC, 0, 0}, - [ASLD]= {ASLD, ASLDCC, 0, 0}, - [ASLW]= {ASLW, ASLWCC, 0, 0}, - [ASRAD]= {ASRAD, ASRADCC, 0, 0}, - [ASRAW]= {ASRAW, ASRAWCC, 0, 0}, - [ASRD]= {ASRD, ASRDCC, 0, 0}, - [ASRW]= {ASRW, ASRWCC, 0, 0}, - [ASUB]= {ASUB, ASUBCC, ASUBV, ASUBVCC}, - [ASUBC]= {ASUBC, ASUBCCC, ASUBCV, ASUBCVCC}, - [ASUBE]= {ASUBE, ASUBECC, ASUBEV, ASUBEVCC}, - [ASUBME]= {ASUBME, ASUBMECC, ASUBMEV, ASUBMEVCC}, - [ASUBZE]= {ASUBZE, ASUBZECC, ASUBZEV, ASUBZEVCC}, - [AXOR]= {AXOR, AXORCC, 0, 0}, -}; - -static void -initvariants(void) -{ - static int initialized; - int i, j; - - if(initialized) - return; - initialized = 1; - - for(i=0; i -#include -#include "gg.h" -#include "../gc/popt.h" - -enum { - NREGVAR = 64, /* 32 general + 32 floating */ -}; - - -static char* regname[] = { - ".R0", - ".R1", - ".R2", - ".R3", - ".R4", - ".R5", - ".R6", - ".R7", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".R16", - ".R17", - ".R18", - ".R19", - ".R20", - ".R21", - ".R22", - ".R23", - ".R24", - ".R25", - ".R26", - ".R27", - ".R28", - ".R29", - ".R30", - ".R31", - ".F0", - ".F1", - ".F2", - ".F3", - ".F4", - ".F5", - ".F6", - ".F7", - ".F8", - ".F9", - ".F10", - ".F11", - ".F12", - ".F13", - ".F14", - ".F15", - ".F16", - ".F17", - ".F18", - ".F19", - ".F20", - ".F21", - ".F22", - ".F23", - ".F24", - ".F25", - ".F26", - ".F27", - ".F28", - ".F29", - ".F30", - ".F31", -}; - -char** -regnames(int *n) -{ - *n = NREGVAR; - return regname; -} - -uint64 -excludedregs(void) -{ - uint64 regbits; - - // Exclude registers with fixed functions - regbits = (1<<0)|RtoB(REGSP)|RtoB(REGG)|RtoB(REGTLS); - // Also exclude floating point registers with fixed constants - regbits |= RtoB(REG_F27)|RtoB(REG_F28)|RtoB(REG_F29)|RtoB(REG_F30)|RtoB(REG_F31); - return regbits; -} - -uint64 -doregbits(int r) -{ - USED(r); - return 0; -} - -/* - * track register variables including external registers: - * bit reg - * 0 R0 - * 1 R1 - * ... ... - * 31 R31 - * 32+0 F0 - * 32+1 F1 - * ... ... - * 32+31 F31 - */ -uint64 -RtoB(int r) -{ - if(r > REG_R0 && r <= REG_R31) - return 1ULL << (r - REG_R0); - if(r >= REG_F0 && r <= REG_F31) - return 1ULL << (32 + r - REG_F0); - return 0; -} - -int -BtoR(uint64 b) -{ - b &= 0xffffffffull; - if(b == 0) - return 0; - return bitno(b) + REG_R0; -} - -int -BtoF(uint64 b) -{ - b >>= 32; - if(b == 0) - return 0; - return bitno(b) + REG_F0; -} diff --git a/src/cmd/9g/reg.go b/src/cmd/9g/reg.go new file mode 100644 index 0000000000..faed60d0ee --- /dev/null +++ b/src/cmd/9g/reg.go @@ -0,0 +1,164 @@ +// Derived from Inferno utils/6c/reg.c +// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package main + +import "cmd/internal/obj/ppc64" +import "cmd/internal/gc" + +const ( + NREGVAR = 64 +) + +var regname = []string{ + ".R0", + ".R1", + ".R2", + ".R3", + ".R4", + ".R5", + ".R6", + ".R7", + ".R8", + ".R9", + ".R10", + ".R11", + ".R12", + ".R13", + ".R14", + ".R15", + ".R16", + ".R17", + ".R18", + ".R19", + ".R20", + ".R21", + ".R22", + ".R23", + ".R24", + ".R25", + ".R26", + ".R27", + ".R28", + ".R29", + ".R30", + ".R31", + ".F0", + ".F1", + ".F2", + ".F3", + ".F4", + ".F5", + ".F6", + ".F7", + ".F8", + ".F9", + ".F10", + ".F11", + ".F12", + ".F13", + ".F14", + ".F15", + ".F16", + ".F17", + ".F18", + ".F19", + ".F20", + ".F21", + ".F22", + ".F23", + ".F24", + ".F25", + ".F26", + ".F27", + ".F28", + ".F29", + ".F30", + ".F31", +} + +func regnames(n *int) []string { + *n = NREGVAR + return regname +} + +func excludedregs() uint64 { + var regbits uint64 + + // Exclude registers with fixed functions + regbits = 1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) + + // Also exclude floating point registers with fixed constants + regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.REG_F31) + + return regbits +} + +func doregbits(r int) uint64 { + return 0 +} + +/* + * track register variables including external registers: + * bit reg + * 0 R0 + * 1 R1 + * ... ... + * 31 R31 + * 32+0 F0 + * 32+1 F1 + * ... ... + * 32+31 F31 + */ +func RtoB(r int) uint64 { + if r > ppc64.REG_R0 && r <= ppc64.REG_R31 { + return 1 << uint(r-ppc64.REG_R0) + } + if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 { + return 1 << uint(32+r-ppc64.REG_F0) + } + return 0 +} + +func BtoR(b uint64) int { + b &= 0xffffffff + if b == 0 { + return 0 + } + return gc.Bitno(b) + ppc64.REG_R0 +} + +func BtoF(b uint64) int { + b >>= 32 + if b == 0 { + return 0 + } + return gc.Bitno(b) + ppc64.REG_F0 +} diff --git a/src/cmd/9g/util.go b/src/cmd/9g/util.go new file mode 100644 index 0000000000..bb5eedb15a --- /dev/null +++ b/src/cmd/9g/util.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +func bool2int(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile deleted file mode 100644 index 58e25faaf9..0000000000 --- a/src/cmd/gc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2012 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -include ../../Make.dist - -install: y.tab.h builtin.c - -y.tab.h: go.y go.errors bisonerrors - bison -v -y -d go.y - # make yystate global, yytname mutable - cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c - mv y1.tab.c y.tab.c - awk -f bisonerrors y.output go.errors >yerr.h - -builtin.c: runtime.go unsafe.go - ./mkbuiltin diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c deleted file mode 100644 index 59ff0abf73..0000000000 --- a/src/cmd/gc/align.c +++ /dev/null @@ -1,689 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -/* - * machine size and rounding - * alignment is dictated around - * the size of a pointer, set in betypeinit - * (see ../6g/galign.c). - */ - -static int defercalc; - -vlong -rnd(vlong o, vlong r) -{ - if(r < 1 || r > 8 || (r&(r-1)) != 0) - fatal("rnd %lld", r); - return (o+r-1)&~(r-1); -} - -static void -offmod(Type *t) -{ - Type *f; - int32 o; - - o = 0; - for(f=t->type; f!=T; f=f->down) { - if(f->etype != TFIELD) - fatal("offmod: not TFIELD: %lT", f); - f->width = o; - o += widthptr; - if(o >= thearch.MAXWIDTH) { - yyerror("interface too large"); - o = widthptr; - } - } -} - -static vlong -widstruct(Type *errtype, Type *t, vlong o, int flag) -{ - Type *f; - int64 w; - int32 maxalign; - vlong starto, lastzero; - - starto = o; - maxalign = flag; - if(maxalign < 1) - maxalign = 1; - lastzero = 0; - for(f=t->type; f!=T; f=f->down) { - if(f->etype != TFIELD) - fatal("widstruct: not TFIELD: %lT", f); - if(f->type == T) { - // broken field, just skip it so that other valid fields - // get a width. - continue; - } - dowidth(f->type); - if(f->type->align > maxalign) - maxalign = f->type->align; - if(f->type->width < 0) - fatal("invalid width %lld", f->type->width); - w = f->type->width; - if(f->type->align > 0) - o = rnd(o, f->type->align); - f->width = o; // really offset for TFIELD - if(f->nname != N) { - // this same stackparam logic is in addrescapes - // in typecheck.c. usually addrescapes runs after - // widstruct, in which case we could drop this, - // but function closure functions are the exception. - if(f->nname->stackparam) { - f->nname->stackparam->xoffset = o; - f->nname->xoffset = 0; - } else - f->nname->xoffset = o; - } - if(w == 0) - lastzero = o; - o += w; - if(o >= thearch.MAXWIDTH) { - yyerror("type %lT too large", errtype); - o = 8; // small but nonzero - } - } - // For nonzero-sized structs which end in a zero-sized thing, we add - // an extra byte of padding to the type. This padding ensures that - // taking the address of the zero-sized thing can't manufacture a - // pointer to the next object in the heap. See issue 9401. - if(flag == 1 && o > starto && o == lastzero) - o++; - - // final width is rounded - if(flag) - o = rnd(o, maxalign); - t->align = maxalign; - - // type width only includes back to first field's offset - t->width = o - starto; - return o; -} - -void -dowidth(Type *t) -{ - int32 et; - int64 w; - int lno; - Type *t1; - - if(widthptr == 0) - fatal("dowidth without betypeinit"); - - if(t == T) - return; - - if(t->width > 0) - return; - - if(t->width == -2) { - lno = lineno; - lineno = t->lineno; - if(!t->broke) { - t->broke = 1; - yyerror("invalid recursive type %T", t); - } - t->width = 0; - lineno = lno; - return; - } - - // break infinite recursion if the broken recursive type - // is referenced again - if(t->broke && t->width == 0) - return; - - // defer checkwidth calls until after we're done - defercalc++; - - lno = lineno; - lineno = t->lineno; - t->width = -2; - t->align = 0; - - et = t->etype; - switch(et) { - case TFUNC: - case TCHAN: - case TMAP: - case TSTRING: - break; - - default: - /* simtype == 0 during bootstrap */ - if(simtype[t->etype] != 0) - et = simtype[t->etype]; - break; - } - - w = 0; - switch(et) { - default: - fatal("dowidth: unknown type: %T", t); - break; - - /* compiler-specific stuff */ - case TINT8: - case TUINT8: - case TBOOL: // bool is int8 - w = 1; - break; - case TINT16: - case TUINT16: - w = 2; - break; - case TINT32: - case TUINT32: - case TFLOAT32: - w = 4; - break; - case TINT64: - case TUINT64: - case TFLOAT64: - case TCOMPLEX64: - w = 8; - t->align = widthreg; - break; - case TCOMPLEX128: - w = 16; - t->align = widthreg; - break; - case TPTR32: - w = 4; - checkwidth(t->type); - break; - case TPTR64: - w = 8; - checkwidth(t->type); - break; - case TUNSAFEPTR: - w = widthptr; - break; - case TINTER: // implemented as 2 pointers - w = 2*widthptr; - t->align = widthptr; - offmod(t); - break; - case TCHAN: // implemented as pointer - w = widthptr; - checkwidth(t->type); - - // make fake type to check later to - // trigger channel argument check. - t1 = typ(TCHANARGS); - t1->type = t; - checkwidth(t1); - break; - case TCHANARGS: - t1 = t->type; - dowidth(t->type); // just in case - if(t1->type->width >= (1<<16)) - yyerror("channel element type too large (>64kB)"); - t->width = 1; - break; - case TMAP: // implemented as pointer - w = widthptr; - checkwidth(t->type); - checkwidth(t->down); - break; - case TFORW: // should have been filled in - if(!t->broke) - yyerror("invalid recursive type %T", t); - w = 1; // anything will do - break; - case TANY: - // dummy type; should be replaced before use. - if(!debug['A']) - fatal("dowidth any"); - w = 1; // anything will do - break; - case TSTRING: - if(sizeof_String == 0) - fatal("early dowidth string"); - w = sizeof_String; - t->align = widthptr; - break; - case TARRAY: - if(t->type == T) - break; - if(t->bound >= 0) { - uint64 cap; - - dowidth(t->type); - if(t->type->width != 0) { - cap = (thearch.MAXWIDTH-1) / t->type->width; - if(t->bound > cap) - yyerror("type %lT larger than address space", t); - } - w = t->bound * t->type->width; - t->align = t->type->align; - } - else if(t->bound == -1) { - w = sizeof_Array; - checkwidth(t->type); - t->align = widthptr; - } - else if(t->bound == -100) { - if(!t->broke) { - yyerror("use of [...] array outside of array literal"); - t->broke = 1; - } - } - else - fatal("dowidth %T", t); // probably [...]T - break; - - case TSTRUCT: - if(t->funarg) - fatal("dowidth fn struct %T", t); - w = widstruct(t, t, 0, 1); - break; - - case TFUNC: - // make fake type to check later to - // trigger function argument computation. - t1 = typ(TFUNCARGS); - t1->type = t; - checkwidth(t1); - - // width of func type is pointer - w = widthptr; - break; - - case TFUNCARGS: - // function is 3 cated structures; - // compute their widths as side-effect. - t1 = t->type; - w = widstruct(t->type, *getthis(t1), 0, 0); - w = widstruct(t->type, *getinarg(t1), w, widthreg); - w = widstruct(t->type, *getoutarg(t1), w, widthreg); - t1->argwid = w; - if(w%widthreg) - warn("bad type %T %d\n", t1, w); - t->align = 1; - break; - } - - if(widthptr == 4 && w != (int32)w) - yyerror("type %T too large", t); - - t->width = w; - if(t->align == 0) { - if(w > 8 || (w&(w-1)) != 0) - fatal("invalid alignment for %T", t); - t->align = w; - } - lineno = lno; - - if(defercalc == 1) - resumecheckwidth(); - else - --defercalc; -} - -/* - * when a type's width should be known, we call checkwidth - * to compute it. during a declaration like - * - * type T *struct { next T } - * - * it is necessary to defer the calculation of the struct width - * until after T has been initialized to be a pointer to that struct. - * similarly, during import processing structs may be used - * before their definition. in those situations, calling - * defercheckwidth() stops width calculations until - * resumecheckwidth() is called, at which point all the - * checkwidths that were deferred are executed. - * dowidth should only be called when the type's size - * is needed immediately. checkwidth makes sure the - * size is evaluated eventually. - */ -typedef struct TypeList TypeList; -struct TypeList { - Type *t; - TypeList *next; -}; - -static TypeList *tlfree; -static TypeList *tlq; - -void -checkwidth(Type *t) -{ - TypeList *l; - - if(t == T) - return; - - // function arg structs should not be checked - // outside of the enclosing function. - if(t->funarg) - fatal("checkwidth %T", t); - - if(!defercalc) { - dowidth(t); - return; - } - if(t->deferwidth) - return; - t->deferwidth = 1; - - l = tlfree; - if(l != nil) - tlfree = l->next; - else - l = mal(sizeof *l); - - l->t = t; - l->next = tlq; - tlq = l; -} - -void -defercheckwidth(void) -{ - // we get out of sync on syntax errors, so don't be pedantic. - if(defercalc && nerrors == 0) - fatal("defercheckwidth"); - defercalc = 1; -} - -void -resumecheckwidth(void) -{ - TypeList *l; - - if(!defercalc) - fatal("resumecheckwidth"); - for(l = tlq; l != nil; l = tlq) { - l->t->deferwidth = 0; - tlq = l->next; - dowidth(l->t); - l->next = tlfree; - tlfree = l; - } - defercalc = 0; -} - -void -typeinit(void) -{ - int i, etype, sameas; - Type *t; - Sym *s, *s1; - - if(widthptr == 0) - fatal("typeinit before betypeinit"); - - for(i=0; isym = pkglookup("Pointer", unsafepkg); - t->sym->def = typenod(t); - - dowidth(types[TUNSAFEPTR]); - - tptr = TPTR32; - if(widthptr == 8) - tptr = TPTR64; - - for(i=TINT8; i<=TUINT64; i++) - isint[i] = 1; - isint[TINT] = 1; - isint[TUINT] = 1; - isint[TUINTPTR] = 1; - - isfloat[TFLOAT32] = 1; - isfloat[TFLOAT64] = 1; - - iscomplex[TCOMPLEX64] = 1; - iscomplex[TCOMPLEX128] = 1; - - isptr[TPTR32] = 1; - isptr[TPTR64] = 1; - - isforw[TFORW] = 1; - - issigned[TINT] = 1; - issigned[TINT8] = 1; - issigned[TINT16] = 1; - issigned[TINT32] = 1; - issigned[TINT64] = 1; - - /* - * initialize okfor - */ - for(i=0; i= nelem(types)) - fatal("typeinit: %s bad etype", s->name); - sameas = thearch.typedefs[i].sameas; - if(sameas < 0 || sameas >= nelem(types)) - fatal("typeinit: %s bad sameas", s->name); - simtype[etype] = sameas; - minfltval[etype] = minfltval[sameas]; - maxfltval[etype] = maxfltval[sameas]; - minintval[etype] = minintval[sameas]; - maxintval[etype] = maxintval[sameas]; - - t = types[etype]; - if(t != T) - fatal("typeinit: %s already defined", s->name); - - t = typ(etype); - t->sym = s1; - - dowidth(t); - types[etype] = t; - s1->def = typenod(t); - } - - Array_array = rnd(0, widthptr); - Array_nel = rnd(Array_array+widthptr, widthint); - Array_cap = rnd(Array_nel+widthint, widthint); - sizeof_Array = rnd(Array_cap+widthint, widthptr); - - // string is same as slice wo the cap - sizeof_String = rnd(Array_nel+widthint, widthptr); - - dowidth(types[TSTRING]); - dowidth(idealstring); -} - -/* - * compute total size of f's in/out arguments. - */ -int -argsize(Type *t) -{ - Iter save; - Type *fp; - int64 w, x; - - w = 0; - - fp = structfirst(&save, getoutarg(t)); - while(fp != T) { - x = fp->width + fp->type->width; - if(x > w) - w = x; - fp = structnext(&save); - } - - fp = funcfirst(&save, t); - while(fp != T) { - x = fp->width + fp->type->width; - if(x > w) - w = x; - fp = funcnext(&save); - } - - w = (w+widthptr-1) & ~(widthptr-1); - if((int)w != w) - fatal("argsize too big"); - return w; -} diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c deleted file mode 100644 index d5d9646d6a..0000000000 --- a/src/cmd/gc/array.c +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -enum { - DEFAULTCAPACITY = 16, -}; - -Array* -arraynew(int capacity, int32 size) -{ - Array *result; - - if(capacity < 0) - fatal("arraynew: capacity %d is not positive", capacity); - if(size < 0) - fatal("arraynew: size %d is not positive\n", size); - result = malloc(sizeof(*result)); - if(result == nil) - fatal("arraynew: malloc failed\n"); - result->length = 0; - result->size = size; - result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity; - result->data = malloc(result->capacity * result->size); - if(result->data == nil) - fatal("arraynew: malloc failed\n"); - return result; -} - -void -arrayfree(Array *array) -{ - if(array == nil) - return; - free(array->data); - free(array); -} - -int -arraylength(Array *array) -{ - return array->length; -} - -void* -arrayget(Array *array, int index) -{ - if(array == nil) - fatal("arrayget: array is nil\n"); - if(index < 0 || index >= array->length) - fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length); - return array->data + index * array->size; -} - -void -arrayset(Array *array, int index, void *element) -{ - if(array == nil) - fatal("arrayset: array is nil\n"); - if(element == nil) - fatal("arrayset: element is nil\n"); - if(index < 0 || index >= array->length) - fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length); - memmove(array->data + index * array->size, element, array->size); -} - -static void -ensurecapacity(Array *array, int capacity) -{ - int32 newcapacity; - char *newdata; - - if(array == nil) - fatal("ensurecapacity: array is nil\n"); - if(capacity < 0) - fatal("ensurecapacity: capacity %d is not positive", capacity); - if(capacity >= array->capacity) { - newcapacity = capacity + (capacity >> 1); - newdata = realloc(array->data, newcapacity * array->size); - if(newdata == nil) - fatal("ensurecapacity: realloc failed\n"); - array->capacity = newcapacity; - array->data = newdata; - } -} - -void -arrayadd(Array *array, void *element) -{ - if(array == nil) - fatal("arrayset: array is nil\n"); - if(element == nil) - fatal("arrayset: element is nil\n"); - ensurecapacity(array, array->length + 1); - array->length++; - arrayset(array, array->length - 1, element); -} - -void -arraysort(Array *array, int (*cmp)(const void*, const void*)) -{ - qsort(array->data, array->length, array->size, cmp); -} diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors deleted file mode 100755 index fa74c67c3b..0000000000 --- a/src/cmd/gc/bisonerrors +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/awk -f -# Copyright 2010 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# This program implements the core idea from -# -# Clinton L. Jeffery, Generating LR syntax error messages from examples, -# ACM TOPLAS 25(5) (September 2003). http://doi.acm.org/10.1145/937563.937566 -# -# It reads Bison's summary of a grammar followed by a file -# like go.errors, replacing lines beginning with % by the -# yystate and yychar that will be active when an error happens -# while parsing that line. -# -# Unlike the system described in the paper, the lines in go.errors -# give grammar symbol name lists, not actual program fragments. -# This is a little less programmer-friendly but doesn't require being -# able to run the text through lex.c. - -BEGIN{ - bison = 1 - grammar = 0 - states = 0 - open = 0 -} - -# In Grammar section of y.output, -# record lhs and length of rhs for each rule. -bison && /^Grammar/ { grammar = 1 } -bison && /^(Terminals|state 0)/ { grammar = 0 } -grammar && NF>0 { - if($2 != "|") { - r = $2 - sub(/:$/, "", r) - } - rulelhs[$1] = r - rulesize[$1] = NF-2 - if(rulesize[$1] == 1 && $3 == "%empty") { - rulesize[$1] = 0 - } - if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") { - rulesize[$1] = 0 - } -} - -# In state dumps, record shift/reduce actions. -bison && /^[Ss]tate 0/ { grammar = 0; states = 1 } - -states && /^[Ss]tate / { state = $2 } -states { statetext[state] = statetext[state] $0 "\n" } - -states && / shift/ { - n = nshift[state]++ - if($0 ~ /and go to/) - shift[state,n] = $7 # GNU Bison - else - shift[state,n] = $3 # Plan 9 Yacc - shifttoken[state,n] = $1 - next -} -states && / (go to|goto)/ { - n = nshift[state]++ - if($0 ~ /go to/) - shift[state,n] = $5 # GNU Bison - else - shift[state,n] = $3 # Plan 9 Yacc - shifttoken[state,n] = $1 - next -} -states && / reduce/ { - n = nreduce[state]++ - if($0 ~ /reduce using rule/) - reduce[state,n] = $5 # GNU Bison - else - reduce[state,n] = $3 # Plan 9 yacc - reducetoken[state,n] = $1 - next -} - -# Skip over the summary information printed by Plan 9 yacc. -/nonterminals$/,/^maximum spread/ { next } - -# First // comment marks the beginning of the pattern file. -/^\/\// { bison = 0; grammar = 0; state = 0 } -bison { next } - -# Treat % as first field on line as introducing a pattern (token sequence). -# Run it through the LR machine and print the induced "yystate, yychar," -# at the point where the error happens. -$1 == "%" { - nstack = 0 - state = 0 - f = 2 - tok = "" - for(;;) { - if(tok == "" && f <= NF) { - tok = $f - f++ - } - found = 0 - for(j=0; j " shift[state,j] - stack[nstack++] = state - state = shift[state,j] - found = 1 - tok = "" - break - } - } - if(found) - continue - for(j=0; j -#include -#include "go.h" - -/* -Bits -bor(Bits a, Bits b) -{ - Bits c; - int i; - - for(i=0; ib[i]) - return 1; - return 0; -} - -/* -int -beq(Bits a, Bits b) -{ - int i; - - for(i=0; ib[n/64] & (1LL << (n%64))) != 0; -} - -void -biset(Bits *a, uint n) -{ - a->b[n/64] |= 1LL << (n%64); -} - -void -biclr(Bits *a, uint n) -{ - a->b[n/64] &= ~(1LL << (n%64)); -} - -int -bitno(uint64 b) -{ - int i; - - for(i=0; i<64; i++) - if(b & (1LL<args, Bits); - while(bany(&bits)) { - i = bnum(bits); - if(first) - first = 0; - else - fmtprint(fp, " "); - if(var[i].node == N || var[i].node->sym == S) - fmtprint(fp, "$%d", i); - else { - fmtprint(fp, "%s(%d)", var[i].node->sym->name, i); - if(var[i].offset != 0) - fmtprint(fp, "%+lld", (vlong)var[i].offset); - } - biclr(&bits, i); - } - return 0; -} diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c deleted file mode 100644 index 1178f622e5..0000000000 --- a/src/cmd/gc/builtin.c +++ /dev/null @@ -1,165 +0,0 @@ -// AUTO-GENERATED by mkbuiltin; DO NOT EDIT -#include -#include -#include "go.h" -char *runtimeimport = - "package runtime\n" - "import runtime \"runtime\"\n" - "func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" - "func @\"\".panicindex ()\n" - "func @\"\".panicslice ()\n" - "func @\"\".panicdivide ()\n" - "func @\"\".throwreturn ()\n" - "func @\"\".throwinit ()\n" - "func @\"\".panicwrap (? string, ? string, ? string)\n" - "func @\"\".gopanic (? interface {})\n" - "func @\"\".gorecover (? *int32) (? interface {})\n" - "func @\"\".printbool (? bool)\n" - "func @\"\".printfloat (? float64)\n" - "func @\"\".printint (? int64)\n" - "func @\"\".printhex (? uint64)\n" - "func @\"\".printuint (? uint64)\n" - "func @\"\".printcomplex (? complex128)\n" - "func @\"\".printstring (? string)\n" - "func @\"\".printpointer (? any)\n" - "func @\"\".printiface (? any)\n" - "func @\"\".printeface (? any)\n" - "func @\"\".printslice (? any)\n" - "func @\"\".printnl ()\n" - "func @\"\".printsp ()\n" - "func @\"\".printlock ()\n" - "func @\"\".printunlock ()\n" - "func @\"\".concatstring2 (? *[32]byte, ? string, ? string) (? string)\n" - "func @\"\".concatstring3 (? *[32]byte, ? string, ? string, ? string) (? string)\n" - "func @\"\".concatstring4 (? *[32]byte, ? string, ? string, ? string, ? string) (? string)\n" - "func @\"\".concatstring5 (? *[32]byte, ? string, ? string, ? string, ? string, ? string) (? string)\n" - "func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n" - "func @\"\".cmpstring (? string, ? string) (? int)\n" - "func @\"\".eqstring (? string, ? string) (? bool)\n" - "func @\"\".intstring (? *[4]byte, ? int64) (? string)\n" - "func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n" - "func @\"\".slicebytetostringtmp (? []byte) (? string)\n" - "func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n" - "func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n" - "func @\"\".stringtoslicebytetmp (? string) (? []byte)\n" - "func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n" - "func @\"\".stringiter (? string, ? int) (? int)\n" - "func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" - "func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" - "func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" - "func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" - "func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" - "func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" - "func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n" - "func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n" - "func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertE2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".assertE2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertE2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".assertI2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertI2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".assertI2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertI2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".assertI2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" - "func @\"\".assertI2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" - "func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" - "func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" - "func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" - "func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" - "func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" - "func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" - "func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" - "func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" - "func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" - "func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" - "func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" - "func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" - "func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" - "func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" - "func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" - "func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" - "func @\"\".mapiternext (@\"\".hiter·1 *any)\n" - "func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" - "func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" - "func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" - "func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" - "func @\"\".closechan (@\"\".hchan·1 any)\n" - "func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" - "func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n" - "func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" - "func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" - "func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" - "func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" - "func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" - "func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n" - "func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" - "func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" - "func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n" - "func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n" - "func @\"\".selectgo (@\"\".sel·1 *byte)\n" - "func @\"\".block ()\n" - "func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" - "func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n" - "func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n" - "func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n" - "func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" - "func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" - "func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" - "func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" - "func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" - "func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" - "func @\"\".int64div (? int64, ? int64) (? int64)\n" - "func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n" - "func @\"\".int64mod (? int64, ? int64) (? int64)\n" - "func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n" - "func @\"\".float64toint64 (? float64) (? int64)\n" - "func @\"\".float64touint64 (? float64) (? uint64)\n" - "func @\"\".int64tofloat64 (? int64) (? float64)\n" - "func @\"\".uint64tofloat64 (? uint64) (? float64)\n" - "func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n" - "func @\"\".racefuncenter (? uintptr)\n" - "func @\"\".racefuncexit ()\n" - "func @\"\".raceread (? uintptr)\n" - "func @\"\".racewrite (? uintptr)\n" - "func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" - "func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" - "\n" - "$$\n"; -char *unsafeimport = - "package unsafe\n" - "import runtime \"runtime\"\n" - "type @\"\".Pointer uintptr\n" - "func @\"\".Offsetof (? any) (? uintptr)\n" - "func @\"\".Sizeof (? any) (? uintptr)\n" - "func @\"\".Alignof (? any) (? uintptr)\n" - "\n" - "$$\n"; diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c deleted file mode 100644 index 2428006c8a..0000000000 --- a/src/cmd/gc/bv.c +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -enum { - WORDSIZE = 4, - WORDBITS = 32, - WORDMASK = WORDBITS - 1, - WORDSHIFT = 5, -}; - -static uintptr -bvsize(uintptr n) -{ - return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE; -} - -int32 -bvbits(Bvec *bv) -{ - return bv->n; -} - -int32 -bvwords(Bvec *bv) -{ - return (bv->n + WORDBITS - 1) / WORDBITS; -} - -Bvec* -bvalloc(int32 n) -{ - Bvec *bv; - uintptr nbytes; - - if(n < 0) - fatal("bvalloc: initial size is negative\n"); - nbytes = sizeof(Bvec) + bvsize(n); - bv = malloc(nbytes); - if(bv == nil) - fatal("bvalloc: malloc failed\n"); - memset(bv, 0, nbytes); - bv->n = n; - return bv; -} - -/* difference */ -void -bvandnot(Bvec *dst, Bvec *src1, Bvec *src2) -{ - int32 i, w; - - if(dst->n != src1->n || dst->n != src2->n) - fatal("bvand: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); - for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) - dst->b[w] = src1->b[w] & ~src2->b[w]; -} - -int -bvcmp(Bvec *bv1, Bvec *bv2) -{ - uintptr nbytes; - - if(bv1->n != bv2->n) - fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n); - nbytes = bvsize(bv1->n); - return memcmp(bv1->b, bv2->b, nbytes); -} - -void -bvcopy(Bvec *dst, Bvec *src) -{ - memmove(dst->b, src->b, bvsize(dst->n)); -} - -Bvec* -bvconcat(Bvec *src1, Bvec *src2) -{ - Bvec *dst; - int32 i; - - dst = bvalloc(src1->n + src2->n); - for(i = 0; i < src1->n; i++) - if(bvget(src1, i)) - bvset(dst, i); - for(i = 0; i < src2->n; i++) - if(bvget(src2, i)) - bvset(dst, i + src1->n); - return dst; -} - -int -bvget(Bvec *bv, int32 i) -{ - if(i < 0 || i >= bv->n) - fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n); - return (bv->b[i>>WORDSHIFT] >> (i&WORDMASK)) & 1; -} - -// bvnext returns the smallest index >= i for which bvget(bv, i) == 1. -// If there is no such index, bvnext returns -1. -int -bvnext(Bvec *bv, int32 i) -{ - uint32 w; - - if(i >= bv->n) - return -1; - - // Jump i ahead to next word with bits. - if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) { - i &= ~WORDMASK; - i += WORDBITS; - while(i < bv->n && bv->b[i>>WORDSHIFT] == 0) - i += WORDBITS; - } - if(i >= bv->n) - return -1; - - // Find 1 bit. - w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK); - while((w&1) == 0) { - w>>=1; - i++; - } - return i; -} - -int -bvisempty(Bvec *bv) -{ - int32 i; - - for(i = 0; i < bv->n; i += WORDBITS) - if(bv->b[i>>WORDSHIFT] != 0) - return 0; - return 1; -} - -void -bvnot(Bvec *bv) -{ - int32 i, w; - - for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++) - bv->b[w] = ~bv->b[w]; -} - -/* union */ -void -bvor(Bvec *dst, Bvec *src1, Bvec *src2) -{ - int32 i, w; - - if(dst->n != src1->n || dst->n != src2->n) - fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); - for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) - dst->b[w] = src1->b[w] | src2->b[w]; -} - -/* intersection */ -void -bvand(Bvec *dst, Bvec *src1, Bvec *src2) -{ - int32 i, w; - - if(dst->n != src1->n || dst->n != src2->n) - fatal("bvor: lengths %d, %d, and %d are not equal", dst->n, src1->n, src2->n); - for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++) - dst->b[w] = src1->b[w] & src2->b[w]; -} - -void -bvprint(Bvec *bv) -{ - int32 i; - - print("#*"); - for(i = 0; i < bv->n; i++) - print("%d", bvget(bv, i)); -} - -void -bvreset(Bvec *bv, int32 i) -{ - uint32 mask; - - if(i < 0 || i >= bv->n) - fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n); - mask = ~(1 << (i % WORDBITS)); - bv->b[i / WORDBITS] &= mask; -} - -void -bvresetall(Bvec *bv) -{ - memset(bv->b, 0x00, bvsize(bv->n)); -} - -void -bvset(Bvec *bv, int32 i) -{ - uint32 mask; - - if(i < 0 || i >= bv->n) - fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n); - mask = 1U << (i % WORDBITS); - bv->b[i / WORDBITS] |= mask; -} diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c deleted file mode 100644 index 35b6d4b1b4..0000000000 --- a/src/cmd/gc/closure.c +++ /dev/null @@ -1,659 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * function literals aka closures - */ - -#include -#include -#include "go.h" - -void -closurehdr(Node *ntype) -{ - Node *n, *name, *a; - NodeList *l; - - n = nod(OCLOSURE, N, N); - n->ntype = ntype; - n->funcdepth = funcdepth; - n->outerfunc = curfn; - - funchdr(n); - - // steal ntype's argument names and - // leave a fresh copy in their place. - // references to these variables need to - // refer to the variables in the external - // function declared below; see walkclosure. - n->list = ntype->list; - n->rlist = ntype->rlist; - ntype->list = nil; - ntype->rlist = nil; - for(l=n->list; l; l=l->next) { - name = l->n->left; - if(name) - name = newname(name->sym); - a = nod(ODCLFIELD, name, l->n->right); - a->isddd = l->n->isddd; - if(name) - name->isddd = a->isddd; - ntype->list = list(ntype->list, a); - } - for(l=n->rlist; l; l=l->next) { - name = l->n->left; - if(name) - name = newname(name->sym); - ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right)); - } -} - -Node* -closurebody(NodeList *body) -{ - Node *func, *v; - NodeList *l; - - if(body == nil) - body = list1(nod(OEMPTY, N, N)); - - func = curfn; - func->nbody = body; - func->endlineno = lineno; - funcbody(func); - - // closure-specific variables are hanging off the - // ordinary ones in the symbol table; see oldname. - // unhook them. - // make the list of pointers for the closure call. - for(l=func->cvars; l; l=l->next) { - v = l->n; - v->closure->closure = v->outer; - v->outerexpr = oldname(v->sym); - } - - return func; -} - -static Node* makeclosure(Node *func); - -void -typecheckclosure(Node *func, int top) -{ - Node *oldfn, *n; - NodeList *l; - int olddd; - - for(l=func->cvars; l; l=l->next) { - n = l->n->closure; - if(!n->captured) { - n->captured = 1; - if(n->decldepth == 0) - fatal("typecheckclosure: var %hN does not have decldepth assigned", n); - // Ignore assignments to the variable in straightline code - // preceding the first capturing by a closure. - if(n->decldepth == decldepth) - n->assigned = 0; - } - } - - for(l=func->dcl; l; l=l->next) - if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT)) - l->n->decldepth = 1; - - oldfn = curfn; - typecheck(&func->ntype, Etype); - func->type = func->ntype->type; - func->top = top; - - // Type check the body now, but only if we're inside a function. - // At top level (in a variable initialization: curfn==nil) we're not - // ready to type check code yet; we'll check it later, because the - // underlying closure function we create is added to xtop. - if(curfn && func->type != T) { - curfn = func; - olddd = decldepth; - decldepth = 1; - typechecklist(func->nbody, Etop); - decldepth = olddd; - curfn = oldfn; - } - - // Create top-level function - xtop = list(xtop, makeclosure(func)); -} - -// closurename returns name for OCLOSURE n. -// It is not as simple as it ought to be, because we typecheck nested closures -// starting from the innermost one. So when we check the inner closure, -// we don't yet have name for the outer closure. This function uses recursion -// to generate names all the way up if necessary. -static Sym* -closurename(Node *n) -{ - static int closgen; - char *outer, *prefix; - int gen; - - if(n->sym != S) - return n->sym; - gen = 0; - outer = nil; - prefix = nil; - if(n->outerfunc == N) { - // Global closure. - outer = "glob"; - prefix = "func"; - gen = ++closgen; - } else if(n->outerfunc->op == ODCLFUNC) { - // The outermost closure inside of a named function. - outer = n->outerfunc->nname->sym->name; - prefix = "func"; - // Yes, functions can be named _. - // Can't use function closgen in such case, - // because it would lead to name clashes. - if(!isblank(n->outerfunc->nname)) - gen = ++n->outerfunc->closgen; - else - gen = ++closgen; - } else if(n->outerfunc->op == OCLOSURE) { - // Nested closure, recurse. - outer = closurename(n->outerfunc)->name; - prefix = ""; - gen = ++n->outerfunc->closgen; - } else - fatal("closurename called for %hN", n); - snprint(namebuf, sizeof namebuf, "%s.%s%d", outer, prefix, gen); - n->sym = lookup(namebuf); - return n->sym; -} - -static Node* -makeclosure(Node *func) -{ - Node *xtype, *xfunc; - - /* - * wrap body in external function - * that begins by reading closure parameters. - */ - xtype = nod(OTFUNC, N, N); - xtype->list = func->list; - xtype->rlist = func->rlist; - - // create the function - xfunc = nod(ODCLFUNC, N, N); - xfunc->nname = newname(closurename(func)); - xfunc->nname->sym->flags |= SymExported; // disable export - xfunc->nname->ntype = xtype; - xfunc->nname->defn = xfunc; - declare(xfunc->nname, PFUNC); - xfunc->nname->funcdepth = func->funcdepth; - xfunc->funcdepth = func->funcdepth; - xfunc->endlineno = func->endlineno; - - xfunc->nbody = func->nbody; - xfunc->dcl = concat(func->dcl, xfunc->dcl); - if(xfunc->nbody == nil) - fatal("empty body - won't generate any code"); - typecheck(&xfunc, Etop); - - xfunc->closure = func; - func->closure = xfunc; - - func->nbody = nil; - func->list = nil; - func->rlist = nil; - - return xfunc; -} - -// capturevars is called in a separate phase after all typechecking is done. -// It decides whether each variable captured by a closure should be captured -// by value or by reference. -// We use value capturing for values <= 128 bytes that are never reassigned -// after capturing (effectively constant). -void -capturevars(Node *xfunc) -{ - Node *func, *v, *outer; - NodeList *l; - int lno; - - lno = lineno; - lineno = xfunc->lineno; - - func = xfunc->closure; - func->enter = nil; - for(l=func->cvars; l; l=l->next) { - v = l->n; - if(v->type == T) { - // if v->type is nil, it means v looked like it was - // going to be used in the closure but wasn't. - // this happens because when parsing a, b, c := f() - // the a, b, c gets parsed as references to older - // a, b, c before the parser figures out this is a - // declaration. - v->op = OXXX; - continue; - } - - // type check the & of closed variables outside the closure, - // so that the outer frame also grabs them and knows they escape. - dowidth(v->type); - outer = v->outerexpr; - v->outerexpr = N; - // out parameters will be assigned to implicitly upon return. - if(outer->class != PPARAMOUT && !v->closure->addrtaken && !v->closure->assigned && v->type->width <= 128) - v->byval = 1; - else { - v->closure->addrtaken = 1; - outer = nod(OADDR, outer, N); - } - if(debug['m'] > 1) { - Sym *name; - char *how; - name = nil; - if(v->curfn && v->curfn->nname) - name = v->curfn->nname->sym; - how = "ref"; - if(v->byval) - how = "value"; - warnl(v->lineno, "%S capturing by %s: %S (addr=%d assign=%d width=%d)", - name, how, - v->sym, v->closure->addrtaken, v->closure->assigned, (int32)v->type->width); - } - typecheck(&outer, Erv); - func->enter = list(func->enter, outer); - } - - lineno = lno; -} - -// transformclosure is called in a separate phase after escape analysis. -// It transform closure bodies to properly reference captured variables. -void -transformclosure(Node *xfunc) -{ - Node *func, *cv, *addr, *v, *f; - NodeList *l, *body; - Type **param, *fld; - vlong offset; - int lno, nvar; - - lno = lineno; - lineno = xfunc->lineno; - func = xfunc->closure; - - if(func->top&Ecall) { - // If the closure is directly called, we transform it to a plain function call - // with variables passed as args. This avoids allocation of a closure object. - // Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE) - // will complete the transformation later. - // For illustration, the following closure: - // func(a int) { - // println(byval) - // byref++ - // }(42) - // becomes: - // func(a int, byval int, &byref *int) { - // println(byval) - // (*&byref)++ - // }(42, byval, &byref) - - // f is ONAME of the actual function. - f = xfunc->nname; - // Get pointer to input arguments and rewind to the end. - // We are going to append captured variables to input args. - param = &getinargx(f->type)->type; - for(; *param; param = &(*param)->down) { - } - for(l=func->cvars; l; l=l->next) { - v = l->n; - if(v->op == OXXX) - continue; - fld = typ(TFIELD); - fld->funarg = 1; - if(v->byval) { - // If v is captured by value, we merely downgrade it to PPARAM. - v->class = PPARAM; - v->ullman = 1; - fld->nname = v; - } else { - // If v of type T is captured by reference, - // we introduce function param &v *T - // and v remains PPARAMREF with &v heapaddr - // (accesses will implicitly deref &v). - snprint(namebuf, sizeof namebuf, "&%s", v->sym->name); - addr = newname(lookup(namebuf)); - addr->type = ptrto(v->type); - addr->class = PPARAM; - v->heapaddr = addr; - fld->nname = addr; - } - fld->type = fld->nname->type; - fld->sym = fld->nname->sym; - // Declare the new param and append it to input arguments. - xfunc->dcl = list(xfunc->dcl, fld->nname); - *param = fld; - param = &fld->down; - } - // Recalculate param offsets. - if(f->type->width > 0) - fatal("transformclosure: width is already calculated"); - dowidth(f->type); - xfunc->type = f->type; // update type of ODCLFUNC - } else { - // The closure is not called, so it is going to stay as closure. - nvar = 0; - body = nil; - offset = widthptr; - for(l=func->cvars; l; l=l->next) { - v = l->n; - if(v->op == OXXX) - continue; - nvar++; - // cv refers to the field inside of closure OSTRUCTLIT. - cv = nod(OCLOSUREVAR, N, N); - cv->type = v->type; - if(!v->byval) - cv->type = ptrto(v->type); - offset = rnd(offset, cv->type->align); - cv->xoffset = offset; - offset += cv->type->width; - - if(v->byval && v->type->width <= 2*widthptr && thearch.thechar == '6') { - // If it is a small variable captured by value, downgrade it to PAUTO. - // This optimization is currently enabled only for amd64, see: - // https://github.com/golang/go/issues/9865 - v->class = PAUTO; - v->ullman = 1; - xfunc->dcl = list(xfunc->dcl, v); - body = list(body, nod(OAS, v, cv)); - } else { - // Declare variable holding addresses taken from closure - // and initialize in entry prologue. - snprint(namebuf, sizeof namebuf, "&%s", v->sym->name); - addr = newname(lookup(namebuf)); - addr->ntype = nod(OIND, typenod(v->type), N); - addr->class = PAUTO; - addr->used = 1; - addr->curfn = xfunc; - xfunc->dcl = list(xfunc->dcl, addr); - v->heapaddr = addr; - if(v->byval) - cv = nod(OADDR, cv, N); - body = list(body, nod(OAS, addr, cv)); - } - } - typechecklist(body, Etop); - walkstmtlist(body); - xfunc->enter = body; - xfunc->needctxt = nvar > 0; - } - - lineno = lno; -} - -Node* -walkclosure(Node *func, NodeList **init) -{ - Node *clos, *typ, *typ1, *v; - NodeList *l; - - // If no closure vars, don't bother wrapping. - if(func->cvars == nil) - return func->closure->nname; - - // Create closure in the form of a composite literal. - // supposing the closure captures an int i and a string s - // and has one float64 argument and no results, - // the generated code looks like: - // - // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s} - // - // The use of the struct provides type information to the garbage - // collector so that it can walk the closure. We could use (in this case) - // [3]unsafe.Pointer instead, but that would leave the gc in the dark. - // The information appears in the binary in the form of type descriptors; - // the struct is unnamed so that closures in multiple packages with the - // same struct type can share the descriptor. - - typ = nod(OTSTRUCT, N, N); - typ->list = list1(nod(ODCLFIELD, newname(lookup(".F")), typenod(types[TUINTPTR]))); - for(l=func->cvars; l; l=l->next) { - v = l->n; - if(v->op == OXXX) - continue; - typ1 = typenod(v->type); - if(!v->byval) - typ1 = nod(OIND, typ1, N); - typ->list = list(typ->list, nod(ODCLFIELD, newname(v->sym), typ1)); - } - - clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); - clos->esc = func->esc; - clos->right->implicit = 1; - clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter); - - // Force type conversion from *struct to the func type. - clos = nod(OCONVNOP, clos, N); - clos->type = func->type; - - typecheck(&clos, Erv); - // typecheck will insert a PTRLIT node under CONVNOP, - // tag it with escape analysis result. - clos->left->esc = func->esc; - // non-escaping temp to use, if any. - // orderexpr did not compute the type; fill it in now. - if(func->alloc != N) { - func->alloc->type = clos->left->left->type; - func->alloc->orig->type = func->alloc->type; - clos->left->right = func->alloc; - func->alloc = N; - } - walkexpr(&clos, init); - - return clos; -} - -static Node *makepartialcall(Node*, Type*, Node*); - -void -typecheckpartialcall(Node *fn, Node *sym) -{ - switch(fn->op) { - case ODOTINTER: - case ODOTMETH: - break; - default: - fatal("invalid typecheckpartialcall"); - } - - // Create top-level function. - fn->nname = makepartialcall(fn, fn->type, sym); - fn->right = sym; - fn->op = OCALLPART; - fn->type = fn->nname->type; -} - -static Node* -makepartialcall(Node *fn, Type *t0, Node *meth) -{ - Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn; - Type *rcvrtype, *basetype, *t; - NodeList *body, *l, *callargs, *retargs; - char *p; - Sym *sym; - Pkg *spkg; - static Pkg* gopkg; - int i, ddd; - - rcvrtype = fn->left->type; - if(exportname(meth->sym->name)) - p = smprint("(%-hT).%s-fm", rcvrtype, meth->sym->name); - else - p = smprint("(%-hT).(%-S)-fm", rcvrtype, meth->sym); - basetype = rcvrtype; - if(isptr[rcvrtype->etype]) - basetype = basetype->type; - if(basetype->etype != TINTER && basetype->sym == S) - fatal("missing base type for %T", rcvrtype); - - spkg = nil; - if(basetype->sym != S) - spkg = basetype->sym->pkg; - if(spkg == nil) { - if(gopkg == nil) - gopkg = mkpkg(newstrlit("go")); - spkg = gopkg; - } - sym = pkglookup(p, spkg); - free(p); - if(sym->flags & SymUniq) - return sym->def; - sym->flags |= SymUniq; - - savecurfn = curfn; - curfn = N; - - xtype = nod(OTFUNC, N, N); - i = 0; - l = nil; - callargs = nil; - ddd = 0; - xfunc = nod(ODCLFUNC, N, N); - curfn = xfunc; - for(t = getinargx(t0)->type; t; t = t->down) { - snprint(namebuf, sizeof namebuf, "a%d", i++); - n = newname(lookup(namebuf)); - n->class = PPARAM; - xfunc->dcl = list(xfunc->dcl, n); - callargs = list(callargs, n); - fld = nod(ODCLFIELD, n, typenod(t->type)); - if(t->isddd) { - fld->isddd = 1; - ddd = 1; - } - l = list(l, fld); - } - xtype->list = l; - i = 0; - l = nil; - retargs = nil; - for(t = getoutargx(t0)->type; t; t = t->down) { - snprint(namebuf, sizeof namebuf, "r%d", i++); - n = newname(lookup(namebuf)); - n->class = PPARAMOUT; - xfunc->dcl = list(xfunc->dcl, n); - retargs = list(retargs, n); - l = list(l, nod(ODCLFIELD, n, typenod(t->type))); - } - xtype->rlist = l; - - xfunc->dupok = 1; - xfunc->nname = newname(sym); - xfunc->nname->sym->flags |= SymExported; // disable export - xfunc->nname->ntype = xtype; - xfunc->nname->defn = xfunc; - declare(xfunc->nname, PFUNC); - - // Declare and initialize variable holding receiver. - body = nil; - xfunc->needctxt = 1; - cv = nod(OCLOSUREVAR, N, N); - cv->xoffset = widthptr; - cv->type = rcvrtype; - if(cv->type->align > widthptr) - cv->xoffset = cv->type->align; - ptr = nod(ONAME, N, N); - ptr->sym = lookup("rcvr"); - ptr->class = PAUTO; - ptr->addable = 1; - ptr->ullman = 1; - ptr->used = 1; - ptr->curfn = xfunc; - xfunc->dcl = list(xfunc->dcl, ptr); - if(isptr[rcvrtype->etype] || isinter(rcvrtype)) { - ptr->ntype = typenod(rcvrtype); - body = list(body, nod(OAS, ptr, cv)); - } else { - ptr->ntype = typenod(ptrto(rcvrtype)); - body = list(body, nod(OAS, ptr, nod(OADDR, cv, N))); - } - - call = nod(OCALL, nod(OXDOT, ptr, meth), N); - call->list = callargs; - call->isddd = ddd; - if(t0->outtuple == 0) { - body = list(body, call); - } else { - n = nod(OAS2, N, N); - n->list = retargs; - n->rlist = list1(call); - body = list(body, n); - n = nod(ORETURN, N, N); - body = list(body, n); - } - - xfunc->nbody = body; - - typecheck(&xfunc, Etop); - sym->def = xfunc; - xtop = list(xtop, xfunc); - curfn = savecurfn; - - return xfunc; -} - -Node* -walkpartialcall(Node *n, NodeList **init) -{ - Node *clos, *typ; - - // Create closure in the form of a composite literal. - // For x.M with receiver (x) type T, the generated code looks like: - // - // clos = &struct{F uintptr; R T}{M.T·f, x} - // - // Like walkclosure above. - - if(isinter(n->left->type)) { - // Trigger panic for method on nil interface now. - // Otherwise it happens in the wrapper and is confusing. - n->left = cheapexpr(n->left, init); - checknil(n->left, init); - } - - typ = nod(OTSTRUCT, N, N); - typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR]))); - typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type))); - - clos = nod(OCOMPLIT, N, nod(OIND, typ, N)); - clos->esc = n->esc; - clos->right->implicit = 1; - clos->list = list1(nod(OCFUNC, n->nname->nname, N)); - clos->list = list(clos->list, n->left); - - // Force type conversion from *struct to the func type. - clos = nod(OCONVNOP, clos, N); - clos->type = n->type; - - typecheck(&clos, Erv); - // typecheck will insert a PTRLIT node under CONVNOP, - // tag it with escape analysis result. - clos->left->esc = n->esc; - // non-escaping temp to use, if any. - // orderexpr did not compute the type; fill it in now. - if(n->alloc != N) { - n->alloc->type = clos->left->left->type; - n->alloc->orig->type = n->alloc->type; - clos->left->right = n->alloc; - n->alloc = N; - } - walkexpr(&clos, init); - - return clos; -} diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c deleted file mode 100644 index 50accb93a3..0000000000 --- a/src/cmd/gc/const.c +++ /dev/null @@ -1,1678 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#define TUP(x,y) (((x)<<16)|(y)) -/*c2go int TUP(int, int); */ - -static Val tocplx(Val); -static Val toflt(Val); -static Val tostr(Val); -static Val copyval(Val); -static void cmplxmpy(Mpcplx*, Mpcplx*); -static void cmplxdiv(Mpcplx*, Mpcplx*); - -/* - * truncate float literal fv to 32-bit or 64-bit precision - * according to type; return truncated value. - */ -Mpflt* -truncfltlit(Mpflt *oldv, Type *t) -{ - double d; - Mpflt *fv; - Val v; - - if(t == T) - return oldv; - - memset(&v, 0, sizeof v); - v.ctype = CTFLT; - v.u.fval = oldv; - overflow(v, t); - - fv = mal(sizeof *fv); - *fv = *oldv; - - // convert large precision literal floating - // into limited precision (float64 or float32) - switch(t->etype) { - case TFLOAT64: - d = mpgetflt(fv); - mpmovecflt(fv, d); - break; - - case TFLOAT32: - d = mpgetflt32(fv); - mpmovecflt(fv, d); - - break; - } - return fv; -} - -/* - * convert n, if literal, to type t. - * implicit conversion. - */ -void -convlit(Node **np, Type *t) -{ - convlit1(np, t, 0); -} - -/* - * convert n, if literal, to type t. - * return a new node if necessary - * (if n is a named constant, can't edit n->type directly). - */ -void -convlit1(Node **np, Type *t, int explicit) -{ - int ct, et; - Node *n, *nn; - - n = *np; - if(n == N || t == T || n->type == T || isideal(t) || n->type == t) - return; - if(!explicit && !isideal(n->type)) - return; - - if(n->op == OLITERAL) { - nn = nod(OXXX, N, N); - *nn = *n; - n = nn; - *np = n; - } - - switch(n->op) { - default: - if(n->type == idealbool) { - if(t->etype == TBOOL) - n->type = t; - else - n->type = types[TBOOL]; - } - if(n->type->etype == TIDEAL) { - convlit(&n->left, t); - convlit(&n->right, t); - n->type = t; - } - return; - case OLITERAL: - // target is invalid type for a constant? leave alone. - if(!okforconst[t->etype] && n->type->etype != TNIL) { - defaultlit(&n, T); - *np = n; - return; - } - break; - case OLSH: - case ORSH: - convlit1(&n->left, t, explicit && isideal(n->left->type)); - t = n->left->type; - if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT) - n->val = toint(n->val); - if(t != T && !isint[t->etype]) { - yyerror("invalid operation: %N (shift of type %T)", n, t); - t = T; - } - n->type = t; - return; - case OCOMPLEX: - if(n->type->etype == TIDEAL) { - switch(t->etype) { - default: - // If trying to convert to non-complex type, - // leave as complex128 and let typechecker complain. - t = types[TCOMPLEX128]; - //fallthrough - case TCOMPLEX128: - n->type = t; - convlit(&n->left, types[TFLOAT64]); - convlit(&n->right, types[TFLOAT64]); - break; - case TCOMPLEX64: - n->type = t; - convlit(&n->left, types[TFLOAT32]); - convlit(&n->right, types[TFLOAT32]); - break; - } - } - return; - } - - // avoided repeated calculations, errors - if(eqtype(n->type, t)) - return; - - ct = consttype(n); - if(ct < 0) - goto bad; - - et = t->etype; - if(et == TINTER) { - if(ct == CTNIL && n->type == types[TNIL]) { - n->type = t; - return; - } - defaultlit(np, T); - return; - } - - switch(ct) { - default: - goto bad; - - case CTNIL: - switch(et) { - default: - n->type = T; - goto bad; - - case TSTRING: - // let normal conversion code handle it - return; - - case TARRAY: - if(!isslice(t)) - goto bad; - break; - - case TPTR32: - case TPTR64: - case TINTER: - case TMAP: - case TCHAN: - case TFUNC: - case TUNSAFEPTR: - break; - - case TUINTPTR: - // A nil literal may be converted to uintptr - // if it is an unsafe.Pointer - if(n->type->etype == TUNSAFEPTR) { - n->val.u.xval = mal(sizeof(*n->val.u.xval)); - mpmovecfix(n->val.u.xval, 0); - n->val.ctype = CTINT; - } else - goto bad; - } - break; - - case CTSTR: - case CTBOOL: - if(et != n->type->etype) - goto bad; - break; - - case CTINT: - case CTRUNE: - case CTFLT: - case CTCPLX: - ct = n->val.ctype; - if(isint[et]) { - switch(ct) { - default: - goto bad; - case CTCPLX: - case CTFLT: - case CTRUNE: - n->val = toint(n->val); - // flowthrough - case CTINT: - overflow(n->val, t); - break; - } - } else - if(isfloat[et]) { - switch(ct) { - default: - goto bad; - case CTCPLX: - case CTINT: - case CTRUNE: - n->val = toflt(n->val); - // flowthrough - case CTFLT: - n->val.u.fval = truncfltlit(n->val.u.fval, t); - break; - } - } else - if(iscomplex[et]) { - switch(ct) { - default: - goto bad; - case CTFLT: - case CTINT: - case CTRUNE: - n->val = tocplx(n->val); - break; - case CTCPLX: - overflow(n->val, t); - break; - } - } else - if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit) - n->val = tostr(n->val); - else - goto bad; - break; - } - n->type = t; - return; - -bad: - if(!n->diag) { - if(!t->broke) - yyerror("cannot convert %N to type %T", n, t); - n->diag = 1; - } - if(isideal(n->type)) { - defaultlit(&n, T); - *np = n; - } - return; -} - -static Val -copyval(Val v) -{ - Mpint *i; - Mpflt *f; - Mpcplx *c; - - switch(v.ctype) { - case CTINT: - case CTRUNE: - i = mal(sizeof(*i)); - mpmovefixfix(i, v.u.xval); - v.u.xval = i; - break; - case CTFLT: - f = mal(sizeof(*f)); - mpmovefltflt(f, v.u.fval); - v.u.fval = f; - break; - case CTCPLX: - c = mal(sizeof(*c)); - mpmovefltflt(&c->real, &v.u.cval->real); - mpmovefltflt(&c->imag, &v.u.cval->imag); - v.u.cval = c; - break; - } - return v; -} - -static Val -tocplx(Val v) -{ - Mpcplx *c; - - switch(v.ctype) { - case CTINT: - case CTRUNE: - c = mal(sizeof(*c)); - mpmovefixflt(&c->real, v.u.xval); - mpmovecflt(&c->imag, 0.0); - v.ctype = CTCPLX; - v.u.cval = c; - break; - case CTFLT: - c = mal(sizeof(*c)); - mpmovefltflt(&c->real, v.u.fval); - mpmovecflt(&c->imag, 0.0); - v.ctype = CTCPLX; - v.u.cval = c; - break; - } - return v; -} - -static Val -toflt(Val v) -{ - Mpflt *f; - - switch(v.ctype) { - case CTINT: - case CTRUNE: - f = mal(sizeof(*f)); - mpmovefixflt(f, v.u.xval); - v.ctype = CTFLT; - v.u.fval = f; - break; - case CTCPLX: - f = mal(sizeof(*f)); - mpmovefltflt(f, &v.u.cval->real); - if(mpcmpfltc(&v.u.cval->imag, 0) != 0) - yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag); - v.ctype = CTFLT; - v.u.fval = f; - break; - } - return v; -} - -Val -toint(Val v) -{ - Mpint *i; - - switch(v.ctype) { - case CTRUNE: - v.ctype = CTINT; - break; - case CTFLT: - i = mal(sizeof(*i)); - if(mpmovefltfix(i, v.u.fval) < 0) - yyerror("constant %#F truncated to integer", v.u.fval); - v.ctype = CTINT; - v.u.xval = i; - break; - case CTCPLX: - i = mal(sizeof(*i)); - if(mpmovefltfix(i, &v.u.cval->real) < 0) - yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag); - if(mpcmpfltc(&v.u.cval->imag, 0) != 0) - yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag); - v.ctype = CTINT; - v.u.xval = i; - break; - } - return v; -} - -int -doesoverflow(Val v, Type *t) -{ - switch(v.ctype) { - case CTINT: - case CTRUNE: - if(!isint[t->etype]) - fatal("overflow: %T integer constant", t); - if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 || - mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0) - return 1; - break; - case CTFLT: - if(!isfloat[t->etype]) - fatal("overflow: %T floating-point constant", t); - if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 || - mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0) - return 1; - break; - case CTCPLX: - if(!iscomplex[t->etype]) - fatal("overflow: %T complex constant", t); - if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 || - mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 || - mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 || - mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0) - return 1; - break; - } - return 0; -} - -void -overflow(Val v, Type *t) -{ - // v has already been converted - // to appropriate form for t. - if(t == T || t->etype == TIDEAL) - return; - - if(!doesoverflow(v, t)) - return; - - switch(v.ctype) { - case CTINT: - case CTRUNE: - yyerror("constant %B overflows %T", v.u.xval, t); - break; - case CTFLT: - yyerror("constant %#F overflows %T", v.u.fval, t); - break; - case CTCPLX: - yyerror("constant %#F overflows %T", v.u.fval, t); - break; - } -} - -static Val -tostr(Val v) -{ - Rune rune; - int l; - Strlit *s; - - switch(v.ctype) { - case CTINT: - case CTRUNE: - if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 || - mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0) - yyerror("overflow in int -> string"); - rune = mpgetfix(v.u.xval); - l = runelen(rune); - s = mal(sizeof(*s)+l); - s->len = l; - runetochar((char*)s->s, &rune); - memset(&v, 0, sizeof v); - v.ctype = CTSTR; - v.u.sval = s; - break; - - case CTFLT: - yyerror("no float -> string"); - - case CTNIL: - memset(&v, 0, sizeof v); - v.ctype = CTSTR; - v.u.sval = mal(sizeof *s); - break; - } - return v; -} - -int -consttype(Node *n) -{ - if(n == N || n->op != OLITERAL) - return -1; - return n->val.ctype; -} - -int -isconst(Node *n, int ct) -{ - int t; - - t = consttype(n); - // If the caller is asking for CTINT, allow CTRUNE too. - // Makes life easier for back ends. - return t == ct || (ct == CTINT && t == CTRUNE); -} - -static Node* -saveorig(Node *n) -{ - Node *n1; - - if(n == n->orig) { - // duplicate node for n->orig. - n1 = nod(OLITERAL, N, N); - n->orig = n1; - *n1 = *n; - } - return n->orig; -} - -/* - * if n is constant, rewrite as OLITERAL node. - */ -void -evconst(Node *n) -{ - Node *nl, *nr, *norig; - int32 len; - Strlit *str; - int wl, wr, lno, et; - Val v, rv; - Mpint b; - NodeList *l1, *l2; - - // pick off just the opcodes that can be - // constant evaluated. - switch(n->op) { - default: - return; - case OADD: - case OAND: - case OANDAND: - case OANDNOT: - case OARRAYBYTESTR: - case OCOM: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLSH: - case OLT: - case OMINUS: - case OMOD: - case OMUL: - case ONE: - case ONOT: - case OOR: - case OOROR: - case OPLUS: - case ORSH: - case OSUB: - case OXOR: - break; - case OCONV: - if(n->type == T) - return; - if(!okforconst[n->type->etype] && n->type->etype != TNIL) - return; - break; - - case OADDSTR: - // merge adjacent constants in the argument list. - for(l1=n->list; l1 != nil; l1= l1->next) { - if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) { - l2 = l1; - len = 0; - while(l2 != nil && isconst(l2->n, CTSTR)) { - nr = l2->n; - len += nr->val.u.sval->len; - l2 = l2->next; - } - // merge from l1 up to but not including l2 - str = mal(sizeof(*str) + len); - str->len = len; - len = 0; - l2 = l1; - while(l2 != nil && isconst(l2->n, CTSTR)) { - nr = l2->n; - memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len); - len += nr->val.u.sval->len; - l2 = l2->next; - } - nl = nod(OXXX, N, N); - *nl = *l1->n; - nl->orig = nl; - nl->val.ctype = CTSTR; - nl->val.u.sval = str; - l1->n = nl; - l1->next = l2; - } - } - // fix list end pointer. - for(l2=n->list; l2 != nil; l2=l2->next) - n->list->end = l2; - // collapse single-constant list to single constant. - if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) { - n->op = OLITERAL; - n->val = n->list->n->val; - } - return; - } - - nl = n->left; - if(nl == N || nl->type == T) - return; - if(consttype(nl) < 0) - return; - wl = nl->type->etype; - if(isint[wl] || isfloat[wl] || iscomplex[wl]) - wl = TIDEAL; - - nr = n->right; - if(nr == N) - goto unary; - if(nr->type == T) - return; - if(consttype(nr) < 0) - return; - wr = nr->type->etype; - if(isint[wr] || isfloat[wr] || iscomplex[wr]) - wr = TIDEAL; - - // check for compatible general types (numeric, string, etc) - if(wl != wr) - goto illegal; - - // check for compatible types. - switch(n->op) { - default: - // ideal const mixes with anything but otherwise must match. - if(nl->type->etype != TIDEAL) { - defaultlit(&nr, nl->type); - n->right = nr; - } - if(nr->type->etype != TIDEAL) { - defaultlit(&nl, nr->type); - n->left = nl; - } - if(nl->type->etype != nr->type->etype) - goto illegal; - break; - - case OLSH: - case ORSH: - // right must be unsigned. - // left can be ideal. - defaultlit(&nr, types[TUINT]); - n->right = nr; - if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype])) - goto illegal; - if(nl->val.ctype != CTRUNE) - nl->val = toint(nl->val); - nr->val = toint(nr->val); - break; - } - - // copy numeric value to avoid modifying - // n->left, in case someone still refers to it (e.g. iota). - v = nl->val; - if(wl == TIDEAL) - v = copyval(v); - - rv = nr->val; - - // convert to common ideal - if(v.ctype == CTCPLX || rv.ctype == CTCPLX) { - v = tocplx(v); - rv = tocplx(rv); - } - if(v.ctype == CTFLT || rv.ctype == CTFLT) { - v = toflt(v); - rv = toflt(rv); - } - - // Rune and int turns into rune. - if(v.ctype == CTRUNE && rv.ctype == CTINT) - rv.ctype = CTRUNE; - if(v.ctype == CTINT && rv.ctype == CTRUNE) { - if(n->op == OLSH || n->op == ORSH) - rv.ctype = CTINT; - else - v.ctype = CTRUNE; - } - - if(v.ctype != rv.ctype) { - // Use of undefined name as constant? - if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0) - return; - fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype); - } - - // run op - switch(TUP(n->op, v.ctype)) { - default: - goto illegal; - case TUP(OADD, CTINT): - case TUP(OADD, CTRUNE): - mpaddfixfix(v.u.xval, rv.u.xval, 0); - break; - case TUP(OSUB, CTINT): - case TUP(OSUB, CTRUNE): - mpsubfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OMUL, CTINT): - case TUP(OMUL, CTRUNE): - mpmulfixfix(v.u.xval, rv.u.xval); - break; - case TUP(ODIV, CTINT): - case TUP(ODIV, CTRUNE): - if(mpcmpfixc(rv.u.xval, 0) == 0) { - yyerror("division by zero"); - mpmovecfix(v.u.xval, 1); - break; - } - mpdivfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OMOD, CTINT): - case TUP(OMOD, CTRUNE): - if(mpcmpfixc(rv.u.xval, 0) == 0) { - yyerror("division by zero"); - mpmovecfix(v.u.xval, 1); - break; - } - mpmodfixfix(v.u.xval, rv.u.xval); - break; - - case TUP(OLSH, CTINT): - case TUP(OLSH, CTRUNE): - mplshfixfix(v.u.xval, rv.u.xval); - break; - case TUP(ORSH, CTINT): - case TUP(ORSH, CTRUNE): - mprshfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OOR, CTINT): - case TUP(OOR, CTRUNE): - mporfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OAND, CTINT): - case TUP(OAND, CTRUNE): - mpandfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OANDNOT, CTINT): - case TUP(OANDNOT, CTRUNE): - mpandnotfixfix(v.u.xval, rv.u.xval); - break; - case TUP(OXOR, CTINT): - case TUP(OXOR, CTRUNE): - mpxorfixfix(v.u.xval, rv.u.xval); - break; - - case TUP(OADD, CTFLT): - mpaddfltflt(v.u.fval, rv.u.fval); - break; - case TUP(OSUB, CTFLT): - mpsubfltflt(v.u.fval, rv.u.fval); - break; - case TUP(OMUL, CTFLT): - mpmulfltflt(v.u.fval, rv.u.fval); - break; - case TUP(ODIV, CTFLT): - if(mpcmpfltc(rv.u.fval, 0) == 0) { - yyerror("division by zero"); - mpmovecflt(v.u.fval, 1.0); - break; - } - mpdivfltflt(v.u.fval, rv.u.fval); - break; - case TUP(OMOD, CTFLT): - // The default case above would print 'ideal % ideal', - // which is not quite an ideal error. - if(!n->diag) { - yyerror("illegal constant expression: floating-point %% operation"); - n->diag = 1; - } - return; - - case TUP(OADD, CTCPLX): - mpaddfltflt(&v.u.cval->real, &rv.u.cval->real); - mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag); - break; - case TUP(OSUB, CTCPLX): - mpsubfltflt(&v.u.cval->real, &rv.u.cval->real); - mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag); - break; - case TUP(OMUL, CTCPLX): - cmplxmpy(v.u.cval, rv.u.cval); - break; - case TUP(ODIV, CTCPLX): - if(mpcmpfltc(&rv.u.cval->real, 0) == 0 && - mpcmpfltc(&rv.u.cval->imag, 0) == 0) { - yyerror("complex division by zero"); - mpmovecflt(&rv.u.cval->real, 1.0); - mpmovecflt(&rv.u.cval->imag, 0.0); - break; - } - cmplxdiv(v.u.cval, rv.u.cval); - break; - - case TUP(OEQ, CTNIL): - goto settrue; - case TUP(ONE, CTNIL): - goto setfalse; - - case TUP(OEQ, CTINT): - case TUP(OEQ, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0) - goto settrue; - goto setfalse; - case TUP(ONE, CTINT): - case TUP(ONE, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0) - goto settrue; - goto setfalse; - case TUP(OLT, CTINT): - case TUP(OLT, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0) - goto settrue; - goto setfalse; - case TUP(OLE, CTINT): - case TUP(OLE, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0) - goto settrue; - goto setfalse; - case TUP(OGE, CTINT): - case TUP(OGE, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0) - goto settrue; - goto setfalse; - case TUP(OGT, CTINT): - case TUP(OGT, CTRUNE): - if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0) - goto settrue; - goto setfalse; - - case TUP(OEQ, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0) - goto settrue; - goto setfalse; - case TUP(ONE, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0) - goto settrue; - goto setfalse; - case TUP(OLT, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0) - goto settrue; - goto setfalse; - case TUP(OLE, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0) - goto settrue; - goto setfalse; - case TUP(OGE, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0) - goto settrue; - goto setfalse; - case TUP(OGT, CTFLT): - if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0) - goto settrue; - goto setfalse; - - case TUP(OEQ, CTCPLX): - if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 && - mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0) - goto settrue; - goto setfalse; - case TUP(ONE, CTCPLX): - if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 || - mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0) - goto settrue; - goto setfalse; - - case TUP(OEQ, CTSTR): - if(cmpslit(nl, nr) == 0) - goto settrue; - goto setfalse; - case TUP(ONE, CTSTR): - if(cmpslit(nl, nr) != 0) - goto settrue; - goto setfalse; - case TUP(OLT, CTSTR): - if(cmpslit(nl, nr) < 0) - goto settrue; - goto setfalse; - case TUP(OLE, CTSTR): - if(cmpslit(nl, nr) <= 0) - goto settrue; - goto setfalse; - case TUP(OGE, CTSTR): - if(cmpslit(nl, nr) >= 0l) - goto settrue; - goto setfalse; - case TUP(OGT, CTSTR): - if(cmpslit(nl, nr) > 0) - goto settrue; - goto setfalse; - - case TUP(OOROR, CTBOOL): - if(v.u.bval || rv.u.bval) - goto settrue; - goto setfalse; - case TUP(OANDAND, CTBOOL): - if(v.u.bval && rv.u.bval) - goto settrue; - goto setfalse; - case TUP(OEQ, CTBOOL): - if(v.u.bval == rv.u.bval) - goto settrue; - goto setfalse; - case TUP(ONE, CTBOOL): - if(v.u.bval != rv.u.bval) - goto settrue; - goto setfalse; - } - goto ret; - -unary: - // copy numeric value to avoid modifying - // nl, in case someone still refers to it (e.g. iota). - v = nl->val; - if(wl == TIDEAL) - v = copyval(v); - - switch(TUP(n->op, v.ctype)) { - default: - if(!n->diag) { - yyerror("illegal constant expression %O %T", n->op, nl->type); - n->diag = 1; - } - return; - - case TUP(OCONV, CTNIL): - case TUP(OARRAYBYTESTR, CTNIL): - if(n->type->etype == TSTRING) { - v = tostr(v); - nl->type = n->type; - break; - } - // fall through - case TUP(OCONV, CTINT): - case TUP(OCONV, CTRUNE): - case TUP(OCONV, CTFLT): - case TUP(OCONV, CTSTR): - convlit1(&nl, n->type, 1); - v = nl->val; - break; - - case TUP(OPLUS, CTINT): - case TUP(OPLUS, CTRUNE): - break; - case TUP(OMINUS, CTINT): - case TUP(OMINUS, CTRUNE): - mpnegfix(v.u.xval); - break; - case TUP(OCOM, CTINT): - case TUP(OCOM, CTRUNE): - et = Txxx; - if(nl->type != T) - et = nl->type->etype; - - // calculate the mask in b - // result will be (a ^ mask) - switch(et) { - default: - // signed guys change sign - mpmovecfix(&b, -1); - break; - - case TUINT8: - case TUINT16: - case TUINT32: - case TUINT64: - case TUINT: - case TUINTPTR: - // unsigned guys invert their bits - mpmovefixfix(&b, maxintval[et]); - break; - } - mpxorfixfix(v.u.xval, &b); - break; - - case TUP(OPLUS, CTFLT): - break; - case TUP(OMINUS, CTFLT): - mpnegflt(v.u.fval); - break; - - case TUP(OPLUS, CTCPLX): - break; - case TUP(OMINUS, CTCPLX): - mpnegflt(&v.u.cval->real); - mpnegflt(&v.u.cval->imag); - break; - - case TUP(ONOT, CTBOOL): - if(!v.u.bval) - goto settrue; - goto setfalse; - } - -ret: - norig = saveorig(n); - *n = *nl; - // restore value of n->orig. - n->orig = norig; - n->val = v; - - // check range. - lno = setlineno(n); - overflow(v, n->type); - lineno = lno; - - // truncate precision for non-ideal float. - if(v.ctype == CTFLT && n->type->etype != TIDEAL) - n->val.u.fval = truncfltlit(v.u.fval, n->type); - return; - -settrue: - norig = saveorig(n); - *n = *nodbool(1); - n->orig = norig; - return; - -setfalse: - norig = saveorig(n); - *n = *nodbool(0); - n->orig = norig; - return; - -illegal: - if(!n->diag) { - yyerror("illegal constant expression: %T %O %T", - nl->type, n->op, nr->type); - n->diag = 1; - } - return; -} - -Node* -nodlit(Val v) -{ - Node *n; - - n = nod(OLITERAL, N, N); - n->val = v; - switch(v.ctype) { - default: - fatal("nodlit ctype %d", v.ctype); - case CTSTR: - n->type = idealstring; - break; - case CTBOOL: - n->type = idealbool; - break; - case CTINT: - case CTRUNE: - case CTFLT: - case CTCPLX: - n->type = types[TIDEAL]; - break; - case CTNIL: - n->type = types[TNIL]; - break; - } - return n; -} - -Node* -nodcplxlit(Val r, Val i) -{ - Node *n; - Mpcplx *c; - - r = toflt(r); - i = toflt(i); - - c = mal(sizeof(*c)); - n = nod(OLITERAL, N, N); - n->type = types[TIDEAL]; - n->val.u.cval = c; - n->val.ctype = CTCPLX; - - if(r.ctype != CTFLT || i.ctype != CTFLT) - fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype); - - mpmovefltflt(&c->real, r.u.fval); - mpmovefltflt(&c->imag, i.u.fval); - return n; -} - -// idealkind returns a constant kind like consttype -// but for an arbitrary "ideal" (untyped constant) expression. -static int -idealkind(Node *n) -{ - int k1, k2; - - if(n == N || !isideal(n->type)) - return CTxxx; - - switch(n->op) { - default: - return CTxxx; - case OLITERAL: - return n->val.ctype; - case OADD: - case OAND: - case OANDNOT: - case OCOM: - case ODIV: - case OMINUS: - case OMOD: - case OMUL: - case OSUB: - case OXOR: - case OOR: - case OPLUS: - // numeric kinds. - k1 = idealkind(n->left); - k2 = idealkind(n->right); - if(k1 > k2) - return k1; - else - return k2; - case OREAL: - case OIMAG: - return CTFLT; - case OCOMPLEX: - return CTCPLX; - case OADDSTR: - return CTSTR; - case OANDAND: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLT: - case ONE: - case ONOT: - case OOROR: - case OCMPSTR: - case OCMPIFACE: - return CTBOOL; - case OLSH: - case ORSH: - // shifts (beware!). - return idealkind(n->left); - } -} - -void -defaultlit(Node **np, Type *t) -{ - int lno; - int ctype; - Node *n, *nn; - Type *t1; - - n = *np; - if(n == N || !isideal(n->type)) - return; - - if(n->op == OLITERAL) { - nn = nod(OXXX, N, N); - *nn = *n; - n = nn; - *np = n; - } - - lno = setlineno(n); - ctype = idealkind(n); - switch(ctype) { - default: - if(t != T) { - convlit(np, t); - return; - } - if(n->val.ctype == CTNIL) { - lineno = lno; - if(!n->diag) { - yyerror("use of untyped nil"); - n->diag = 1; - } - n->type = T; - break; - } - if(n->val.ctype == CTSTR) { - t1 = types[TSTRING]; - convlit(np, t1); - break; - } - yyerror("defaultlit: unknown literal: %N", n); - break; - case CTxxx: - fatal("defaultlit: idealkind is CTxxx: %+N", n); - break; - case CTBOOL: - t1 = types[TBOOL]; - if(t != T && t->etype == TBOOL) - t1 = t; - convlit(np, t1); - break; - case CTINT: - t1 = types[TINT]; - goto num; - case CTRUNE: - t1 = runetype; - goto num; - case CTFLT: - t1 = types[TFLOAT64]; - goto num; - case CTCPLX: - t1 = types[TCOMPLEX128]; - goto num; - } - lineno = lno; - return; - -num: - if(t != T) { - if(isint[t->etype]) { - t1 = t; - n->val = toint(n->val); - } - else - if(isfloat[t->etype]) { - t1 = t; - n->val = toflt(n->val); - } - else - if(iscomplex[t->etype]) { - t1 = t; - n->val = tocplx(n->val); - } - } - overflow(n->val, t1); - convlit(np, t1); - lineno = lno; - return; -} - -/* - * defaultlit on both nodes simultaneously; - * if they're both ideal going in they better - * get the same type going out. - * force means must assign concrete (non-ideal) type. - */ -void -defaultlit2(Node **lp, Node **rp, int force) -{ - Node *l, *r; - int lkind, rkind; - - l = *lp; - r = *rp; - if(l->type == T || r->type == T) - return; - if(!isideal(l->type)) { - convlit(rp, l->type); - return; - } - if(!isideal(r->type)) { - convlit(lp, r->type); - return; - } - if(!force) - return; - if(l->type->etype == TBOOL) { - convlit(lp, types[TBOOL]); - convlit(rp, types[TBOOL]); - } - lkind = idealkind(l); - rkind = idealkind(r); - if(lkind == CTCPLX || rkind == CTCPLX) { - convlit(lp, types[TCOMPLEX128]); - convlit(rp, types[TCOMPLEX128]); - return; - } - if(lkind == CTFLT || rkind == CTFLT) { - convlit(lp, types[TFLOAT64]); - convlit(rp, types[TFLOAT64]); - return; - } - - if(lkind == CTRUNE || rkind == CTRUNE) { - convlit(lp, runetype); - convlit(rp, runetype); - return; - } - - convlit(lp, types[TINT]); - convlit(rp, types[TINT]); -} - -int -cmpslit(Node *l, Node *r) -{ - int32 l1, l2, i, m; - uchar *s1, *s2; - - l1 = l->val.u.sval->len; - l2 = r->val.u.sval->len; - s1 = (uchar*)l->val.u.sval->s; - s2 = (uchar*)r->val.u.sval->s; - - m = l1; - if(l2 < m) - m = l2; - - for(i=0; i s2[i]) - return +1; - return -1; - } - if(l1 == l2) - return 0; - if(l1 > l2) - return +1; - return -1; -} - -int -smallintconst(Node *n) -{ - if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T) - switch(simtype[n->type->etype]) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TBOOL: - case TPTR32: - return 1; - case TIDEAL: - case TINT64: - case TUINT64: - case TPTR64: - if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0 - || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0) - break; - return 1; - } - return 0; -} - -long -nonnegconst(Node *n) -{ - if(n->op == OLITERAL && n->type != T) - switch(simtype[n->type->etype]) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TIDEAL: - // check negative and 2^31 - if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0 - || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0) - break; - return mpgetfix(n->val.u.xval); - } - return -1; -} - -/* - * convert x to type et and back to int64 - * for sign extension and truncation. - */ -static int64 -iconv(int64 x, int et) -{ - switch(et) { - case TINT8: - x = (int8)x; - break; - case TUINT8: - x = (uint8)x; - break; - case TINT16: - x = (int16)x; - break; - case TUINT16: - x = (uint64)x; - break; - case TINT32: - x = (int32)x; - break; - case TUINT32: - x = (uint32)x; - break; - case TINT64: - case TUINT64: - break; - } - return x; -} - -/* - * convert constant val to type t; leave in con. - * for back end. - */ -void -convconst(Node *con, Type *t, Val *val) -{ - int64 i; - int tt; - - tt = simsimtype(t); - - // copy the constant for conversion - nodconst(con, types[TINT8], 0); - con->type = t; - con->val = *val; - - if(isint[tt]) { - con->val.ctype = CTINT; - con->val.u.xval = mal(sizeof *con->val.u.xval); - switch(val->ctype) { - default: - fatal("convconst ctype=%d %lT", val->ctype, t); - case CTINT: - case CTRUNE: - i = mpgetfix(val->u.xval); - break; - case CTBOOL: - i = val->u.bval; - break; - case CTNIL: - i = 0; - break; - } - i = iconv(i, tt); - mpmovecfix(con->val.u.xval, i); - return; - } - - if(isfloat[tt]) { - con->val = toflt(con->val); - if(con->val.ctype != CTFLT) - fatal("convconst ctype=%d %T", con->val.ctype, t); - if(tt == TFLOAT32) - con->val.u.fval = truncfltlit(con->val.u.fval, t); - return; - } - - if(iscomplex[tt]) { - con->val = tocplx(con->val); - if(tt == TCOMPLEX64) { - con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]); - con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]); - } - return; - } - - fatal("convconst %lT constant", t); - -} - -// complex multiply v *= rv -// (a, b) * (c, d) = (a*c - b*d, b*c + a*d) -static void -cmplxmpy(Mpcplx *v, Mpcplx *rv) -{ - Mpflt ac, bd, bc, ad; - - mpmovefltflt(&ac, &v->real); - mpmulfltflt(&ac, &rv->real); // ac - - mpmovefltflt(&bd, &v->imag); - mpmulfltflt(&bd, &rv->imag); // bd - - mpmovefltflt(&bc, &v->imag); - mpmulfltflt(&bc, &rv->real); // bc - - mpmovefltflt(&ad, &v->real); - mpmulfltflt(&ad, &rv->imag); // ad - - mpmovefltflt(&v->real, &ac); - mpsubfltflt(&v->real, &bd); // ac-bd - - mpmovefltflt(&v->imag, &bc); - mpaddfltflt(&v->imag, &ad); // bc+ad -} - -// complex divide v /= rv -// (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d) -static void -cmplxdiv(Mpcplx *v, Mpcplx *rv) -{ - Mpflt ac, bd, bc, ad, cc_plus_dd; - - mpmovefltflt(&cc_plus_dd, &rv->real); - mpmulfltflt(&cc_plus_dd, &rv->real); // cc - - mpmovefltflt(&ac, &rv->imag); - mpmulfltflt(&ac, &rv->imag); // dd - - mpaddfltflt(&cc_plus_dd, &ac); // cc+dd - - mpmovefltflt(&ac, &v->real); - mpmulfltflt(&ac, &rv->real); // ac - - mpmovefltflt(&bd, &v->imag); - mpmulfltflt(&bd, &rv->imag); // bd - - mpmovefltflt(&bc, &v->imag); - mpmulfltflt(&bc, &rv->real); // bc - - mpmovefltflt(&ad, &v->real); - mpmulfltflt(&ad, &rv->imag); // ad - - mpmovefltflt(&v->real, &ac); - mpaddfltflt(&v->real, &bd); // ac+bd - mpdivfltflt(&v->real, &cc_plus_dd); // (ac+bd)/(cc+dd) - - mpmovefltflt(&v->imag, &bc); - mpsubfltflt(&v->imag, &ad); // bc-ad - mpdivfltflt(&v->imag, &cc_plus_dd); // (bc+ad)/(cc+dd) -} - -static int hascallchan(Node*); - -// Is n a Go language constant (as opposed to a compile-time constant)? -// Expressions derived from nil, like string([]byte(nil)), while they -// may be known at compile time, are not Go language constants. -// Only called for expressions known to evaluated to compile-time -// constants. -int -isgoconst(Node *n) -{ - Node *l; - Type *t; - - if(n->orig != N) - n = n->orig; - - switch(n->op) { - case OADD: - case OADDSTR: - case OAND: - case OANDAND: - case OANDNOT: - case OCOM: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLSH: - case OLT: - case OMINUS: - case OMOD: - case OMUL: - case ONE: - case ONOT: - case OOR: - case OOROR: - case OPLUS: - case ORSH: - case OSUB: - case OXOR: - case OIOTA: - case OCOMPLEX: - case OREAL: - case OIMAG: - if(isgoconst(n->left) && (n->right == N || isgoconst(n->right))) - return 1; - break; - - case OCONV: - if(okforconst[n->type->etype] && isgoconst(n->left)) - return 1; - break; - - case OLEN: - case OCAP: - l = n->left; - if(isgoconst(l)) - return 1; - // Special case: len/cap is constant when applied to array or - // pointer to array when the expression does not contain - // function calls or channel receive operations. - t = l->type; - if(t != T && isptr[t->etype]) - t = t->type; - if(isfixedarray(t) && !hascallchan(l)) - return 1; - break; - - case OLITERAL: - if(n->val.ctype != CTNIL) - return 1; - break; - - case ONAME: - l = n->sym->def; - if(l && l->op == OLITERAL && n->val.ctype != CTNIL) - return 1; - break; - - case ONONAME: - if(n->sym->def != N && n->sym->def->op == OIOTA) - return 1; - break; - - case OCALL: - // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof. - l = n->left; - while(l->op == OPAREN) - l = l->left; - if(l->op != ONAME || l->sym->pkg != unsafepkg) - break; - if(strcmp(l->sym->name, "Alignof") == 0 || - strcmp(l->sym->name, "Offsetof") == 0 || - strcmp(l->sym->name, "Sizeof") == 0) - return 1; - break; - } - - //dump("nonconst", n); - return 0; -} - -static int -hascallchan(Node *n) -{ - NodeList *l; - - if(n == N) - return 0; - switch(n->op) { - case OAPPEND: - case OCALL: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - case OCAP: - case OCLOSE: - case OCOMPLEX: - case OCOPY: - case ODELETE: - case OIMAG: - case OLEN: - case OMAKE: - case ONEW: - case OPANIC: - case OPRINT: - case OPRINTN: - case OREAL: - case ORECOVER: - case ORECV: - return 1; - } - - if(hascallchan(n->left) || - hascallchan(n->right)) - return 1; - - for(l=n->list; l; l=l->next) - if(hascallchan(l->n)) - return 1; - for(l=n->rlist; l; l=l->next) - if(hascallchan(l->n)) - return 1; - - return 0; -} diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c deleted file mode 100644 index 26c21df82a..0000000000 --- a/src/cmd/gc/cplx.c +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -static void subnode(Node *nr, Node *ni, Node *nc); -static void minus(Node *nl, Node *res); - void complexminus(Node*, Node*); - void complexadd(int op, Node*, Node*, Node*); - void complexmul(Node*, Node*, Node*); - -#define CASE(a,b) (((a)<<16)|((b)<<0)) - -/*c2go -static int -CASE(int a, int b) -{ - return a<<16 | b; -} -*/ - -static int -overlap(Node *f, Node *t) -{ - // check whether f and t could be overlapping stack references. - // not exact, because it's hard to check for the stack register - // in portable code. close enough: worst case we will allocate - // an extra temporary and the registerizer will clean it up. - return f->op == OINDREG && - t->op == OINDREG && - f->xoffset+f->type->width >= t->xoffset && - t->xoffset+t->type->width >= f->xoffset; -} - -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -void -complexmove(Node *f, Node *t) -{ - int ft, tt; - Node n1, n2, n3, n4, tmp; - - if(debug['g']) { - dump("\ncomplexmove-f", f); - dump("complexmove-t", t); - } - - if(!t->addable) - fatal("complexmove: to not addable"); - - ft = simsimtype(f->type); - tt = simsimtype(t->type); - switch(CASE(ft,tt)) { - - default: - fatal("complexmove: unknown conversion: %T -> %T\n", - f->type, t->type); - - case CASE(TCOMPLEX64,TCOMPLEX64): - case CASE(TCOMPLEX64,TCOMPLEX128): - case CASE(TCOMPLEX128,TCOMPLEX64): - case CASE(TCOMPLEX128,TCOMPLEX128): - // complex to complex move/convert. - // make f addable. - // also use temporary if possible stack overlap. - if(!f->addable || overlap(f, t)) { - tempname(&tmp, f->type); - complexmove(f, &tmp); - f = &tmp; - } - - subnode(&n1, &n2, f); - subnode(&n3, &n4, t); - - thearch.cgen(&n1, &n3); - thearch.cgen(&n2, &n4); - break; - } -} - -int -complexop(Node *n, Node *res) -{ - if(n != N && n->type != T) - if(iscomplex[n->type->etype]) { - goto maybe; - } - if(res != N && res->type != T) - if(iscomplex[res->type->etype]) { - goto maybe; - } - - if(n->op == OREAL || n->op == OIMAG) - goto yes; - - goto no; - -maybe: - switch(n->op) { - case OCONV: // implemented ops - case OADD: - case OSUB: - case OMUL: - case OMINUS: - case OCOMPLEX: - case OREAL: - case OIMAG: - goto yes; - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: - goto yes; - } - -no: -//dump("\ncomplex-no", n); - return 0; -yes: -//dump("\ncomplex-yes", n); - return 1; -} - -void -complexgen(Node *n, Node *res) -{ - Node *nl, *nr; - Node tnl, tnr; - Node n1, n2, tmp; - int tl, tr; - - if(debug['g']) { - dump("\ncomplexgen-n", n); - dump("complexgen-res", res); - } - - while(n->op == OCONVNOP) - n = n->left; - - // pick off float/complex opcodes - switch(n->op) { - case OCOMPLEX: - if(res->addable) { - subnode(&n1, &n2, res); - tempname(&tmp, n1.type); - thearch.cgen(n->left, &tmp); - thearch.cgen(n->right, &n2); - thearch.cgen(&tmp, &n1); - return; - } - break; - - case OREAL: - case OIMAG: - nl = n->left; - if(!nl->addable) { - tempname(&tmp, nl->type); - complexgen(nl, &tmp); - nl = &tmp; - } - subnode(&n1, &n2, nl); - if(n->op == OREAL) { - thearch.cgen(&n1, res); - return; - } - thearch.cgen(&n2, res); - return; - } - - // perform conversion from n to res - tl = simsimtype(res->type); - tl = cplxsubtype(tl); - tr = simsimtype(n->type); - tr = cplxsubtype(tr); - if(tl != tr) { - if(!n->addable) { - tempname(&n1, n->type); - complexmove(n, &n1); - n = &n1; - } - complexmove(n, res); - return; - } - - if(!res->addable) { - thearch.igen(res, &n1, N); - thearch.cgen(n, &n1); - thearch.regfree(&n1); - return; - } - if(n->addable) { - complexmove(n, res); - return; - } - - switch(n->op) { - default: - dump("complexgen: unknown op", n); - fatal("complexgen: unknown op %O", n->op); - - case ODOT: - case ODOTPTR: - case OINDEX: - case OIND: - case ONAME: // PHEAP or PPARAMREF var - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - thearch.igen(n, &n1, res); - complexmove(&n1, res); - thearch.regfree(&n1); - return; - - case OCONV: - case OADD: - case OSUB: - case OMUL: - case OMINUS: - case OCOMPLEX: - case OREAL: - case OIMAG: - break; - } - - nl = n->left; - if(nl == N) - return; - nr = n->right; - - // make both sides addable in ullman order - if(nr != N) { - if(nl->ullman > nr->ullman && !nl->addable) { - tempname(&tnl, nl->type); - thearch.cgen(nl, &tnl); - nl = &tnl; - } - if(!nr->addable) { - tempname(&tnr, nr->type); - thearch.cgen(nr, &tnr); - nr = &tnr; - } - } - if(!nl->addable) { - tempname(&tnl, nl->type); - thearch.cgen(nl, &tnl); - nl = &tnl; - } - - switch(n->op) { - default: - fatal("complexgen: unknown op %O", n->op); - break; - - case OCONV: - complexmove(nl, res); - break; - - case OMINUS: - complexminus(nl, res); - break; - - case OADD: - case OSUB: - complexadd(n->op, nl, nr, res); - break; - - case OMUL: - complexmul(nl, nr, res); - break; - } -} - -void -complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to) -{ - Node tnl, tnr; - Node n1, n2, n3, n4; - Node na, nb, nc; - - // make both sides addable in ullman order - if(nr != N) { - if(nl->ullman > nr->ullman && !nl->addable) { - tempname(&tnl, nl->type); - thearch.cgen(nl, &tnl); - nl = &tnl; - } - if(!nr->addable) { - tempname(&tnr, nr->type); - thearch.cgen(nr, &tnr); - nr = &tnr; - } - } - if(!nl->addable) { - tempname(&tnl, nl->type); - thearch.cgen(nl, &tnl); - nl = &tnl; - } - - // build tree - // real(l) == real(r) && imag(l) == imag(r) - - subnode(&n1, &n2, nl); - subnode(&n3, &n4, nr); - - memset(&na, 0, sizeof(na)); - na.op = OANDAND; - na.left = &nb; - na.right = &nc; - na.type = types[TBOOL]; - - memset(&nb, 0, sizeof(nb)); - nb.op = OEQ; - nb.left = &n1; - nb.right = &n3; - nb.type = types[TBOOL]; - - memset(&nc, 0, sizeof(nc)); - nc.op = OEQ; - nc.left = &n2; - nc.right = &n4; - nc.type = types[TBOOL]; - - if(op == ONE) - true = !true; - - thearch.bgen(&na, true, likely, to); -} - -void -nodfconst(Node *n, Type *t, Mpflt* fval) -{ - memset(n, 0, sizeof(*n)); - n->op = OLITERAL; - n->addable = 1; - ullmancalc(n); - n->val.u.fval = fval; - n->val.ctype = CTFLT; - n->type = t; - - if(!isfloat[t->etype]) - fatal("nodfconst: bad type %T", t); -} - -// break addable nc-complex into nr-real and ni-imaginary -static void -subnode(Node *nr, Node *ni, Node *nc) -{ - int tc; - Type *t; - - if(!nc->addable) - fatal("subnode not addable"); - - tc = simsimtype(nc->type); - tc = cplxsubtype(tc); - t = types[tc]; - - if(nc->op == OLITERAL) { - nodfconst(nr, t, &nc->val.u.cval->real); - nodfconst(ni, t, &nc->val.u.cval->imag); - return; - } - - *nr = *nc; - nr->type = t; - - *ni = *nc; - ni->type = t; - ni->xoffset += t->width; -} - -// generate code res = -nl -static void -minus(Node *nl, Node *res) -{ - Node ra; - - memset(&ra, 0, sizeof(ra)); - ra.op = OMINUS; - ra.left = nl; - ra.type = nl->type; - thearch.cgen(&ra, res); -} - -// build and execute tree -// real(res) = -real(nl) -// imag(res) = -imag(nl) -void -complexminus(Node *nl, Node *res) -{ - Node n1, n2, n5, n6; - - subnode(&n1, &n2, nl); - subnode(&n5, &n6, res); - - minus(&n1, &n5); - minus(&n2, &n6); -} - - -// build and execute tree -// real(res) = real(nl) op real(nr) -// imag(res) = imag(nl) op imag(nr) -void -complexadd(int op, Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3, n4, n5, n6; - Node ra; - - subnode(&n1, &n2, nl); - subnode(&n3, &n4, nr); - subnode(&n5, &n6, res); - - memset(&ra, 0, sizeof(ra)); - ra.op = op; - ra.left = &n1; - ra.right = &n3; - ra.type = n1.type; - thearch.cgen(&ra, &n5); - - memset(&ra, 0, sizeof(ra)); - ra.op = op; - ra.left = &n2; - ra.right = &n4; - ra.type = n2.type; - thearch.cgen(&ra, &n6); -} - -// build and execute tree -// tmp = real(nl)*real(nr) - imag(nl)*imag(nr) -// imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr) -// real(res) = tmp -void -complexmul(Node *nl, Node *nr, Node *res) -{ - Node n1, n2, n3, n4, n5, n6; - Node rm1, rm2, ra, tmp; - - subnode(&n1, &n2, nl); - subnode(&n3, &n4, nr); - subnode(&n5, &n6, res); - tempname(&tmp, n5.type); - - // real part -> tmp - memset(&rm1, 0, sizeof(rm1)); - rm1.op = OMUL; - rm1.left = &n1; - rm1.right = &n3; - rm1.type = n1.type; - - memset(&rm2, 0, sizeof(rm2)); - rm2.op = OMUL; - rm2.left = &n2; - rm2.right = &n4; - rm2.type = n2.type; - - memset(&ra, 0, sizeof(ra)); - ra.op = OSUB; - ra.left = &rm1; - ra.right = &rm2; - ra.type = rm1.type; - thearch.cgen(&ra, &tmp); - - // imag part - memset(&rm1, 0, sizeof(rm1)); - rm1.op = OMUL; - rm1.left = &n1; - rm1.right = &n4; - rm1.type = n1.type; - - memset(&rm2, 0, sizeof(rm2)); - rm2.op = OMUL; - rm2.left = &n2; - rm2.right = &n3; - rm2.type = n2.type; - - memset(&ra, 0, sizeof(ra)); - ra.op = OADD; - ra.left = &rm1; - ra.right = &rm2; - ra.type = rm1.type; - thearch.cgen(&ra, &n6); - - // tmp ->real part - thearch.cgen(&tmp, &n5); -} diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c deleted file mode 100644 index 9a6c0023f5..0000000000 --- a/src/cmd/gc/dcl.c +++ /dev/null @@ -1,1479 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "y.tab.h" - -static void funcargs(Node*); -static void funcargs2(Type*); - -static int -dflag(void) -{ - if(!debug['d']) - return 0; - if(debug['y']) - return 1; - if(incannedimport) - return 0; - return 1; -} - -/* - * declaration stack & operations - */ - -static void -dcopy(Sym *a, Sym *b) -{ - a->pkg = b->pkg; - a->name = b->name; - a->def = b->def; - a->block = b->block; - a->lastlineno = b->lastlineno; -} - -static Sym* -push(void) -{ - Sym *d; - - d = mal(sizeof(*d)); - d->lastlineno = lineno; - d->link = dclstack; - dclstack = d; - return d; -} - -static Sym* -pushdcl(Sym *s) -{ - Sym *d; - - d = push(); - dcopy(d, s); - if(dflag()) - print("\t%L push %S %p\n", lineno, s, s->def); - return d; -} - -void -popdcl(void) -{ - Sym *d, *s; - int lno; - -// if(dflag()) -// print("revert\n"); - - for(d=dclstack; d!=S; d=d->link) { - if(d->name == nil) - break; - s = pkglookup(d->name, d->pkg); - lno = s->lastlineno; - dcopy(s, d); - d->lastlineno = lno; - if(dflag()) - print("\t%L pop %S %p\n", lineno, s, s->def); - } - if(d == S) - fatal("popdcl: no mark"); - dclstack = d->link; - block = d->block; -} - -void -poptodcl(void) -{ - // pop the old marker and push a new one - // (cannot reuse the existing one) - // because we use the markers to identify blocks - // for the goto restriction checks. - popdcl(); - markdcl(); -} - -void -markdcl(void) -{ - Sym *d; - - d = push(); - d->name = nil; // used as a mark in fifo - d->block = block; - - blockgen++; - block = blockgen; - -// if(dflag()) -// print("markdcl\n"); -} - -void -dumpdcl(char *st) -{ - Sym *s, *d; - int i; - - USED(st); - - i = 0; - for(d=dclstack; d!=S; d=d->link) { - i++; - print(" %.2d %p", i, d); - if(d->name == nil) { - print("\n"); - continue; - } - print(" '%s'", d->name); - s = pkglookup(d->name, d->pkg); - print(" %S\n", s); - } -} - -void -testdclstack(void) -{ - Sym *d; - - for(d=dclstack; d!=S; d=d->link) { - if(d->name == nil) { - if(nerrors != 0) - errorexit(); - yyerror("mark left on the stack"); - continue; - } - } -} - -void -redeclare(Sym *s, char *where) -{ - Strlit *pkgstr; - int line1, line2; - - if(s->lastlineno == 0) { - pkgstr = s->origpkg ? s->origpkg->path : s->pkg->path; - yyerror("%S redeclared %s\n" - "\tprevious declaration during import \"%Z\"", - s, where, pkgstr); - } else { - line1 = parserline(); - line2 = s->lastlineno; - - // When an import and a declaration collide in separate files, - // present the import as the "redeclared", because the declaration - // is visible where the import is, but not vice versa. - // See issue 4510. - if(s->def == N) { - line2 = line1; - line1 = s->lastlineno; - } - - yyerrorl(line1, "%S redeclared %s\n" - "\tprevious declaration at %L", - s, where, line2); - } -} - -static int vargen; - -/* - * declare individual names - var, typ, const - */ -void -declare(Node *n, int ctxt) -{ - Sym *s; - int gen; - static int typegen; - - if(ctxt == PDISCARD) - return; - - if(isblank(n)) - return; - - n->lineno = parserline(); - s = n->sym; - - // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later. - if(importpkg == nil && !typecheckok && s->pkg != localpkg) - yyerror("cannot declare name %S", s); - - if(ctxt == PEXTERN && strcmp(s->name, "init") == 0) - yyerror("cannot declare init - must be func", s); - - gen = 0; - if(ctxt == PEXTERN) { - externdcl = list(externdcl, n); - if(dflag()) - print("\t%L global decl %S %p\n", lineno, s, n); - } else { - if(curfn == nil && ctxt == PAUTO) - fatal("automatic outside function"); - if(curfn != nil) - curfn->dcl = list(curfn->dcl, n); - if(n->op == OTYPE) - gen = ++typegen; - else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil) - gen = ++vargen; - pushdcl(s); - n->curfn = curfn; - } - if(ctxt == PAUTO) - n->xoffset = 0; - - if(s->block == block) { - // functype will print errors about duplicate function arguments. - // Don't repeat the error here. - if(ctxt != PPARAM && ctxt != PPARAMOUT) - redeclare(s, "in this block"); - } - - s->block = block; - s->lastlineno = parserline(); - s->def = n; - n->vargen = gen; - n->funcdepth = funcdepth; - n->class = ctxt; - - autoexport(n, ctxt); -} - -void -addvar(Node *n, Type *t, int ctxt) -{ - if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T) - fatal("addvar: n=%N t=%T nil", n, t); - - n->op = ONAME; - declare(n, ctxt); - n->type = t; -} - -/* - * declare variables from grammar - * new_name_list (type | [type] = expr_list) - */ -NodeList* -variter(NodeList *vl, Node *t, NodeList *el) -{ - int doexpr; - Node *v, *e, *as2; - NodeList *init; - - init = nil; - doexpr = el != nil; - - if(count(el) == 1 && count(vl) > 1) { - e = el->n; - as2 = nod(OAS2, N, N); - as2->list = vl; - as2->rlist = list1(e); - for(; vl; vl=vl->next) { - v = vl->n; - v->op = ONAME; - declare(v, dclcontext); - v->ntype = t; - v->defn = as2; - if(funcdepth > 0) - init = list(init, nod(ODCL, v, N)); - } - return list(init, as2); - } - - for(; vl; vl=vl->next) { - if(doexpr) { - if(el == nil) { - yyerror("missing expression in var declaration"); - break; - } - e = el->n; - el = el->next; - } else - e = N; - - v = vl->n; - v->op = ONAME; - declare(v, dclcontext); - v->ntype = t; - - if(e != N || funcdepth > 0 || isblank(v)) { - if(funcdepth > 0) - init = list(init, nod(ODCL, v, N)); - e = nod(OAS, v, e); - init = list(init, e); - if(e->right != N) - v->defn = e; - } - } - if(el != nil) - yyerror("extra expression in var declaration"); - return init; -} - -/* - * declare constants from grammar - * new_name_list [[type] = expr_list] - */ -NodeList* -constiter(NodeList *vl, Node *t, NodeList *cl) -{ - Node *v, *c; - NodeList *vv; - - vv = nil; - if(cl == nil) { - if(t != N) - yyerror("const declaration cannot have type without expression"); - cl = lastconst; - t = lasttype; - } else { - lastconst = cl; - lasttype = t; - } - cl = listtreecopy(cl); - - for(; vl; vl=vl->next) { - if(cl == nil) { - yyerror("missing value in const declaration"); - break; - } - c = cl->n; - cl = cl->next; - - v = vl->n; - v->op = OLITERAL; - declare(v, dclcontext); - - v->ntype = t; - v->defn = c; - - vv = list(vv, nod(ODCLCONST, v, N)); - } - if(cl != nil) - yyerror("extra expression in const declaration"); - iota += 1; - return vv; -} - -/* - * this generates a new name node, - * typically for labels or other one-off names. - */ -Node* -newname(Sym *s) -{ - Node *n; - - if(s == S) - fatal("newname nil"); - - n = nod(ONAME, N, N); - n->sym = s; - n->type = T; - n->addable = 1; - n->ullman = 1; - n->xoffset = 0; - return n; -} - -/* - * this generates a new name node for a name - * being declared. - */ -Node* -dclname(Sym *s) -{ - Node *n; - - n = newname(s); - n->op = ONONAME; // caller will correct it - return n; -} - -Node* -typenod(Type *t) -{ - // if we copied another type with *t = *u - // then t->nod might be out of date, so - // check t->nod->type too - if(t->nod == N || t->nod->type != t) { - t->nod = nod(OTYPE, N, N); - t->nod->type = t; - t->nod->sym = t->sym; - } - return t->nod; -} - - -/* - * this will return an old name - * that has already been pushed on the - * declaration list. a diagnostic is - * generated if no name has been defined. - */ -Node* -oldname(Sym *s) -{ - Node *n; - Node *c; - - n = s->def; - if(n == N) { - // maybe a top-level name will come along - // to give this a definition later. - // walkdef will check s->def again once - // all the input source has been processed. - n = newname(s); - n->op = ONONAME; - n->iota = iota; // save current iota value in const declarations - } - if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) { - // inner func is referring to var in outer func. - // - // TODO(rsc): If there is an outer variable x and we - // are parsing x := 5 inside the closure, until we get to - // the := it looks like a reference to the outer x so we'll - // make x a closure variable unnecessarily. - if(n->closure == N || n->closure->funcdepth != funcdepth) { - // create new closure var. - c = nod(ONAME, N, N); - c->sym = s; - c->class = PPARAMREF; - c->isddd = n->isddd; - c->defn = n; - c->addable = 0; - c->ullman = 2; - c->funcdepth = funcdepth; - c->outer = n->closure; - n->closure = c; - c->closure = n; - c->xoffset = 0; - curfn->cvars = list(curfn->cvars, c); - } - // return ref to closure var, not original - return n->closure; - } - return n; -} - -/* - * := declarations - */ - -static int -colasname(Node *n) -{ - switch(n->op) { - case ONAME: - case ONONAME: - case OPACK: - case OTYPE: - case OLITERAL: - return n->sym != S; - } - return 0; -} - -void -colasdefn(NodeList *left, Node *defn) -{ - int nnew, nerr; - NodeList *l; - Node *n; - - for(l=left; l; l=l->next) - if(l->n->sym != S) - l->n->sym->flags |= SymUniq; - - nnew = 0; - nerr = 0; - for(l=left; l; l=l->next) { - n = l->n; - if(isblank(n)) - continue; - if(!colasname(n)) { - yyerrorl(defn->lineno, "non-name %N on left side of :=", n); - nerr++; - continue; - } - if((n->sym->flags & SymUniq) == 0) { - yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym); - n->diag++; - nerr++; - continue; - } - n->sym->flags &= ~SymUniq; - if(n->sym->block == block) - continue; - - nnew++; - n = newname(n->sym); - declare(n, dclcontext); - n->defn = defn; - defn->ninit = list(defn->ninit, nod(ODCL, n, N)); - l->n = n; - } - if(nnew == 0 && nerr == 0) - yyerrorl(defn->lineno, "no new variables on left side of :="); -} - -Node* -colas(NodeList *left, NodeList *right, int32 lno) -{ - Node *as; - - as = nod(OAS2, N, N); - as->list = left; - as->rlist = right; - as->colas = 1; - as->lineno = lno; - colasdefn(left, as); - - // make the tree prettier; not necessary - if(count(left) == 1 && count(right) == 1) { - as->left = as->list->n; - as->right = as->rlist->n; - as->list = nil; - as->rlist = nil; - as->op = OAS; - } - - return as; -} - -/* - * declare the arguments in an - * interface field declaration. - */ -void -ifacedcl(Node *n) -{ - if(n->op != ODCLFIELD || n->right == N) - fatal("ifacedcl"); - - if(isblank(n->left)) - yyerror("methods must have a unique non-blank name"); - - dclcontext = PPARAM; - markdcl(); - funcdepth++; - n->outer = curfn; - curfn = n; - funcargs(n->right); - - // funcbody is normally called after the parser has - // seen the body of a function but since an interface - // field declaration does not have a body, we must - // call it now to pop the current declaration context. - dclcontext = PAUTO; - funcbody(n); -} - -/* - * declare the function proper - * and declare the arguments. - * called in extern-declaration context - * returns in auto-declaration context. - */ -void -funchdr(Node *n) -{ - // change the declaration context from extern to auto - if(funcdepth == 0 && dclcontext != PEXTERN) - fatal("funchdr: dclcontext"); - - dclcontext = PAUTO; - markdcl(); - funcdepth++; - - n->outer = curfn; - curfn = n; - - if(n->nname) - funcargs(n->nname->ntype); - else if (n->ntype) - funcargs(n->ntype); - else - funcargs2(n->type); -} - -static void -funcargs(Node *nt) -{ - Node *n, *nn; - NodeList *l; - int gen; - - if(nt->op != OTFUNC) - fatal("funcargs %O", nt->op); - - // re-start the variable generation number - // we want to use small numbers for the return variables, - // so let them have the chunk starting at 1. - vargen = count(nt->rlist); - - // declare the receiver and in arguments. - // no n->defn because type checking of func header - // will not fill in the types until later - if(nt->left != N) { - n = nt->left; - if(n->op != ODCLFIELD) - fatal("funcargs receiver %O", n->op); - if(n->left != N) { - n->left->op = ONAME; - n->left->ntype = n->right; - declare(n->left, PPARAM); - if(dclcontext == PAUTO) - n->left->vargen = ++vargen; - } - } - for(l=nt->list; l; l=l->next) { - n = l->n; - if(n->op != ODCLFIELD) - fatal("funcargs in %O", n->op); - if(n->left != N) { - n->left->op = ONAME; - n->left->ntype = n->right; - declare(n->left, PPARAM); - if(dclcontext == PAUTO) - n->left->vargen = ++vargen; - } - } - - // declare the out arguments. - gen = count(nt->list); - int i = 0; - for(l=nt->rlist; l; l=l->next) { - n = l->n; - - if(n->op != ODCLFIELD) - fatal("funcargs out %O", n->op); - - if(n->left == N) { - // Name so that escape analysis can track it. ~r stands for 'result'. - snprint(namebuf, sizeof(namebuf), "~r%d", gen++); - n->left = newname(lookup(namebuf)); - // TODO: n->left->missing = 1; - } - - n->left->op = ONAME; - - if(isblank(n->left)) { - // Give it a name so we can assign to it during return. ~b stands for 'blank'. - // The name must be different from ~r above because if you have - // func f() (_ int) - // func g() int - // f is allowed to use a plain 'return' with no arguments, while g is not. - // So the two cases must be distinguished. - // We do not record a pointer to the original node (n->orig). - // Having multiple names causes too much confusion in later passes. - nn = nod(OXXX, N, N); - *nn = *n->left; - nn->orig = nn; - snprint(namebuf, sizeof(namebuf), "~b%d", gen++); - nn->sym = lookup(namebuf); - n->left = nn; - } - - n->left->ntype = n->right; - declare(n->left, PPARAMOUT); - if(dclcontext == PAUTO) - n->left->vargen = ++i; - } -} - -/* - * Same as funcargs, except run over an already constructed TFUNC. - * This happens during import, where the hidden_fndcl rule has - * used functype directly to parse the function's type. - */ -static void -funcargs2(Type *t) -{ - Type *ft; - Node *n; - - if(t->etype != TFUNC) - fatal("funcargs2 %T", t); - - if(t->thistuple) - for(ft=getthisx(t)->type; ft; ft=ft->down) { - if(!ft->nname || !ft->nname->sym) - continue; - n = ft->nname; // no need for newname(ft->nname->sym) - n->type = ft->type; - declare(n, PPARAM); - } - - if(t->intuple) - for(ft=getinargx(t)->type; ft; ft=ft->down) { - if(!ft->nname || !ft->nname->sym) - continue; - n = ft->nname; - n->type = ft->type; - declare(n, PPARAM); - } - - if(t->outtuple) - for(ft=getoutargx(t)->type; ft; ft=ft->down) { - if(!ft->nname || !ft->nname->sym) - continue; - n = ft->nname; - n->type = ft->type; - declare(n, PPARAMOUT); - } -} - -/* - * finish the body. - * called in auto-declaration context. - * returns in extern-declaration context. - */ -void -funcbody(Node *n) -{ - // change the declaration context from auto to extern - if(dclcontext != PAUTO) - fatal("funcbody: dclcontext"); - popdcl(); - funcdepth--; - curfn = n->outer; - n->outer = N; - if(funcdepth == 0) - dclcontext = PEXTERN; -} - -/* - * new type being defined with name s. - */ -Node* -typedcl0(Sym *s) -{ - Node *n; - - n = newname(s); - n->op = OTYPE; - declare(n, dclcontext); - return n; -} - -/* - * node n, which was returned by typedcl0 - * is being declared to have uncompiled type t. - * return the ODCLTYPE node to use. - */ -Node* -typedcl1(Node *n, Node *t, int local) -{ - n->ntype = t; - n->local = local; - return nod(ODCLTYPE, n, N); -} - -/* - * structs, functions, and methods. - * they don't belong here, but where do they belong? - */ - -static void -checkembeddedtype(Type *t) -{ - if (t == T) - return; - - if(t->sym == S && isptr[t->etype]) { - t = t->type; - if(t->etype == TINTER) - yyerror("embedded type cannot be a pointer to interface"); - } - if(isptr[t->etype]) - yyerror("embedded type cannot be a pointer"); - else if(t->etype == TFORW && t->embedlineno == 0) - t->embedlineno = lineno; -} - -static Type* -structfield(Node *n) -{ - Type *f; - int lno; - - lno = lineno; - lineno = n->lineno; - - if(n->op != ODCLFIELD) - fatal("structfield: oops %N\n", n); - - f = typ(TFIELD); - f->isddd = n->isddd; - - if(n->right != N) { - typecheck(&n->right, Etype); - n->type = n->right->type; - if(n->left != N) - n->left->type = n->type; - if(n->embedded) - checkembeddedtype(n->type); - } - n->right = N; - - f->type = n->type; - if(f->type == T) - f->broke = 1; - - switch(n->val.ctype) { - case CTSTR: - f->note = n->val.u.sval; - break; - default: - yyerror("field annotation must be string"); - // fallthrough - case CTxxx: - f->note = nil; - break; - } - - if(n->left && n->left->op == ONAME) { - f->nname = n->left; - f->embedded = n->embedded; - f->sym = f->nname->sym; - } - - lineno = lno; - return f; -} - -static uint32 uniqgen; - -static void -checkdupfields(Type *t, char* what) -{ - int lno; - - lno = lineno; - - for( ; t; t=t->down) { - if(t->sym && t->nname && !isblank(t->nname)) { - if(t->sym->uniqgen == uniqgen) { - lineno = t->nname->lineno; - yyerror("duplicate %s %s", what, t->sym->name); - } else - t->sym->uniqgen = uniqgen; - } - } - - lineno = lno; -} - -/* - * convert a parsed id/type list into - * a type for struct/interface/arglist - */ -Type* -tostruct(NodeList *l) -{ - Type *t, *f, **tp; - t = typ(TSTRUCT); - - for(tp = &t->type; l; l=l->next) { - f = structfield(l->n); - - *tp = f; - tp = &f->down; - } - - for(f=t->type; f && !t->broke; f=f->down) - if(f->broke) - t->broke = 1; - - uniqgen++; - checkdupfields(t->type, "field"); - - if (!t->broke) - checkwidth(t); - - return t; -} - -static Type* -tofunargs(NodeList *l) -{ - Type *t, *f, **tp; - - t = typ(TSTRUCT); - t->funarg = 1; - - for(tp = &t->type; l; l=l->next) { - f = structfield(l->n); - f->funarg = 1; - - // esc.c needs to find f given a PPARAM to add the tag. - if(l->n->left && l->n->left->class == PPARAM) - l->n->left->paramfld = f; - - *tp = f; - tp = &f->down; - } - - for(f=t->type; f && !t->broke; f=f->down) - if(f->broke) - t->broke = 1; - - return t; -} - -static Type* -interfacefield(Node *n) -{ - Type *f; - int lno; - - lno = lineno; - lineno = n->lineno; - - if(n->op != ODCLFIELD) - fatal("interfacefield: oops %N\n", n); - - if (n->val.ctype != CTxxx) - yyerror("interface method cannot have annotation"); - - f = typ(TFIELD); - f->isddd = n->isddd; - - if(n->right != N) { - if(n->left != N) { - // queue resolution of method type for later. - // right now all we need is the name list. - // avoids cycles for recursive interface types. - n->type = typ(TINTERMETH); - n->type->nname = n->right; - n->left->type = n->type; - queuemethod(n); - - if(n->left->op == ONAME) { - f->nname = n->left; - f->embedded = n->embedded; - f->sym = f->nname->sym; - } - - } else { - - typecheck(&n->right, Etype); - n->type = n->right->type; - - if(n->embedded) - checkembeddedtype(n->type); - - if(n->type) - switch(n->type->etype) { - case TINTER: - break; - case TFORW: - yyerror("interface type loop involving %T", n->type); - f->broke = 1; - break; - default: - yyerror("interface contains embedded non-interface %T", n->type); - f->broke = 1; - break; - } - } - } - - n->right = N; - - f->type = n->type; - if(f->type == T) - f->broke = 1; - - lineno = lno; - return f; -} - -Type* -tointerface(NodeList *l) -{ - Type *t, *f, **tp, *t1; - - t = typ(TINTER); - - tp = &t->type; - for(; l; l=l->next) { - f = interfacefield(l->n); - - if (l->n->left == N && f->type->etype == TINTER) { - // embedded interface, inline methods - for(t1=f->type->type; t1; t1=t1->down) { - f = typ(TFIELD); - f->type = t1->type; - f->broke = t1->broke; - f->sym = t1->sym; - if(f->sym) - f->nname = newname(f->sym); - *tp = f; - tp = &f->down; - } - } else { - *tp = f; - tp = &f->down; - } - } - - for(f=t->type; f && !t->broke; f=f->down) - if(f->broke) - t->broke = 1; - - uniqgen++; - checkdupfields(t->type, "method"); - t = sortinter(t); - checkwidth(t); - - return t; -} - -Node* -embedded(Sym *s, Pkg *pkg) -{ - Node *n; - char *name; - - // Names sometimes have disambiguation junk - // appended after a center dot. Discard it when - // making the name for the embedded struct field. - enum { CenterDot = 0xB7 }; - name = s->name; - if(utfrune(s->name, CenterDot)) { - name = strdup(s->name); - *utfrune(name, CenterDot) = 0; - } - - if(exportname(name)) - n = newname(lookup(name)); - else if(s->pkg == builtinpkg) - // The name of embedded builtins belongs to pkg. - n = newname(pkglookup(name, pkg)); - else - n = newname(pkglookup(name, s->pkg)); - n = nod(ODCLFIELD, n, oldname(s)); - n->embedded = 1; - return n; -} - -/* - * check that the list of declarations is either all anonymous or all named - */ - -static Node* -findtype(NodeList *l) -{ - for(; l; l=l->next) - if(l->n->op == OKEY) - return l->n->right; - return N; -} - -NodeList* -checkarglist(NodeList *all, int input) -{ - int named; - Node *n, *t, *nextt; - NodeList *l; - - named = 0; - for(l=all; l; l=l->next) { - if(l->n->op == OKEY) { - named = 1; - break; - } - } - if(named) { - n = N; - for(l=all; l; l=l->next) { - n = l->n; - if(n->op != OKEY && n->sym == S) { - yyerror("mixed named and unnamed function parameters"); - break; - } - } - if(l == nil && n != N && n->op != OKEY) - yyerror("final function parameter must have type"); - } - - nextt = nil; - for(l=all; l; l=l->next) { - // can cache result from findtype to avoid - // quadratic behavior here, but unlikely to matter. - n = l->n; - if(named) { - if(n->op == OKEY) { - t = n->right; - n = n->left; - nextt = nil; - } else { - if(nextt == nil) - nextt = findtype(l); - t = nextt; - } - } else { - t = n; - n = N; - } - - // during import l->n->op is OKEY, but l->n->left->sym == S - // means it was a '?', not that it was - // a lone type This doesn't matter for the exported - // declarations, which are parsed by rules that don't - // use checkargs, but can happen for func literals in - // the inline bodies. - // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ? - if(importpkg && n->sym == S) - n = N; - - if(n != N && n->sym == S) { - t = n; - n = N; - } - if(n != N) - n = newname(n->sym); - n = nod(ODCLFIELD, n, t); - if(n->right != N && n->right->op == ODDD) { - if(!input) - yyerror("cannot use ... in output argument list"); - else if(l->next != nil) - yyerror("can only use ... as final argument in list"); - n->right->op = OTARRAY; - n->right->right = n->right->left; - n->right->left = N; - n->isddd = 1; - if(n->left != N) - n->left->isddd = 1; - } - l->n = n; - } - return all; -} - - -Node* -fakethis(void) -{ - Node *n; - - n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT)))); - return n; -} - -/* - * Is this field a method on an interface? - * Those methods have an anonymous - * *struct{} as the receiver. - * (See fakethis above.) - */ -int -isifacemethod(Type *f) -{ - Type *rcvr; - Type *t; - - rcvr = getthisx(f)->type; - if(rcvr->sym != S) - return 0; - t = rcvr->type; - if(!isptr[t->etype]) - return 0; - t = t->type; - if(t->sym != S || t->etype != TSTRUCT || t->type != T) - return 0; - return 1; -} - -/* - * turn a parsed function declaration - * into a type - */ -Type* -functype(Node *this, NodeList *in, NodeList *out) -{ - Type *t; - NodeList *rcvr; - Sym *s; - - t = typ(TFUNC); - - rcvr = nil; - if(this) - rcvr = list1(this); - t->type = tofunargs(rcvr); - t->type->down = tofunargs(out); - t->type->down->down = tofunargs(in); - - uniqgen++; - checkdupfields(t->type->type, "argument"); - checkdupfields(t->type->down->type, "argument"); - checkdupfields(t->type->down->down->type, "argument"); - - if (t->type->broke || t->type->down->broke || t->type->down->down->broke) - t->broke = 1; - - if(this) - t->thistuple = 1; - t->outtuple = count(out); - t->intuple = count(in); - t->outnamed = 0; - if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) { - s = out->n->left->orig->sym; - if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result - t->outnamed = 1; - } - - return t; -} - -Sym* -methodsym(Sym *nsym, Type *t0, int iface) -{ - Sym *s; - char *p; - Type *t; - char *suffix; - Pkg *spkg; - static Pkg *toppkg; - - t = t0; - if(t == T) - goto bad; - s = t->sym; - if(s == S && isptr[t->etype]) { - t = t->type; - if(t == T) - goto bad; - s = t->sym; - } - spkg = nil; - if(s != S) - spkg = s->pkg; - - // if t0 == *t and t0 has a sym, - // we want to see *t, not t0, in the method name. - if(t != t0 && t0->sym) - t0 = ptrto(t); - - suffix = ""; - if(iface) { - dowidth(t0); - if(t0->width < types[tptr]->width) - suffix = "·i"; - } - if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) { - if(t0->sym == S && isptr[t0->etype]) - p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix); - else - p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix); - } else { - if(t0->sym == S && isptr[t0->etype]) - p = smprint("(%-hT).%s%s", t0, nsym->name, suffix); - else - p = smprint("%-hT.%s%s", t0, nsym->name, suffix); - } - if(spkg == nil) { - if(toppkg == nil) - toppkg = mkpkg(newstrlit("go")); - spkg = toppkg; - } - s = pkglookup(p, spkg); - free(p); - return s; - -bad: - yyerror("illegal receiver type: %T", t0); - return S; -} - -Node* -methodname(Node *n, Type *t) -{ - Sym *s; - - s = methodsym(n->sym, t, 0); - if(s == S) - return n; - return newname(s); -} - -Node* -methodname1(Node *n, Node *t) -{ - char *star; - char *p; - - star = nil; - if(t->op == OIND) { - star = "*"; - t = t->left; - } - if(t->sym == S || isblank(n)) - return newname(n->sym); - - if(star) - p = smprint("(%s%S).%S", star, t->sym, n->sym); - else - p = smprint("%S.%S", t->sym, n->sym); - - if(exportname(t->sym->name)) - n = newname(lookup(p)); - else - n = newname(pkglookup(p, t->sym->pkg)); - free(p); - return n; -} - -/* - * add a method, declared as a function, - * n is fieldname, pa is base type, t is function type - */ -void -addmethod(Sym *sf, Type *t, int local, int nointerface) -{ - Type *f, *d, *pa; - Node *n; - - // get field sym - if(sf == S) - fatal("no method symbol"); - - // get parent type sym - pa = getthisx(t)->type; // ptr to this structure - if(pa == T) { - yyerror("missing receiver"); - return; - } - - pa = pa->type; - f = methtype(pa, 1); - if(f == T) { - t = pa; - if(t == T) // rely on typecheck having complained before - return; - if(t != T) { - if(isptr[t->etype]) { - if(t->sym != S) { - yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); - return; - } - t = t->type; - } - if(t->broke) // rely on typecheck having complained before - return; - if(t->sym == S) { - yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t); - return; - } - if(isptr[t->etype]) { - yyerror("invalid receiver type %T (%T is a pointer type)", pa, t); - return; - } - if(t->etype == TINTER) { - yyerror("invalid receiver type %T (%T is an interface type)", pa, t); - return; - } - } - // Should have picked off all the reasons above, - // but just in case, fall back to generic error. - yyerror("invalid receiver type %T (%lT / %lT)", pa, pa, t); - return; - } - - pa = f; - if(pa->etype == TSTRUCT) { - for(f=pa->type; f; f=f->down) { - if(f->sym == sf) { - yyerror("type %T has both field and method named %S", pa, sf); - return; - } - } - } - - if(local && !pa->local) { - // defining method on non-local type. - yyerror("cannot define new methods on non-local type %T", pa); - return; - } - - n = nod(ODCLFIELD, newname(sf), N); - n->type = t; - - d = T; // last found - for(f=pa->method; f!=T; f=f->down) { - d = f; - if(f->etype != TFIELD) - fatal("addmethod: not TFIELD: %lT", f); - if(strcmp(sf->name, f->sym->name) != 0) - continue; - if(!eqtype(t, f->type)) - yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t); - return; - } - - f = structfield(n); - f->nointerface = nointerface; - - // during import unexported method names should be in the type's package - if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg) - fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name); - - if(d == T) - pa->method = f; - else - d->down = f; - return; -} - -void -funccompile(Node *n) -{ - stksize = BADWIDTH; - maxarg = 0; - - if(n->type == T) { - if(nerrors == 0) - fatal("funccompile missing type"); - return; - } - - // assign parameter offsets - checkwidth(n->type); - - if(curfn) - fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym); - - stksize = 0; - dclcontext = PAUTO; - funcdepth = n->funcdepth + 1; - compile(n); - curfn = nil; - funcdepth = 0; - dclcontext = PEXTERN; -} - -Sym* -funcsym(Sym *s) -{ - char *p; - Sym *s1; - - p = smprint("%s·f", s->name); - s1 = pkglookup(p, s->pkg); - free(p); - if(s1->def == N) { - s1->def = newname(s1); - s1->def->shortname = newname(s); - funcsyms = list(funcsyms, s1->def); - } - return s1; -} diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go deleted file mode 100644 index 03df93a3eb..0000000000 --- a/src/cmd/gc/doc.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -/* - -Gc is the generic label for the family of Go compilers -that function as part of the (modified) Plan 9 tool chain. The C compiler -documentation at - - http://plan9.bell-labs.com/sys/doc/comp.pdf (Tools overview) - http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture) - -gives the overall design of the tool chain. Aside from a few adapted pieces, -such as the optimizer, the Go compilers are wholly new programs. - -The compiler reads in a set of Go files, typically suffixed ".go". They -must all be part of one package. The output is a single intermediate file -representing the "binary assembly" of the compiled package, ready as input -for the linker (6l, etc.). - -The generated files contain type information about the symbols exported by -the package and about types used by symbols imported by the package from -other packages. It is therefore not necessary when compiling client C of -package P to read the files of P's dependencies, only the compiled output -of P. - -Command Line - -Usage: - go tool 6g [flags] file... -The specified files must be Go source files and all part of the same package. -Substitute 6g with 8g or 5g where appropriate. - -Flags: - -o file - output file, default file.6 for 6g, etc. - -pack - write an archive file rather than an object file - -e - normally the compiler quits after 10 errors; -e prints all errors - -p path - assume that path is the eventual import path for this code, - and diagnose any attempt to import a package that depends on it. - -D path - treat a relative import as relative to path - -L - show entire file path when printing line numbers in errors - -I dir1 -I dir2 - add dir1 and dir2 to the list of paths to check for imported packages - -N - disable optimizations - -nolocalimports - disallow local (relative) imports - -S - write assembly language text to standard output (code only) - -S -S - write assembly language text to standard output (code and data) - -u - disallow importing packages not marked as safe; implies -nolocalimports - -V - print the compiler version - -race - compile with race detection enabled - -There are also a number of debugging flags; run the command with no arguments -to get a usage message. - -Compiler Directives - -The compiler accepts two compiler directives in the form of // comments at the -beginning of a line. To distinguish them from non-directive comments, the directives -require no space between the slashes and the name of the directive. However, since -they are comments, tools unaware of the directive convention or of a particular -directive can skip over a directive like any other comment. - - //line path/to/file:linenumber - -The //line directive specifies that the source line that follows should be recorded -as having come from the given file path and line number. Successive lines are -recorded using increasing line numbers, until the next directive. This directive -typically appears in machine-generated code, so that compilers and debuggers -will show lines in the original input to the generator. - - //go:noescape - -The //go:noescape directive specifies that the next declaration in the file, which -must be a func without a body (meaning that it has an implementation not written -in Go) does not allow any of the pointers passed as arguments to escape into the -heap or into the values returned from the function. This information can be used as -during the compiler's escape analysis of Go code calling the function. -*/ -package main diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c deleted file mode 100644 index 5b09c0b7fb..0000000000 --- a/src/cmd/gc/esc.c +++ /dev/null @@ -1,1342 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Escape analysis. - -#include -#include -#include "go.h" - -// Run analysis on minimal sets of mutually recursive functions -// or single non-recursive functions, bottom up. -// -// Finding these sets is finding strongly connected components -// in the static call graph. The algorithm for doing that is taken -// from Sedgewick, Algorithms, Second Edition, p. 482, with two -// adaptations. -// -// First, a hidden closure function (n->curfn != N) cannot be the -// root of a connected component. Refusing to use it as a root -// forces it into the component of the function in which it appears. -// The analysis assumes that closures and the functions in which they -// appear are analyzed together, so that the aliasing between their -// variables can be modeled more precisely. -// -// Second, each function becomes two virtual nodes in the graph, -// with numbers n and n+1. We record the function's node number as n -// but search from node n+1. If the search tells us that the component -// number (min) is n+1, we know that this is a trivial component: one function -// plus its closures. If the search tells us that the component number is -// n, then there was a path from node n+1 back to node n, meaning that -// the function set is mutually recursive. The escape analysis can be -// more precise when analyzing a single non-recursive function than -// when analyzing a set of mutually recursive functions. - -static NodeList *stack; -static uint32 visitgen; -static uint32 visit(Node*); -static uint32 visitcode(Node*, uint32); -static uint32 visitcodelist(NodeList*, uint32); - -static void analyze(NodeList*, int); - -enum -{ - EscFuncUnknown = 0, - EscFuncPlanned, - EscFuncStarted, - EscFuncTagged, -}; - -void -escapes(NodeList *all) -{ - NodeList *l; - - for(l=all; l; l=l->next) - l->n->walkgen = 0; - - visitgen = 0; - for(l=all; l; l=l->next) - if(l->n->op == ODCLFUNC && l->n->curfn == N) - visit(l->n); - - for(l=all; l; l=l->next) - l->n->walkgen = 0; -} - -static uint32 -visit(Node *n) -{ - uint32 min, recursive; - NodeList *l, *block; - - if(n->walkgen > 0) { - // already visited - return n->walkgen; - } - - visitgen++; - n->walkgen = visitgen; - visitgen++; - min = visitgen; - - l = mal(sizeof *l); - l->next = stack; - l->n = n; - stack = l; - min = visitcodelist(n->nbody, min); - if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) { - // This node is the root of a strongly connected component. - - // The original min passed to visitcodelist was n->walkgen+1. - // If visitcodelist found its way back to n->walkgen, then this - // block is a set of mutually recursive functions. - // Otherwise it's just a lone function that does not recurse. - recursive = min == n->walkgen; - - // Remove connected component from stack. - // Mark walkgen so that future visits return a large number - // so as not to affect the caller's min. - block = stack; - for(l=stack; l->n != n; l=l->next) - l->n->walkgen = (uint32)~0U; - n->walkgen = (uint32)~0U; - stack = l->next; - l->next = nil; - - // Run escape analysis on this set of functions. - analyze(block, recursive); - } - - return min; -} - -static uint32 -visitcodelist(NodeList *l, uint32 min) -{ - for(; l; l=l->next) - min = visitcode(l->n, min); - return min; -} - -static uint32 -visitcode(Node *n, uint32 min) -{ - Node *fn; - uint32 m; - - if(n == N) - return min; - - min = visitcodelist(n->ninit, min); - min = visitcode(n->left, min); - min = visitcode(n->right, min); - min = visitcodelist(n->list, min); - min = visitcode(n->ntest, min); - min = visitcode(n->nincr, min); - min = visitcodelist(n->nbody, min); - min = visitcodelist(n->nelse, min); - min = visitcodelist(n->rlist, min); - - if(n->op == OCALLFUNC || n->op == OCALLMETH) { - fn = n->left; - if(n->op == OCALLMETH) - fn = n->left->right->sym->def; - if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn) - if((m = visit(fn->defn)) < min) - min = m; - } - - if(n->op == OCLOSURE) - if((m = visit(n->closure)) < min) - min = m; - - return min; -} - -// An escape analysis pass for a set of functions. -// -// First escfunc, esc and escassign recurse over the ast of each -// function to dig out flow(dst,src) edges between any -// pointer-containing nodes and store them in dst->escflowsrc. For -// variables assigned to a variable in an outer scope or used as a -// return value, they store a flow(theSink, src) edge to a fake node -// 'the Sink'. For variables referenced in closures, an edge -// flow(closure, &var) is recorded and the flow of a closure itself to -// an outer scope is tracked the same way as other variables. -// -// Then escflood walks the graph starting at theSink and tags all -// variables of it can reach an & node as escaping and all function -// parameters it can reach as leaking. -// -// If a value's address is taken but the address does not escape, -// then the value can stay on the stack. If the value new(T) does -// not escape, then new(T) can be rewritten into a stack allocation. -// The same is true of slice literals. -// -// If optimizations are disabled (-N), this code is not used. -// Instead, the compiler assumes that any value whose address -// is taken without being immediately dereferenced -// needs to be moved to the heap, and new(T) and slice -// literals are always real allocations. - -typedef struct EscState EscState; - -static void escfunc(EscState*, Node *func); -static void esclist(EscState*, NodeList *l, Node *up); -static void esc(EscState*, Node *n, Node *up); -static void escloopdepthlist(EscState*, NodeList *l); -static void escloopdepth(EscState*, Node *n); -static void escassign(EscState*, Node *dst, Node *src); -static void esccall(EscState*, Node*, Node *up); -static void escflows(EscState*, Node *dst, Node *src); -static void escflood(EscState*, Node *dst); -static void escwalk(EscState*, int level, Node *dst, Node *src); -static void esctag(EscState*, Node *func); - -struct EscState { - // Fake node that all - // - return values and output variables - // - parameters on imported functions not marked 'safe' - // - assignments to global variables - // flow to. - Node theSink; - - // If an analyzed function is recorded to return - // pieces obtained via indirection from a parameter, - // and later there is a call f(x) to that function, - // we create a link funcParam <- x to record that fact. - // The funcParam node is handled specially in escflood. - Node funcParam; - - NodeList* dsts; // all dst nodes - int loopdepth; // for detecting nested loop scopes - int pdepth; // for debug printing in recursions. - int dstcount, edgecount; // diagnostic - NodeList* noesc; // list of possible non-escaping nodes, for printing - int recursive; // recursive function or group of mutually recursive functions. -}; - -static Strlit *tags[16]; - -static Strlit* -mktag(int mask) -{ - Strlit *s; - char buf[40]; - - switch(mask&EscMask) { - case EscNone: - case EscReturn: - break; - default: - fatal("escape mktag"); - } - - mask >>= EscBits; - - if(mask < nelem(tags) && tags[mask] != nil) - return tags[mask]; - - snprint(buf, sizeof buf, "esc:0x%x", mask); - s = newstrlit(buf); - if(mask < nelem(tags)) - tags[mask] = s; - return s; -} - -static int -parsetag(Strlit *note) -{ - int em; - - if(note == nil) - return EscUnknown; - if(strncmp(note->s, "esc:", 4) != 0) - return EscUnknown; - em = atoi(note->s + 4); - if (em == 0) - return EscNone; - return EscReturn | (em << EscBits); -} - -static void -analyze(NodeList *all, int recursive) -{ - NodeList *l; - EscState es, *e; - - memset(&es, 0, sizeof es); - e = &es; - e->theSink.op = ONAME; - e->theSink.orig = &e->theSink; - e->theSink.class = PEXTERN; - e->theSink.sym = lookup(".sink"); - e->theSink.escloopdepth = -1; - e->recursive = recursive; - - e->funcParam.op = ONAME; - e->funcParam.orig = &e->funcParam; - e->funcParam.class = PAUTO; - e->funcParam.sym = lookup(".param"); - e->funcParam.escloopdepth = 10000000; - - for(l=all; l; l=l->next) - if(l->n->op == ODCLFUNC) - l->n->esc = EscFuncPlanned; - - // flow-analyze functions - for(l=all; l; l=l->next) - if(l->n->op == ODCLFUNC) - escfunc(e, l->n); - - // print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount); - - // visit the upstream of each dst, mark address nodes with - // addrescapes, mark parameters unsafe - for(l = e->dsts; l; l=l->next) - escflood(e, l->n); - - // for all top level functions, tag the typenodes corresponding to the param nodes - for(l=all; l; l=l->next) - if(l->n->op == ODCLFUNC) - esctag(e, l->n); - - if(debug['m']) { - for(l=e->noesc; l; l=l->next) - if(l->n->esc == EscNone) - warnl(l->n->lineno, "%S %hN does not escape", - (l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S, - l->n); - } -} - - -static void -escfunc(EscState *e, Node *func) -{ - Node *savefn; - NodeList *ll; - int saveld; - -// print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":""); - - if(func->esc != 1) - fatal("repeat escfunc %N", func->nname); - func->esc = EscFuncStarted; - - saveld = e->loopdepth; - e->loopdepth = 1; - savefn = curfn; - curfn = func; - - for(ll=curfn->dcl; ll; ll=ll->next) { - if(ll->n->op != ONAME) - continue; - switch (ll->n->class) { - case PPARAMOUT: - // out params are in a loopdepth between the sink and all local variables - ll->n->escloopdepth = 0; - break; - case PPARAM: - ll->n->escloopdepth = 1; - if(ll->n->type && !haspointers(ll->n->type)) - break; - if(curfn->nbody == nil && !curfn->noescape) - ll->n->esc = EscHeap; - else - ll->n->esc = EscNone; // prime for escflood later - e->noesc = list(e->noesc, ll->n); - break; - } - } - - // in a mutually recursive group we lose track of the return values - if(e->recursive) - for(ll=curfn->dcl; ll; ll=ll->next) - if(ll->n->op == ONAME && ll->n->class == PPARAMOUT) - escflows(e, &e->theSink, ll->n); - - escloopdepthlist(e, curfn->nbody); - esclist(e, curfn->nbody, curfn); - curfn = savefn; - e->loopdepth = saveld; -} - -// Mark labels that have no backjumps to them as not increasing e->loopdepth. -// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat -// and set it to one of the following two. Then in esc we'll clear it again. -static Label looping; -static Label nonlooping; - -static void -escloopdepthlist(EscState *e, NodeList *l) -{ - for(; l; l=l->next) - escloopdepth(e, l->n); -} - -static void -escloopdepth(EscState *e, Node *n) -{ - if(n == N) - return; - - escloopdepthlist(e, n->ninit); - - switch(n->op) { - case OLABEL: - if(!n->left || !n->left->sym) - fatal("esc:label without label: %+N", n); - // Walk will complain about this label being already defined, but that's not until - // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc - // if(n->left->sym->label != nil) - // fatal("escape analysis messed up analyzing label: %+N", n); - n->left->sym->label = &nonlooping; - break; - case OGOTO: - if(!n->left || !n->left->sym) - fatal("esc:goto without label: %+N", n); - // If we come past one that's uninitialized, this must be a (harmless) forward jump - // but if it's set to nonlooping the label must have preceded this goto. - if(n->left->sym->label == &nonlooping) - n->left->sym->label = &looping; - break; - } - - escloopdepth(e, n->left); - escloopdepth(e, n->right); - escloopdepthlist(e, n->list); - escloopdepth(e, n->ntest); - escloopdepth(e, n->nincr); - escloopdepthlist(e, n->nbody); - escloopdepthlist(e, n->nelse); - escloopdepthlist(e, n->rlist); - -} - -static void -esclist(EscState *e, NodeList *l, Node *up) -{ - for(; l; l=l->next) - esc(e, l->n, up); -} - -static void -esc(EscState *e, Node *n, Node *up) -{ - int lno; - NodeList *ll, *lr; - Node *a, *v; - - if(n == N) - return; - - lno = setlineno(n); - - // ninit logically runs at a different loopdepth than the rest of the for loop. - esclist(e, n->ninit, n); - - if(n->op == OFOR || n->op == ORANGE) - e->loopdepth++; - - // type switch variables have no ODCL. - // process type switch as declaration. - // must happen before processing of switch body, - // so before recursion. - if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) { - for(ll=n->list; ll; ll=ll->next) { // cases - // ll->n->nname is the variable per case - if(ll->n->nname) - ll->n->nname->escloopdepth = e->loopdepth; - } - } - - esc(e, n->left, n); - esc(e, n->right, n); - esc(e, n->ntest, n); - esc(e, n->nincr, n); - esclist(e, n->nbody, n); - esclist(e, n->nelse, n); - esclist(e, n->list, n); - esclist(e, n->rlist, n); - - if(n->op == OFOR || n->op == ORANGE) - e->loopdepth--; - - if(debug['m'] > 1) - print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth, - (curfn && curfn->nname) ? curfn->nname->sym : S, n); - - switch(n->op) { - case ODCL: - // Record loop depth at declaration. - if(n->left) - n->left->escloopdepth = e->loopdepth; - break; - - case OLABEL: - if(n->left->sym->label == &nonlooping) { - if(debug['m'] > 1) - print("%L:%N non-looping label\n", lineno, n); - } else if(n->left->sym->label == &looping) { - if(debug['m'] > 1) - print("%L: %N looping label\n", lineno, n); - e->loopdepth++; - } - // See case OLABEL in escloopdepth above - // else if(n->left->sym->label == nil) - // fatal("escape analysis missed or messed up a label: %+N", n); - - n->left->sym->label = nil; - break; - - case ORANGE: - // Everything but fixed array is a dereference. - if(isfixedarray(n->type) && n->list && n->list->next) - escassign(e, n->list->next->n, n->right); - break; - - case OSWITCH: - if(n->ntest && n->ntest->op == OTYPESW) { - for(ll=n->list; ll; ll=ll->next) { // cases - // ntest->right is the argument of the .(type), - // ll->n->nname is the variable per case - escassign(e, ll->n->nname, n->ntest->right); - } - } - break; - - case OAS: - case OASOP: - // Filter out the following special case. - // - // func (b *Buffer) Foo() { - // n, m := ... - // b.buf = b.buf[n:m] - // } - // - // This assignment is a no-op for escape analysis, - // it does not store any new pointers into b that were not already there. - // However, without this special case b will escape, because we assign to OIND/ODOTPTR. - if((n->left->op == OIND || n->left->op == ODOTPTR) && n->left->left->op == ONAME && // dst is ONAME dereference - (n->right->op == OSLICE || n->right->op == OSLICE3 || n->right->op == OSLICESTR) && // src is slice operation - (n->right->left->op == OIND || n->right->left->op == ODOTPTR) && n->right->left->left->op == ONAME && // slice is applied to ONAME dereference - n->left->left == n->right->left->left) { // dst and src reference the same base ONAME - // Here we also assume that the statement will not contain calls, - // that is, that order will move any calls to init. - // Otherwise base ONAME value could change between the moments - // when we evaluate it for dst and for src. - // - // Note, this optimization does not apply to OSLICEARR, - // because it does introduce a new pointer into b that was not already there - // (pointer to b itself). After such assignment, if b contents escape, - // b escapes as well. If we ignore such OSLICEARR, we will conclude - // that b does not escape when b contents do. - if(debug['m']) { - warnl(n->lineno, "%S ignoring self-assignment to %hN", - (n->curfn && n->curfn->nname) ? n->curfn->nname->sym : S, n->left); - } - break; - } - escassign(e, n->left, n->right); - break; - - case OAS2: // x,y = a,b - if(count(n->list) == count(n->rlist)) - for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) - escassign(e, ll->n, lr->n); - break; - - case OAS2RECV: // v, ok = <-ch - case OAS2MAPR: // v, ok = m[k] - case OAS2DOTTYPE: // v, ok = x.(type) - escassign(e, n->list->n, n->rlist->n); - break; - - case OSEND: // ch <- x - escassign(e, &e->theSink, n->right); - break; - - case ODEFER: - if(e->loopdepth == 1) // top level - break; - // arguments leak out of scope - // TODO: leak to a dummy node instead - // fallthrough - case OPROC: - // go f(x) - f and x escape - escassign(e, &e->theSink, n->left->left); - escassign(e, &e->theSink, n->left->right); // ODDDARG for call - for(ll=n->left->list; ll; ll=ll->next) - escassign(e, &e->theSink, ll->n); - break; - - case OCALLMETH: - case OCALLFUNC: - case OCALLINTER: - esccall(e, n, up); - break; - - case OAS2FUNC: // x,y = f() - // esccall already done on n->rlist->n. tie it's escretval to n->list - lr=n->rlist->n->escretval; - for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next) - escassign(e, ll->n, lr->n); - if(lr || ll) - fatal("esc oas2func"); - break; - - case ORETURN: - ll=n->list; - if(count(n->list) == 1 && curfn->type->outtuple > 1) { - // OAS2FUNC in disguise - // esccall already done on n->list->n - // tie n->list->n->escretval to curfn->dcl PPARAMOUT's - ll = n->list->n->escretval; - } - - for(lr = curfn->dcl; lr && ll; lr=lr->next) { - if (lr->n->op != ONAME || lr->n->class != PPARAMOUT) - continue; - escassign(e, lr->n, ll->n); - ll = ll->next; - } - if (ll != nil) - fatal("esc return list"); - break; - - case OPANIC: - // Argument could leak through recover. - escassign(e, &e->theSink, n->left); - break; - - case OAPPEND: - if(!n->isddd) - for(ll=n->list->next; ll; ll=ll->next) - escassign(e, &e->theSink, ll->n); // lose track of assign to dereference - break; - - case OCONV: - case OCONVNOP: - case OCONVIFACE: - escassign(e, n, n->left); - break; - - case OARRAYLIT: - if(isslice(n->type)) { - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - n->escloopdepth = e->loopdepth; - // Values make it to memory, lose track. - for(ll=n->list; ll; ll=ll->next) - escassign(e, &e->theSink, ll->n->right); - } else { - // Link values to array. - for(ll=n->list; ll; ll=ll->next) - escassign(e, n, ll->n->right); - } - break; - - case OSTRUCTLIT: - // Link values to struct. - for(ll=n->list; ll; ll=ll->next) - escassign(e, n, ll->n->right); - break; - - case OPTRLIT: - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - n->escloopdepth = e->loopdepth; - // Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too. - escassign(e, n, n->left); - break; - - case OCALLPART: - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - n->escloopdepth = e->loopdepth; - // Contents make it to memory, lose track. - escassign(e, &e->theSink, n->left); - break; - - case OMAPLIT: - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - n->escloopdepth = e->loopdepth; - // Keys and values make it to memory, lose track. - for(ll=n->list; ll; ll=ll->next) { - escassign(e, &e->theSink, ll->n->left); - escassign(e, &e->theSink, ll->n->right); - } - break; - - case OCLOSURE: - // Link addresses of captured variables to closure. - for(ll=n->cvars; ll; ll=ll->next) { - v = ll->n; - if(v->op == OXXX) // unnamed out argument; see dcl.c:/^funcargs - continue; - a = v->closure; - if(!v->byval) { - a = nod(OADDR, a, N); - a->lineno = v->lineno; - a->escloopdepth = e->loopdepth; - typecheck(&a, Erv); - } - escassign(e, n, a); - } - // fallthrough - case OMAKECHAN: - case OMAKEMAP: - case OMAKESLICE: - case ONEW: - case OARRAYRUNESTR: - case OARRAYBYTESTR: - case OSTRARRAYRUNE: - case OSTRARRAYBYTE: - case ORUNESTR: - n->escloopdepth = e->loopdepth; - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - break; - - case OADDSTR: - n->escloopdepth = e->loopdepth; - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - // Arguments of OADDSTR do not escape. - break; - - case OADDR: - n->esc = EscNone; // until proven otherwise - e->noesc = list(e->noesc, n); - // current loop depth is an upper bound on actual loop depth - // of addressed value. - n->escloopdepth = e->loopdepth; - // for &x, use loop depth of x if known. - // it should always be known, but if not, be conservative - // and keep the current loop depth. - if(n->left->op == ONAME) { - switch(n->left->class) { - case PAUTO: - if(n->left->escloopdepth != 0) - n->escloopdepth = n->left->escloopdepth; - break; - case PPARAM: - case PPARAMOUT: - // PPARAM is loop depth 1 always. - // PPARAMOUT is loop depth 0 for writes - // but considered loop depth 1 for address-of, - // so that writing the address of one result - // to another (or the same) result makes the - // first result move to the heap. - n->escloopdepth = 1; - break; - } - } - break; - } - - lineno = lno; -} - -// Assert that expr somehow gets assigned to dst, if non nil. for -// dst==nil, any name node expr still must be marked as being -// evaluated in curfn. For expr==nil, dst must still be examined for -// evaluations inside it (e.g *f(x) = y) -static void -escassign(EscState *e, Node *dst, Node *src) -{ - int lno; - NodeList *ll; - - if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX) - return; - - if(debug['m'] > 1) - print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth, - (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src); - - setlineno(dst); - - // Analyze lhs of assignment. - // Replace dst with e->theSink if we can't track it. - switch(dst->op) { - default: - dump("dst", dst); - fatal("escassign: unexpected dst"); - - case OARRAYLIT: - case OCLOSURE: - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case OMAPLIT: - case OSTRUCTLIT: - case OPTRLIT: - case OCALLPART: - break; - - case ONAME: - if(dst->class == PEXTERN) - dst = &e->theSink; - break; - case ODOT: // treat "dst.x = src" as "dst = src" - escassign(e, dst->left, src); - return; - case OINDEX: - if(isfixedarray(dst->left->type)) { - escassign(e, dst->left, src); - return; - } - dst = &e->theSink; // lose track of dereference - break; - case OIND: - case ODOTPTR: - dst = &e->theSink; // lose track of dereference - break; - case OINDEXMAP: - // lose track of key and value - escassign(e, &e->theSink, dst->right); - dst = &e->theSink; - break; - } - - lno = setlineno(src); - e->pdepth++; - - switch(src->op) { - case OADDR: // dst = &x - case OIND: // dst = *x - case ODOTPTR: // dst = (*x).f - case ONAME: - case OPARAM: - case ODDDARG: - case OPTRLIT: - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - case OMAKECHAN: - case OMAKEMAP: - case OMAKESLICE: - case OARRAYRUNESTR: - case OARRAYBYTESTR: - case OSTRARRAYRUNE: - case OSTRARRAYBYTE: - case OADDSTR: - case ONEW: - case OCLOSURE: - case OCALLPART: - case ORUNESTR: - escflows(e, dst, src); - break; - - case OCALLMETH: - case OCALLFUNC: - case OCALLINTER: - // Flowing multiple returns to a single dst happens when - // analyzing "go f(g())": here g() flows to sink (issue 4529). - for(ll=src->escretval; ll; ll=ll->next) - escflows(e, dst, ll->n); - break; - - case ODOT: - // A non-pointer escaping from a struct does not concern us. - if(src->type && !haspointers(src->type)) - break; - // fallthrough - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case ODOTMETH: // treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC - // iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here - case ODOTTYPE: - case ODOTTYPE2: - case OSLICE: - case OSLICE3: - case OSLICEARR: - case OSLICE3ARR: - case OSLICESTR: - // Conversions, field access, slice all preserve the input value. - escassign(e, dst, src->left); - break; - - case OAPPEND: - // Append returns first argument. - escassign(e, dst, src->list->n); - break; - - case OINDEX: - // Index of array preserves input value. - if(isfixedarray(src->left->type)) - escassign(e, dst, src->left); - break; - - case OADD: - case OSUB: - case OOR: - case OXOR: - case OMUL: - case ODIV: - case OMOD: - case OLSH: - case ORSH: - case OAND: - case OANDNOT: - case OPLUS: - case OMINUS: - case OCOM: - // Might be pointer arithmetic, in which case - // the operands flow into the result. - // TODO(rsc): Decide what the story is here. This is unsettling. - escassign(e, dst, src->left); - escassign(e, dst, src->right); - break; - } - - e->pdepth--; - lineno = lno; -} - -static int -escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src) -{ - int em, em0; - - em = parsetag(note); - - if(em == EscUnknown) { - escassign(e, &e->theSink, src); - return em; - } - - if(em == EscNone) - return em; - - // If content inside parameter (reached via indirection) - // escapes back to results, mark as such. - if(em & EscContentEscapes) - escassign(e, &e->funcParam, src); - - em0 = em; - for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next) - if(em & 1) - escassign(e, dsts->n, src); - - if (em != 0 && dsts == nil) - fatal("corrupt esc tag %Z or messed up escretval list\n", note); - return em0; -} - -// This is a bit messier than fortunate, pulled out of esc's big -// switch for clarity. We either have the paramnodes, which may be -// connected to other things through flows or we have the parameter type -// nodes, which may be marked "noescape". Navigating the ast is slightly -// different for methods vs plain functions and for imported vs -// this-package -static void -esccall(EscState *e, Node *n, Node *up) -{ - NodeList *ll, *lr; - Node *a, *fn, *src; - Type *t, *fntype; - char buf[40]; - int i; - - fn = N; - switch(n->op) { - default: - fatal("esccall"); - - case OCALLFUNC: - fn = n->left; - fntype = fn->type; - break; - - case OCALLMETH: - fn = n->left->right->sym->def; - if(fn) - fntype = fn->type; - else - fntype = n->left->type; - break; - - case OCALLINTER: - fntype = n->left->type; - break; - } - - ll = n->list; - if(n->list != nil && n->list->next == nil) { - a = n->list->n; - if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()). - ll = a->escretval; - } - - if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) { - // function in same mutually recursive group. Incorporate into flow graph. -// print("esc local fn: %N\n", fn->ntype); - if(fn->defn->esc == EscFuncUnknown || n->escretval != nil) - fatal("graph inconsistency"); - - // set up out list on this call node - for(lr=fn->ntype->rlist; lr; lr=lr->next) - n->escretval = list(n->escretval, lr->n->left); // type.rlist -> dclfield -> ONAME (PPARAMOUT) - - // Receiver. - if(n->op != OCALLFUNC) - escassign(e, fn->ntype->left->left, n->left->left); - - for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) { - src = ll->n; - if(lr->n->isddd && !n->isddd) { - // Introduce ODDDARG node to represent ... allocation. - src = nod(ODDDARG, N, N); - src->type = typ(TARRAY); - src->type->type = lr->n->type->type; - src->type->bound = count(ll); - src->type = ptrto(src->type); // make pointer so it will be tracked - src->escloopdepth = e->loopdepth; - src->lineno = n->lineno; - src->esc = EscNone; // until we find otherwise - e->noesc = list(e->noesc, src); - n->right = src; - } - if(lr->n->left != N) - escassign(e, lr->n->left, src); - if(src != ll->n) - break; - } - // "..." arguments are untracked - for(; ll; ll=ll->next) - escassign(e, &e->theSink, ll->n); - - return; - } - - // Imported or completely analyzed function. Use the escape tags. - if(n->escretval != nil) - fatal("esc already decorated call %+N\n", n); - - // set up out list on this call node with dummy auto ONAMES in the current (calling) function. - i = 0; - for(t=getoutargx(fntype)->type; t; t=t->down) { - src = nod(ONAME, N, N); - snprint(buf, sizeof buf, ".dum%d", i++); - src->sym = lookup(buf); - src->type = t->type; - src->class = PAUTO; - src->curfn = curfn; - src->escloopdepth = e->loopdepth; - src->used = 1; - src->lineno = n->lineno; - n->escretval = list(n->escretval, src); - } - -// print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval); - - // Receiver. - if(n->op != OCALLFUNC) { - t = getthisx(fntype)->type; - src = n->left->left; - if(haspointers(t->type)) - escassignfromtag(e, t->note, n->escretval, src); - } - - for(t=getinargx(fntype)->type; ll; ll=ll->next) { - src = ll->n; - if(t->isddd && !n->isddd) { - // Introduce ODDDARG node to represent ... allocation. - src = nod(ODDDARG, N, N); - src->escloopdepth = e->loopdepth; - src->lineno = n->lineno; - src->type = typ(TARRAY); - src->type->type = t->type->type; - src->type->bound = count(ll); - src->type = ptrto(src->type); // make pointer so it will be tracked - src->esc = EscNone; // until we find otherwise - e->noesc = list(e->noesc, src); - n->right = src; - } - if(haspointers(t->type)) { - if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) { - a = src; - while(a->op == OCONVNOP) - a = a->left; - switch(a->op) { - case OCALLPART: - case OCLOSURE: - case ODDDARG: - case OARRAYLIT: - case OPTRLIT: - case OSTRUCTLIT: - // The callee has already been analyzed, so its arguments have esc tags. - // The argument is marked as not escaping at all. - // Record that fact so that any temporary used for - // synthesizing this expression can be reclaimed when - // the function returns. - // This 'noescape' is even stronger than the usual esc == EscNone. - // src->esc == EscNone means that src does not escape the current function. - // src->noescape = 1 here means that src does not escape this statement - // in the current function. - a->noescape = 1; - break; - } - } - } - if(src != ll->n) - break; - t = t->down; - } - // "..." arguments are untracked - for(; ll; ll=ll->next) - escassign(e, &e->theSink, ll->n); -} - -// Store the link src->dst in dst, throwing out some quick wins. -static void -escflows(EscState *e, Node *dst, Node *src) -{ - if(dst == nil || src == nil || dst == src) - return; - - // Don't bother building a graph for scalars. - if(src->type && !haspointers(src->type)) - return; - - if(debug['m']>2) - print("%L::flows:: %hN <- %hN\n", lineno, dst, src); - - if(dst->escflowsrc == nil) { - e->dsts = list(e->dsts, dst); - e->dstcount++; - } - e->edgecount++; - - dst->escflowsrc = list(dst->escflowsrc, src); -} - -// Whenever we hit a reference node, the level goes up by one, and whenever -// we hit an OADDR, the level goes down by one. as long as we're on a level > 0 -// finding an OADDR just means we're following the upstream of a dereference, -// so this address doesn't leak (yet). -// If level == 0, it means the /value/ of this node can reach the root of this flood. -// so if this node is an OADDR, it's argument should be marked as escaping iff -// it's currfn/e->loopdepth are different from the flood's root. -// Once an object has been moved to the heap, all of it's upstream should be considered -// escaping to the global scope. -static void -escflood(EscState *e, Node *dst) -{ - NodeList *l; - - switch(dst->op) { - case ONAME: - case OCLOSURE: - break; - default: - return; - } - - if(debug['m']>1) - print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst, - (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S, - dst->escloopdepth); - - for(l = dst->escflowsrc; l; l=l->next) { - walkgen++; - escwalk(e, 0, dst, l->n); - } -} - -// There appear to be some loops in the escape graph, causing -// arbitrary recursion into deeper and deeper levels. -// Cut this off safely by making minLevel sticky: once you -// get that deep, you cannot go down any further but you also -// cannot go up any further. This is a conservative fix. -// Making minLevel smaller (more negative) would handle more -// complex chains of indirections followed by address-of operations, -// at the cost of repeating the traversal once for each additional -// allowed level when a loop is encountered. Using -2 suffices to -// pass all the tests we have written so far, which we assume matches -// the level of complexity we want the escape analysis code to handle. -#define MinLevel (-2) -/*c2go enum { MinLevel = -2 };*/ - -static void -escwalk(EscState *e, int level, Node *dst, Node *src) -{ - NodeList *ll; - int leaks, newlevel; - - if(src->walkgen == walkgen && src->esclevel <= level) - return; - src->walkgen = walkgen; - src->esclevel = level; - - if(debug['m']>1) - print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n", - level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src, - (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth); - - e->pdepth++; - - // Input parameter flowing to output parameter? - if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) { - if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) { - if(level == 0) { - if(debug['m']) - warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym); - if((src->esc&EscMask) != EscReturn) - src->esc = EscReturn; - src->esc |= 1<<((dst->vargen-1) + EscReturnBits); - goto recurse; - } else if(level > 0) { - if(debug['m']) - warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym); - if((src->esc&EscMask) != EscReturn) - src->esc = EscReturn; - src->esc |= EscContentEscapes; - goto recurse; - } - } - } - - // The second clause is for values pointed at by an object passed to a call - // that returns something reached via indirect from the object. - // We don't know which result it is or how many indirects, so we treat it as leaking. - leaks = level <= 0 && dst->escloopdepth < src->escloopdepth || - level < 0 && dst == &e->funcParam && haspointers(src->type); - - switch(src->op) { - case ONAME: - if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) { - src->esc = EscScope; - if(debug['m']) - warnl(src->lineno, "leaking param: %hN", src); - } - - // Treat a PPARAMREF closure variable as equivalent to the - // original variable. - if(src->class == PPARAMREF) { - if(leaks && debug['m']) - warnl(src->lineno, "leaking closure reference %hN", src); - escwalk(e, level, dst, src->closure); - } - break; - - case OPTRLIT: - case OADDR: - if(leaks) { - src->esc = EscHeap; - addrescapes(src->left); - if(debug['m']) - warnl(src->lineno, "%hN escapes to heap", src); - } - newlevel = level; - if(level > MinLevel) - newlevel--; - escwalk(e, newlevel, dst, src->left); - break; - - case OARRAYLIT: - if(isfixedarray(src->type)) - break; - // fall through - case ODDDARG: - case OMAKECHAN: - case OMAKEMAP: - case OMAKESLICE: - case OARRAYRUNESTR: - case OARRAYBYTESTR: - case OSTRARRAYRUNE: - case OSTRARRAYBYTE: - case OADDSTR: - case OMAPLIT: - case ONEW: - case OCLOSURE: - case OCALLPART: - case ORUNESTR: - if(leaks) { - src->esc = EscHeap; - if(debug['m']) - warnl(src->lineno, "%hN escapes to heap", src); - } - break; - - case ODOT: - case OSLICE: - case OSLICEARR: - case OSLICE3: - case OSLICE3ARR: - case OSLICESTR: - escwalk(e, level, dst, src->left); - break; - - case OINDEX: - if(isfixedarray(src->left->type)) { - escwalk(e, level, dst, src->left); - break; - } - // fall through - case ODOTPTR: - case OINDEXMAP: - case OIND: - newlevel = level; - if(level > MinLevel) - newlevel++; - escwalk(e, newlevel, dst, src->left); - } - -recurse: - for(ll=src->escflowsrc; ll; ll=ll->next) - escwalk(e, level, dst, ll->n); - - e->pdepth--; -} - -static void -esctag(EscState *e, Node *func) -{ - Node *savefn; - NodeList *ll; - Type *t; - - USED(e); - func->esc = EscFuncTagged; - - // External functions are assumed unsafe, - // unless //go:noescape is given before the declaration. - if(func->nbody == nil) { - if(func->noescape) { - for(t=getinargx(func->type)->type; t; t=t->down) - if(haspointers(t->type)) - t->note = mktag(EscNone); - } - return; - } - - savefn = curfn; - curfn = func; - - for(ll=curfn->dcl; ll; ll=ll->next) { - if(ll->n->op != ONAME || ll->n->class != PPARAM) - continue; - - switch (ll->n->esc&EscMask) { - case EscNone: // not touched by escflood - case EscReturn: - if(haspointers(ll->n->type)) // don't bother tagging for scalars - ll->n->paramfld->note = mktag(ll->n->esc); - break; - case EscHeap: // touched by escflood, moved to heap - case EscScope: // touched by escflood, value leaves scope - break; - } - } - - curfn = savefn; -} diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c deleted file mode 100644 index 91f4957dc2..0000000000 --- a/src/cmd/gc/export.c +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "y.tab.h" - -static NodeList *asmlist; - -static void dumpexporttype(Type *t); - -// Mark n's symbol as exported -void -exportsym(Node *n) -{ - if(n == N || n->sym == S) - return; - if(n->sym->flags & (SymExport|SymPackage)) { - if(n->sym->flags & SymPackage) - yyerror("export/package mismatch: %S", n->sym); - return; - } - n->sym->flags |= SymExport; - - if(debug['E']) - print("export symbol %S\n", n->sym); - exportlist = list(exportlist, n); -} - -int -exportname(char *s) -{ - Rune r; - - if((uchar)s[0] < Runeself) - return 'A' <= s[0] && s[0] <= 'Z'; - chartorune(&r, s); - return isupperrune(r); -} - -static int -initname(char *s) -{ - return strcmp(s, "init") == 0; -} - -// exportedsym reports whether a symbol will be visible -// to files that import our package. -static int -exportedsym(Sym *sym) -{ - // Builtins are visible everywhere. - if(sym->pkg == builtinpkg || sym->origpkg == builtinpkg) - return 1; - - return sym->pkg == localpkg && exportname(sym->name); -} - -void -autoexport(Node *n, int ctxt) -{ - if(n == N || n->sym == S) - return; - if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN) - return; - if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left) // method - return; - // -A is for cmd/gc/mkbuiltin script, so export everything - if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name)) - exportsym(n); - if(asmhdr && n->sym->pkg == localpkg && !(n->sym->flags & SymAsm)) { - n->sym->flags |= SymAsm; - asmlist = list(asmlist, n); - } - -} - -static void -dumppkg(Pkg *p) -{ - char *suffix; - - if(p == nil || p == localpkg || p->exported || p == builtinpkg) - return; - p->exported = 1; - suffix = ""; - if(!p->direct) - suffix = " // indirect"; - Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix); -} - -// Look for anything we need for the inline body -static void reexportdep(Node *n); -static void -reexportdeplist(NodeList *ll) -{ - for(; ll ;ll=ll->next) - reexportdep(ll->n); -} - -static void -reexportdep(Node *n) -{ - Type *t; - - if(!n) - return; - - //print("reexportdep %+hN\n", n); - switch(n->op) { - case ONAME: - switch(n->class&~PHEAP) { - case PFUNC: - // methods will be printed along with their type - // nodes for T.Method expressions - if(n->left && n->left->op == OTYPE) - break; - // nodes for method calls. - if(!n->type || n->type->thistuple > 0) - break; - // fallthrough - case PEXTERN: - if(n->sym && !exportedsym(n->sym)) { - if(debug['E']) - print("reexport name %S\n", n->sym); - exportlist = list(exportlist, n); - } - } - break; - - case ODCL: - // Local variables in the bodies need their type. - t = n->left->type; - if(t != types[t->etype] && t != idealbool && t != idealstring) { - if(isptr[t->etype]) - t = t->type; - if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { - if(debug['E']) - print("reexport type %S from declaration\n", t->sym); - exportlist = list(exportlist, t->sym->def); - } - } - break; - - case OLITERAL: - t = n->type; - if(t != types[n->type->etype] && t != idealbool && t != idealstring) { - if(isptr[t->etype]) - t = t->type; - if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { - if(debug['E']) - print("reexport literal type %S\n", t->sym); - exportlist = list(exportlist, t->sym->def); - } - } - // fallthrough - case OTYPE: - if(n->sym && !exportedsym(n->sym)) { - if(debug['E']) - print("reexport literal/type %S\n", n->sym); - exportlist = list(exportlist, n); - } - break; - - // for operations that need a type when rendered, put the type on the export list. - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case ORUNESTR: - case OARRAYBYTESTR: - case OARRAYRUNESTR: - case OSTRARRAYBYTE: - case OSTRARRAYRUNE: - case ODOTTYPE: - case ODOTTYPE2: - case OSTRUCTLIT: - case OARRAYLIT: - case OPTRLIT: - case OMAKEMAP: - case OMAKESLICE: - case OMAKECHAN: - t = n->type; - if(!t->sym && t->type) - t = t->type; - if(t && t->sym && t->sym->def && !exportedsym(t->sym)) { - if(debug['E']) - print("reexport type for expression %S\n", t->sym); - exportlist = list(exportlist, t->sym->def); - } - break; - } - - reexportdep(n->left); - reexportdep(n->right); - reexportdeplist(n->list); - reexportdeplist(n->rlist); - reexportdeplist(n->ninit); - reexportdep(n->ntest); - reexportdep(n->nincr); - reexportdeplist(n->nbody); - reexportdeplist(n->nelse); -} - - -static void -dumpexportconst(Sym *s) -{ - Node *n; - Type *t; - - n = s->def; - typecheck(&n, Erv); - if(n == N || n->op != OLITERAL) - fatal("dumpexportconst: oconst nil: %S", s); - - t = n->type; // may or may not be specified - dumpexporttype(t); - - if(t != T && !isideal(t)) - Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val); - else - Bprint(bout, "\tconst %#S = %#V\n", s, &n->val); -} - -static void -dumpexportvar(Sym *s) -{ - Node *n; - Type *t; - - n = s->def; - typecheck(&n, Erv|Ecall); - if(n == N || n->type == T) { - yyerror("variable exported but not defined: %S", s); - return; - } - - t = n->type; - dumpexporttype(t); - - if(t->etype == TFUNC && n->class == PFUNC) { - if (n->inl) { - // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. - // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package - if(debug['l'] < 2) - typecheckinl(n); - // NOTE: The space after %#S here is necessary for ld's export data parser. - Bprint(bout, "\tfunc %#S %#hT { %#H }\n", s, t, n->inl); - reexportdeplist(n->inl); - } else - Bprint(bout, "\tfunc %#S %#hT\n", s, t); - } else - Bprint(bout, "\tvar %#S %#T\n", s, t); -} - -static int -methodbyname(const void *va, const void *vb) -{ - Type *a, *b; - - a = *(Type**)va; - b = *(Type**)vb; - return strcmp(a->sym->name, b->sym->name); -} - -static void -dumpexporttype(Type *t) -{ - Type *f; - Type **m; - int i, n; - - if(t == T) - return; - if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype) - return; - t->printed = 1; - - if(t->sym != S && t->etype != TFIELD) - dumppkg(t->sym->pkg); - - dumpexporttype(t->type); - dumpexporttype(t->down); - - if (t->sym == S || t->etype == TFIELD) - return; - - n = 0; - for(f=t->method; f!=T; f=f->down) { - dumpexporttype(f); - n++; - } - - m = mal(n*sizeof m[0]); - i = 0; - for(f=t->method; f!=T; f=f->down) - m[i++] = f; - qsort(m, n, sizeof m[0], methodbyname); - - Bprint(bout, "\ttype %#S %#lT\n", t->sym, t); - for(i=0; inointerface) - Bprint(bout, "\t//go:nointerface\n"); - if (f->type->nname && f->type->nname->inl) { // nname was set by caninl - // when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet. - // currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package - if(debug['l'] < 2) - typecheckinl(f->type->nname); - Bprint(bout, "\tfunc (%#T) %#hhS %#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl); - reexportdeplist(f->type->nname->inl); - } else - Bprint(bout, "\tfunc (%#T) %#hhS %#hT\n", getthisx(f->type)->type, f->sym, f->type); - } -} - -static void -dumpsym(Sym *s) -{ - if(s->flags & SymExported) - return; - s->flags |= SymExported; - - if(s->def == N) { - yyerror("unknown export symbol: %S", s); - return; - } -// print("dumpsym %O %+S\n", s->def->op, s); - dumppkg(s->pkg); - - switch(s->def->op) { - default: - yyerror("unexpected export symbol: %O %S", s->def->op, s); - break; - - case OLITERAL: - dumpexportconst(s); - break; - - case OTYPE: - if(s->def->type->etype == TFORW) - yyerror("export of incomplete type %S", s); - else - dumpexporttype(s->def->type); - break; - - case ONAME: - dumpexportvar(s); - break; - } -} - -void -dumpexport(void) -{ - NodeList *l; - int32 i, lno; - Pkg *p; - - lno = lineno; - - Bprint(bout, "\n$$\npackage %s", localpkg->name); - if(safemode) - Bprint(bout, " safe"); - Bprint(bout, "\n"); - - for(i=0; ilink) - if(p->direct) - dumppkg(p); - - for(l=exportlist; l; l=l->next) { - lineno = l->n->lineno; - dumpsym(l->n->sym); - } - - Bprint(bout, "\n$$\n"); - lineno = lno; -} - -/* - * import - */ - -/* - * return the sym for ss, which should match lexical - */ -Sym* -importsym(Sym *s, int op) -{ - char *pkgstr; - - if(s->def != N && s->def->op != op) { - pkgstr = smprint("during import \"%Z\"", importpkg->path); - redeclare(s, pkgstr); - } - - // mark the symbol so it is not reexported - if(s->def == N) { - if(exportname(s->name) || initname(s->name)) - s->flags |= SymExport; - else - s->flags |= SymPackage; // package scope - } - return s; -} - -/* - * return the type pkg.name, forward declaring if needed - */ -Type* -pkgtype(Sym *s) -{ - Type *t; - - importsym(s, OTYPE); - if(s->def == N || s->def->op != OTYPE) { - t = typ(TFORW); - t->sym = s; - s->def = typenod(t); - } - if(s->def->type == T) - yyerror("pkgtype %S", s); - return s->def->type; -} - -void -importimport(Sym *s, Strlit *z) -{ - // Informational: record package name - // associated with import path, for use in - // human-readable messages. - Pkg *p; - - if(isbadimport(z)) - errorexit(); - p = mkpkg(z); - if(p->name == nil) { - p->name = s->name; - pkglookup(s->name, nil)->npkg++; - } else if(strcmp(p->name, s->name) != 0) - yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path); - - if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) { - yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z); - errorexit(); - } -} - -void -importconst(Sym *s, Type *t, Node *n) -{ - Node *n1; - - importsym(s, OLITERAL); - convlit(&n, t); - - if(s->def != N) // TODO: check if already the same. - return; - - if(n->op != OLITERAL) { - yyerror("expression must be a constant"); - return; - } - - if(n->sym != S) { - n1 = nod(OXXX, N, N); - *n1 = *n; - n = n1; - } - n->orig = newname(s); - n->sym = s; - declare(n, PEXTERN); - - if(debug['E']) - print("import const %S\n", s); -} - -void -importvar(Sym *s, Type *t) -{ - Node *n; - - importsym(s, ONAME); - if(s->def != N && s->def->op == ONAME) { - if(eqtype(t, s->def->type)) - return; - yyerror("inconsistent definition for var %S during import\n\t%T (in \"%Z\")\n\t%T (in \"%Z\")", s, s->def->type, s->importdef->path, t, importpkg->path); - } - n = newname(s); - s->importdef = importpkg; - n->type = t; - declare(n, PEXTERN); - - if(debug['E']) - print("import var %S %lT\n", s, t); -} - -void -importtype(Type *pt, Type *t) -{ - Node *n; - - // override declaration in unsafe.go for Pointer. - // there is no way in Go code to define unsafe.Pointer - // so we have to supply it. - if(incannedimport && - strcmp(importpkg->name, "unsafe") == 0 && - strcmp(pt->nod->sym->name, "Pointer") == 0) { - t = types[TUNSAFEPTR]; - } - - if(pt->etype == TFORW) { - n = pt->nod; - copytype(pt->nod, t); - pt->nod = n; // unzero nod - pt->sym->importdef = importpkg; - pt->sym->lastlineno = parserline(); - declare(n, PEXTERN); - checkwidth(pt); - } else if(!eqtype(pt->orig, t)) - yyerror("inconsistent definition for type %S during import\n\t%lT (in \"%Z\")\n\t%lT (in \"%Z\")", pt->sym, pt, pt->sym->importdef->path, t, importpkg->path); - - if(debug['E']) - print("import type %T %lT\n", pt, t); -} - -void -dumpasmhdr(void) -{ - Biobuf *b; - NodeList *l; - Node *n; - Type *t; - - b = Bopen(asmhdr, OWRITE); - if(b == nil) - fatal("open %s: %r", asmhdr); - Bprint(b, "// generated by %cg -asmhdr from package %s\n\n", thearch.thechar, localpkg->name); - for(l=asmlist; l; l=l->next) { - n = l->n; - if(isblanksym(n->sym)) - continue; - switch(n->op) { - case OLITERAL: - Bprint(b, "#define const_%s %#V\n", n->sym->name, &n->val); - break; - case OTYPE: - t = n->type; - if(t->etype != TSTRUCT || t->map != T || t->funarg) - break; - Bprint(b, "#define %s__size %d\n", t->sym->name, (int)t->width); - for(t=t->type; t != T; t=t->down) - if(!isblanksym(t->sym)) - Bprint(b, "#define %s_%s %d\n", n->sym->name, t->sym->name, (int)t->width); - break; - } - } - - Bterm(b); -} diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c deleted file mode 100644 index bd0a29f6e1..0000000000 --- a/src/cmd/gc/fmt.c +++ /dev/null @@ -1,1697 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "opnames.h" - -// -// Format conversions -// %L int Line numbers -// -// %E int etype values (aka 'Kind') -// -// %O int Node Opcodes -// Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg) -// -// %J Node* Node details -// Flags: "%hJ" suppresses things not relevant until walk. -// -// %V Val* Constant values -// -// %S Sym* Symbols -// Flags: +,- #: mode (see below) -// "%hS" unqualified identifier in any mode -// "%hhS" in export mode: unqualified identifier if exported, qualified if not -// -// %T Type* Types -// Flags: +,- #: mode (see below) -// 'l' definition instead of name. -// 'h' omit "func" and receiver in function types -// 'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix. -// -// %N Node* Nodes -// Flags: +,- #: mode (see below) -// 'h' (only in +/debug mode) suppress recursion -// 'l' (only in Error mode) print "foo (type Bar)" -// -// %H NodeList* NodeLists -// Flags: those of %N -// ',' separate items with ',' instead of ';' -// -// %Z Strlit* String literals -// -// In mparith1.c: -// %B Mpint* Big integers -// %F Mpflt* Big floats -// -// %S, %T and %N obey use the following flags to set the format mode: -enum { - FErr, // error mode (default) - FDbg, // "%+N" debug mode - FExp, // "%#N" export mode - FTypeId, // "%-N" turning-types-into-symbols-mode: identical types give identical strings -}; -static int fmtmode; -static int fmtpkgpfx; // %uT stickyness -// -// E.g. for %S: %+S %#S %-S print an identifier properly qualified for debug/export/internal mode. -// -// The mode flags +, - and # are sticky, meaning they persist through -// recursions of %N, %T and %S, but not the h and l flags. The u flag is -// sticky only on %T recursions and only used in %-/Sym mode. - -// -// Useful format combinations: -// -// %+N %+H multiline recursive debug dump of node/nodelist -// %+hN %+hH non recursive debug dump -// -// %#N %#T export format -// %#lT type definition instead of name -// %#hT omit"func" and receiver in function signature -// -// %lN "foo (type Bar)" for error messages -// -// %-T type identifiers -// %-hT type identifiers without "func" and arg names in type signatures (methodsym) -// %-uT type identifiers with package name instead of prefix (typesym, dcommontype, typehash) -// - - -static int -setfmode(unsigned long *flags) -{ - int fm; - - fm = fmtmode; - if(*flags & FmtSign) - fmtmode = FDbg; - else if(*flags & FmtSharp) - fmtmode = FExp; - else if(*flags & FmtLeft) - fmtmode = FTypeId; - - *flags &= ~(FmtSharp|FmtLeft|FmtSign); - return fm; -} - -// Fmt "%L": Linenumbers -static int -Lconv(Fmt *fp) -{ - return linklinefmt(ctxt, fp); -} - -static char* -goopnames[] = -{ - [OADDR] = "&", - [OADD] = "+", - [OADDSTR] = "+", - [OANDAND] = "&&", - [OANDNOT] = "&^", - [OAND] = "&", - [OAPPEND] = "append", - [OAS] = "=", - [OAS2] = "=", - [OBREAK] = "break", - [OCALL] = "function call", // not actual syntax - [OCAP] = "cap", - [OCASE] = "case", - [OCLOSE] = "close", - [OCOMPLEX] = "complex", - [OCOM] = "^", - [OCONTINUE] = "continue", - [OCOPY] = "copy", - [ODEC] = "--", - [ODELETE] = "delete", - [ODEFER] = "defer", - [ODIV] = "/", - [OEQ] = "==", - [OFALL] = "fallthrough", - [OFOR] = "for", - [OGE] = ">=", - [OGOTO] = "goto", - [OGT] = ">", - [OIF] = "if", - [OIMAG] = "imag", - [OINC] = "++", - [OIND] = "*", - [OLEN] = "len", - [OLE] = "<=", - [OLSH] = "<<", - [OLT] = "<", - [OMAKE] = "make", - [OMINUS] = "-", - [OMOD] = "%", - [OMUL] = "*", - [ONEW] = "new", - [ONE] = "!=", - [ONOT] = "!", - [OOROR] = "||", - [OOR] = "|", - [OPANIC] = "panic", - [OPLUS] = "+", - [OPRINTN] = "println", - [OPRINT] = "print", - [ORANGE] = "range", - [OREAL] = "real", - [ORECV] = "<-", - [ORECOVER] = "recover", - [ORETURN] = "return", - [ORSH] = ">>", - [OSELECT] = "select", - [OSEND] = "<-", - [OSUB] = "-", - [OSWITCH] = "switch", - [OXOR] = "^", -}; - -// Fmt "%O": Node opcodes -int -Oconv(Fmt *fp) -{ - int o; - - o = va_arg(fp->args, int); - if((fp->flags & FmtSharp) || fmtmode != FDbg) - if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil) - return fmtstrcpy(fp, goopnames[o]); - - if(o >= 0 && o < nelem(opnames) && opnames[o] != nil) - return fmtstrcpy(fp, opnames[o]); - - return fmtprint(fp, "O-%d", o); -} - -static const char* classnames[] = { - "Pxxx", - "PEXTERN", - "PAUTO", - "PPARAM", - "PPARAMOUT", - "PPARAMREF", - "PFUNC", -}; - -// Fmt "%J": Node details. -static int -Jconv(Fmt *fp) -{ - Node *n; - char *s; - int c; - - n = va_arg(fp->args, Node*); - - c = fp->flags&FmtShort; - - if(!c && n->ullman != 0) - fmtprint(fp, " u(%d)", n->ullman); - - if(!c && n->addable != 0) - fmtprint(fp, " a(%d)", n->addable); - - if(!c && n->vargen != 0) - fmtprint(fp, " g(%d)", n->vargen); - - if(n->lineno != 0) - fmtprint(fp, " l(%d)", n->lineno); - - if(!c && n->xoffset != BADWIDTH) - fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta); - - if(n->class != 0) { - s = ""; - if(n->class & PHEAP) s = ",heap"; - if((n->class & ~PHEAP) < nelem(classnames)) - fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s); - else - fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s); - } - - if(n->colas != 0) - fmtprint(fp, " colas(%d)", n->colas); - - if(n->funcdepth != 0) - fmtprint(fp, " f(%d)", n->funcdepth); - - switch(n->esc) { - case EscUnknown: - break; - case EscHeap: - fmtprint(fp, " esc(h)"); - break; - case EscScope: - fmtprint(fp, " esc(s)"); - break; - case EscNone: - fmtprint(fp, " esc(no)"); - break; - case EscNever: - if(!c) - fmtprint(fp, " esc(N)"); - break; - default: - fmtprint(fp, " esc(%d)", n->esc); - break; - } - - if(n->escloopdepth) - fmtprint(fp, " ld(%d)", n->escloopdepth); - - if(!c && n->typecheck != 0) - fmtprint(fp, " tc(%d)", n->typecheck); - - if(!c && n->dodata != 0) - fmtprint(fp, " dd(%d)", n->dodata); - - if(n->isddd != 0) - fmtprint(fp, " isddd(%d)", n->isddd); - - if(n->implicit != 0) - fmtprint(fp, " implicit(%d)", n->implicit); - - if(n->embedded != 0) - fmtprint(fp, " embedded(%d)", n->embedded); - - if(n->addrtaken != 0) - fmtprint(fp, " addrtaken"); - - if(n->assigned != 0) - fmtprint(fp, " assigned"); - - if(!c && n->used != 0) - fmtprint(fp, " used(%d)", n->used); - return 0; -} - -// Fmt "%V": Values -static int -Vconv(Fmt *fp) -{ - Val *v; - vlong x; - - v = va_arg(fp->args, Val*); - - switch(v->ctype) { - case CTINT: - if((fp->flags & FmtSharp) || fmtmode == FExp) - return fmtprint(fp, "%#B", v->u.xval); - return fmtprint(fp, "%B", v->u.xval); - case CTRUNE: - x = mpgetfix(v->u.xval); - if(' ' <= x && x < 0x80 && x != '\\' && x != '\'') - return fmtprint(fp, "'%c'", (int)x); - if(0 <= x && x < (1<<16)) - return fmtprint(fp, "'\\u%04ux'", (int)x); - if(0 <= x && x <= Runemax) - return fmtprint(fp, "'\\U%08llux'", x); - return fmtprint(fp, "('\\x00' + %B)", v->u.xval); - case CTFLT: - if((fp->flags & FmtSharp) || fmtmode == FExp) - return fmtprint(fp, "%F", v->u.fval); - return fmtprint(fp, "%#F", v->u.fval); - case CTCPLX: - if((fp->flags & FmtSharp) || fmtmode == FExp) - return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag); - if(mpcmpfltc(&v->u.cval->real, 0) == 0) - return fmtprint(fp, "%#Fi", &v->u.cval->imag); - if(mpcmpfltc(&v->u.cval->imag, 0) == 0) - return fmtprint(fp, "%#F", &v->u.cval->real); - if(mpcmpfltc(&v->u.cval->imag, 0) < 0) - return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag); - return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag); - case CTSTR: - return fmtprint(fp, "\"%Z\"", v->u.sval); - case CTBOOL: - if( v->u.bval) - return fmtstrcpy(fp, "true"); - return fmtstrcpy(fp, "false"); - case CTNIL: - return fmtstrcpy(fp, "nil"); - } - return fmtprint(fp, "", v->ctype); -} - -// Fmt "%Z": escaped string literals -static int -Zconv(Fmt *fp) -{ - Rune r; - Strlit *sp; - char *s, *se; - int n; - - sp = va_arg(fp->args, Strlit*); - if(sp == nil) - return fmtstrcpy(fp, ""); - - s = sp->s; - se = s + sp->len; - - // NOTE: Keep in sync with ../ld/go.c:/^Zconv. - while(s < se) { - n = chartorune(&r, s); - s += n; - switch(r) { - case Runeerror: - if(n == 1) { - fmtprint(fp, "\\x%02x", (uchar)*(s-1)); - break; - } - // fall through - default: - if(r < ' ') { - fmtprint(fp, "\\x%02x", r); - break; - } - fmtrune(fp, r); - break; - case '\t': - fmtstrcpy(fp, "\\t"); - break; - case '\n': - fmtstrcpy(fp, "\\n"); - break; - case '\"': - case '\\': - fmtrune(fp, '\\'); - fmtrune(fp, r); - break; - case 0xFEFF: // BOM, basically disallowed in source code - fmtstrcpy(fp, "\\uFEFF"); - break; - } - } - return 0; -} - -/* -s%,%,\n%g -s%\n+%\n%g -s%^[ ]*T%%g -s%,.*%%g -s%.+% [T&] = "&",%g -s%^ ........*\]%&~%g -s%~ %%g -*/ - -static char* -etnames[] = -{ - [TINT] = "INT", - [TUINT] = "UINT", - [TINT8] = "INT8", - [TUINT8] = "UINT8", - [TINT16] = "INT16", - [TUINT16] = "UINT16", - [TINT32] = "INT32", - [TUINT32] = "UINT32", - [TINT64] = "INT64", - [TUINT64] = "UINT64", - [TUINTPTR] = "UINTPTR", - [TFLOAT32] = "FLOAT32", - [TFLOAT64] = "FLOAT64", - [TCOMPLEX64] = "COMPLEX64", - [TCOMPLEX128] = "COMPLEX128", - [TBOOL] = "BOOL", - [TPTR32] = "PTR32", - [TPTR64] = "PTR64", - [TFUNC] = "FUNC", - [TARRAY] = "ARRAY", - [TSTRUCT] = "STRUCT", - [TCHAN] = "CHAN", - [TMAP] = "MAP", - [TINTER] = "INTER", - [TFORW] = "FORW", - [TFIELD] = "FIELD", - [TSTRING] = "STRING", - [TANY] = "ANY", -}; - -// Fmt "%E": etype -static int -Econv(Fmt *fp) -{ - int et; - - et = va_arg(fp->args, int); - if(et >= 0 && et < nelem(etnames) && etnames[et] != nil) - return fmtstrcpy(fp, etnames[et]); - return fmtprint(fp, "E-%d", et); -} - -// Fmt "%S": syms -static int -symfmt(Fmt *fp, Sym *s) -{ - char *p; - - if(s->pkg && !(fp->flags&FmtShort)) { - switch(fmtmode) { - case FErr: // This is for the user - if(s->pkg == localpkg) - return fmtstrcpy(fp, s->name); - // If the name was used by multiple packages, display the full path, - if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1) - return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name); - return fmtprint(fp, "%s.%s", s->pkg->name, s->name); - case FDbg: - return fmtprint(fp, "%s.%s", s->pkg->name, s->name); - case FTypeId: - if(fp->flags&FmtUnsigned) - return fmtprint(fp, "%s.%s", s->pkg->name, s->name); // dcommontype, typehash - return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name); // (methodsym), typesym, weaksym - case FExp: - if(s->name && s->name[0] == '.') - fatal("exporting synthetic symbol %s", s->name); - if(s->pkg != builtinpkg) - return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name); - } - } - - if(fp->flags&FmtByte) { // FmtByte (hh) implies FmtShort (h) - // skip leading "type." in method name - p = utfrrune(s->name, '.'); - if(p) - p++; - else - p = s->name; - - // exportname needs to see the name without the prefix too. - if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg) - return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p); - - return fmtstrcpy(fp, p); - } - - return fmtstrcpy(fp, s->name); -} - -static char* -basicnames[] = -{ - [TINT] = "int", - [TUINT] = "uint", - [TINT8] = "int8", - [TUINT8] = "uint8", - [TINT16] = "int16", - [TUINT16] = "uint16", - [TINT32] = "int32", - [TUINT32] = "uint32", - [TINT64] = "int64", - [TUINT64] = "uint64", - [TUINTPTR] = "uintptr", - [TFLOAT32] = "float32", - [TFLOAT64] = "float64", - [TCOMPLEX64] = "complex64", - [TCOMPLEX128] = "complex128", - [TBOOL] = "bool", - [TANY] = "any", - [TSTRING] = "string", - [TNIL] = "nil", - [TIDEAL] = "untyped number", - [TBLANK] = "blank", -}; - -static int -typefmt(Fmt *fp, Type *t) -{ - Type *t1; - Sym *s; - - if(t == T) - return fmtstrcpy(fp, ""); - - if (t == bytetype || t == runetype) { - // in %-T mode collapse rune and byte with their originals. - if(fmtmode != FTypeId) - return fmtprint(fp, "%hS", t->sym); - t = types[t->etype]; - } - - if(t == errortype) - return fmtstrcpy(fp, "error"); - - // Unless the 'l' flag was specified, if the type has a name, just print that name. - if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) { - switch(fmtmode) { - case FTypeId: - if(fp->flags&FmtShort) { - if(t->vargen) - return fmtprint(fp, "%hS·%d", t->sym, t->vargen); - return fmtprint(fp, "%hS", t->sym); - } - if(fp->flags&FmtUnsigned) - return fmtprint(fp, "%uS", t->sym); - // fallthrough - case FExp: - if(t->sym->pkg == localpkg && t->vargen) - return fmtprint(fp, "%S·%d", t->sym, t->vargen); - break; - } - return fmtprint(fp, "%S", t->sym); - } - - if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) { - if(fmtmode == FErr && (t == idealbool || t == idealstring)) - fmtstrcpy(fp, "untyped "); - return fmtstrcpy(fp, basicnames[t->etype]); - } - - if(fmtmode == FDbg) - fmtprint(fp, "%E-", t->etype); - - switch(t->etype) { - case TPTR32: - case TPTR64: - if(fmtmode == FTypeId && (fp->flags&FmtShort)) - return fmtprint(fp, "*%hT", t->type); - return fmtprint(fp, "*%T", t->type); - - case TARRAY: - if(t->bound >= 0) - return fmtprint(fp, "[%lld]%T", t->bound, t->type); - if(t->bound == -100) - return fmtprint(fp, "[...]%T", t->type); - return fmtprint(fp, "[]%T", t->type); - - case TCHAN: - switch(t->chan) { - case Crecv: - return fmtprint(fp, "<-chan %T", t->type); - case Csend: - return fmtprint(fp, "chan<- %T", t->type); - } - - if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv) - return fmtprint(fp, "chan (%T)", t->type); - return fmtprint(fp, "chan %T", t->type); - - case TMAP: - return fmtprint(fp, "map[%T]%T", t->down, t->type); - - case TINTER: - fmtstrcpy(fp, "interface {"); - for(t1=t->type; t1!=T; t1=t1->down) - if(exportname(t1->sym->name)) { - if(t1->down) - fmtprint(fp, " %hS%hT;", t1->sym, t1->type); - else - fmtprint(fp, " %hS%hT ", t1->sym, t1->type); - } else { - // non-exported method names must be qualified - if(t1->down) - fmtprint(fp, " %uS%hT;", t1->sym, t1->type); - else - fmtprint(fp, " %uS%hT ", t1->sym, t1->type); - } - fmtstrcpy(fp, "}"); - return 0; - - case TFUNC: - if(fp->flags & FmtShort) { - fmtprint(fp, "%T", getinargx(t)); - } else { - if(t->thistuple) - fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t)); - else - fmtprint(fp, "func%T", getinargx(t)); - } - switch(t->outtuple) { - case 0: - break; - case 1: - if(fmtmode != FExp) { - fmtprint(fp, " %T", getoutargx(t)->type->type); // struct->field->field's type - break; - } - default: - fmtprint(fp, " %T", getoutargx(t)); - break; - } - return 0; - - case TSTRUCT: - // Format the bucket struct for map[x]y as map.bucket[x]y. - // This avoids a recursive print that generates very long names. - if(t->map != T) { - if(t->map->bucket == t) { - return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type); - } - if(t->map->hmap == t) { - return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type); - } - if(t->map->hiter == t) { - return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type); - } - yyerror("unknown internal map type"); - } - - if(t->funarg) { - fmtstrcpy(fp, "("); - if(fmtmode == FTypeId || fmtmode == FErr) { // no argument names on function signature, and no "noescape"/"nosplit" tags - for(t1=t->type; t1!=T; t1=t1->down) - if(t1->down) - fmtprint(fp, "%hT, ", t1); - else - fmtprint(fp, "%hT", t1); - } else { - for(t1=t->type; t1!=T; t1=t1->down) - if(t1->down) - fmtprint(fp, "%T, ", t1); - else - fmtprint(fp, "%T", t1); - } - fmtstrcpy(fp, ")"); - } else { - fmtstrcpy(fp, "struct {"); - for(t1=t->type; t1!=T; t1=t1->down) - if(t1->down) - fmtprint(fp, " %lT;", t1); - else - fmtprint(fp, " %lT ", t1); - fmtstrcpy(fp, "}"); - } - return 0; - - case TFIELD: - if(!(fp->flags&FmtShort)) { - s = t->sym; - - // Take the name from the original, lest we substituted it with ~r%d or ~b%d. - // ~r%d is a (formerly) unnamed result. - if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) { - if(t->nname->orig != N) { - s = t->nname->orig->sym; - if(s != S && s->name[0] == '~') { - if(s->name[1] == 'r') // originally an unnamed result - s = S; - else if(s->name[1] == 'b') // originally the blank identifier _ - s = lookup("_"); - } - } else - s = S; - } - - if(s != S && !t->embedded) { - if(t->funarg) - fmtprint(fp, "%N ", t->nname); - else if(fp->flags&FmtLong) - fmtprint(fp, "%hhS ", s); // qualify non-exported names (used on structs, not on funarg) - else - fmtprint(fp, "%S ", s); - } else if(fmtmode == FExp) { - // TODO(rsc) this breaks on the eliding of unused arguments in the backend - // when this is fixed, the special case in dcl.c checkarglist can go. - //if(t->funarg) - // fmtstrcpy(fp, "_ "); - //else - if(t->embedded && s->pkg != nil && s->pkg->path->len > 0) - fmtprint(fp, "@\"%Z\".? ", s->pkg->path); - else - fmtstrcpy(fp, "? "); - } - } - - if(t->isddd) - fmtprint(fp, "...%T", t->type->type); - else - fmtprint(fp, "%T", t->type); - - if(!(fp->flags&FmtShort) && t->note) - fmtprint(fp, " \"%Z\"", t->note); - return 0; - - case TFORW: - if(t->sym) - return fmtprint(fp, "undefined %S", t->sym); - return fmtstrcpy(fp, "undefined"); - - case TUNSAFEPTR: - if(fmtmode == FExp) - return fmtprint(fp, "@\"unsafe\".Pointer"); - return fmtprint(fp, "unsafe.Pointer"); - } - - if(fmtmode == FExp) - fatal("missing %E case during export", t->etype); - // Don't know how to handle - fall back to detailed prints. - return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type); -} - -// Statements which may be rendered with a simplestmt as init. -static int -stmtwithinit(int op) -{ - switch(op) { - case OIF: - case OFOR: - case OSWITCH: - return 1; - } - return 0; -} - -static int -stmtfmt(Fmt *f, Node *n) -{ - int complexinit, simpleinit, extrablock; - - // some statements allow for an init, but at most one, - // but we may have an arbitrary number added, eg by typecheck - // and inlining. If it doesn't fit the syntax, emit an enclosing - // block starting with the init statements. - - // if we can just say "for" n->ninit; ... then do so - simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op); - // otherwise, print the inits as separate statements - complexinit = n->ninit && !simpleinit && (fmtmode != FErr); - // but if it was for if/for/switch, put in an extra surrounding block to limit the scope - extrablock = complexinit && stmtwithinit(n->op); - - if(extrablock) - fmtstrcpy(f, "{"); - - if(complexinit) - fmtprint(f, " %H; ", n->ninit); - - switch(n->op){ - case ODCL: - if(fmtmode == FExp) { - switch(n->left->class&~PHEAP) { - case PPARAM: - case PPARAMOUT: - case PAUTO: - fmtprint(f, "var %N %T", n->left, n->left->type); - goto ret; - } - } - fmtprint(f, "var %S %T", n->left->sym, n->left->type); - break; - - case ODCLFIELD: - if(n->left) - fmtprint(f, "%N %N", n->left, n->right); - else - fmtprint(f, "%N", n->right); - break; - - case OAS: - // Don't export "v = " initializing statements, hope they're always - // preceded by the DCL which will be re-parsed and typecheck to reproduce - // the "v = " again. - if(fmtmode == FExp && n->right == N) - break; - - if(n->colas && !complexinit) - fmtprint(f, "%N := %N", n->left, n->right); - else - fmtprint(f, "%N = %N", n->left, n->right); - break; - - case OASOP: - if(n->implicit) { - if(n->etype == OADD) - fmtprint(f, "%N++", n->left); - else - fmtprint(f, "%N--", n->left); - break; - } - fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right); - break; - - case OAS2: - if(n->colas && !complexinit) { - fmtprint(f, "%,H := %,H", n->list, n->rlist); - break; - } - // fallthrough - case OAS2DOTTYPE: - case OAS2FUNC: - case OAS2MAPR: - case OAS2RECV: - fmtprint(f, "%,H = %,H", n->list, n->rlist); - break; - - case ORETURN: - fmtprint(f, "return %,H", n->list); - break; - - case ORETJMP: - fmtprint(f, "retjmp %S", n->sym); - break; - - case OPROC: - fmtprint(f, "go %N", n->left); - break; - - case ODEFER: - fmtprint(f, "defer %N", n->left); - break; - - case OIF: - if(simpleinit) - fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody); - else - fmtprint(f, "if %N { %H }", n->ntest, n->nbody); - if(n->nelse) - fmtprint(f, " else { %H }", n->nelse); - break; - - case OFOR: - if(fmtmode == FErr) { // TODO maybe only if FmtShort, same below - fmtstrcpy(f, "for loop"); - break; - } - - fmtstrcpy(f, "for"); - if(simpleinit) - fmtprint(f, " %N;", n->ninit->n); - else if(n->nincr) - fmtstrcpy(f, " ;"); - - if(n->ntest) - fmtprint(f, " %N", n->ntest); - - if(n->nincr) - fmtprint(f, "; %N", n->nincr); - else if(simpleinit) - fmtstrcpy(f, ";"); - - - fmtprint(f, " { %H }", n->nbody); - break; - - case ORANGE: - if(fmtmode == FErr) { - fmtstrcpy(f, "for loop"); - break; - } - - if(n->list == nil) { - fmtprint(f, "for range %N { %H }", n->right, n->nbody); - break; - } - fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody); - break; - - case OSELECT: - case OSWITCH: - if(fmtmode == FErr) { - fmtprint(f, "%O statement", n->op); - break; - } - - fmtprint(f, "%#O", n->op); - if(simpleinit) - fmtprint(f, " %N;", n->ninit->n); - if(n->ntest) - fmtprint(f, "%N", n->ntest); - - fmtprint(f, " { %H }", n->list); - break; - - case OCASE: - case OXCASE: - if(n->list) - fmtprint(f, "case %,H: %H", n->list, n->nbody); - else - fmtprint(f, "default: %H", n->nbody); - break; - - case OBREAK: - case OCONTINUE: - case OGOTO: - case OFALL: - case OXFALL: - if(n->left) - fmtprint(f, "%#O %N", n->op, n->left); - else - fmtprint(f, "%#O", n->op); - break; - - case OEMPTY: - break; - - case OLABEL: - fmtprint(f, "%N: ", n->left); - break; - - } -ret: - - if(extrablock) - fmtstrcpy(f, "}"); - - return 0; -} - - -static int opprec[] = { - [OAPPEND] = 8, - [OARRAYBYTESTR] = 8, - [OARRAYLIT] = 8, - [OARRAYRUNESTR] = 8, - [OCALLFUNC] = 8, - [OCALLINTER] = 8, - [OCALLMETH] = 8, - [OCALL] = 8, - [OCAP] = 8, - [OCLOSE] = 8, - [OCONVIFACE] = 8, - [OCONVNOP] = 8, - [OCONV] = 8, - [OCOPY] = 8, - [ODELETE] = 8, - [OLEN] = 8, - [OLITERAL] = 8, - [OMAKESLICE] = 8, - [OMAKE] = 8, - [OMAPLIT] = 8, - [ONAME] = 8, - [ONEW] = 8, - [ONONAME] = 8, - [OPACK] = 8, - [OPANIC] = 8, - [OPAREN] = 8, - [OPRINTN] = 8, - [OPRINT] = 8, - [ORUNESTR] = 8, - [OSTRARRAYBYTE] = 8, - [OSTRARRAYRUNE] = 8, - [OSTRUCTLIT] = 8, - [OTARRAY] = 8, - [OTCHAN] = 8, - [OTFUNC] = 8, - [OTINTER] = 8, - [OTMAP] = 8, - [OTSTRUCT] = 8, - - [OINDEXMAP] = 8, - [OINDEX] = 8, - [OSLICE] = 8, - [OSLICESTR] = 8, - [OSLICEARR] = 8, - [OSLICE3] = 8, - [OSLICE3ARR] = 8, - [ODOTINTER] = 8, - [ODOTMETH] = 8, - [ODOTPTR] = 8, - [ODOTTYPE2] = 8, - [ODOTTYPE] = 8, - [ODOT] = 8, - [OXDOT] = 8, - [OCALLPART] = 8, - - [OPLUS] = 7, - [ONOT] = 7, - [OCOM] = 7, - [OMINUS] = 7, - [OADDR] = 7, - [OIND] = 7, - [ORECV] = 7, - - [OMUL] = 6, - [ODIV] = 6, - [OMOD] = 6, - [OLSH] = 6, - [ORSH] = 6, - [OAND] = 6, - [OANDNOT] = 6, - - [OADD] = 5, - [OSUB] = 5, - [OOR] = 5, - [OXOR] = 5, - - [OEQ] = 4, - [OLT] = 4, - [OLE] = 4, - [OGE] = 4, - [OGT] = 4, - [ONE] = 4, - [OCMPSTR] = 4, - [OCMPIFACE] = 4, - - [OSEND] = 3, - [OANDAND] = 2, - [OOROR] = 1, - - // Statements handled by stmtfmt - [OAS] = -1, - [OAS2] = -1, - [OAS2DOTTYPE] = -1, - [OAS2FUNC] = -1, - [OAS2MAPR] = -1, - [OAS2RECV] = -1, - [OASOP] = -1, - [OBREAK] = -1, - [OCASE] = -1, - [OCONTINUE] = -1, - [ODCL] = -1, - [ODCLFIELD] = -1, - [ODEFER] = -1, - [OEMPTY] = -1, - [OFALL] = -1, - [OFOR] = -1, - [OGOTO] = -1, - [OIF] = -1, - [OLABEL] = -1, - [OPROC] = -1, - [ORANGE] = -1, - [ORETURN] = -1, - [OSELECT] = -1, - [OSWITCH] = -1, - [OXCASE] = -1, - [OXFALL] = -1, - - [OEND] = 0 -}; - -static int -exprfmt(Fmt *f, Node *n, int prec) -{ - int nprec; - int ptrlit; - NodeList *l; - - while(n && n->implicit && (n->op == OIND || n->op == OADDR)) - n = n->left; - - if(n == N) - return fmtstrcpy(f, ""); - - nprec = opprec[n->op]; - if(n->op == OTYPE && n->sym != S) - nprec = 8; - - if(prec > nprec) - return fmtprint(f, "(%N)", n); - - switch(n->op) { - case OPAREN: - return fmtprint(f, "(%N)", n->left); - - case ODDDARG: - return fmtprint(f, "... argument"); - - case OREGISTER: - return fmtprint(f, "%R", n->val.u.reg); - - case OLITERAL: // this is a bit of a mess - if(fmtmode == FErr && n->sym != S) - return fmtprint(f, "%S", n->sym); - if(n->val.ctype == CTNIL && n->orig != N && n->orig != n) - return exprfmt(f, n->orig, prec); - if(n->type != T && n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) { - // Need parens when type begins with what might - // be misinterpreted as a unary operator: * or <-. - if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv)) - return fmtprint(f, "(%T)(%V)", n->type, &n->val); - else - return fmtprint(f, "%T(%V)", n->type, &n->val); - } - return fmtprint(f, "%V", &n->val); - - case ONAME: - // Special case: name used as local variable in export. - // _ becomes ~b%d internally; print as _ for export - if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b') - return fmtprint(f, "_"); - if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0) - return fmtprint(f, "%S·%d", n->sym, n->vargen); - - // Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method, - // but for export, this should be rendered as (*pkg.T).meth. - // These nodes have the special property that they are names with a left OTYPE and a right ONAME. - if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) { - if(isptr[n->left->type->etype]) - return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym); - else - return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym); - } - //fallthrough - case OPACK: - case ONONAME: - return fmtprint(f, "%S", n->sym); - - case OTYPE: - if(n->type == T && n->sym != S) - return fmtprint(f, "%S", n->sym); - return fmtprint(f, "%T", n->type); - - case OTARRAY: - if(n->left) - return fmtprint(f, "[]%N", n->left); - return fmtprint(f, "[]%N", n->right); // happens before typecheck - - case OTMAP: - return fmtprint(f, "map[%N]%N", n->left, n->right); - - case OTCHAN: - switch(n->etype) { - case Crecv: - return fmtprint(f, "<-chan %N", n->left); - case Csend: - return fmtprint(f, "chan<- %N", n->left); - default: - if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) - return fmtprint(f, "chan (%N)", n->left); - else - return fmtprint(f, "chan %N", n->left); - } - - case OTSTRUCT: - return fmtprint(f, ""); - - case OTINTER: - return fmtprint(f, ""); - - case OTFUNC: - return fmtprint(f, ""); - - case OCLOSURE: - if(fmtmode == FErr) - return fmtstrcpy(f, "func literal"); - if(n->nbody) - return fmtprint(f, "%T { %H }", n->type, n->nbody); - return fmtprint(f, "%T { %H }", n->type, n->closure->nbody); - - case OCOMPLIT: - ptrlit = n->right != N && n->right->implicit && n->right->type && isptr[n->right->type->etype]; - if(fmtmode == FErr) { - if(n->right != N && n->right->type != T && !n->implicit) { - if(ptrlit) - return fmtprint(f, "&%T literal", n->right->type->type); - else - return fmtprint(f, "%T literal", n->right->type); - } - return fmtstrcpy(f, "composite literal"); - } - if(fmtmode == FExp && ptrlit) - // typecheck has overwritten OIND by OTYPE with pointer type. - return fmtprint(f, "(&%T{ %,H })", n->right->type->type, n->list); - return fmtprint(f, "(%N{ %,H })", n->right, n->list); - - case OPTRLIT: - if(fmtmode == FExp && n->left->implicit) - return fmtprint(f, "%N", n->left); - return fmtprint(f, "&%N", n->left); - - case OSTRUCTLIT: - if(fmtmode == FExp) { // requires special handling of field names - if(n->implicit) - fmtstrcpy(f, "{"); - else - fmtprint(f, "(%T{", n->type); - for(l=n->list; l; l=l->next) { - fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right); - - if(l->next) - fmtstrcpy(f, ","); - else - fmtstrcpy(f, " "); - } - if(!n->implicit) - return fmtstrcpy(f, "})"); - return fmtstrcpy(f, "}"); - } - // fallthrough - - case OARRAYLIT: - case OMAPLIT: - if(fmtmode == FErr) - return fmtprint(f, "%T literal", n->type); - if(fmtmode == FExp && n->implicit) - return fmtprint(f, "{ %,H }", n->list); - return fmtprint(f, "(%T{ %,H })", n->type, n->list); - - case OKEY: - if(n->left && n->right) { - if(fmtmode == FExp && n->left->type && n->left->type->etype == TFIELD) { - // requires special handling of field names - return fmtprint(f, "%hhS:%N", n->left->sym, n->right); - } else - return fmtprint(f, "%N:%N", n->left, n->right); - } - if(!n->left && n->right) - return fmtprint(f, ":%N", n->right); - if(n->left && !n->right) - return fmtprint(f, "%N:", n->left); - return fmtstrcpy(f, ":"); - - case OXDOT: - case ODOT: - case ODOTPTR: - case ODOTINTER: - case ODOTMETH: - case OCALLPART: - exprfmt(f, n->left, nprec); - if(n->right == N || n->right->sym == S) - return fmtstrcpy(f, "."); - return fmtprint(f, ".%hhS", n->right->sym); - - case ODOTTYPE: - case ODOTTYPE2: - exprfmt(f, n->left, nprec); - if(n->right != N) - return fmtprint(f, ".(%N)", n->right); - return fmtprint(f, ".(%T)", n->type); - - case OINDEX: - case OINDEXMAP: - case OSLICE: - case OSLICESTR: - case OSLICEARR: - case OSLICE3: - case OSLICE3ARR: - exprfmt(f, n->left, nprec); - return fmtprint(f, "[%N]", n->right); - - case OCOPY: - case OCOMPLEX: - return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right); - - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case OARRAYBYTESTR: - case OARRAYRUNESTR: - case OSTRARRAYBYTE: - case OSTRARRAYRUNE: - case ORUNESTR: - if(n->type == T || n->type->sym == S) - return fmtprint(f, "(%T)(%N)", n->type, n->left); - if(n->left) - return fmtprint(f, "%T(%N)", n->type, n->left); - return fmtprint(f, "%T(%,H)", n->type, n->list); - - case OREAL: - case OIMAG: - case OAPPEND: - case OCAP: - case OCLOSE: - case ODELETE: - case OLEN: - case OMAKE: - case ONEW: - case OPANIC: - case ORECOVER: - case OPRINT: - case OPRINTN: - if(n->left) - return fmtprint(f, "%#O(%N)", n->op, n->left); - if(n->isddd) - return fmtprint(f, "%#O(%,H...)", n->op, n->list); - return fmtprint(f, "%#O(%,H)", n->op, n->list); - - case OCALL: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - exprfmt(f, n->left, nprec); - if(n->isddd) - return fmtprint(f, "(%,H...)", n->list); - return fmtprint(f, "(%,H)", n->list); - - case OMAKEMAP: - case OMAKECHAN: - case OMAKESLICE: - if(n->list) // pre-typecheck - return fmtprint(f, "make(%T, %,H)", n->type, n->list); - if(n->right) - return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right); - if(n->left) - return fmtprint(f, "make(%T, %N)", n->type, n->left); - return fmtprint(f, "make(%T)", n->type); - - // Unary - case OPLUS: - case OMINUS: - case OADDR: - case OCOM: - case OIND: - case ONOT: - case ORECV: - if(n->left->op == n->op) - fmtprint(f, "%#O ", n->op); - else - fmtprint(f, "%#O", n->op); - return exprfmt(f, n->left, nprec+1); - - // Binary - case OADD: - case OAND: - case OANDAND: - case OANDNOT: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLT: - case OLSH: - case OMOD: - case OMUL: - case ONE: - case OOR: - case OOROR: - case ORSH: - case OSEND: - case OSUB: - case OXOR: - exprfmt(f, n->left, nprec); - fmtprint(f, " %#O ", n->op); - exprfmt(f, n->right, nprec+1); - return 0; - - case OADDSTR: - for(l=n->list; l; l=l->next) { - if(l != n->list) - fmtprint(f, " + "); - exprfmt(f, l->n, nprec); - } - return 0; - - case OCMPSTR: - case OCMPIFACE: - exprfmt(f, n->left, nprec); - fmtprint(f, " %#O ", n->etype); - exprfmt(f, n->right, nprec+1); - return 0; - } - - return fmtprint(f, "", n->op); -} - -static int -nodefmt(Fmt *f, Node *n) -{ - Type *t; - - t = n->type; - - // we almost always want the original, except in export mode for literals - // this saves the importer some work, and avoids us having to redo some - // special casing for package unsafe - if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N) - n = n->orig; - - if(f->flags&FmtLong && t != T) { - if(t->etype == TNIL) - return fmtprint(f, "nil"); - else - return fmtprint(f, "%N (type %T)", n, t); - } - - // TODO inlining produces expressions with ninits. we can't print these yet. - - if(opprec[n->op] < 0) - return stmtfmt(f, n); - - return exprfmt(f, n, 0); -} - -static int dumpdepth; - -static void -indent(Fmt *fp) -{ - int i; - - fmtstrcpy(fp, "\n"); - for(i = 0; i < dumpdepth; ++i) - fmtstrcpy(fp, ". "); -} - -static int -nodedump(Fmt *fp, Node *n) -{ - int recur; - - if(n == N) - return 0; - - recur = !(fp->flags&FmtShort); - - if(recur) { - indent(fp); - if(dumpdepth > 10) - return fmtstrcpy(fp, "..."); - - if(n->ninit != nil) { - fmtprint(fp, "%O-init%H", n->op, n->ninit); - indent(fp); - } - } - -// fmtprint(fp, "[%p]", n); - - switch(n->op) { - default: - fmtprint(fp, "%O%J", n->op, n); - break; - case OREGISTER: - case OINDREG: - fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n); - break; - case OLITERAL: - fmtprint(fp, "%O-%V%J", n->op, &n->val, n); - break; - case ONAME: - case ONONAME: - if(n->sym != S) - fmtprint(fp, "%O-%S%J", n->op, n->sym, n); - else - fmtprint(fp, "%O%J", n->op, n); - if(recur && n->type == T && n->ntype) { - indent(fp); - fmtprint(fp, "%O-ntype%N", n->op, n->ntype); - } - break; - case OASOP: - fmtprint(fp, "%O-%O%J", n->op, n->etype, n); - break; - case OTYPE: - fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type); - if(recur && n->type == T && n->ntype) { - indent(fp); - fmtprint(fp, "%O-ntype%N", n->op, n->ntype); - } - break; - } - - if(n->sym != S && n->op != ONAME) - fmtprint(fp, " %S G%d", n->sym, n->vargen); - - if(n->type != T) - fmtprint(fp, " %T", n->type); - - if(recur) { - if(n->left) - fmtprint(fp, "%N", n->left); - if(n->right) - fmtprint(fp, "%N", n->right); - if(n->list) { - indent(fp); - fmtprint(fp, "%O-list%H", n->op, n->list); - } - if(n->rlist) { - indent(fp); - fmtprint(fp, "%O-rlist%H", n->op, n->rlist); - } - if(n->ntest) { - indent(fp); - fmtprint(fp, "%O-test%N", n->op, n->ntest); - } - if(n->nbody) { - indent(fp); - fmtprint(fp, "%O-body%H", n->op, n->nbody); - } - if(n->nelse) { - indent(fp); - fmtprint(fp, "%O-else%H", n->op, n->nelse); - } - if(n->nincr) { - indent(fp); - fmtprint(fp, "%O-incr%N", n->op, n->nincr); - } - } - - return 0; -} - -// Fmt "%S": syms -// Flags: "%hS" suppresses qualifying with package -static int -Sconv(Fmt *fp) -{ - Sym *s; - int r, sm; - unsigned long sf; - - if(fp->flags&FmtLong) - return linksymfmt(fp); - - s = va_arg(fp->args, Sym*); - if(s == S) - return fmtstrcpy(fp, ""); - - if(s->name && s->name[0] == '_' && s->name[1] == '\0') - return fmtstrcpy(fp, "_"); - - sf = fp->flags; - sm = setfmode(&fp->flags); - r = symfmt(fp, s); - fp->flags = sf; - fmtmode = sm; - return r; -} - -// Fmt "%T": types. -// Flags: 'l' print definition, not name -// 'h' omit 'func' and receiver from function types, short type names -// 'u' package name, not prefix (FTypeId mode, sticky) -int -Tconv(Fmt *fp) -{ - Type *t; - int r, sm; - unsigned long sf; - - t = va_arg(fp->args, Type*); - if(t == T) - return fmtstrcpy(fp, ""); - - if(t->trecur > 4) - return fmtstrcpy(fp, "<...>"); - - t->trecur++; - sf = fp->flags; - sm = setfmode(&fp->flags); - - if(fmtmode == FTypeId && (sf&FmtUnsigned)) - fmtpkgpfx++; - if(fmtpkgpfx) - fp->flags |= FmtUnsigned; - - r = typefmt(fp, t); - - if(fmtmode == FTypeId && (sf&FmtUnsigned)) - fmtpkgpfx--; - - fp->flags = sf; - fmtmode = sm; - t->trecur--; - return r; -} - -// Fmt '%N': Nodes. -// Flags: 'l' suffix with "(type %T)" where possible -// '+h' in debug mode, don't recurse, no multiline output -static int -Nconv(Fmt *fp) -{ - Node *n; - int r, sm; - unsigned long sf; - - n = va_arg(fp->args, Node*); - if(n == N) - return fmtstrcpy(fp, ""); - sf = fp->flags; - sm = setfmode(&fp->flags); - - r = -1; - switch(fmtmode) { - case FErr: - case FExp: - r = nodefmt(fp, n); - break; - case FDbg: - dumpdepth++; - r = nodedump(fp, n); - dumpdepth--; - break; - default: - fatal("unhandled %%N mode"); - } - - fp->flags = sf; - fmtmode = sm; - return r; -} - -// Fmt '%H': NodeList. -// Flags: all those of %N plus ',': separate with comma's instead of semicolons. -static int -Hconv(Fmt *fp) -{ - NodeList *l; - int r, sm; - unsigned long sf; - char *sep; - - l = va_arg(fp->args, NodeList*); - - if(l == nil && fmtmode == FDbg) - return fmtstrcpy(fp, ""); - - sf = fp->flags; - sm = setfmode(&fp->flags); - r = 0; - sep = "; "; - if(fmtmode == FDbg) - sep = "\n"; - else if(fp->flags & FmtComma) - sep = ", "; - - for(;l; l=l->next) { - r += fmtprint(fp, "%N", l->n); - if(l->next) - r += fmtstrcpy(fp, sep); - } - - fp->flags = sf; - fmtmode = sm; - return r; -} - -void -fmtinstallgo(void) -{ - fmtmode = FErr; - fmtinstall('E', Econv); // etype opcodes - fmtinstall('J', Jconv); // all the node flags - fmtinstall('H', Hconv); // node lists - fmtinstall('L', Lconv); // line number - fmtinstall('N', Nconv); // node pointer - fmtinstall('O', Oconv); // node opcodes - fmtinstall('S', Sconv); // sym pointer - fmtinstall('T', Tconv); // type pointer - fmtinstall('V', Vconv); // val pointer - fmtinstall('Z', Zconv); // escaped string - - // These are in mparith1.c - fmtinstall('B', Bconv); // big numbers - fmtinstall('F', Fconv); // big float numbers - -} - -void -dumplist(char *s, NodeList *l) -{ - print("%s%+H\n", s, l); -} - -void -dump(char *s, Node *n) -{ - print("%s [%p]%+N\n", s, n, n); -} diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c deleted file mode 100644 index 72bcc492a5..0000000000 --- a/src/cmd/gc/gen.c +++ /dev/null @@ -1,987 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * portable half of code generator. - * mainly statements and control flow. - */ - -#include -#include -#include "go.h" - -static void cgen_dcl(Node *n); -static void cgen_proc(Node *n, int proc); -static void checkgoto(Node*, Node*); - -static Label *labellist; -static Label *lastlabel; - -Node* -sysfunc(char *name) -{ - Node *n; - - n = newname(pkglookup(name, runtimepkg)); - n->class = PFUNC; - return n; -} - -/* - * the address of n has been taken and might be used after - * the current function returns. mark any local vars - * as needing to move to the heap. - */ -void -addrescapes(Node *n) -{ - char buf[100]; - Node *oldfn; - - switch(n->op) { - default: - // probably a type error already. - // dump("addrescapes", n); - break; - - case ONAME: - if(n == nodfp) - break; - - // if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping. - // on PPARAM it means something different. - if(n->class == PAUTO && n->esc == EscNever) - break; - - switch(n->class) { - case PPARAMREF: - addrescapes(n->defn); - break; - case PPARAM: - case PPARAMOUT: - // if func param, need separate temporary - // to hold heap pointer. - // the function type has already been checked - // (we're in the function body) - // so the param already has a valid xoffset. - - // expression to refer to stack copy - n->stackparam = nod(OPARAM, n, N); - n->stackparam->type = n->type; - n->stackparam->addable = 1; - if(n->xoffset == BADWIDTH) - fatal("addrescapes before param assignment"); - n->stackparam->xoffset = n->xoffset; - // fallthrough - - case PAUTO: - n->class |= PHEAP; - n->addable = 0; - n->ullman = 2; - n->xoffset = 0; - - // create stack variable to hold pointer to heap - oldfn = curfn; - curfn = n->curfn; - n->heapaddr = temp(ptrto(n->type)); - snprint(buf, sizeof buf, "&%S", n->sym); - n->heapaddr->sym = lookup(buf); - n->heapaddr->orig->sym = n->heapaddr->sym; - n->esc = EscHeap; - if(debug['m']) - print("%L: moved to heap: %N\n", n->lineno, n); - curfn = oldfn; - break; - } - break; - - case OIND: - case ODOTPTR: - break; - - case ODOT: - case OINDEX: - // ODOTPTR has already been introduced, - // so these are the non-pointer ODOT and OINDEX. - // In &x[0], if x is a slice, then x does not - // escape--the pointer inside x does, but that - // is always a heap pointer anyway. - if(!isslice(n->left->type)) - addrescapes(n->left); - break; - } -} - -void -clearlabels(void) -{ - Label *l; - - for(l=labellist; l!=L; l=l->link) - l->sym->label = L; - - labellist = L; - lastlabel = L; -} - -static Label* -newlab(Node *n) -{ - Sym *s; - Label *lab; - - s = n->left->sym; - if((lab = s->label) == L) { - lab = mal(sizeof(*lab)); - if(lastlabel == nil) - labellist = lab; - else - lastlabel->link = lab; - lastlabel = lab; - lab->sym = s; - s->label = lab; - } - - if(n->op == OLABEL) { - if(lab->def != N) - yyerror("label %S already defined at %L", s, lab->def->lineno); - else - lab->def = n; - } else - lab->use = list(lab->use, n); - - return lab; -} - -void -checklabels(void) -{ - Label *lab; - NodeList *l; - - for(lab=labellist; lab!=L; lab=lab->link) { - if(lab->def == N) { - for(l=lab->use; l; l=l->next) - yyerrorl(l->n->lineno, "label %S not defined", lab->sym); - continue; - } - if(lab->use == nil && !lab->used) { - yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym); - continue; - } - if(lab->gotopc != P) - fatal("label %S never resolved", lab->sym); - for(l=lab->use; l; l=l->next) - checkgoto(l->n, lab->def); - } -} - -static void -checkgoto(Node *from, Node *to) -{ - int nf, nt; - Sym *block, *dcl, *fs, *ts; - int lno; - - if(from->sym == to->sym) - return; - - nf = 0; - for(fs=from->sym; fs; fs=fs->link) - nf++; - nt = 0; - for(fs=to->sym; fs; fs=fs->link) - nt++; - fs = from->sym; - for(; nf > nt; nf--) - fs = fs->link; - if(fs != to->sym) { - lno = lineno; - setlineno(from); - - // decide what to complain about. - // prefer to complain about 'into block' over declarations, - // so scan backward to find most recent block or else dcl. - block = S; - dcl = S; - ts = to->sym; - for(; nt > nf; nt--) { - if(ts->pkg == nil) - block = ts; - else - dcl = ts; - ts = ts->link; - } - while(ts != fs) { - if(ts->pkg == nil) - block = ts; - else - dcl = ts; - ts = ts->link; - fs = fs->link; - } - - if(block) - yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno); - else - yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno); - lineno = lno; - } -} - -static Label* -stmtlabel(Node *n) -{ - Label *lab; - - if(n->sym != S) - if((lab = n->sym->label) != L) - if(lab->def != N) - if(lab->def->defn == n) - return lab; - return L; -} - -/* - * compile statements - */ -void -genlist(NodeList *l) -{ - for(; l; l=l->next) - gen(l->n); -} - -void -gen(Node *n) -{ - int32 lno; - Prog *scontin, *sbreak; - Prog *p1, *p2, *p3; - Label *lab; - int32 wasregalloc; - -//dump("gen", n); - - lno = setlineno(n); - wasregalloc = thearch.anyregalloc(); - - if(n == N) - goto ret; - - if(n->ninit) - genlist(n->ninit); - - setlineno(n); - - switch(n->op) { - default: - fatal("gen: unknown op %+hN", n); - break; - - case OCASE: - case OFALL: - case OXCASE: - case OXFALL: - case ODCLCONST: - case ODCLFUNC: - case ODCLTYPE: - break; - - case OEMPTY: - break; - - case OBLOCK: - genlist(n->list); - break; - - case OLABEL: - if(isblanksym(n->left->sym)) - break; - - lab = newlab(n); - - // if there are pending gotos, resolve them all to the current pc. - for(p1=lab->gotopc; p1; p1=p2) { - p2 = unpatch(p1); - patch(p1, pc); - } - lab->gotopc = P; - if(lab->labelpc == P) - lab->labelpc = pc; - - if(n->defn) { - switch(n->defn->op) { - case OFOR: - case OSWITCH: - case OSELECT: - // so stmtlabel can find the label - n->defn->sym = lab->sym; - } - } - break; - - case OGOTO: - // if label is defined, emit jump to it. - // otherwise save list of pending gotos in lab->gotopc. - // the list is linked through the normal jump target field - // to avoid a second list. (the jumps are actually still - // valid code, since they're just going to another goto - // to the same label. we'll unwind it when we learn the pc - // of the label in the OLABEL case above.) - lab = newlab(n); - if(lab->labelpc != P) - gjmp(lab->labelpc); - else - lab->gotopc = gjmp(lab->gotopc); - break; - - case OBREAK: - if(n->left != N) { - lab = n->left->sym->label; - if(lab == L) { - yyerror("break label not defined: %S", n->left->sym); - break; - } - lab->used = 1; - if(lab->breakpc == P) { - yyerror("invalid break label %S", n->left->sym); - break; - } - gjmp(lab->breakpc); - break; - } - if(breakpc == P) { - yyerror("break is not in a loop"); - break; - } - gjmp(breakpc); - break; - - case OCONTINUE: - if(n->left != N) { - lab = n->left->sym->label; - if(lab == L) { - yyerror("continue label not defined: %S", n->left->sym); - break; - } - lab->used = 1; - if(lab->continpc == P) { - yyerror("invalid continue label %S", n->left->sym); - break; - } - gjmp(lab->continpc); - break; - } - if(continpc == P) { - yyerror("continue is not in a loop"); - break; - } - gjmp(continpc); - break; - - case OFOR: - sbreak = breakpc; - p1 = gjmp(P); // goto test - breakpc = gjmp(P); // break: goto done - scontin = continpc; - continpc = pc; - - // define break and continue labels - if((lab = stmtlabel(n)) != L) { - lab->breakpc = breakpc; - lab->continpc = continpc; - } - gen(n->nincr); // contin: incr - patch(p1, pc); // test: - thearch.bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break - genlist(n->nbody); // body - gjmp(continpc); - patch(breakpc, pc); // done: - continpc = scontin; - breakpc = sbreak; - if(lab) { - lab->breakpc = P; - lab->continpc = P; - } - break; - - case OIF: - p1 = gjmp(P); // goto test - p2 = gjmp(P); // p2: goto else - patch(p1, pc); // test: - thearch.bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2 - genlist(n->nbody); // then - p3 = gjmp(P); // goto done - patch(p2, pc); // else: - genlist(n->nelse); // else - patch(p3, pc); // done: - break; - - case OSWITCH: - sbreak = breakpc; - p1 = gjmp(P); // goto test - breakpc = gjmp(P); // break: goto done - - // define break label - if((lab = stmtlabel(n)) != L) - lab->breakpc = breakpc; - - patch(p1, pc); // test: - genlist(n->nbody); // switch(test) body - patch(breakpc, pc); // done: - breakpc = sbreak; - if(lab != L) - lab->breakpc = P; - break; - - case OSELECT: - sbreak = breakpc; - p1 = gjmp(P); // goto test - breakpc = gjmp(P); // break: goto done - - // define break label - if((lab = stmtlabel(n)) != L) - lab->breakpc = breakpc; - - patch(p1, pc); // test: - genlist(n->nbody); // select() body - patch(breakpc, pc); // done: - breakpc = sbreak; - if(lab != L) - lab->breakpc = P; - break; - - case ODCL: - cgen_dcl(n->left); - break; - - case OAS: - if(gen_as_init(n)) - break; - cgen_as(n->left, n->right); - break; - - case OCALLMETH: - cgen_callmeth(n, 0); - break; - - case OCALLINTER: - thearch.cgen_callinter(n, N, 0); - break; - - case OCALLFUNC: - thearch.cgen_call(n, 0); - break; - - case OPROC: - cgen_proc(n, 1); - break; - - case ODEFER: - cgen_proc(n, 2); - break; - - case ORETURN: - case ORETJMP: - thearch.cgen_ret(n); - break; - - case OCHECKNIL: - cgen_checknil(n->left); - break; - - case OVARKILL: - gvarkill(n->left); - break; - } - -ret: - if(thearch.anyregalloc() != wasregalloc) { - dump("node", n); - fatal("registers left allocated"); - } - - lineno = lno; -} - -/* - * generate call to non-interface method - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -void -cgen_callmeth(Node *n, int proc) -{ - Node n2; - Node *l; - - // generate a rewrite in n2 for the method call - // (p.f)(...) goes to (f)(p,...) - - l = n->left; - if(l->op != ODOTMETH) - fatal("cgen_callmeth: not dotmethod: %N"); - - n2 = *n; - n2.op = OCALLFUNC; - n2.left = l->right; - n2.left->type = l->type; - - if(n2.left->op == ONAME) - n2.left->class = PFUNC; - thearch.cgen_call(&n2, proc); -} - -/* - * generate code to start new proc running call n. - */ -static void -cgen_proc(Node *n, int proc) -{ - switch(n->left->op) { - default: - fatal("cgen_proc: unknown call %O", n->left->op); - - case OCALLMETH: - cgen_callmeth(n->left, proc); - break; - - case OCALLINTER: - thearch.cgen_callinter(n->left, N, proc); - break; - - case OCALLFUNC: - thearch.cgen_call(n->left, proc); - break; - } - -} - -/* - * generate declaration. - * have to allocate heap copy - * for escaped variables. - */ -static void -cgen_dcl(Node *n) -{ - if(debug['g']) - dump("\ncgen-dcl", n); - if(n->op != ONAME) { - dump("cgen_dcl", n); - fatal("cgen_dcl"); - } - if(!(n->class & PHEAP)) - return; - if(compiling_runtime) - yyerror("%N escapes to heap, not allowed in runtime.", n); - if(n->alloc == nil) - n->alloc = callnew(n->type); - cgen_as(n->heapaddr, n->alloc); -} - -/* - * generate discard of value - */ -static void -cgen_discard(Node *nr) -{ - Node tmp; - - if(nr == N) - return; - - switch(nr->op) { - case ONAME: - if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF) - gused(nr); - break; - - // unary - case OADD: - case OAND: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLSH: - case OLT: - case OMOD: - case OMUL: - case ONE: - case OOR: - case ORSH: - case OSUB: - case OXOR: - cgen_discard(nr->left); - cgen_discard(nr->right); - break; - - // binary - case OCAP: - case OCOM: - case OLEN: - case OMINUS: - case ONOT: - case OPLUS: - cgen_discard(nr->left); - break; - - case OIND: - cgen_checknil(nr->left); - break; - - // special enough to just evaluate - default: - tempname(&tmp, nr->type); - cgen_as(&tmp, nr); - gused(&tmp); - } -} - -/* - * clearslim generates code to zero a slim node. - */ -void -clearslim(Node *n) -{ - Node z; - Mpflt zero; - - memset(&z, 0, sizeof(z)); - z.op = OLITERAL; - z.type = n->type; - z.addable = 1; - - switch(simtype[n->type->etype]) { - case TCOMPLEX64: - case TCOMPLEX128: - z.val.u.cval = mal(sizeof(*z.val.u.cval)); - mpmovecflt(&z.val.u.cval->real, 0.0); - mpmovecflt(&z.val.u.cval->imag, 0.0); - break; - - case TFLOAT32: - case TFLOAT64: - mpmovecflt(&zero, 0.0); - z.val.ctype = CTFLT; - z.val.u.fval = &zero; - break; - - case TPTR32: - case TPTR64: - case TCHAN: - case TMAP: - z.val.ctype = CTNIL; - break; - - case TBOOL: - z.val.ctype = CTBOOL; - break; - - case TINT8: - case TINT16: - case TINT32: - case TINT64: - case TUINT8: - case TUINT16: - case TUINT32: - case TUINT64: - z.val.ctype = CTINT; - z.val.u.xval = mal(sizeof(*z.val.u.xval)); - mpmovecfix(z.val.u.xval, 0); - break; - - default: - fatal("clearslim called on type %T", n->type); - } - - ullmancalc(&z); - thearch.cgen(&z, n); -} - -/* - * generate assignment: - * nl = nr - * nr == N means zero nl. - */ -void -cgen_as(Node *nl, Node *nr) -{ - Type *tl; - - if(debug['g']) { - dump("cgen_as", nl); - dump("cgen_as = ", nr); - } - - while(nr != N && nr->op == OCONVNOP) - nr = nr->left; - - if(nl == N || isblank(nl)) { - cgen_discard(nr); - return; - } - - if(nr == N || iszero(nr)) { - // heaps should already be clear - if(nr == N && (nl->class & PHEAP)) - return; - - tl = nl->type; - if(tl == T) - return; - if(isfat(tl)) { - if(nl->op == ONAME) - gvardef(nl); - thearch.clearfat(nl); - return; - } - clearslim(nl); - return; - } - - tl = nl->type; - if(tl == T) - return; - - thearch.cgen(nr, nl); -} - -/* - * generate: - * res = iface{typ, data} - * n->left is typ - * n->right is data - */ -void -cgen_eface(Node *n, Node *res) -{ - /* - * the right node of an eface may contain function calls that uses res as an argument, - * so it's important that it is done first - */ - Node dst; - Node *tmp; - - tmp = temp(types[tptr]); - thearch.cgen(n->right, tmp); - - gvardef(res); - - dst = *res; - dst.type = types[tptr]; - dst.xoffset += widthptr; - thearch.cgen(tmp, &dst); - - dst.xoffset -= widthptr; - thearch.cgen(n->left, &dst); -} - -/* - * generate: - * res = s[lo, hi]; - * n->left is s - * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)]) - * caller (cgen) guarantees res is an addable ONAME. - * - * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR. - */ -void -cgen_slice(Node *n, Node *res) -{ - Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con; - Prog *p1, *p2; - - cap = n->list->n; - len = n->list->next->n; - offs = N; - if(n->list->next->next) - offs = n->list->next->next->n; - - // evaluate base pointer first, because it is the only - // possibly complex expression. once that is evaluated - // and stored, updating the len and cap can be done - // without making any calls, so without doing anything that - // might cause preemption or garbage collection. - // this makes the whole slice update atomic as far as the - // garbage collector can see. - - base = temp(types[TUINTPTR]); - tmplen = temp(types[TINT]); - if(n->op != OSLICESTR) - tmpcap = temp(types[TINT]); - else - tmpcap = tmplen; - - if(isnil(n->left)) { - tempname(&src, n->left->type); - thearch.cgen(n->left, &src); - } else - src = *n->left; - if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR) - src.xoffset += Array_array; - - if(n->op == OSLICEARR || n->op == OSLICE3ARR) { - if(!isptr[n->left->type->etype]) - fatal("slicearr is supposed to work on pointer: %+N\n", n); - thearch.cgen(&src, base); - cgen_checknil(base); - } else { - src.type = types[tptr]; - thearch.cgen(&src, base); - } - - // committed to the update - gvardef(res); - - // compute len and cap. - // len = n-i, cap = m-i, and offs = i*width. - // computing offs last lets the multiply overwrite i. - thearch.cgen(len, tmplen); - if(n->op != OSLICESTR) - thearch.cgen(cap, tmpcap); - - // if new cap != 0 { base += add } - // This avoids advancing base past the end of the underlying array/string, - // so that it cannot point at the next object in memory. - // If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero. - // In essence we are replacing x[i:j:k] where i == j == k - // or x[i:j] where i == j == cap(x) with x[0:0:0]. - if(offs != N) { - p1 = gjmp(P); - p2 = gjmp(P); - patch(p1, pc); - - nodconst(&con, tmpcap->type, 0); - cmp = nod(OEQ, tmpcap, &con); - typecheck(&cmp, Erv); - thearch.bgen(cmp, 1, -1, p2); - - add = nod(OADD, base, offs); - typecheck(&add, Erv); - thearch.cgen(add, base); - - patch(p2, pc); - } - - // dst.array = src.array [ + lo *width ] - dst = *res; - dst.xoffset += Array_array; - dst.type = types[tptr]; - thearch.cgen(base, &dst); - - // dst.len = hi [ - lo ] - dst = *res; - dst.xoffset += Array_nel; - dst.type = types[simtype[TUINT]]; - thearch.cgen(tmplen, &dst); - - if(n->op != OSLICESTR) { - // dst.cap = cap [ - lo ] - dst = *res; - dst.xoffset += Array_cap; - dst.type = types[simtype[TUINT]]; - thearch.cgen(tmpcap, &dst); - } -} - -/* - * gather series of offsets - * >=0 is direct addressed field - * <0 is pointer to next field (+1) - */ -int -dotoffset(Node *n, int64 *oary, Node **nn) -{ - int i; - - switch(n->op) { - case ODOT: - if(n->xoffset == BADWIDTH) { - dump("bad width in dotoffset", n); - fatal("bad width in dotoffset"); - } - i = dotoffset(n->left, oary, nn); - if(i > 0) { - if(oary[i-1] >= 0) - oary[i-1] += n->xoffset; - else - oary[i-1] -= n->xoffset; - break; - } - if(i < 10) - oary[i++] = n->xoffset; - break; - - case ODOTPTR: - if(n->xoffset == BADWIDTH) { - dump("bad width in dotoffset", n); - fatal("bad width in dotoffset"); - } - i = dotoffset(n->left, oary, nn); - if(i < 10) - oary[i++] = -(n->xoffset+1); - break; - - default: - *nn = n; - return 0; - } - if(i >= 10) - *nn = N; - return i; -} - -/* - * make a new off the books - */ -void -tempname(Node *nn, Type *t) -{ - Node *n; - Sym *s; - - if(curfn == N) - fatal("no curfn for tempname"); - - if(t == T) { - yyerror("tempname called with nil type"); - t = types[TINT32]; - } - - // give each tmp a different name so that there - // a chance to registerizer them - snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen); - statuniqgen++; - s = lookup(namebuf); - n = nod(ONAME, N, N); - n->sym = s; - s->def = n; - n->type = t; - n->class = PAUTO; - n->addable = 1; - n->ullman = 1; - n->esc = EscNever; - n->curfn = curfn; - curfn->dcl = list(curfn->dcl, n); - - dowidth(t); - n->xoffset = 0; - *nn = *n; -} - -Node* -temp(Type *t) -{ - Node *n; - - n = nod(OXXX, N, N); - tempname(n, t); - n->sym->def->used = 1; - return n->orig; -} diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors deleted file mode 100644 index f90d619901..0000000000 --- a/src/cmd/gc/go.errors +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Example-based syntax error messages. -// See bisonerrors, Makefile, go.y. - -static struct { - int yystate; - int yychar; - char *msg; -} yymsg[] = { - // Each line of the form % token list - // is converted by bisonerrors into the yystate and yychar caused - // by that token list. - - % loadsys package LIMPORT '(' LLITERAL import_package import_there ',' - "unexpected comma during import block", - - % loadsys package LIMPORT LNAME ';' - "missing import path; require quoted string", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';' - "missing { after if clause", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';' - "missing { after switch clause", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';' - "missing { after for clause", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY - "missing { after for clause", - - % loadsys package imports LFUNC LNAME '(' ')' ';' '{' - "unexpected semicolon or newline before {", - - % loadsys package imports LTYPE LNAME ';' - "unexpected semicolon or newline in type declaration", - - % loadsys package imports LCHAN '}' - "unexpected } in channel type", - - % loadsys package imports LCHAN ')' - "unexpected ) in channel type", - - % loadsys package imports LCHAN ',' - "unexpected comma in channel type", - - % loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE - "unexpected semicolon or newline before else", - - % loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME - "name list not allowed in interface type", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME - "var declaration not allowed in for initializer", - - % loadsys package imports LVAR LNAME '[' ']' LNAME '{' - "unexpected { at end of statement", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{' - "unexpected { at end of statement", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';' - "argument to go/defer must be function call", - - % loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';' - "need trailing comma before newline in composite literal", - - % loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';' - "need trailing comma before newline in composite literal", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME - "nested func not allowed", - - % loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';' - "else must be followed by if or statement block" -}; diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h deleted file mode 100644 index 92584f6c58..0000000000 --- a/src/cmd/gc/go.h +++ /dev/null @@ -1,1757 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include - -#undef OAPPEND - -// avoid -#undef isblank -#define isblank goisblank - -#ifndef EXTERN -#define EXTERN extern -#endif - -#undef BUFSIZ - -// The parser's maximum stack size. -// We have to use a #define macro here since yacc -// or bison will check for its definition and use -// a potentially smaller value if it is undefined. -#define YYMAXDEPTH 500 - -enum -{ - NHUNK = 50000, - BUFSIZ = 8192, - NSYMB = 500, - NHASH = 1024, - STRINGSZ = 200, - MAXALIGN = 7, - UINF = 100, - - PRIME1 = 3, - - AUNK = 100, - - // These values are known by runtime. - // The MEMx and NOEQx values must run in parallel. See algtype. - AMEM = 0, - AMEM0, - AMEM8, - AMEM16, - AMEM32, - AMEM64, - AMEM128, - ANOEQ, - ANOEQ0, - ANOEQ8, - ANOEQ16, - ANOEQ32, - ANOEQ64, - ANOEQ128, - ASTRING, - AINTER, - ANILINTER, - ASLICE, - AFLOAT32, - AFLOAT64, - ACPLX64, - ACPLX128, - - BADWIDTH = -1000000000, - - MaxStackVarSize = 10*1024*1024, -}; - -/* - * note this is the representation - * of the compilers string literals, - * it is not the runtime representation - */ -typedef struct Strlit Strlit; -struct Strlit -{ - int32 len; - char s[1]; // variable -}; - -enum -{ - Mpscale = 29, // safely smaller than bits in a long - Mpprec = 16, // Mpscale*Mpprec is max number of bits - Mpnorm = Mpprec - 1, // significant words in a normalized float - Mpbase = 1L << Mpscale, - Mpsign = Mpbase >> 1, - Mpmask = Mpbase - 1, - Mpdebug = 0, -}; - -typedef struct Mpint Mpint; -struct Mpint -{ - long a[Mpprec]; - uchar neg; - uchar ovf; -}; - -typedef struct Mpflt Mpflt; -struct Mpflt -{ - Mpint val; - short exp; -}; - -typedef struct Mpcplx Mpcplx; -struct Mpcplx -{ - Mpflt real; - Mpflt imag; -}; - -typedef struct Val Val; -struct Val -{ - short ctype; - union - { - short reg; // OREGISTER - short bval; // bool value CTBOOL - Mpint* xval; // int CTINT, rune CTRUNE - Mpflt* fval; // float CTFLT - Mpcplx* cval; // float CTCPLX - Strlit* sval; // string CTSTR - } u; -}; -typedef struct Array Array; -typedef struct Bvec Bvec; -typedef struct Pkg Pkg; -typedef struct Sym Sym; -typedef struct Node Node; -typedef struct NodeList NodeList; -typedef struct Type Type; -typedef struct Label Label; - -struct Array -{ - int32 length; // number of elements - int32 size; // element size - int32 capacity; // size of data in elements - char *data; // element storage -}; - -struct Type -{ - uchar etype; - uchar nointerface; - uchar noalg; - uchar chan; - uchar trecur; // to detect loops - uchar printed; - uchar embedded; // TFIELD embedded type - uchar siggen; - uchar funarg; // on TSTRUCT and TFIELD - uchar copyany; - uchar local; // created in this file - uchar deferwidth; - uchar broke; // broken type definition. - uchar isddd; // TFIELD is ... argument - uchar align; - uchar haspointers; // 0 unknown, 1 no, 2 yes - - Node* nod; // canonical OTYPE node - Type* orig; // original type (type literal or predefined type) - int lineno; - - // TFUNC - int thistuple; - int outtuple; - int intuple; - uchar outnamed; - - Type* method; - Type* xmethod; - - Sym* sym; - int32 vargen; // unique name for OTYPE/ONAME - - Node* nname; - vlong argwid; - - // most nodes - Type* type; // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx - vlong width; // offset in TFIELD, width in all others - - // TFIELD - Type* down; // next struct field, also key type in TMAP - Type* outer; // outer struct - Strlit* note; // literal string annotation - - // TARRAY - vlong bound; // negative is dynamic array - - // TMAP - Type* bucket; // internal type representing a hash bucket - Type* hmap; // internal type representing a Hmap (map header object) - Type* hiter; // internal type representing hash iterator state - Type* map; // link from the above 3 internal types back to the map type. - - int32 maplineno; // first use of TFORW as map key - int32 embedlineno; // first use of TFORW as embedded type - - // for TFORW, where to copy the eventual value to - NodeList *copyto; - - Node *lastfn; // for usefield -}; -#define T ((Type*)0) - -typedef struct InitEntry InitEntry; -typedef struct InitPlan InitPlan; - -struct InitEntry -{ - vlong xoffset; // struct, array only - Node *key; // map only - Node *expr; -}; - -struct InitPlan -{ - vlong lit; // bytes of initialized non-zero literals - vlong zero; // bytes of zeros - vlong expr; // bytes of run-time computed expressions - - InitEntry *e; - int len; - int cap; -}; - -enum -{ - EscUnknown, - EscHeap, - EscScope, - EscNone, - EscReturn, - EscNever, - EscBits = 3, - EscMask = (1< ONAME/PPARAMREF - int top; // top context (Ecall, Eproc, etc) - - // ONAME substitute while inlining - Node* inlvar; - - // OPACK - Pkg* pkg; - - // OARRAYLIT, OMAPLIT, OSTRUCTLIT. - InitPlan* initplan; - - // Escape analysis. - NodeList* escflowsrc; // flow(this, src) - NodeList* escretval; // on OCALLxxx, list of dummy return values - int escloopdepth; // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes - - Sym* sym; // various - int32 vargen; // unique name for OTYPE/ONAME - int32 lineno; - int32 endlineno; - vlong xoffset; - vlong stkdelta; // offset added by stack frame compaction phase. - int32 ostk; - int32 iota; - uint32 walkgen; - int32 esclevel; - void* opt; // for optimization passes -}; -#define N ((Node*)0) - -/* - * Every node has a walkgen field. - * If you want to do a traversal of a node graph that - * might contain duplicates and want to avoid - * visiting the same nodes twice, increment walkgen - * before starting. Then before processing a node, do - * - * if(n->walkgen == walkgen) - * return; - * n->walkgen = walkgen; - * - * Such a walk cannot call another such walk recursively, - * because of the use of the global walkgen. - */ -EXTERN uint32 walkgen; - -struct NodeList -{ - Node* n; - NodeList* next; - NodeList* end; -}; - -enum -{ - SymExport = 1<<0, // to be exported - SymPackage = 1<<1, - SymExported = 1<<2, // already written out by export - SymUniq = 1<<3, - SymSiggen = 1<<4, - SymAsm = 1<<5, - SymAlgGen = 1<<6, -}; - -struct Sym -{ - ushort lexical; - uchar flags; - uchar sym; // huffman encoding in object file - Sym* link; - int32 npkg; // number of imported packages with this name - uint32 uniqgen; - Pkg* importdef; // where imported definition was found - char* linkname; // link name - - // saved and restored by dcopy - Pkg* pkg; - char* name; // variable name - Node* def; // definition: ONAME OTYPE OPACK or OLITERAL - Label* label; // corresponding label (ephemeral) - int32 block; // blocknumber to catch redeclaration - int32 lastlineno; // last declaration for diagnostic - Pkg* origpkg; // original package for . import - LSym* lsym; -}; -#define S ((Sym*)0) - -EXTERN Sym* dclstack; - -struct Pkg -{ - char* name; // package name - Strlit* path; // string literal used in import statement - Sym* pathsym; - char* prefix; // escaped path for use in symbol table - Pkg* link; - uchar imported; // export data of this package was parsed - char exported; // import line written in export data - char direct; // imported directly - char safe; // whether the package is marked as safe -}; - -typedef struct Iter Iter; -struct Iter -{ - int done; - Type* tfunc; - Type* t; - Node** an; - Node* n; -}; - -// Node ops. -enum -{ - OXXX, - - // names - ONAME, // var, const or func name - ONONAME, // unnamed arg or return value: f(int, string) (int, error) { etc } - OTYPE, // type name - OPACK, // import - OLITERAL, // literal - - // expressions - OADD, // x + y - OSUB, // x - y - OOR, // x | y - OXOR, // x ^ y - OADDSTR, // s + "foo" - OADDR, // &x - OANDAND, // b0 && b1 - OAPPEND, // append - OARRAYBYTESTR, // string(bytes) - OARRAYBYTESTRTMP, // string(bytes) ephemeral - OARRAYRUNESTR, // string(runes) - OSTRARRAYBYTE, // []byte(s) - OSTRARRAYBYTETMP, // []byte(s) ephemeral - OSTRARRAYRUNE, // []rune(s) - OAS, // x = y or x := y - OAS2, // x, y, z = xx, yy, zz - OAS2FUNC, // x, y = f() - OAS2RECV, // x, ok = <-c - OAS2MAPR, // x, ok = m["foo"] - OAS2DOTTYPE, // x, ok = I.(int) - OASOP, // x += y - OCALL, // function call, method call or type conversion, possibly preceded by defer or go. - OCALLFUNC, // f() - OCALLMETH, // t.Method() - OCALLINTER, // err.Error() - OCALLPART, // t.Method (without ()) - OCAP, // cap - OCLOSE, // close - OCLOSURE, // f = func() { etc } - OCMPIFACE, // err1 == err2 - OCMPSTR, // s1 == s2 - OCOMPLIT, // composite literal, typechecking may convert to a more specific OXXXLIT. - OMAPLIT, // M{"foo":3, "bar":4} - OSTRUCTLIT, // T{x:3, y:4} - OARRAYLIT, // [2]int{3, 4} - OPTRLIT, // &T{x:3, y:4} - OCONV, // var i int; var u uint; i = int(u) - OCONVIFACE, // I(t) - OCONVNOP, // type Int int; var i int; var j Int; i = int(j) - OCOPY, // copy - ODCL, // var x int - ODCLFUNC, // func f() or func (r) f() - ODCLFIELD, // struct field, interface field, or func/method argument/return value. - ODCLCONST, // const pi = 3.14 - ODCLTYPE, // type Int int - ODELETE, // delete - ODOT, // t.x - ODOTPTR, // p.x that is implicitly (*p).x - ODOTMETH, // t.Method - ODOTINTER, // err.Error - OXDOT, // t.x, typechecking may convert to a more specific ODOTXXX. - ODOTTYPE, // e = err.(MyErr) - ODOTTYPE2, // e, ok = err.(MyErr) - OEQ, // x == y - ONE, // x != y - OLT, // x < y - OLE, // x <= y - OGE, // x >= y - OGT, // x > y - OIND, // *p - OINDEX, // a[i] - OINDEXMAP, // m[s] - OKEY, // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc. - OPARAM, // The on-stack copy of a parameter or return value that escapes. - OLEN, // len - OMAKE, // make, typechecking may convert to a more specific OMAKEXXX. - OMAKECHAN, // make(chan int) - OMAKEMAP, // make(map[string]int) - OMAKESLICE, // make([]int, 0) - OMUL, // x * y - ODIV, // x / y - OMOD, // x % y - OLSH, // x << u - ORSH, // x >> u - OAND, // x & y - OANDNOT, // x &^ y - ONEW, // new - ONOT, // !b - OCOM, // ^x - OPLUS, // +x - OMINUS, // -y - OOROR, // b1 || b2 - OPANIC, // panic - OPRINT, // print - OPRINTN, // println - OPAREN, // (x) - OSEND, // c <- x - OSLICE, // v[1:2], typechecking may convert to a more specific OSLICEXXX. - OSLICEARR, // a[1:2] - OSLICESTR, // s[1:2] - OSLICE3, // v[1:2:3], typechecking may convert to OSLICE3ARR. - OSLICE3ARR, // a[1:2:3] - ORECOVER, // recover - ORECV, // <-c - ORUNESTR, // string(i) - OSELRECV, // case x = <-c: - OSELRECV2, // case x, ok = <-c: - OIOTA, // iota - OREAL, // real - OIMAG, // imag - OCOMPLEX, // complex - - // statements - OBLOCK, // block of code - OBREAK, // break - OCASE, // case, after being verified by swt.c's casebody. - OXCASE, // case, before verification. - OCONTINUE, // continue - ODEFER, // defer - OEMPTY, // no-op - OFALL, // fallthrough, after being verified by swt.c's casebody. - OXFALL, // fallthrough, before verification. - OFOR, // for - OGOTO, // goto - OIF, // if - OLABEL, // label: - OPROC, // go - ORANGE, // range - ORETURN, // return - OSELECT, // select - OSWITCH, // switch x - OTYPESW, // switch err.(type) - - // types - OTCHAN, // chan int - OTMAP, // map[string]int - OTSTRUCT, // struct{} - OTINTER, // interface{} - OTFUNC, // func() - OTARRAY, // []int, [8]int, [N]int or [...]int - - // misc - ODDD, // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}. - ODDDARG, // func f(args ...int), introduced by escape analysis. - OINLCALL, // intermediary representation of an inlined call. - OEFACE, // itable and data words of an empty-interface value. - OITAB, // itable word of an interface value. - OSPTR, // base pointer of a slice or string. - OCLOSUREVAR, // variable reference at beginning of closure function - OCFUNC, // reference to c function pointer (not go func value) - OCHECKNIL, // emit code to ensure pointer/interface not nil - OVARKILL, // variable is dead - - // thearch-specific registers - OREGISTER, // a register, such as AX. - OINDREG, // offset plus indirect of a register, such as 8(SP). - - // 386/amd64-specific opcodes - OCMP, // compare: ACMP. - ODEC, // decrement: ADEC. - OINC, // increment: AINC. - OEXTEND, // extend: ACWD/ACDQ/ACQO. - OHMUL, // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both). - OLROT, // left rotate: AROL. - ORROTC, // right rotate-carry: ARCR. - ORETJMP, // return to other function - - OEND, -}; - -enum -{ - Txxx, // 0 - - TINT8, TUINT8, // 1 - TINT16, TUINT16, - TINT32, TUINT32, - TINT64, TUINT64, - TINT, TUINT, TUINTPTR, - - TCOMPLEX64, // 12 - TCOMPLEX128, - - TFLOAT32, // 14 - TFLOAT64, - - TBOOL, // 16 - - TPTR32, TPTR64, // 17 - - TFUNC, // 19 - TARRAY, - T_old_DARRAY, - TSTRUCT, // 22 - TCHAN, - TMAP, - TINTER, // 25 - TFORW, - TFIELD, - TANY, - TSTRING, - TUNSAFEPTR, - - // pseudo-types for literals - TIDEAL, // 31 - TNIL, - TBLANK, - - // pseudo-type for frame layout - TFUNCARGS, - TCHANARGS, - TINTERMETH, - - NTYPE, -}; - -enum -{ - CTxxx, - - CTINT, - CTRUNE, - CTFLT, - CTCPLX, - CTSTR, - CTBOOL, - CTNIL, -}; - -enum -{ - /* types of channel */ - /* must match ../../pkg/nreflect/type.go:/Chandir */ - Cxxx, - Crecv = 1<<0, - Csend = 1<<1, - Cboth = Crecv | Csend, -}; - -// declaration context -enum -{ - Pxxx, - - PEXTERN, // global variable - PAUTO, // local variables - PPARAM, // input arguments - PPARAMOUT, // output results - PPARAMREF, // closure variable reference - PFUNC, // global function - - PDISCARD, // discard during parse of duplicate import - - PHEAP = 1<<7, // an extra bit to identify an escaped variable -}; - -enum -{ - Etop = 1<<1, // evaluated at statement level - Erv = 1<<2, // evaluated in value context - Etype = 1<<3, - Ecall = 1<<4, // call-only expressions are ok - Efnstruct = 1<<5, // multivalue function returns are ok - Eiota = 1<<6, // iota is ok - Easgn = 1<<7, // assigning to expression - Eindir = 1<<8, // indirecting through expression - Eaddr = 1<<9, // taking address of expression - Eproc = 1<<10, // inside a go statement - Ecomplit = 1<<11, // type in composite literal -}; - -enum { - BITS = 3, - NVAR = (BITS*64) -}; - -typedef struct Bits Bits; -struct Bits -{ - uint64 b[BITS]; -}; - -EXTERN Bits zbits; - -struct Bvec -{ - int32 n; // number of bits - uint32 b[]; -}; - -typedef struct Var Var; -struct Var -{ - vlong offset; - Node* node; - Var* nextinnode; - int width; - int id; - char name; - char etype; - char addr; -}; - -EXTERN Var var[NVAR]; - -typedef struct Typedef Typedef; -struct Typedef -{ - char* name; - int etype; - int sameas; -}; - -typedef struct Sig Sig; -struct Sig -{ - char* name; - Pkg* pkg; - Sym* isym; - Sym* tsym; - Type* type; - Type* mtype; - int32 offset; - Sig* link; -}; - -typedef struct Io Io; -struct Io -{ - char* infile; - Biobuf* bin; - int32 ilineno; - int nlsemi; - int eofnl; - int last; - int peekc; - int peekc1; // second peekc for ... - char* cp; // used for content when bin==nil - int importsafe; -}; - -typedef struct Dlist Dlist; -struct Dlist -{ - Type* field; -}; - -typedef struct Idir Idir; -struct Idir -{ - Idir* link; - char* dir; -}; - -/* - * argument passing to/from - * smagic and umagic - */ -typedef struct Magic Magic; -struct Magic -{ - int w; // input for both - width - int s; // output for both - shift - int bad; // output for both - unexpected failure - - // magic multiplier for signed literal divisors - int64 sd; // input - literal divisor - int64 sm; // output - multiplier - - // magic multiplier for unsigned literal divisors - uint64 ud; // input - literal divisor - uint64 um; // output - multiplier - int ua; // output - adder -}; - -struct Label -{ - uchar used; - Sym* sym; - Node* def; - NodeList* use; - Label* link; - - // for use during gen - Prog* gotopc; // pointer to unresolved gotos - Prog* labelpc; // pointer to code - Prog* breakpc; // pointer to code - Prog* continpc; // pointer to code -}; -#define L ((Label*)0) - -/* - * note this is the runtime representation - * of the compilers arrays. - * - * typedef struct - * { // must not move anything - * uchar array[8]; // pointer to data - * uchar nel[4]; // number of elements - * uchar cap[4]; // allocated number of elements - * } Array; - */ -EXTERN int Array_array; // runtime offsetof(Array,array) - same for String -EXTERN int Array_nel; // runtime offsetof(Array,nel) - same for String -EXTERN int Array_cap; // runtime offsetof(Array,cap) -EXTERN int sizeof_Array; // runtime sizeof(Array) - - -/* - * note this is the runtime representation - * of the compilers strings. - * - * typedef struct - * { // must not move anything - * uchar array[8]; // pointer to data - * uchar nel[4]; // number of elements - * } String; - */ -EXTERN int sizeof_String; // runtime sizeof(String) - -EXTERN Dlist dotlist[10]; // size is max depth of embeddeds - -EXTERN Io curio; -EXTERN Io pushedio; -EXTERN int32 lexlineno; -EXTERN int32 lineno; -EXTERN int32 prevlineno; - -EXTERN Fmt pragcgobuf; - -EXTERN char* infile; -EXTERN char* outfile; -EXTERN Biobuf* bout; -EXTERN int nerrors; -EXTERN int nsavederrors; -EXTERN int nsyntaxerrors; -EXTERN int decldepth; -EXTERN int safemode; -EXTERN int nolocalimports; -EXTERN char namebuf[NSYMB]; -EXTERN char lexbuf[NSYMB]; -EXTERN char litbuf[NSYMB]; -EXTERN int debug[256]; -EXTERN char* debugstr; -EXTERN int debug_checknil; -EXTERN Sym* hash[NHASH]; -EXTERN Sym* importmyname; // my name for package -EXTERN Pkg* localpkg; // package being compiled -EXTERN Pkg* importpkg; // package being imported -EXTERN Pkg* structpkg; // package that declared struct, during import -EXTERN Pkg* builtinpkg; // fake package for builtins -EXTERN Pkg* gostringpkg; // fake pkg for Go strings -EXTERN Pkg* itabpkg; // fake pkg for itab cache -EXTERN Pkg* runtimepkg; // package runtime -EXTERN Pkg* racepkg; // package runtime/race -EXTERN Pkg* stringpkg; // fake package for C strings -EXTERN Pkg* typepkg; // fake package for runtime type info (headers) -EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data) -EXTERN Pkg* weaktypepkg; // weak references to runtime type info -EXTERN Pkg* unsafepkg; // package unsafe -EXTERN Pkg* trackpkg; // fake package for field tracking -EXTERN Pkg* rawpkg; // fake package for raw symbol names -EXTERN Pkg* phash[128]; -EXTERN int tptr; // either TPTR32 or TPTR64 -extern char* runtimeimport; -extern char* unsafeimport; -EXTERN char* myimportpath; -EXTERN Idir* idirs; -EXTERN char* localimport; -EXTERN char* asmhdr; - -EXTERN Type* types[NTYPE]; -EXTERN Type* idealstring; -EXTERN Type* idealbool; -EXTERN Type* bytetype; -EXTERN Type* runetype; -EXTERN Type* errortype; -EXTERN uchar simtype[NTYPE]; -EXTERN uchar isptr[NTYPE]; -EXTERN uchar isforw[NTYPE]; -EXTERN uchar isint[NTYPE]; -EXTERN uchar isfloat[NTYPE]; -EXTERN uchar iscomplex[NTYPE]; -EXTERN uchar issigned[NTYPE]; -EXTERN uchar issimple[NTYPE]; - -EXTERN uchar okforeq[NTYPE]; -EXTERN uchar okforadd[NTYPE]; -EXTERN uchar okforand[NTYPE]; -EXTERN uchar okfornone[NTYPE]; -EXTERN uchar okforcmp[NTYPE]; -EXTERN uchar okforbool[NTYPE]; -EXTERN uchar okforcap[NTYPE]; -EXTERN uchar okforlen[NTYPE]; -EXTERN uchar okforarith[NTYPE]; -EXTERN uchar okforconst[NTYPE]; -EXTERN uchar* okfor[OEND]; -EXTERN uchar iscmp[OEND]; - -EXTERN Mpint* minintval[NTYPE]; -EXTERN Mpint* maxintval[NTYPE]; -EXTERN Mpflt* minfltval[NTYPE]; -EXTERN Mpflt* maxfltval[NTYPE]; - -EXTERN NodeList* xtop; -EXTERN NodeList* externdcl; -EXTERN NodeList* exportlist; -EXTERN NodeList* importlist; // imported functions and methods with inlinable bodies -EXTERN NodeList* funcsyms; -EXTERN int dclcontext; // PEXTERN/PAUTO -EXTERN int incannedimport; -EXTERN int statuniqgen; // name generator for static temps -EXTERN int loophack; - -EXTERN int32 iota; -EXTERN NodeList* lastconst; -EXTERN Node* lasttype; -EXTERN vlong maxarg; -EXTERN vlong stksize; // stack size for current frame -EXTERN vlong stkptrsize; // prefix of stack containing pointers -EXTERN int32 blockgen; // max block number -EXTERN int32 block; // current block number -EXTERN int hasdefer; // flag that curfn has defer statetment - -EXTERN Node* curfn; - -EXTERN int widthptr; -EXTERN int widthint; -EXTERN int widthreg; - -EXTERN Node* typesw; -EXTERN Node* nblank; - -EXTERN int use_sse; - -EXTERN char* hunk; -EXTERN int32 nhunk; -EXTERN int32 thunk; - -EXTERN int funcdepth; -EXTERN int typecheckok; -EXTERN int compiling_runtime; -EXTERN int compiling_wrappers; -EXTERN int inl_nonlocal; -EXTERN int use_writebarrier; -EXTERN int pure_go; -EXTERN char* flag_installsuffix; -EXTERN int flag_race; -EXTERN int flag_largemodel; -EXTERN int noescape; -EXTERN int nosplit; -EXTERN int nowritebarrier; -EXTERN int debuglive; -EXTERN Link* ctxt; - -EXTERN int nointerface; -EXTERN int writearchive; - -EXTERN Biobuf bstdout; - -EXTERN int nacl; - -/* - * y.tab.c - */ -int yyparse(void); - -/* - * align.c - */ -int argsize(Type *t); -void checkwidth(Type *t); -void defercheckwidth(void); -void dowidth(Type *t); -void resumecheckwidth(void); -vlong rnd(vlong o, vlong r); -void typeinit(void); - -/* - * array.c - */ -Array* arraynew(int32 capacity, int32 size); -void arrayfree(Array *array); -int32 arraylength(Array *array); -void* arrayget(Array *array, int32 index); -void arrayset(Array *array, int32 index, void *element); -void arrayadd(Array *array, void *element); -void arraysort(Array* array, int (*cmp)(const void*, const void*)); - -/* - * bits.c - */ -int Qconv(Fmt *fp); -Bits band(Bits a, Bits b); -int bany(Bits *a); -int beq(Bits a, Bits b); -int bitno(uint64 b); -Bits blsh(uint n); -Bits bnot(Bits a); -int bnum(Bits a); -Bits bor(Bits a, Bits b); -int btest(Bits *a, uint n); -void biset(Bits *a, uint n); -void biclr(Bits *a, uint n); - -/* - * bv.c - */ -Bvec* bvalloc(int32 n); -void bvandnot(Bvec *dst, Bvec *src1, Bvec *src2); -int bvcmp(Bvec *bv1, Bvec *bv2); -void bvcopy(Bvec *dst, Bvec *src); -Bvec* bvconcat(Bvec *src1, Bvec *src2); -int bvget(Bvec *bv, int32 i); -int32 bvnext(Bvec *bv, int32 i); -int bvisempty(Bvec *bv); -void bvnot(Bvec *bv); -void bvor(Bvec *dst, Bvec *src1, Bvec *src2); -void bvand(Bvec *dst, Bvec *src1, Bvec *src2); -void bvprint(Bvec *bv); -void bvreset(Bvec *bv, int32 i); -void bvresetall(Bvec *bv); -void bvset(Bvec *bv, int32 i); - -/* - * closure.c - */ -Node* closurebody(NodeList *body); -void closurehdr(Node *ntype); -void typecheckclosure(Node *func, int top); -void capturevars(Node *func); -void transformclosure(Node *func); -Node* walkclosure(Node *func, NodeList **init); -void typecheckpartialcall(Node*, Node*); -Node* walkpartialcall(Node*, NodeList**); - -/* - * const.c - */ -int cmpslit(Node *l, Node *r); -int consttype(Node *n); -void convconst(Node *con, Type *t, Val *val); -void convlit(Node **np, Type *t); -void convlit1(Node **np, Type *t, int explicit); -void defaultlit(Node **np, Type *t); -void defaultlit2(Node **lp, Node **rp, int force); -void evconst(Node *n); -int isconst(Node *n, int ct); -int isgoconst(Node *n); -Node* nodcplxlit(Val r, Val i); -Node* nodlit(Val v); -long nonnegconst(Node *n); -int doesoverflow(Val v, Type *t); -void overflow(Val v, Type *t); -int smallintconst(Node *n); -Val toint(Val v); -Mpflt* truncfltlit(Mpflt *oldv, Type *t); - -/* - * cplx.c - */ -void complexadd(int op, Node *nl, Node *nr, Node *res); -void complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to); -void complexgen(Node *n, Node *res); -void complexminus(Node *nl, Node *res); -void complexmove(Node *f, Node *t); -void complexmul(Node *nl, Node *nr, Node *res); -int complexop(Node *n, Node *res); -void nodfconst(Node *n, Type *t, Mpflt* fval); - -/* - * dcl.c - */ -void addmethod(Sym *sf, Type *t, int local, int nointerface); -void addvar(Node *n, Type *t, int ctxt); -NodeList* checkarglist(NodeList *all, int input); -Node* colas(NodeList *left, NodeList *right, int32 lno); -void colasdefn(NodeList *left, Node *defn); -NodeList* constiter(NodeList *vl, Node *t, NodeList *cl); -Node* dclname(Sym *s); -void declare(Node *n, int ctxt); -void dumpdcl(char *st); -Node* embedded(Sym *s, Pkg *pkg); -Node* fakethis(void); -void funcbody(Node *n); -void funccompile(Node *n); -void funchdr(Node *n); -Type* functype(Node *this, NodeList *in, NodeList *out); -void ifacedcl(Node *n); -int isifacemethod(Type *f); -void markdcl(void); -Node* methodname(Node *n, Type *t); -Node* methodname1(Node *n, Node *t); -Sym* methodsym(Sym *nsym, Type *t0, int iface); -Node* newname(Sym *s); -Node* oldname(Sym *s); -void popdcl(void); -void poptodcl(void); -void redeclare(Sym *s, char *where); -void testdclstack(void); -Type* tointerface(NodeList *l); -Type* tostruct(NodeList *l); -Node* typedcl0(Sym *s); -Node* typedcl1(Node *n, Node *t, int local); -Node* typenod(Type *t); -NodeList* variter(NodeList *vl, Node *t, NodeList *el); -Sym* funcsym(Sym*); - -/* - * esc.c - */ -void escapes(NodeList*); - -/* - * export.c - */ -void autoexport(Node *n, int ctxt); -void dumpexport(void); -void dumpasmhdr(void); -int exportname(char *s); -void exportsym(Node *n); -void importconst(Sym *s, Type *t, Node *n); -void importimport(Sym *s, Strlit *z); -Sym* importsym(Sym *s, int op); -void importtype(Type *pt, Type *t); -void importvar(Sym *s, Type *t); -Type* pkgtype(Sym *s); - -/* - * fmt.c - */ -void fmtinstallgo(void); -void dump(char *s, Node *n); -void dumplist(char *s, NodeList *l); - -/* - * gen.c - */ -void addrescapes(Node *n); -void cgen_as(Node *nl, Node *nr); -void cgen_callmeth(Node *n, int proc); -void cgen_eface(Node* n, Node* res); -void cgen_slice(Node* n, Node* res); -void clearlabels(void); -void clearslim(Node*); -void checklabels(void); -int dotoffset(Node *n, int64 *oary, Node **nn); -void gen(Node *n); -void genlist(NodeList *l); -Node* sysfunc(char *name); -void tempname(Node *n, Type *t); -Node* temp(Type*); - -/* - * init.c - */ -void fninit(NodeList *n); -Sym* renameinit(void); - -/* - * inl.c - */ -void caninl(Node *fn); -void inlcalls(Node *fn); -void typecheckinl(Node *fn); - -/* - * lex.c - */ -void cannedimports(char *file, char *cp); -void importfile(Val *f, int line); -char* lexname(int lex); -char* expstring(void); -void mkpackage(char* pkgname); -void unimportfile(void); -int32 yylex(void); -extern int yylast; -extern int yyprev; - -/* - * mparith1.c - */ -int Bconv(Fmt *fp); -int Fconv(Fmt *fp); -void mpaddcfix(Mpint *a, vlong c); -void mpaddcflt(Mpflt *a, double c); -void mpatofix(Mpint *a, char *as); -void mpatoflt(Mpflt *a, char *as); -int mpcmpfixc(Mpint *b, vlong c); -int mpcmpfixfix(Mpint *a, Mpint *b); -int mpcmpfixflt(Mpint *a, Mpflt *b); -int mpcmpfltc(Mpflt *b, double c); -int mpcmpfltfix(Mpflt *a, Mpint *b); -int mpcmpfltflt(Mpflt *a, Mpflt *b); -void mpcomfix(Mpint *a); -void mpdivfixfix(Mpint *a, Mpint *b); -void mpmodfixfix(Mpint *a, Mpint *b); -void mpmovefixfix(Mpint *a, Mpint *b); -void mpmovefixflt(Mpflt *a, Mpint *b); -int mpmovefltfix(Mpint *a, Mpflt *b); -void mpmovefltflt(Mpflt *a, Mpflt *b); -void mpmulcfix(Mpint *a, vlong c); -void mpmulcflt(Mpflt *a, double c); -void mpsubfixfix(Mpint *a, Mpint *b); -void mpsubfltflt(Mpflt *a, Mpflt *b); - -/* - * mparith2.c - */ -void mpaddfixfix(Mpint *a, Mpint *b, int); -void mpandfixfix(Mpint *a, Mpint *b); -void mpandnotfixfix(Mpint *a, Mpint *b); -void mpdivfract(Mpint *a, Mpint *b); -void mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d); -vlong mpgetfix(Mpint *a); -void mplshfixfix(Mpint *a, Mpint *b); -void mpmovecfix(Mpint *a, vlong c); -void mpmulfixfix(Mpint *a, Mpint *b); -void mpmulfract(Mpint *a, Mpint *b); -void mpnegfix(Mpint *a); -void mporfixfix(Mpint *a, Mpint *b); -void mprshfixfix(Mpint *a, Mpint *b); -void mpshiftfix(Mpint *a, int s); -int mptestfix(Mpint *a); -void mpxorfixfix(Mpint *a, Mpint *b); - -/* - * mparith3.c - */ -void mpaddfltflt(Mpflt *a, Mpflt *b); -void mpdivfltflt(Mpflt *a, Mpflt *b); -double mpgetflt(Mpflt *a); -double mpgetflt32(Mpflt *a); -void mpmovecflt(Mpflt *a, double c); -void mpmulfltflt(Mpflt *a, Mpflt *b); -void mpnegflt(Mpflt *a); -void mpnorm(Mpflt *a); -void mpsetexp(Mpflt *a, int exp); -int mptestflt(Mpflt *a); -int sigfig(Mpflt *a); - -/* - * obj.c - */ -void Bputname(Biobuf *b, LSym *s); -int duint16(Sym *s, int off, uint16 v); -int duint32(Sym *s, int off, uint32 v); -int duint64(Sym *s, int off, uint64 v); -int duint8(Sym *s, int off, uint8 v); -int duintptr(Sym *s, int off, uint64 v); -void dumpobj(void); -Sym* stringsym(char*, int); -void slicebytes(Node*, char*, int); -LSym* linksym(Sym*); - -/* - * order.c - */ -void order(Node *fn); -void orderstmtinplace(Node **stmt); - -/* - * range.c - */ -void typecheckrange(Node *n); -void walkrange(Node *n); - -/* - * reflect.c - */ -void dumptypestructs(void); -Type* methodfunc(Type *f, Type*); -Node* typename(Type *t); -Sym* typesym(Type *t); -Sym* typenamesym(Type *t); -Sym* tracksym(Type *t); -Sym* typesymprefix(char *prefix, Type *t); -int haspointers(Type *t); -Type* hmap(Type *t); -Type* hiter(Type* t); -Type* mapbucket(Type *t); - -/* - * select.c - */ -void typecheckselect(Node *sel); -void walkselect(Node *sel); - -/* - * sinit.c - */ -void anylit(int, Node *n, Node *var, NodeList **init); -int gen_as_init(Node *n); -NodeList* initfix(NodeList *l); -int oaslit(Node *n, NodeList **init); -int stataddr(Node *nam, Node *n); - -/* - * subr.c - */ -Node* adddot(Node *n); -int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase); -void addinit(Node**, NodeList*); -Type* aindex(Node *b, Type *t); -int algtype(Type *t); -int algtype1(Type *t, Type **bad); -void argtype(Node *on, Type *t); -Node* assignconv(Node *n, Type *t, char *context); -int assignop(Type *src, Type *dst, char **why); -void badtype(int o, Type *tl, Type *tr); -int brcom(int a); -int brrev(int a); -NodeList* concat(NodeList *a, NodeList *b); -int convertop(Type *src, Type *dst, char **why); -Node* copyexpr(Node*, Type*, NodeList**); -int count(NodeList *l); -int cplxsubtype(int et); -int eqtype(Type *t1, Type *t2); -int eqtypenoname(Type *t1, Type *t2); -void errorexit(void); -void expandmeth(Type *t); -void fatal(char *fmt, ...); -void flusherrors(void); -void frame(int context); -Type* funcfirst(Iter *s, Type *t); -Type* funcnext(Iter *s); -void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface); -void genhash(Sym *sym, Type *t); -void geneq(Sym *sym, Type *t); -Type** getinarg(Type *t); -Type* getinargx(Type *t); -Type** getoutarg(Type *t); -Type* getoutargx(Type *t); -Type** getthis(Type *t); -Type* getthisx(Type *t); -int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr); -void importdot(Pkg *opkg, Node *pack); -int is64(Type *t); -int isbadimport(Strlit *s); -int isblank(Node *n); -int isblanksym(Sym *s); -int isdirectiface(Type*); -int isfixedarray(Type *t); -int isideal(Type *t); -int isinter(Type *t); -int isnil(Node *n); -int isnilinter(Type *t); -int isptrto(Type *t, int et); -int isslice(Type *t); -int istype(Type *t, int et); -int iszero(Node *n); -void linehist(char *file, int32 off, int relative); -NodeList* list(NodeList *l, Node *n); -NodeList* list1(Node *n); -void listsort(NodeList**, int(*f)(Node*, Node*)); -Node* liststmt(NodeList *l); -NodeList* listtreecopy(NodeList *l); -Sym* lookup(char *name); -void* mal(int32 n); -Type* maptype(Type *key, Type *val); -Type* methtype(Type *t, int mustname); -Pkg* mkpkg(Strlit *path); -Sym* ngotype(Node *n); -int noconv(Type *t1, Type *t2); -Node* nod(int op, Node *nleft, Node *nright); -Node* nodbool(int b); -void nodconst(Node *n, Type *t, int64 v); -Node* nodintconst(int64 v); -Node* nodfltconst(Mpflt *v); -Node* nodnil(void); -int parserline(void); -Sym* pkglookup(char *name, Pkg *pkg); -int powtwo(Node *n); -Type* ptrto(Type *t); -void* remal(void *p, int32 on, int32 n); -Sym* restrictlookup(char *name, Pkg *pkg); -Node* safeexpr(Node *n, NodeList **init); -void saveerrors(void); -Node* cheapexpr(Node *n, NodeList **init); -Node* localexpr(Node *n, Type *t, NodeList **init); -void saveorignode(Node *n); -int32 setlineno(Node *n); -void setmaxarg(Type *t, int32 extra); -Type* shallow(Type *t); -int simsimtype(Type *t); -void smagic(Magic *m); -Type* sortinter(Type *t); -uint32 stringhash(char *p); -Strlit* newstrlit(char *s); -int structcount(Type *t); -Type* structfirst(Iter *s, Type **nn); -Type* structnext(Iter *s); -Node* syslook(char *name, int copy); -Type* tounsigned(Type *t); -Node* treecopy(Node *n); -Type* typ(int et); -uint32 typehash(Type *t); -void ullmancalc(Node *n); -void umagic(Magic *m); -void warn(char *fmt, ...); -void warnl(int line, char *fmt, ...); -void yyerror(char *fmt, ...); -void yyerrorl(int line, char *fmt, ...); -void adderrorname(Node*); - -/* - * swt.c - */ -void typecheckswitch(Node *n); -void walkswitch(Node *sw); - -/* - * typecheck.c - */ -int islvalue(Node *n); -int samesafeexpr(Node *l, Node *r); -Node* typecheck(Node **np, int top); -void typechecklist(NodeList *l, int top); -Node* typecheckdef(Node *n); -void copytype(Node *n, Type *t); -void checkreturn(Node*); -void checkassign(Node *stmt, Node*); -void queuemethod(Node *n); - -/* - * unsafe.c - */ -int isunsafebuiltin(Node *n); -Node* unsafenmagic(Node *n); - -/* - * walk.c - */ -Node* callnew(Type *t); -Node* chanfn(char *name, int n, Type *t); -Node* mkcall(char *name, Type *t, NodeList **init, ...); -Node* mkcall1(Node *fn, Type *t, NodeList **init, ...); -int vmatch1(Node *l, Node *r); -void walk(Node *fn); -void walkexpr(Node **np, NodeList **init); -void walkexprlist(NodeList *l, NodeList **init); -void walkexprlistsafe(NodeList *l, NodeList **init); -void walkexprlistcheap(NodeList *l, NodeList **init); -void walkstmt(Node **np); -void walkstmtlist(NodeList *l); -Node* conv(Node*, Type*); -int candiscard(Node*); -int needwritebarrier(Node*, Node*); -Node* outervalue(Node*); -void usefield(Node*); - -/* - * thearch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c - */ -#define P ((Prog*)0) - -EXTERN Prog* continpc; -EXTERN Prog* breakpc; -EXTERN Prog* pc; -EXTERN Prog* firstpc; - -EXTERN Node* nodfp; -EXTERN int disable_checknil; -EXTERN vlong zerosize; - -void checknil(Node*, NodeList**); -void cgen_checknil(Node*); -void compile(Node*); -int duintxx(Sym *s, int off, uint64 v, int wid); -void gvardef(Node*); -void gvarkill(Node*); -void movelarge(NodeList*); -void liveness(Node*, Prog*, Sym*, Sym*); -void twobitwalktype1(Type*, vlong*, Bvec*); - -#pragma varargck type "B" Mpint* -#pragma varargck type "E" int -#pragma varargck type "E" uint -#pragma varargck type "F" Mpflt* -#pragma varargck type "H" NodeList* -#pragma varargck type "J" Node* -#pragma varargck type "lL" int32 -#pragma varargck type "L" int32 -#pragma varargck type "N" Node* -#pragma varargck type "lN" Node* -#pragma varargck type "O" int -#pragma varargck type "O" uint -#pragma varargck type "Q" Bits -#pragma varargck type "S" Sym* -#pragma varargck type "lS" LSym* -#pragma varargck type "T" Type* -#pragma varargck type "lT" Type* -#pragma varargck type "V" Val* -#pragma varargck type "Z" Strlit* - -/* - * racewalk.c - */ -void racewalk(Node *fn); - -/* - * flow.c - */ -typedef struct Flow Flow; -typedef struct Graph Graph; - -struct Flow { - Prog* prog; // actual instruction - Flow* p1; // predecessors of this instruction: p1, - Flow* p2; // and then p2 linked though p2link. - Flow* p2link; - Flow* s1; // successors of this instruction (at most two: s1 and s2). - Flow* s2; - Flow* link; // next instruction in function code - - int32 active; // usable by client - - int32 id; // sequence number in flow graph - int32 rpo; // reverse post ordering - uint16 loop; // x5 for every loop - uchar refset; // diagnostic generated - - void* data; // for use by client -}; - -struct Graph -{ - Flow* start; - int num; - - // After calling flowrpo, rpo lists the flow nodes in reverse postorder, - // and each non-dead Flow node f has g->rpo[f->rpo] == f. - Flow** rpo; -}; - -void fixjmp(Prog*); -Graph* flowstart(Prog*, int); -void flowrpo(Graph*); -void flowend(Graph*); -void mergetemp(Prog*); -void nilopt(Prog*); -int noreturn(Prog*); -Flow* uniqp(Flow*); -Flow* uniqs(Flow*); - -/* - * interface to back end - */ - -typedef struct ProgInfo ProgInfo; -struct ProgInfo -{ - uint32 flags; // the bits below - uint64 reguse; // registers implicitly used by this instruction - uint64 regset; // registers implicitly set by this instruction - uint64 regindex; // registers used by addressing mode -}; - -enum -{ - // Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA. - Pseudo = 1<<1, - - // There's nothing to say about the instruction, - // but it's still okay to see. - OK = 1<<2, - - // Size of right-side write, or right-side read if no write. - SizeB = 1<<3, - SizeW = 1<<4, - SizeL = 1<<5, - SizeQ = 1<<6, - SizeF = 1<<7, // float aka float32 - SizeD = 1<<8, // double aka float64 - - // Left side (Prog.from): address taken, read, write. - LeftAddr = 1<<9, - LeftRead = 1<<10, - LeftWrite = 1<<11, - - // Register in middle (Prog.reg); only ever read. (arm, ppc64) - RegRead = 1<<12, - CanRegRead = 1<<13, - - // Right side (Prog.to): address taken, read, write. - RightAddr = 1<<14, - RightRead = 1<<15, - RightWrite = 1<<16, - - // Instruction kinds - Move = 1<<17, // straight move - Conv = 1<<18, // size conversion - Cjmp = 1<<19, // conditional jump - Break = 1<<20, // breaks control flow (no fallthrough) - Call = 1<<21, // function call - Jump = 1<<22, // jump - Skip = 1<<23, // data instruction - - // Set, use, or kill of carry bit. - // Kill means we never look at the carry bit after this kind of instruction. - SetCarry = 1<<24, - UseCarry = 1<<25, - KillCarry = 1<<26, - - // Special cases for register use. (amd64, 386) - ShiftCX = 1<<27, // possible shift by CX - ImulAXDX = 1<<28, // possible multiply into DX:AX - - // Instruction updates whichever of from/to is type D_OREG. (ppc64) - PostInc = 1<<29, -}; - -typedef struct Arch Arch; - -struct Arch -{ - int thechar; - char *thestring; - LinkArch *thelinkarch; - Typedef *typedefs; - - int REGSP; - int REGCTXT; - vlong MAXWIDTH; - - int (*anyregalloc)(void); - void (*betypeinit)(void); - void (*bgen)(Node*, int, int, Prog*); - void (*cgen)(Node*, Node*); - void (*cgen_call)(Node*, int); - void (*cgen_callinter)(Node*, Node*, int); - void (*cgen_ret)(Node*); - void (*clearfat)(Node*); - void (*defframe)(Prog*); - void (*excise)(Flow*); - void (*expandchecks)(Prog*); - void (*gclean)(void); - void (*ginit)(void); - Prog* (*gins)(int, Node*, Node*); - void (*ginscall)(Node*, int); - void (*igen)(Node*, Node*, Node*); - void (*linkarchinit)(void); - void (*peep)(Prog*); - void (*proginfo)(ProgInfo*, Prog*); - void (*regalloc)(Node*, Type*, Node*); - void (*regfree)(Node*); - int (*regtyp)(Addr*); - int (*sameaddr)(Addr*, Addr*); - int (*smallindir)(Addr*, Addr*); - int (*stackaddr)(Addr*); - uint64 (*excludedregs)(void); - uint64 (*RtoB)(int); - uint64 (*FtoB)(int); - int (*BtoR)(uint64); - int (*BtoF)(uint64); - int (*optoas)(int, Type*); - uint64 (*doregbits)(int); - char **(*regnames)(int*); -}; - -void afunclit(Addr*, Node*); -void clearp(Prog*); -int dgostringptr(Sym*, int, char*); -int dgostrlitptr(Sym*, int, Strlit*); -int dsname(Sym*, int, char*, int); -int dsymptr(Sym*, int, Sym*, int); -void dumpdata(void); -void fixautoused(Prog*); -void gdata(Node*, Node*, int); -void gdatacomplex(Node*, Mpcplx*); -void gdatastring(Node*, Strlit*); -void ggloblnod(Node*); -void ggloblsym(Sym*, int32, int8); -Prog* gjmp(Prog*); -void gtrack(Sym*); -void gused(Node*); -int isfat(Type*); -void markautoused(Prog*); -void naddr(Node*, Addr*, int); -Plist* newplist(void); -Node* nodarg(Type*, int); -void patch(Prog*, Prog*); -Prog* unpatch(Prog*); -void datagostring(Strlit *sval, Addr *a); -int ismem(Node*); -int samereg(Node*, Node*); -void regopt(Prog*); -int Tconv(Fmt*); -int Oconv(Fmt*); -Prog* gbranch(int as, Type *t, int likely); -void nodindreg(Node *n, Type *t, int r); -void nodreg(Node *n, Type *t, int r); -Prog* prog(int as); -void datastring(char*, int, Addr*); - -EXTERN int32 pcloc; - -EXTERN Arch thearch; - -EXTERN Node *newproc; -EXTERN Node *deferproc; -EXTERN Node *deferreturn; -EXTERN Node *panicindex; -EXTERN Node *panicslice; -EXTERN Node *throwreturn; - -int gcmain(int, char**); diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y deleted file mode 100644 index dc8b530562..0000000000 --- a/src/cmd/gc/go.y +++ /dev/null @@ -1,2225 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * Go language grammar. - * - * The Go semicolon rules are: - * - * 1. all statements and declarations are terminated by semicolons. - * 2. semicolons can be omitted before a closing ) or }. - * 3. semicolons are inserted by the lexer before a newline - * following a specific list of tokens. - * - * Rules #1 and #2 are accomplished by writing the lists as - * semicolon-separated lists with an optional trailing semicolon. - * Rule #3 is implemented in yylex. - */ - -%{ -#include -#include /* if we don't, bison will, and go.h re-#defines getc */ -#include -#include "go.h" - -static void fixlbrace(int); -%} -%union { - Node* node; - NodeList* list; - Type* type; - Sym* sym; - struct Val val; - int i; -} - -// |sed 's/.* //' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx /' - -%token LLITERAL -%token LASOP LCOLAS -%token LBREAK LCASE LCHAN LCONST LCONTINUE LDDD -%token LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO -%token LIF LIMPORT LINTERFACE LMAP LNAME -%token LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH -%token LTYPE LVAR - -%token LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT -%token LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH - -%type lbrace import_here -%type sym packname -%type oliteral - -%type stmt ntype -%type arg_type -%type case caseblock -%type compound_stmt dotname embed expr complitexpr bare_complitexpr -%type expr_or_type -%type fndcl hidden_fndcl fnliteral -%type for_body for_header for_stmt if_header if_stmt non_dcl_stmt -%type interfacedcl keyval labelname name -%type name_or_type non_expr_type -%type new_name dcl_name oexpr typedclname -%type onew_name -%type osimple_stmt pexpr pexpr_no_paren -%type pseudocall range_stmt select_stmt -%type simple_stmt -%type switch_stmt uexpr -%type xfndcl typedcl start_complit - -%type xdcl fnbody fnres loop_body dcl_name_list -%type new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list -%type oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list -%type interfacedcl_list vardcl vardcl_list structdcl structdcl_list -%type common_dcl constdcl constdcl1 constdcl_list typedcl_list - -%type convtype comptype dotdotdot -%type indcl interfacetype structtype ptrtype -%type recvchantype non_recvchantype othertype fnret_type fntype - -%type hidden_importsym hidden_pkg_importsym - -%type hidden_constant hidden_literal hidden_funarg -%type hidden_interfacedcl hidden_structdcl - -%type hidden_funres -%type ohidden_funres -%type hidden_funarg_list ohidden_funarg_list -%type hidden_interfacedcl_list ohidden_interfacedcl_list -%type hidden_structdcl_list ohidden_structdcl_list - -%type hidden_type hidden_type_misc hidden_pkgtype -%type hidden_type_func -%type hidden_type_recv_chan hidden_type_non_recv_chan - -%left LCOMM /* outside the usual hierarchy; here for good error messages */ - -%left LOROR -%left LANDAND -%left LEQ LNE LLE LGE LLT LGT -%left '+' '-' '|' '^' -%left '*' '/' '%' '&' LLSH LRSH LANDNOT - -/* - * manual override of shift/reduce conflicts. - * the general form is that we assign a precedence - * to the token being shifted and then introduce - * NotToken with lower precedence or PreferToToken with higher - * and annotate the reducing rule accordingly. - */ -%left NotPackage -%left LPACKAGE - -%left NotParen -%left '(' - -%left ')' -%left PreferToRightParen - -%error-verbose - -%% -file: - loadsys - package - imports - xdcl_list - { - xtop = concat(xtop, $4); - } - -package: - %prec NotPackage - { - prevlineno = lineno; - yyerror("package statement must be first"); - errorexit(); - } -| LPACKAGE sym ';' - { - mkpackage($2->name); - } - -/* - * this loads the definitions for the low-level runtime functions, - * so that the compiler can generate calls to them, - * but does not make the name "runtime" visible as a package. - */ -loadsys: - { - importpkg = runtimepkg; - - if(debug['A']) - cannedimports("runtime.builtin", "package runtime\n\n$$\n\n"); - else - cannedimports("runtime.builtin", runtimeimport); - curio.importsafe = 1; - } - import_package - import_there - { - importpkg = nil; - } - -imports: -| imports import ';' - -import: - LIMPORT import_stmt -| LIMPORT '(' import_stmt_list osemi ')' -| LIMPORT '(' ')' - -import_stmt: - import_here import_package import_there - { - Pkg *ipkg; - Sym *my; - Node *pack; - - ipkg = importpkg; - my = importmyname; - importpkg = nil; - importmyname = S; - - if(my == nil) - my = lookup(ipkg->name); - - pack = nod(OPACK, N, N); - pack->sym = my; - pack->pkg = ipkg; - pack->lineno = $1; - - if(my->name[0] == '.') { - importdot(ipkg, pack); - break; - } - if(strcmp(my->name, "init") == 0) { - yyerror("cannot import package as init - init must be a func"); - break; - } - if(my->name[0] == '_' && my->name[1] == '\0') - break; - if(my->def) { - lineno = $1; - redeclare(my, "as imported package name"); - } - my->def = pack; - my->lastlineno = $1; - my->block = 1; // at top level - } -| import_here import_there - { - // When an invalid import path is passed to importfile, - // it calls yyerror and then sets up a fake import with - // no package statement. This allows us to test more - // than one invalid import statement in a single file. - if(nerrors == 0) - fatal("phase error in import"); - } - -import_stmt_list: - import_stmt -| import_stmt_list ';' import_stmt - -import_here: - LLITERAL - { - // import with original name - $$ = parserline(); - importmyname = S; - importfile(&$1, $$); - } -| sym LLITERAL - { - // import with given name - $$ = parserline(); - importmyname = $1; - importfile(&$2, $$); - } -| '.' LLITERAL - { - // import into my name space - $$ = parserline(); - importmyname = lookup("."); - importfile(&$2, $$); - } - -import_package: - LPACKAGE LNAME import_safety ';' - { - if(importpkg->name == nil) { - importpkg->name = $2->name; - pkglookup($2->name, nil)->npkg++; - } else if(strcmp(importpkg->name, $2->name) != 0) - yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path); - importpkg->direct = 1; - importpkg->safe = curio.importsafe; - - if(safemode && !curio.importsafe) - yyerror("cannot import unsafe package \"%Z\"", importpkg->path); - } - -import_safety: -| LNAME - { - if(strcmp($1->name, "safe") == 0) - curio.importsafe = 1; - } - -import_there: - { - defercheckwidth(); - } - hidden_import_list '$' '$' - { - resumecheckwidth(); - unimportfile(); - } - -/* - * declarations - */ -xdcl: - { - yyerror("empty top-level declaration"); - $$ = nil; - } -| common_dcl -| xfndcl - { - $$ = list1($1); - } -| non_dcl_stmt - { - yyerror("non-declaration statement outside function body"); - $$ = nil; - } -| error - { - $$ = nil; - } - -common_dcl: - LVAR vardcl - { - $$ = $2; - } -| LVAR '(' vardcl_list osemi ')' - { - $$ = $3; - } -| LVAR '(' ')' - { - $$ = nil; - } -| lconst constdcl - { - $$ = $2; - iota = -100000; - lastconst = nil; - } -| lconst '(' constdcl osemi ')' - { - $$ = $3; - iota = -100000; - lastconst = nil; - } -| lconst '(' constdcl ';' constdcl_list osemi ')' - { - $$ = concat($3, $5); - iota = -100000; - lastconst = nil; - } -| lconst '(' ')' - { - $$ = nil; - iota = -100000; - } -| LTYPE typedcl - { - $$ = list1($2); - } -| LTYPE '(' typedcl_list osemi ')' - { - $$ = $3; - } -| LTYPE '(' ')' - { - $$ = nil; - } - -lconst: - LCONST - { - iota = 0; - } - -vardcl: - dcl_name_list ntype - { - $$ = variter($1, $2, nil); - } -| dcl_name_list ntype '=' expr_list - { - $$ = variter($1, $2, $4); - } -| dcl_name_list '=' expr_list - { - $$ = variter($1, nil, $3); - } - -constdcl: - dcl_name_list ntype '=' expr_list - { - $$ = constiter($1, $2, $4); - } -| dcl_name_list '=' expr_list - { - $$ = constiter($1, N, $3); - } - -constdcl1: - constdcl -| dcl_name_list ntype - { - $$ = constiter($1, $2, nil); - } -| dcl_name_list - { - $$ = constiter($1, N, nil); - } - -typedclname: - sym - { - // different from dclname because the name - // becomes visible right here, not at the end - // of the declaration. - $$ = typedcl0($1); - } - -typedcl: - typedclname ntype - { - $$ = typedcl1($1, $2, 1); - } - -simple_stmt: - expr - { - $$ = $1; - - // These nodes do not carry line numbers. - // Since a bare name used as an expression is an error, - // introduce a wrapper node to give the correct line. - switch($$->op) { - case ONAME: - case ONONAME: - case OTYPE: - case OPACK: - case OLITERAL: - $$ = nod(OPAREN, $$, N); - $$->implicit = 1; - break; - } - } -| expr LASOP expr - { - $$ = nod(OASOP, $1, $3); - $$->etype = $2; // rathole to pass opcode - } -| expr_list '=' expr_list - { - if($1->next == nil && $3->next == nil) { - // simple - $$ = nod(OAS, $1->n, $3->n); - break; - } - // multiple - $$ = nod(OAS2, N, N); - $$->list = $1; - $$->rlist = $3; - } -| expr_list LCOLAS expr_list - { - if($3->n->op == OTYPESW) { - $$ = nod(OTYPESW, N, $3->n->right); - if($3->next != nil) - yyerror("expr.(type) must be alone in list"); - if($1->next != nil) - yyerror("argument count mismatch: %d = %d", count($1), 1); - else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n)) - yyerror("invalid variable name %N in type switch", $1->n); - else - $$->left = dclname($1->n->sym); // it's a colas, so must not re-use an oldname. - break; - } - $$ = colas($1, $3, $2); - } -| expr LINC - { - $$ = nod(OASOP, $1, nodintconst(1)); - $$->implicit = 1; - $$->etype = OADD; - } -| expr LDEC - { - $$ = nod(OASOP, $1, nodintconst(1)); - $$->implicit = 1; - $$->etype = OSUB; - } - -case: - LCASE expr_or_type_list ':' - { - Node *n, *nn; - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - $$ = nod(OXCASE, N, N); - $$->list = $2; - if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { - // type switch - declare variable - nn = newname(n->sym); - declare(nn, dclcontext); - $$->nname = nn; - - // keep track of the instances for reporting unused - nn->defn = typesw->right; - } - } -| LCASE expr_or_type_list '=' expr ':' - { - Node *n; - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - $$ = nod(OXCASE, N, N); - if($2->next == nil) - n = nod(OAS, $2->n, $4); - else { - n = nod(OAS2, N, N); - n->list = $2; - n->rlist = list1($4); - } - $$->list = list1(n); - } -| LCASE expr_or_type_list LCOLAS expr ':' - { - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - $$ = nod(OXCASE, N, N); - $$->list = list1(colas($2, list1($4), $3)); - } -| LDEFAULT ':' - { - Node *n, *nn; - - markdcl(); - $$ = nod(OXCASE, N, N); - if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { - // type switch - declare variable - nn = newname(n->sym); - declare(nn, dclcontext); - $$->nname = nn; - - // keep track of the instances for reporting unused - nn->defn = typesw->right; - } - } - -compound_stmt: - '{' - { - markdcl(); - } - stmt_list '}' - { - if($3 == nil) - $$ = nod(OEMPTY, N, N); - else - $$ = liststmt($3); - popdcl(); - } - -caseblock: - case - { - // If the last token read by the lexer was consumed - // as part of the case, clear it (parser has cleared yychar). - // If the last token read by the lexer was the lookahead - // leave it alone (parser has it cached in yychar). - // This is so that the stmt_list action doesn't look at - // the case tokens if the stmt_list is empty. - yylast = yychar; - $1->xoffset = block; - } - stmt_list - { - int last; - - // This is the only place in the language where a statement - // list is not allowed to drop the final semicolon, because - // it's the only place where a statement list is not followed - // by a closing brace. Handle the error for pedantry. - - // Find the final token of the statement list. - // yylast is lookahead; yyprev is last of stmt_list - last = yyprev; - - if(last > 0 && last != ';' && yychar != '}') - yyerror("missing statement after label"); - $$ = $1; - $$->nbody = $3; - popdcl(); - } - -caseblock_list: - { - $$ = nil; - } -| caseblock_list caseblock - { - $$ = list($1, $2); - } - -loop_body: - LBODY - { - markdcl(); - } - stmt_list '}' - { - $$ = $3; - popdcl(); - } - -range_stmt: - expr_list '=' LRANGE expr - { - $$ = nod(ORANGE, N, $4); - $$->list = $1; - $$->etype = 0; // := flag - } -| expr_list LCOLAS LRANGE expr - { - $$ = nod(ORANGE, N, $4); - $$->list = $1; - $$->colas = 1; - colasdefn($1, $$); - } -| LRANGE expr - { - $$ = nod(ORANGE, N, $2); - $$->etype = 0; // := flag - } - -for_header: - osimple_stmt ';' osimple_stmt ';' osimple_stmt - { - // init ; test ; incr - if($5 != N && $5->colas != 0) - yyerror("cannot declare in the for-increment"); - $$ = nod(OFOR, N, N); - if($1 != N) - $$->ninit = list1($1); - $$->ntest = $3; - $$->nincr = $5; - } -| osimple_stmt - { - // normal test - $$ = nod(OFOR, N, N); - $$->ntest = $1; - } -| range_stmt - -for_body: - for_header loop_body - { - $$ = $1; - $$->nbody = concat($$->nbody, $2); - } - -for_stmt: - LFOR - { - markdcl(); - } - for_body - { - $$ = $3; - popdcl(); - } - -if_header: - osimple_stmt - { - // test - $$ = nod(OIF, N, N); - $$->ntest = $1; - } -| osimple_stmt ';' osimple_stmt - { - // init ; test - $$ = nod(OIF, N, N); - if($1 != N) - $$->ninit = list1($1); - $$->ntest = $3; - } - -/* IF cond body (ELSE IF cond body)* (ELSE block)? */ -if_stmt: - LIF - { - markdcl(); - } - if_header - { - if($3->ntest == N) - yyerror("missing condition in if statement"); - } - loop_body - { - $3->nbody = $5; - } - elseif_list else - { - Node *n; - NodeList *nn; - - $$ = $3; - n = $3; - popdcl(); - for(nn = concat($7, $8); nn; nn = nn->next) { - if(nn->n->op == OIF) - popdcl(); - n->nelse = list1(nn->n); - n = nn->n; - } - } - -elseif: - LELSE LIF - { - markdcl(); - } - if_header loop_body - { - if($4->ntest == N) - yyerror("missing condition in if statement"); - $4->nbody = $5; - $$ = list1($4); - } - -elseif_list: - { - $$ = nil; - } -| elseif_list elseif - { - $$ = concat($1, $2); - } - -else: - { - $$ = nil; - } -| LELSE compound_stmt - { - NodeList *node; - - node = mal(sizeof *node); - node->n = $2; - node->end = node; - $$ = node; - } - -switch_stmt: - LSWITCH - { - markdcl(); - } - if_header - { - Node *n; - n = $3->ntest; - if(n != N && n->op != OTYPESW) - n = N; - typesw = nod(OXXX, typesw, n); - } - LBODY caseblock_list '}' - { - $$ = $3; - $$->op = OSWITCH; - $$->list = $6; - typesw = typesw->left; - popdcl(); - } - -select_stmt: - LSELECT - { - typesw = nod(OXXX, typesw, N); - } - LBODY caseblock_list '}' - { - $$ = nod(OSELECT, N, N); - $$->lineno = typesw->lineno; - $$->list = $4; - typesw = typesw->left; - } - -/* - * expressions - */ -expr: - uexpr -| expr LOROR expr - { - $$ = nod(OOROR, $1, $3); - } -| expr LANDAND expr - { - $$ = nod(OANDAND, $1, $3); - } -| expr LEQ expr - { - $$ = nod(OEQ, $1, $3); - } -| expr LNE expr - { - $$ = nod(ONE, $1, $3); - } -| expr LLT expr - { - $$ = nod(OLT, $1, $3); - } -| expr LLE expr - { - $$ = nod(OLE, $1, $3); - } -| expr LGE expr - { - $$ = nod(OGE, $1, $3); - } -| expr LGT expr - { - $$ = nod(OGT, $1, $3); - } -| expr '+' expr - { - $$ = nod(OADD, $1, $3); - } -| expr '-' expr - { - $$ = nod(OSUB, $1, $3); - } -| expr '|' expr - { - $$ = nod(OOR, $1, $3); - } -| expr '^' expr - { - $$ = nod(OXOR, $1, $3); - } -| expr '*' expr - { - $$ = nod(OMUL, $1, $3); - } -| expr '/' expr - { - $$ = nod(ODIV, $1, $3); - } -| expr '%' expr - { - $$ = nod(OMOD, $1, $3); - } -| expr '&' expr - { - $$ = nod(OAND, $1, $3); - } -| expr LANDNOT expr - { - $$ = nod(OANDNOT, $1, $3); - } -| expr LLSH expr - { - $$ = nod(OLSH, $1, $3); - } -| expr LRSH expr - { - $$ = nod(ORSH, $1, $3); - } - /* not an expression anymore, but left in so we can give a good error */ -| expr LCOMM expr - { - $$ = nod(OSEND, $1, $3); - } - -uexpr: - pexpr -| '*' uexpr - { - $$ = nod(OIND, $2, N); - } -| '&' uexpr - { - if($2->op == OCOMPLIT) { - // Special case for &T{...}: turn into (*T){...}. - $$ = $2; - $$->right = nod(OIND, $$->right, N); - $$->right->implicit = 1; - } else { - $$ = nod(OADDR, $2, N); - } - } -| '+' uexpr - { - $$ = nod(OPLUS, $2, N); - } -| '-' uexpr - { - $$ = nod(OMINUS, $2, N); - } -| '!' uexpr - { - $$ = nod(ONOT, $2, N); - } -| '~' uexpr - { - yyerror("the bitwise complement operator is ^"); - $$ = nod(OCOM, $2, N); - } -| '^' uexpr - { - $$ = nod(OCOM, $2, N); - } -| LCOMM uexpr - { - $$ = nod(ORECV, $2, N); - } - -/* - * call-like statements that - * can be preceded by 'defer' and 'go' - */ -pseudocall: - pexpr '(' ')' - { - $$ = nod(OCALL, $1, N); - } -| pexpr '(' expr_or_type_list ocomma ')' - { - $$ = nod(OCALL, $1, N); - $$->list = $3; - } -| pexpr '(' expr_or_type_list LDDD ocomma ')' - { - $$ = nod(OCALL, $1, N); - $$->list = $3; - $$->isddd = 1; - } - -pexpr_no_paren: - LLITERAL - { - $$ = nodlit($1); - } -| name -| pexpr '.' sym - { - if($1->op == OPACK) { - Sym *s; - s = restrictlookup($3->name, $1->pkg); - $1->used = 1; - $$ = oldname(s); - break; - } - $$ = nod(OXDOT, $1, newname($3)); - } -| pexpr '.' '(' expr_or_type ')' - { - $$ = nod(ODOTTYPE, $1, $4); - } -| pexpr '.' '(' LTYPE ')' - { - $$ = nod(OTYPESW, N, $1); - } -| pexpr '[' expr ']' - { - $$ = nod(OINDEX, $1, $3); - } -| pexpr '[' oexpr ':' oexpr ']' - { - $$ = nod(OSLICE, $1, nod(OKEY, $3, $5)); - } -| pexpr '[' oexpr ':' oexpr ':' oexpr ']' - { - if($5 == N) - yyerror("middle index required in 3-index slice"); - if($7 == N) - yyerror("final index required in 3-index slice"); - $$ = nod(OSLICE3, $1, nod(OKEY, $3, nod(OKEY, $5, $7))); - } -| pseudocall -| convtype '(' expr ocomma ')' - { - // conversion - $$ = nod(OCALL, $1, N); - $$->list = list1($3); - } -| comptype lbrace start_complit braced_keyval_list '}' - { - $$ = $3; - $$->right = $1; - $$->list = $4; - fixlbrace($2); - } -| pexpr_no_paren '{' start_complit braced_keyval_list '}' - { - $$ = $3; - $$->right = $1; - $$->list = $4; - } -| '(' expr_or_type ')' '{' start_complit braced_keyval_list '}' - { - yyerror("cannot parenthesize type in composite literal"); - $$ = $5; - $$->right = $2; - $$->list = $6; - } -| fnliteral - -start_complit: - { - // composite expression. - // make node early so we get the right line number. - $$ = nod(OCOMPLIT, N, N); - } - -keyval: - expr ':' complitexpr - { - $$ = nod(OKEY, $1, $3); - } - -bare_complitexpr: - expr - { - // These nodes do not carry line numbers. - // Since a composite literal commonly spans several lines, - // the line number on errors may be misleading. - // Introduce a wrapper node to give the correct line. - $$ = $1; - switch($$->op) { - case ONAME: - case ONONAME: - case OTYPE: - case OPACK: - case OLITERAL: - $$ = nod(OPAREN, $$, N); - $$->implicit = 1; - } - } -| '{' start_complit braced_keyval_list '}' - { - $$ = $2; - $$->list = $3; - } - -complitexpr: - expr -| '{' start_complit braced_keyval_list '}' - { - $$ = $2; - $$->list = $3; - } - -pexpr: - pexpr_no_paren -| '(' expr_or_type ')' - { - $$ = $2; - - // Need to know on lhs of := whether there are ( ). - // Don't bother with the OPAREN in other cases: - // it's just a waste of memory and time. - switch($$->op) { - case ONAME: - case ONONAME: - case OPACK: - case OTYPE: - case OLITERAL: - case OTYPESW: - $$ = nod(OPAREN, $$, N); - } - } - -expr_or_type: - expr -| non_expr_type %prec PreferToRightParen - -name_or_type: - ntype - -lbrace: - LBODY - { - $$ = LBODY; - } -| '{' - { - $$ = '{'; - } - -/* - * names and types - * newname is used before declared - * oldname is used after declared - */ -new_name: - sym - { - if($1 == S) - $$ = N; - else - $$ = newname($1); - } - -dcl_name: - sym - { - $$ = dclname($1); - } - -onew_name: - { - $$ = N; - } -| new_name - -sym: - LNAME - { - $$ = $1; - // during imports, unqualified non-exported identifiers are from builtinpkg - if(importpkg != nil && !exportname($1->name)) - $$ = pkglookup($1->name, builtinpkg); - } -| hidden_importsym -| '?' - { - $$ = S; - } - -hidden_importsym: - '@' LLITERAL '.' LNAME - { - Pkg *p; - - if($2.u.sval->len == 0) - p = importpkg; - else { - if(isbadimport($2.u.sval)) - errorexit(); - p = mkpkg($2.u.sval); - } - $$ = pkglookup($4->name, p); - } -| '@' LLITERAL '.' '?' - { - Pkg *p; - - if($2.u.sval->len == 0) - p = importpkg; - else { - if(isbadimport($2.u.sval)) - errorexit(); - p = mkpkg($2.u.sval); - } - $$ = pkglookup("?", p); - } - -name: - sym %prec NotParen - { - $$ = oldname($1); - if($$->pack != N) - $$->pack->used = 1; - } - -labelname: - new_name - -/* - * to avoid parsing conflicts, type is split into - * channel types - * function types - * parenthesized types - * any other type - * the type system makes additional restrictions, - * but those are not implemented in the grammar. - */ -dotdotdot: - LDDD - { - yyerror("final argument in variadic function missing type"); - $$ = nod(ODDD, typenod(typ(TINTER)), N); - } -| LDDD ntype - { - $$ = nod(ODDD, $2, N); - } - -ntype: - recvchantype -| fntype -| othertype -| ptrtype -| dotname -| '(' ntype ')' - { - $$ = $2; - } - -non_expr_type: - recvchantype -| fntype -| othertype -| '*' non_expr_type - { - $$ = nod(OIND, $2, N); - } - -non_recvchantype: - fntype -| othertype -| ptrtype -| dotname -| '(' ntype ')' - { - $$ = $2; - } - -convtype: - fntype -| othertype - -comptype: - othertype - -fnret_type: - recvchantype -| fntype -| othertype -| ptrtype -| dotname - -dotname: - name -| name '.' sym - { - if($1->op == OPACK) { - Sym *s; - s = restrictlookup($3->name, $1->pkg); - $1->used = 1; - $$ = oldname(s); - break; - } - $$ = nod(OXDOT, $1, newname($3)); - } - -othertype: - '[' oexpr ']' ntype - { - $$ = nod(OTARRAY, $2, $4); - } -| '[' LDDD ']' ntype - { - // array literal of nelem - $$ = nod(OTARRAY, nod(ODDD, N, N), $4); - } -| LCHAN non_recvchantype - { - $$ = nod(OTCHAN, $2, N); - $$->etype = Cboth; - } -| LCHAN LCOMM ntype - { - $$ = nod(OTCHAN, $3, N); - $$->etype = Csend; - } -| LMAP '[' ntype ']' ntype - { - $$ = nod(OTMAP, $3, $5); - } -| structtype -| interfacetype - -ptrtype: - '*' ntype - { - $$ = nod(OIND, $2, N); - } - -recvchantype: - LCOMM LCHAN ntype - { - $$ = nod(OTCHAN, $3, N); - $$->etype = Crecv; - } - -structtype: - LSTRUCT lbrace structdcl_list osemi '}' - { - $$ = nod(OTSTRUCT, N, N); - $$->list = $3; - fixlbrace($2); - } -| LSTRUCT lbrace '}' - { - $$ = nod(OTSTRUCT, N, N); - fixlbrace($2); - } - -interfacetype: - LINTERFACE lbrace interfacedcl_list osemi '}' - { - $$ = nod(OTINTER, N, N); - $$->list = $3; - fixlbrace($2); - } -| LINTERFACE lbrace '}' - { - $$ = nod(OTINTER, N, N); - fixlbrace($2); - } - -/* - * function stuff - * all in one place to show how crappy it all is - */ -xfndcl: - LFUNC fndcl fnbody - { - $$ = $2; - if($$ == N) - break; - if(noescape && $3 != nil) - yyerror("can only use //go:noescape with external func implementations"); - $$->nbody = $3; - $$->endlineno = lineno; - $$->noescape = noescape; - $$->nosplit = nosplit; - $$->nowritebarrier = nowritebarrier; - funcbody($$); - } - -fndcl: - sym '(' oarg_type_list_ocomma ')' fnres - { - Node *t; - - $$ = N; - $3 = checkarglist($3, 1); - - if(strcmp($1->name, "init") == 0) { - $1 = renameinit(); - if($3 != nil || $5 != nil) - yyerror("func init must have no arguments and no return values"); - } - if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) { - if($3 != nil || $5 != nil) - yyerror("func main must have no arguments and no return values"); - } - - t = nod(OTFUNC, N, N); - t->list = $3; - t->rlist = $5; - - $$ = nod(ODCLFUNC, N, N); - $$->nname = newname($1); - $$->nname->defn = $$; - $$->nname->ntype = t; // TODO: check if nname already has an ntype - declare($$->nname, PFUNC); - - funchdr($$); - } -| '(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres - { - Node *rcvr, *t; - - $$ = N; - $2 = checkarglist($2, 0); - $6 = checkarglist($6, 1); - - if($2 == nil) { - yyerror("method has no receiver"); - break; - } - if($2->next != nil) { - yyerror("method has multiple receivers"); - break; - } - rcvr = $2->n; - if(rcvr->op != ODCLFIELD) { - yyerror("bad receiver in method"); - break; - } - - t = nod(OTFUNC, rcvr, N); - t->list = $6; - t->rlist = $8; - - $$ = nod(ODCLFUNC, N, N); - $$->shortname = newname($4); - $$->nname = methodname1($$->shortname, rcvr->right); - $$->nname->defn = $$; - $$->nname->ntype = t; - $$->nname->nointerface = nointerface; - declare($$->nname, PFUNC); - - funchdr($$); - } - -hidden_fndcl: - hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres - { - Sym *s; - Type *t; - - $$ = N; - - s = $1; - t = functype(N, $3, $5); - - importsym(s, ONAME); - if(s->def != N && s->def->op == ONAME) { - if(eqtype(t, s->def->type)) { - dclcontext = PDISCARD; // since we skip funchdr below - break; - } - yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t); - } - - $$ = newname(s); - $$->type = t; - declare($$, PFUNC); - - funchdr($$); - } -| '(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres - { - $$ = methodname1(newname($4), $2->n->right); - $$->type = functype($2->n, $6, $8); - - checkwidth($$->type); - addmethod($4, $$->type, 0, nointerface); - nointerface = 0; - funchdr($$); - - // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as - // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled - // out by typecheck's lookdot as this $$->ttype. So by providing - // this back link here we avoid special casing there. - $$->type->nname = $$; - } - -fntype: - LFUNC '(' oarg_type_list_ocomma ')' fnres - { - $3 = checkarglist($3, 1); - $$ = nod(OTFUNC, N, N); - $$->list = $3; - $$->rlist = $5; - } - -fnbody: - { - $$ = nil; - } -| '{' stmt_list '}' - { - $$ = $2; - if($$ == nil) - $$ = list1(nod(OEMPTY, N, N)); - } - -fnres: - %prec NotParen - { - $$ = nil; - } -| fnret_type - { - $$ = list1(nod(ODCLFIELD, N, $1)); - } -| '(' oarg_type_list_ocomma ')' - { - $2 = checkarglist($2, 0); - $$ = $2; - } - -fnlitdcl: - fntype - { - closurehdr($1); - } - -fnliteral: - fnlitdcl lbrace stmt_list '}' - { - $$ = closurebody($3); - fixlbrace($2); - } -| fnlitdcl error - { - $$ = closurebody(nil); - } - -/* - * lists of things - * note that they are left recursive - * to conserve yacc stack. they need to - * be reversed to interpret correctly - */ -xdcl_list: - { - $$ = nil; - } -| xdcl_list xdcl ';' - { - $$ = concat($1, $2); - if(nsyntaxerrors == 0) - testdclstack(); - nointerface = 0; - noescape = 0; - nosplit = 0; - nowritebarrier = 0; - } - -vardcl_list: - vardcl -| vardcl_list ';' vardcl - { - $$ = concat($1, $3); - } - -constdcl_list: - constdcl1 -| constdcl_list ';' constdcl1 - { - $$ = concat($1, $3); - } - -typedcl_list: - typedcl - { - $$ = list1($1); - } -| typedcl_list ';' typedcl - { - $$ = list($1, $3); - } - -structdcl_list: - structdcl -| structdcl_list ';' structdcl - { - $$ = concat($1, $3); - } - -interfacedcl_list: - interfacedcl - { - $$ = list1($1); - } -| interfacedcl_list ';' interfacedcl - { - $$ = list($1, $3); - } - -structdcl: - new_name_list ntype oliteral - { - NodeList *l; - - Node *n; - l = $1; - if(l == nil) { - // ? symbol, during import (list1(N) == nil) - n = $2; - if(n->op == OIND) - n = n->left; - n = embedded(n->sym, importpkg); - n->right = $2; - n->val = $3; - $$ = list1(n); - break; - } - - for(l=$1; l; l=l->next) { - l->n = nod(ODCLFIELD, l->n, $2); - l->n->val = $3; - } - } -| embed oliteral - { - $1->val = $2; - $$ = list1($1); - } -| '(' embed ')' oliteral - { - $2->val = $4; - $$ = list1($2); - yyerror("cannot parenthesize embedded type"); - } -| '*' embed oliteral - { - $2->right = nod(OIND, $2->right, N); - $2->val = $3; - $$ = list1($2); - } -| '(' '*' embed ')' oliteral - { - $3->right = nod(OIND, $3->right, N); - $3->val = $5; - $$ = list1($3); - yyerror("cannot parenthesize embedded type"); - } -| '*' '(' embed ')' oliteral - { - $3->right = nod(OIND, $3->right, N); - $3->val = $5; - $$ = list1($3); - yyerror("cannot parenthesize embedded type"); - } - -packname: - LNAME - { - Node *n; - - $$ = $1; - n = oldname($1); - if(n->pack != N) - n->pack->used = 1; - } -| LNAME '.' sym - { - Pkg *pkg; - - if($1->def == N || $1->def->op != OPACK) { - yyerror("%S is not a package", $1); - pkg = localpkg; - } else { - $1->def->used = 1; - pkg = $1->def->pkg; - } - $$ = restrictlookup($3->name, pkg); - } - -embed: - packname - { - $$ = embedded($1, localpkg); - } - -interfacedcl: - new_name indcl - { - $$ = nod(ODCLFIELD, $1, $2); - ifacedcl($$); - } -| packname - { - $$ = nod(ODCLFIELD, N, oldname($1)); - } -| '(' packname ')' - { - $$ = nod(ODCLFIELD, N, oldname($2)); - yyerror("cannot parenthesize embedded type"); - } - -indcl: - '(' oarg_type_list_ocomma ')' fnres - { - // without func keyword - $2 = checkarglist($2, 1); - $$ = nod(OTFUNC, fakethis(), N); - $$->list = $2; - $$->rlist = $4; - } - -/* - * function arguments. - */ -arg_type: - name_or_type -| sym name_or_type - { - $$ = nod(ONONAME, N, N); - $$->sym = $1; - $$ = nod(OKEY, $$, $2); - } -| sym dotdotdot - { - $$ = nod(ONONAME, N, N); - $$->sym = $1; - $$ = nod(OKEY, $$, $2); - } -| dotdotdot - -arg_type_list: - arg_type - { - $$ = list1($1); - } -| arg_type_list ',' arg_type - { - $$ = list($1, $3); - } - -oarg_type_list_ocomma: - { - $$ = nil; - } -| arg_type_list ocomma - { - $$ = $1; - } - -/* - * statement - */ -stmt: - { - $$ = N; - } -| compound_stmt -| common_dcl - { - $$ = liststmt($1); - } -| non_dcl_stmt -| error - { - $$ = N; - } - -non_dcl_stmt: - simple_stmt -| for_stmt -| switch_stmt -| select_stmt -| if_stmt -| labelname ':' - { - $1 = nod(OLABEL, $1, N); - $1->sym = dclstack; // context, for goto restrictions - } - stmt - { - NodeList *l; - - $1->defn = $4; - l = list1($1); - if($4) - l = list(l, $4); - $$ = liststmt(l); - } -| LFALL - { - // will be converted to OFALL - $$ = nod(OXFALL, N, N); - $$->xoffset = block; - } -| LBREAK onew_name - { - $$ = nod(OBREAK, $2, N); - } -| LCONTINUE onew_name - { - $$ = nod(OCONTINUE, $2, N); - } -| LGO pseudocall - { - $$ = nod(OPROC, $2, N); - } -| LDEFER pseudocall - { - $$ = nod(ODEFER, $2, N); - } -| LGOTO new_name - { - $$ = nod(OGOTO, $2, N); - $$->sym = dclstack; // context, for goto restrictions - } -| LRETURN oexpr_list - { - $$ = nod(ORETURN, N, N); - $$->list = $2; - if($$->list == nil && curfn != N) { - NodeList *l; - - for(l=curfn->dcl; l; l=l->next) { - if(l->n->class == PPARAM) - continue; - if(l->n->class != PPARAMOUT) - break; - if(l->n->sym->def != l->n) - yyerror("%s is shadowed during return", l->n->sym->name); - } - } - } - -stmt_list: - stmt - { - $$ = nil; - if($1 != N) - $$ = list1($1); - } -| stmt_list ';' stmt - { - $$ = $1; - if($3 != N) - $$ = list($$, $3); - } - -new_name_list: - new_name - { - $$ = list1($1); - } -| new_name_list ',' new_name - { - $$ = list($1, $3); - } - -dcl_name_list: - dcl_name - { - $$ = list1($1); - } -| dcl_name_list ',' dcl_name - { - $$ = list($1, $3); - } - -expr_list: - expr - { - $$ = list1($1); - } -| expr_list ',' expr - { - $$ = list($1, $3); - } - -expr_or_type_list: - expr_or_type - { - $$ = list1($1); - } -| expr_or_type_list ',' expr_or_type - { - $$ = list($1, $3); - } - -/* - * list of combo of keyval and val - */ -keyval_list: - keyval - { - $$ = list1($1); - } -| bare_complitexpr - { - $$ = list1($1); - } -| keyval_list ',' keyval - { - $$ = list($1, $3); - } -| keyval_list ',' bare_complitexpr - { - $$ = list($1, $3); - } - -braced_keyval_list: - { - $$ = nil; - } -| keyval_list ocomma - { - $$ = $1; - } - -/* - * optional things - */ -osemi: -| ';' - -ocomma: -| ',' - -oexpr: - { - $$ = N; - } -| expr - -oexpr_list: - { - $$ = nil; - } -| expr_list - -osimple_stmt: - { - $$ = N; - } -| simple_stmt - -ohidden_funarg_list: - { - $$ = nil; - } -| hidden_funarg_list - -ohidden_structdcl_list: - { - $$ = nil; - } -| hidden_structdcl_list - -ohidden_interfacedcl_list: - { - $$ = nil; - } -| hidden_interfacedcl_list - -oliteral: - { - $$.ctype = CTxxx; - } -| LLITERAL - -/* - * import syntax from package header - */ -hidden_import: - LIMPORT LNAME LLITERAL ';' - { - importimport($2, $3.u.sval); - } -| LVAR hidden_pkg_importsym hidden_type ';' - { - importvar($2, $3); - } -| LCONST hidden_pkg_importsym '=' hidden_constant ';' - { - importconst($2, types[TIDEAL], $4); - } -| LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';' - { - importconst($2, $3, $5); - } -| LTYPE hidden_pkgtype hidden_type ';' - { - importtype($2, $3); - } -| LFUNC hidden_fndcl fnbody ';' - { - if($2 == N) { - dclcontext = PEXTERN; // since we skip the funcbody below - break; - } - - $2->inl = $3; - - funcbody($2); - importlist = list(importlist, $2); - - if(debug['E']) { - print("import [%Z] func %lN \n", importpkg->path, $2); - if(debug['m'] > 2 && $2->inl) - print("inl body:%+H\n", $2->inl); - } - } - -hidden_pkg_importsym: - hidden_importsym - { - $$ = $1; - structpkg = $$->pkg; - } - -hidden_pkgtype: - hidden_pkg_importsym - { - $$ = pkgtype($1); - importsym($1, OTYPE); - } - -/* - * importing types - */ - -hidden_type: - hidden_type_misc -| hidden_type_recv_chan -| hidden_type_func - -hidden_type_non_recv_chan: - hidden_type_misc -| hidden_type_func - -hidden_type_misc: - hidden_importsym - { - $$ = pkgtype($1); - } -| LNAME - { - // predefined name like uint8 - $1 = pkglookup($1->name, builtinpkg); - if($1->def == N || $1->def->op != OTYPE) { - yyerror("%s is not a type", $1->name); - $$ = T; - } else - $$ = $1->def->type; - } -| '[' ']' hidden_type - { - $$ = aindex(N, $3); - } -| '[' LLITERAL ']' hidden_type - { - $$ = aindex(nodlit($2), $4); - } -| LMAP '[' hidden_type ']' hidden_type - { - $$ = maptype($3, $5); - } -| LSTRUCT '{' ohidden_structdcl_list '}' - { - $$ = tostruct($3); - } -| LINTERFACE '{' ohidden_interfacedcl_list '}' - { - $$ = tointerface($3); - } -| '*' hidden_type - { - $$ = ptrto($2); - } -| LCHAN hidden_type_non_recv_chan - { - $$ = typ(TCHAN); - $$->type = $2; - $$->chan = Cboth; - } -| LCHAN '(' hidden_type_recv_chan ')' - { - $$ = typ(TCHAN); - $$->type = $3; - $$->chan = Cboth; - } -| LCHAN LCOMM hidden_type - { - $$ = typ(TCHAN); - $$->type = $3; - $$->chan = Csend; - } - -hidden_type_recv_chan: - LCOMM LCHAN hidden_type - { - $$ = typ(TCHAN); - $$->type = $3; - $$->chan = Crecv; - } - -hidden_type_func: - LFUNC '(' ohidden_funarg_list ')' ohidden_funres - { - $$ = functype(nil, $3, $5); - } - -hidden_funarg: - sym hidden_type oliteral - { - $$ = nod(ODCLFIELD, N, typenod($2)); - if($1) - $$->left = newname($1); - $$->val = $3; - } -| sym LDDD hidden_type oliteral - { - Type *t; - - t = typ(TARRAY); - t->bound = -1; - t->type = $3; - - $$ = nod(ODCLFIELD, N, typenod(t)); - if($1) - $$->left = newname($1); - $$->isddd = 1; - $$->val = $4; - } - -hidden_structdcl: - sym hidden_type oliteral - { - Sym *s; - Pkg *p; - - if($1 != S && strcmp($1->name, "?") != 0) { - $$ = nod(ODCLFIELD, newname($1), typenod($2)); - $$->val = $3; - } else { - s = $2->sym; - if(s == S && isptr[$2->etype]) - s = $2->type->sym; - p = importpkg; - if($1 != S) - p = $1->pkg; - $$ = embedded(s, p); - $$->right = typenod($2); - $$->val = $3; - } - } - -hidden_interfacedcl: - sym '(' ohidden_funarg_list ')' ohidden_funres - { - $$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5))); - } -| hidden_type - { - $$ = nod(ODCLFIELD, N, typenod($1)); - } - -ohidden_funres: - { - $$ = nil; - } -| hidden_funres - -hidden_funres: - '(' ohidden_funarg_list ')' - { - $$ = $2; - } -| hidden_type - { - $$ = list1(nod(ODCLFIELD, N, typenod($1))); - } - -/* - * importing constants - */ - -hidden_literal: - LLITERAL - { - $$ = nodlit($1); - } -| '-' LLITERAL - { - $$ = nodlit($2); - switch($$->val.ctype){ - case CTINT: - case CTRUNE: - mpnegfix($$->val.u.xval); - break; - case CTFLT: - mpnegflt($$->val.u.fval); - break; - case CTCPLX: - mpnegflt(&$$->val.u.cval->real); - mpnegflt(&$$->val.u.cval->imag); - break; - default: - yyerror("bad negated constant"); - } - } -| sym - { - $$ = oldname(pkglookup($1->name, builtinpkg)); - if($$->op != OLITERAL) - yyerror("bad constant %S", $$->sym); - } - -hidden_constant: - hidden_literal -| '(' hidden_literal '+' hidden_literal ')' - { - if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) { - $$ = $2; - mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0); - break; - } - $4->val.u.cval->real = $4->val.u.cval->imag; - mpmovecflt(&$4->val.u.cval->imag, 0.0); - $$ = nodcplxlit($2->val, $4->val); - } - -hidden_import_list: -| hidden_import_list hidden_import - -hidden_funarg_list: - hidden_funarg - { - $$ = list1($1); - } -| hidden_funarg_list ',' hidden_funarg - { - $$ = list($1, $3); - } - -hidden_structdcl_list: - hidden_structdcl - { - $$ = list1($1); - } -| hidden_structdcl_list ';' hidden_structdcl - { - $$ = list($1, $3); - } - -hidden_interfacedcl_list: - hidden_interfacedcl - { - $$ = list1($1); - } -| hidden_interfacedcl_list ';' hidden_interfacedcl - { - $$ = list($1, $3); - } - -%% - -static void -fixlbrace(int lbr) -{ - // If the opening brace was an LBODY, - // set up for another one now that we're done. - // See comment in lex.c about loophack. - if(lbr == LBODY) - loophack = 1; -} - diff --git a/src/cmd/gc/gsubr.c b/src/cmd/gc/gsubr.c deleted file mode 100644 index 5175ae34f5..0000000000 --- a/src/cmd/gc/gsubr.c +++ /dev/null @@ -1,654 +0,0 @@ -// Derived from Inferno utils/6c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "go.h" -#include "../../runtime/funcdata.h" -#include "../ld/textflag.h" - -void -ggloblnod(Node *nam) -{ - Prog *p; - - p = thearch.gins(AGLOBL, nam, N); - p->lineno = nam->lineno; - p->from.sym->gotype = linksym(ngotype(nam)); - p->to.sym = nil; - p->to.type = TYPE_CONST; - p->to.offset = nam->type->width; - if(nam->readonly) - p->from3.offset = RODATA; - if(nam->type != T && !haspointers(nam->type)) - p->from3.offset |= NOPTR; -} - -void -gtrack(Sym *s) -{ - Prog *p; - - p = thearch.gins(AUSEFIELD, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.sym = linksym(s); -} - -void -ggloblsym(Sym *s, int32 width, int8 flags) -{ - Prog *p; - - p = thearch.gins(AGLOBL, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.sym = linksym(s); - p->to.type = TYPE_CONST; - p->to.offset = width; - p->from3.offset = flags; -} - -void -clearp(Prog *p) -{ - nopout(p); - p->as = AEND; - p->pc = pcloc; - pcloc++; -} - -static int ddumped; -static Prog *dfirst; -static Prog *dpc; - -/* - * generate and return proc with p->as = as, - * linked into program. pc is next instruction. - */ -Prog* -prog(int as) -{ - Prog *p; - - if(as == ADATA || as == AGLOBL) { - if(ddumped) - fatal("already dumped data"); - if(dpc == nil) { - dpc = mal(sizeof(*dpc)); - dfirst = dpc; - } - p = dpc; - dpc = mal(sizeof(*dpc)); - p->link = dpc; - } else { - p = pc; - pc = mal(sizeof(*pc)); - clearp(pc); - p->link = pc; - } - - if(lineno == 0) { - if(debug['K']) - warn("prog: line 0"); - } - - p->as = as; - p->lineno = lineno; - return p; -} - -void -dumpdata(void) -{ - ddumped = 1; - if(dfirst == nil) - return; - newplist(); - *pc = *dfirst; - pc = dpc; - clearp(pc); -} - -/* - * generate a branch. - * t is ignored. - * likely values are for branch prediction: - * -1 unlikely - * 0 no opinion - * +1 likely - */ -Prog* -gbranch(int as, Type *t, int likely) -{ - Prog *p; - - USED(t); - - p = prog(as); - p->to.type = TYPE_BRANCH; - p->to.u.branch = P; - if(as != AJMP && likely != 0 && thearch.thechar != '9') { - p->from.type = TYPE_CONST; - p->from.offset = likely > 0; - } - return p; -} - -/* - * patch previous branch to jump to to. - */ -void -patch(Prog *p, Prog *to) -{ - if(p->to.type != TYPE_BRANCH) - fatal("patch: not a branch"); - p->to.u.branch = to; - p->to.offset = to->pc; -} - -Prog* -unpatch(Prog *p) -{ - Prog *q; - - if(p->to.type != TYPE_BRANCH) - fatal("unpatch: not a branch"); - q = p->to.u.branch; - p->to.u.branch = P; - p->to.offset = 0; - return q; -} - -/* - * start a new Prog list. - */ -Plist* -newplist(void) -{ - Plist *pl; - - pl = linknewplist(ctxt); - - pc = mal(sizeof(*pc)); - clearp(pc); - pl->firstpc = pc; - - return pl; -} - -void -gused(Node *n) -{ - thearch.gins(ANOP, n, N); // used -} - -Prog* -gjmp(Prog *to) -{ - Prog *p; - - p = gbranch(AJMP, T, 0); - if(to != P) - patch(p, to); - return p; -} - -int -isfat(Type *t) -{ - if(t != T) - switch(t->etype) { - case TSTRUCT: - case TARRAY: - case TSTRING: - case TINTER: // maybe remove later - return 1; - } - return 0; -} - -/* - * naddr of func generates code for address of func. - * if using opcode that can take address implicitly, - * call afunclit to fix up the argument. - */ -void -afunclit(Addr *a, Node *n) -{ - if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) { - a->type = TYPE_MEM; - a->sym = linksym(n->sym); - } -} - -/* - * initialize n to be register r of type t. - */ -void -nodreg(Node *n, Type *t, int r) -{ - if(t == T) - fatal("nodreg: t nil"); - - memset(n, 0, sizeof(*n)); - n->op = OREGISTER; - n->addable = 1; - ullmancalc(n); - n->val.u.reg = r; - n->type = t; -} - -/* - * initialize n to be indirect of register r; n is type t. - */ -void -nodindreg(Node *n, Type *t, int r) -{ - nodreg(n, t, r); - n->op = OINDREG; -} - -/* - * Is this node a memory operand? - */ -int -ismem(Node *n) -{ - switch(n->op) { - case OITAB: - case OSPTR: - case OLEN: - case OCAP: - case OINDREG: - case ONAME: - case OPARAM: - case OCLOSUREVAR: - return 1; - case OADDR: - return thearch.thechar == '6' || thearch.thechar == '9'; // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too - } - return 0; -} - -// Sweep the prog list to mark any used nodes. -void -markautoused(Prog* p) -{ - for (; p; p = p->link) { - if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL) - continue; - - if (p->from.node) - ((Node*)(p->from.node))->used = 1; - - if (p->to.node) - ((Node*)(p->to.node))->used = 1; - } -} - -// Fixup instructions after allocauto (formerly compactframe) has moved all autos around. -void -fixautoused(Prog *p) -{ - Prog **lp; - - for (lp=&p; (p=*lp) != P; ) { - if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) { - *lp = p->link; - continue; - } - if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) { - // Cannot remove VARDEF instruction, because - unlike TYPE handled above - - // VARDEFs are interspersed with other code, and a jump might be using the - // VARDEF as a target. Replace with a no-op instead. A later pass will remove - // the no-ops. - nopout(p); - continue; - } - if (p->from.name == NAME_AUTO && p->from.node) - p->from.offset += ((Node*)(p->from.node))->stkdelta; - - if (p->to.name == NAME_AUTO && p->to.node) - p->to.offset += ((Node*)(p->to.node))->stkdelta; - - lp = &p->link; - } -} - -int -samereg(Node *a, Node *b) -{ - if(a == N || b == N) - return 0; - if(a->op != OREGISTER) - return 0; - if(b->op != OREGISTER) - return 0; - if(a->val.u.reg != b->val.u.reg) - return 0; - return 1; -} - -Node* -nodarg(Type *t, int fp) -{ - Node *n; - NodeList *l; - Type *first; - Iter savet; - - // entire argument struct, not just one arg - if(t->etype == TSTRUCT && t->funarg) { - n = nod(ONAME, N, N); - n->sym = lookup(".args"); - n->type = t; - first = structfirst(&savet, &t); - if(first == nil) - fatal("nodarg: bad struct"); - if(first->width == BADWIDTH) - fatal("nodarg: offset not computed for %T", t); - n->xoffset = first->width; - n->addable = 1; - goto fp; - } - - if(t->etype != TFIELD) - fatal("nodarg: not field %T", t); - - if(fp == 1) { - for(l=curfn->dcl; l; l=l->next) { - n = l->n; - if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym) - return n; - } - } - - n = nod(ONAME, N, N); - n->type = t->type; - n->sym = t->sym; - - if(t->width == BADWIDTH) - fatal("nodarg: offset not computed for %T", t); - n->xoffset = t->width; - n->addable = 1; - n->orig = t->nname; - -fp: - // Rewrite argument named _ to __, - // or else the assignment to _ will be - // discarded during code generation. - if(isblank(n)) - n->sym = lookup("__"); - - switch(fp) { - case 0: // output arg - n->op = OINDREG; - n->val.u.reg = thearch.REGSP; - if(thearch.thechar == '5') - n->xoffset += 4; - if(thearch.thechar == '9') - n->xoffset += 8; - break; - - case 1: // input arg - n->class = PPARAM; - break; - - case 2: // offset output arg -fatal("shouldn't be used"); - n->op = OINDREG; - n->val.u.reg = thearch.REGSP; - n->xoffset += types[tptr]->width; - break; - } - n->typecheck = 1; - return n; -} - -/* - * generate code to compute n; - * make a refer to result. - */ -void -naddr(Node *n, Addr *a, int canemitcode) -{ - Sym *s; - - *a = zprog.from; - if(n == N) - return; - - if(n->type != T && n->type->etype != TIDEAL) { - // TODO(rsc): This is undone by the selective clearing of width below, - // to match architectures that were not as aggressive in setting width - // during naddr. Those widths must be cleared to avoid triggering - // failures in gins when it detects real but heretofore latent (and one - // hopes innocuous) type mismatches. - // The type mismatches should be fixed and the clearing below removed. - dowidth(n->type); - a->width = n->type->width; - } - - switch(n->op) { - default: - fatal("naddr: bad %O %D", n->op, a); - break; - - case OREGISTER: - a->type = TYPE_REG; - a->reg = n->val.u.reg; - a->sym = nil; - if(thearch.thechar == '8') // TODO(rsc): Never clear a->width. - a->width = 0; - break; - - case OINDREG: - a->type = TYPE_MEM; - a->reg = n->val.u.reg; - a->sym = linksym(n->sym); - a->offset = n->xoffset; - if(a->offset != (int32)a->offset) - yyerror("offset %lld too large for OINDREG", a->offset); - if(thearch.thechar == '8') // TODO(rsc): Never clear a->width. - a->width = 0; - break; - - case OPARAM: - // n->left is PHEAP ONAME for stack parameter. - // compute address of actual parameter on stack. - a->etype = simtype[n->left->type->etype]; - a->width = n->left->type->width; - a->offset = n->xoffset; - a->sym = linksym(n->left->sym); - a->type = TYPE_MEM; - a->name = NAME_PARAM; - a->node = n->left->orig; - break; - - case OCLOSUREVAR: - if(!curfn->needctxt) - fatal("closurevar without needctxt"); - a->type = TYPE_MEM; - a->reg = thearch.REGCTXT; - a->sym = nil; - a->offset = n->xoffset; - break; - - case OCFUNC: - naddr(n->left, a, canemitcode); - a->sym = linksym(n->left->sym); - break; - - case ONAME: - a->etype = 0; - if(n->type != T) - a->etype = simtype[n->type->etype]; - a->offset = n->xoffset; - s = n->sym; - a->node = n->orig; - //if(a->node >= (Node*)&n) - // fatal("stack node"); - if(s == S) - s = lookup(".noname"); - if(n->method) { - if(n->type != T) - if(n->type->sym != S) - if(n->type->sym->pkg != nil) - s = pkglookup(s->name, n->type->sym->pkg); - } - - a->type = TYPE_MEM; - switch(n->class) { - default: - fatal("naddr: ONAME class %S %d\n", n->sym, n->class); - case PEXTERN: - a->name = NAME_EXTERN; - break; - case PAUTO: - a->name = NAME_AUTO; - break; - case PPARAM: - case PPARAMOUT: - a->name = NAME_PARAM; - break; - case PFUNC: - a->name = NAME_EXTERN; - a->type = TYPE_ADDR; - a->width = widthptr; - s = funcsym(s); - break; - } - a->sym = linksym(s); - break; - - case OLITERAL: - if(thearch.thechar == '8') - a->width = 0; - switch(n->val.ctype) { - default: - fatal("naddr: const %lT", n->type); - break; - case CTFLT: - a->type = TYPE_FCONST; - a->u.dval = mpgetflt(n->val.u.fval); - break; - case CTINT: - case CTRUNE: - a->sym = nil; - a->type = TYPE_CONST; - a->offset = mpgetfix(n->val.u.xval); - break; - case CTSTR: - datagostring(n->val.u.sval, a); - break; - case CTBOOL: - a->sym = nil; - a->type = TYPE_CONST; - a->offset = n->val.u.bval; - break; - case CTNIL: - a->sym = nil; - a->type = TYPE_CONST; - a->offset = 0; - break; - } - break; - - case OADDR: - naddr(n->left, a, canemitcode); - a->etype = tptr; - if(thearch.thechar != '5' && thearch.thechar != '9') // TODO(rsc): Do this even for arm, ppc64. - a->width = widthptr; - if(a->type != TYPE_MEM) - fatal("naddr: OADDR %D (from %O)", a, n->left->op); - a->type = TYPE_ADDR; - break; - - case OITAB: - // itable of interface value - naddr(n->left, a, canemitcode); - if(a->type == TYPE_CONST && a->offset == 0) - break; // itab(nil) - a->etype = tptr; - a->width = widthptr; - break; - - case OSPTR: - // pointer in a string or slice - naddr(n->left, a, canemitcode); - if(a->type == TYPE_CONST && a->offset == 0) - break; // ptr(nil) - a->etype = simtype[tptr]; - a->offset += Array_array; - a->width = widthptr; - break; - - case OLEN: - // len of string or slice - naddr(n->left, a, canemitcode); - if(a->type == TYPE_CONST && a->offset == 0) - break; // len(nil) - a->etype = simtype[TUINT]; - if(thearch.thechar == '9') - a->etype = simtype[TINT]; - a->offset += Array_nel; - if(thearch.thechar != '5') // TODO(rsc): Do this even on arm. - a->width = widthint; - break; - - case OCAP: - // cap of string or slice - naddr(n->left, a, canemitcode); - if(a->type == TYPE_CONST && a->offset == 0) - break; // cap(nil) - a->etype = simtype[TUINT]; - if(thearch.thechar == '9') - a->etype = simtype[TINT]; - a->offset += Array_cap; - if(thearch.thechar != '5') // TODO(rsc): Do this even on arm. - a->width = widthint; - break; - -// case OADD: -// if(n->right->op == OLITERAL) { -// v = n->right->vconst; -// naddr(n->left, a, canemitcode); -// } else -// if(n->left->op == OLITERAL) { -// v = n->left->vconst; -// naddr(n->right, a, canemitcode); -// } else -// goto bad; -// a->offset += v; -// break; - - } -} diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c deleted file mode 100644 index f1484ea1a6..0000000000 --- a/src/cmd/gc/init.c +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -/* - * a function named init is a special case. - * it is called by the initialization before - * main is run. to make it unique within a - * package and also uncallable, the name, - * normally "pkg.init", is altered to "pkg.init.1". - */ -Sym* -renameinit(void) -{ - static int initgen; - - snprint(namebuf, sizeof(namebuf), "init.%d", ++initgen); - return lookup(namebuf); -} - -/* - * hand-craft the following initialization code - * var initdone· uint8 (1) - * func init() (2) - * if initdone· != 0 { (3) - * if initdone· == 2 (4) - * return - * throw(); (5) - * } - * initdone· = 1; (6) - * // over all matching imported symbols - * .init() (7) - * { } (8) - * init.() // if any (9) - * initdone· = 2; (10) - * return (11) - * } - */ -static int -anyinit(NodeList *n) -{ - uint32 h; - Sym *s; - NodeList *l; - - // are there any interesting init statements - for(l=n; l; l=l->next) { - switch(l->n->op) { - case ODCLFUNC: - case ODCLCONST: - case ODCLTYPE: - case OEMPTY: - break; - case OAS: - if(isblank(l->n->left) && candiscard(l->n->right)) - break; - // fall through - default: - return 1; - } - } - - // is this main - if(strcmp(localpkg->name, "main") == 0) - return 1; - - // is there an explicit init function - s = lookup("init.1"); - if(s->def != N) - return 1; - - // are there any imported init functions - for(h=0; hlink) { - if(s->name[0] != 'i' || strcmp(s->name, "init") != 0) - continue; - if(s->def == N) - continue; - return 1; - } - - // then none - return 0; -} - -void -fninit(NodeList *n) -{ - int i; - Node *gatevar; - Node *a, *b, *fn; - NodeList *r; - uint32 h; - Sym *s, *initsym; - - if(debug['A']) { - // sys.go or unsafe.go during compiler build - return; - } - - n = initfix(n); - if(!anyinit(n)) - return; - - r = nil; - - // (1) - snprint(namebuf, sizeof(namebuf), "initdone·"); - gatevar = newname(lookup(namebuf)); - addvar(gatevar, types[TUINT8], PEXTERN); - - // (2) - maxarg = 0; - snprint(namebuf, sizeof(namebuf), "init"); - - fn = nod(ODCLFUNC, N, N); - initsym = lookup(namebuf); - fn->nname = newname(initsym); - fn->nname->defn = fn; - fn->nname->ntype = nod(OTFUNC, N, N); - declare(fn->nname, PFUNC); - funchdr(fn); - - // (3) - a = nod(OIF, N, N); - a->ntest = nod(ONE, gatevar, nodintconst(0)); - r = list(r, a); - - // (4) - b = nod(OIF, N, N); - b->ntest = nod(OEQ, gatevar, nodintconst(2)); - b->nbody = list1(nod(ORETURN, N, N)); - a->nbody = list1(b); - - // (5) - b = syslook("throwinit", 0); - b = nod(OCALL, b, N); - a->nbody = list(a->nbody, b); - - // (6) - a = nod(OAS, gatevar, nodintconst(1)); - r = list(r, a); - - // (7) - for(h=0; hlink) { - if(s->name[0] != 'i' || strcmp(s->name, "init") != 0) - continue; - if(s->def == N) - continue; - if(s == initsym) - continue; - - // could check that it is fn of no args/returns - a = nod(OCALL, s->def, N); - r = list(r, a); - } - - // (8) - r = concat(r, n); - - // (9) - // could check that it is fn of no args/returns - for(i=1;; i++) { - snprint(namebuf, sizeof(namebuf), "init.%d", i); - s = lookup(namebuf); - if(s->def == N) - break; - a = nod(OCALL, s->def, N); - r = list(r, a); - } - - // (10) - a = nod(OAS, gatevar, nodintconst(2)); - r = list(r, a); - - // (11) - a = nod(ORETURN, N, N); - r = list(r, a); - exportsym(fn->nname); - - fn->nbody = r; - funcbody(fn); - - curfn = fn; - typecheck(&fn, Etop); - typechecklist(r, Etop); - curfn = nil; - funccompile(fn); -} diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c deleted file mode 100644 index 45e15bb9b7..0000000000 --- a/src/cmd/gc/inl.c +++ /dev/null @@ -1,986 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -// The inlining facility makes 2 passes: first caninl determines which -// functions are suitable for inlining, and for those that are it -// saves a copy of the body. Then inlcalls walks each function body to -// expand calls to inlinable functions. -// -// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1, -// making 1 the default and -l disable. -ll and more is useful to flush out bugs. -// These additional levels (beyond -l) may be buggy and are not supported. -// 0: disabled -// 1: 40-nodes leaf functions, oneliners, lazy typechecking (default) -// 2: early typechecking of all imported bodies -// 3: allow variadic functions -// 4: allow non-leaf functions , (breaks runtime.Caller) -// 5: transitive inlining -// -// At some point this may get another default and become switch-offable with -N. -// -// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying -// which calls get inlined or not, more is for debugging, and may go away at any point. -// -// TODO: -// - inline functions with ... args -// - handle T.meth(f()) with func f() (t T, arg, arg, ) - -#include -#include -#include "go.h" - -// Used by caninl. -static Node* inlcopy(Node *n); -static NodeList* inlcopylist(NodeList *ll); -static int ishairy(Node *n, int *budget); -static int ishairylist(NodeList *ll, int *budget); - -// Used by inlcalls -static void inlnodelist(NodeList *l); -static void inlnode(Node **np); -static void mkinlcall(Node **np, Node *fn, int isddd); -static Node* inlvar(Node *n); -static Node* retvar(Type *n, int i); -static Node* argvar(Type *n, int i); -static Node* newlabel(void); -static Node* inlsubst(Node *n); -static NodeList* inlsubstlist(NodeList *l); - -static void setlno(Node*, int); - -// Used during inlsubst[list] -static Node *inlfn; // function currently being inlined -static Node *inlretlabel; // target of the goto substituted in place of a return -static NodeList *inlretvars; // temp out variables - -// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods -// the ->sym can be re-used in the local package, so peel it off the receiver's type. -static Pkg* -fnpkg(Node *fn) -{ - Type *rcvr; - - if(fn->type->thistuple) { - // method - rcvr = getthisx(fn->type)->type->type; - if(isptr[rcvr->etype]) - rcvr = rcvr->type; - if(!rcvr->sym) - fatal("receiver with no sym: [%S] %lN (%T)", fn->sym, fn, rcvr); - return rcvr->sym->pkg; - } - // non-method - return fn->sym->pkg; -} - -// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck -// because they're a copy of an already checked body. -void -typecheckinl(Node *fn) -{ - Node *savefn; - Pkg *pkg; - int save_safemode, lno; - - lno = setlineno(fn); - - // typecheckinl is only for imported functions; - // their bodies may refer to unsafe as long as the package - // was marked safe during import (which was checked then). - // the ->inl of a local function has been typechecked before caninl copied it. - pkg = fnpkg(fn); - if (pkg == localpkg || pkg == nil) - return; // typecheckinl on local function - - if (debug['m']>2) - print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl); - - save_safemode = safemode; - safemode = 0; - - savefn = curfn; - curfn = fn; - typechecklist(fn->inl, Etop); - curfn = savefn; - - safemode = save_safemode; - - lineno = lno; -} - -// Caninl determines whether fn is inlineable. -// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy. -// fn and ->nbody will already have been typechecked. -void -caninl(Node *fn) -{ - Node *savefn; - Type *t; - int budget; - - if(fn->op != ODCLFUNC) - fatal("caninl %N", fn); - if(!fn->nname) - fatal("caninl no nname %+N", fn); - - // If fn has no body (is defined outside of Go), cannot inline it. - if(fn->nbody == nil) - return; - - if(fn->typecheck == 0) - fatal("caninl on non-typechecked function %N", fn); - - // can't handle ... args yet - if(debug['l'] < 3) - for(t=fn->type->type->down->down->type; t; t=t->down) - if(t->isddd) - return; - - budget = 40; // allowed hairyness - if(ishairylist(fn->nbody, &budget)) - return; - - savefn = curfn; - curfn = fn; - - fn->nname->inl = fn->nbody; - fn->nbody = inlcopylist(fn->nname->inl); - fn->nname->inldcl = inlcopylist(fn->nname->defn->dcl); - - // hack, TODO, check for better way to link method nodes back to the thing with the ->inl - // this is so export can find the body of a method - fn->type->nname = fn->nname; - - if(debug['m'] > 1) - print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl); - else if(debug['m']) - print("%L: can inline %N\n", fn->lineno, fn->nname); - - curfn = savefn; -} - -// Look for anything we want to punt on. -static int -ishairylist(NodeList *ll, int* budget) -{ - for(;ll;ll=ll->next) - if(ishairy(ll->n, budget)) - return 1; - return 0; -} - -static int -ishairy(Node *n, int *budget) -{ - if(!n) - return 0; - - // Things that are too hairy, irrespective of the budget - switch(n->op) { - case OCALL: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - case OPANIC: - case ORECOVER: - if(debug['l'] < 4) - return 1; - break; - - case OCLOSURE: - case OCALLPART: - case ORANGE: - case OFOR: - case OSELECT: - case OSWITCH: - case OPROC: - case ODEFER: - case ODCLTYPE: // can't print yet - case ODCLCONST: // can't print yet - case ORETJMP: - return 1; - - break; - } - - (*budget)--; - - return *budget < 0 || - ishairy(n->left, budget) || - ishairy(n->right, budget) || - ishairylist(n->list, budget) || - ishairylist(n->rlist, budget) || - ishairylist(n->ninit, budget) || - ishairy(n->ntest, budget) || - ishairy(n->nincr, budget) || - ishairylist(n->nbody, budget) || - ishairylist(n->nelse, budget); -} - -// Inlcopy and inlcopylist recursively copy the body of a function. -// Any name-like node of non-local class is marked for re-export by adding it to -// the exportlist. -static NodeList* -inlcopylist(NodeList *ll) -{ - NodeList *l; - - l = nil; - for(; ll; ll=ll->next) - l = list(l, inlcopy(ll->n)); - return l; -} - -static Node* -inlcopy(Node *n) -{ - Node *m; - - if(n == N) - return N; - - switch(n->op) { - case ONAME: - case OTYPE: - case OLITERAL: - return n; - } - - m = nod(OXXX, N, N); - *m = *n; - m->inl = nil; - m->left = inlcopy(n->left); - m->right = inlcopy(n->right); - m->list = inlcopylist(n->list); - m->rlist = inlcopylist(n->rlist); - m->ninit = inlcopylist(n->ninit); - m->ntest = inlcopy(n->ntest); - m->nincr = inlcopy(n->nincr); - m->nbody = inlcopylist(n->nbody); - m->nelse = inlcopylist(n->nelse); - - return m; -} - - -// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any -// calls made to inlineable functions. This is the external entry point. -void -inlcalls(Node *fn) -{ - Node *savefn; - - savefn = curfn; - curfn = fn; - inlnode(&fn); - if(fn != curfn) - fatal("inlnode replaced curfn"); - curfn = savefn; -} - -// Turn an OINLCALL into a statement. -static void -inlconv2stmt(Node *n) -{ - n->op = OBLOCK; - // n->ninit stays - n->list = n->nbody; - n->nbody = nil; - n->rlist = nil; -} - -// Turn an OINLCALL into a single valued expression. -static void -inlconv2expr(Node **np) -{ - Node *n, *r; - n = *np; - r = n->rlist->n; - addinit(&r, concat(n->ninit, n->nbody)); - *np = r; -} - -// Turn the rlist (with the return values) of the OINLCALL in -// n into an expression list lumping the ninit and body -// containing the inlined statements on the first list element so -// order will be preserved Used in return, oas2func and call -// statements. -static NodeList* -inlconv2list(Node *n) -{ - NodeList *l; - - if(n->op != OINLCALL || n->rlist == nil) - fatal("inlconv2list %+N\n", n); - - l = n->rlist; - addinit(&l->n, concat(n->ninit, n->nbody)); - return l; -} - -static void -inlnodelist(NodeList *l) -{ - for(; l; l=l->next) - inlnode(&l->n); -} - -// inlnode recurses over the tree to find inlineable calls, which will -// be turned into OINLCALLs by mkinlcall. When the recursion comes -// back up will examine left, right, list, rlist, ninit, ntest, nincr, -// nbody and nelse and use one of the 4 inlconv/glue functions above -// to turn the OINLCALL into an expression, a statement, or patch it -// in to this nodes list or rlist as appropriate. -// NOTE it makes no sense to pass the glue functions down the -// recursion to the level where the OINLCALL gets created because they -// have to edit /this/ n, so you'd have to push that one down as well, -// but then you may as well do it here. so this is cleaner and -// shorter and less complicated. -static void -inlnode(Node **np) -{ - Node *n; - NodeList *l; - int lno; - - if(*np == nil) - return; - - n = *np; - - switch(n->op) { - case ODEFER: - case OPROC: - // inhibit inlining of their argument - switch(n->left->op) { - case OCALLFUNC: - case OCALLMETH: - n->left->etype = n->op; - } - - case OCLOSURE: - // TODO do them here (or earlier), - // so escape analysis can avoid more heapmoves. - return; - } - - lno = setlineno(n); - - inlnodelist(n->ninit); - for(l=n->ninit; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2stmt(l->n); - - inlnode(&n->left); - if(n->left && n->left->op == OINLCALL) - inlconv2expr(&n->left); - - inlnode(&n->right); - if(n->right && n->right->op == OINLCALL) - inlconv2expr(&n->right); - - inlnodelist(n->list); - switch(n->op) { - case OBLOCK: - for(l=n->list; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2stmt(l->n); - break; - - case ORETURN: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - case OAPPEND: - case OCOMPLEX: - // if we just replaced arg in f(arg()) or return arg with an inlined call - // and arg returns multiple values, glue as list - if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) { - n->list = inlconv2list(n->list->n); - break; - } - - // fallthrough - default: - for(l=n->list; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2expr(&l->n); - } - - inlnodelist(n->rlist); - switch(n->op) { - case OAS2FUNC: - if(n->rlist->n->op == OINLCALL) { - n->rlist = inlconv2list(n->rlist->n); - n->op = OAS2; - n->typecheck = 0; - typecheck(np, Etop); - break; - } - - // fallthrough - default: - for(l=n->rlist; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2expr(&l->n); - - } - - inlnode(&n->ntest); - if(n->ntest && n->ntest->op == OINLCALL) - inlconv2expr(&n->ntest); - - inlnode(&n->nincr); - if(n->nincr && n->nincr->op == OINLCALL) - inlconv2stmt(n->nincr); - - inlnodelist(n->nbody); - for(l=n->nbody; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2stmt(l->n); - - inlnodelist(n->nelse); - for(l=n->nelse; l; l=l->next) - if(l->n->op == OINLCALL) - inlconv2stmt(l->n); - - // with all the branches out of the way, it is now time to - // transmogrify this node itself unless inhibited by the - // switch at the top of this function. - switch(n->op) { - case OCALLFUNC: - case OCALLMETH: - if (n->etype == OPROC || n->etype == ODEFER) - return; - } - - switch(n->op) { - case OCALLFUNC: - if(debug['m']>3) - print("%L:call to func %+N\n", n->lineno, n->left); - if(n->left->inl) // normal case - mkinlcall(np, n->left, n->isddd); - else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right && n->left->right->op == ONAME) // methods called as functions - if(n->left->sym->def) - mkinlcall(np, n->left->sym->def, n->isddd); - break; - - case OCALLMETH: - if(debug['m']>3) - print("%L:call to meth %lN\n", n->lineno, n->left->right); - // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function. - if(n->left->type == T) - fatal("no function type for [%p] %+N\n", n->left, n->left); - - if(n->left->type->nname == N) - fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type); - - mkinlcall(np, n->left->type->nname, n->isddd); - - break; - } - - lineno = lno; -} - -static void mkinlcall1(Node **np, Node *fn, int isddd); - -static void -mkinlcall(Node **np, Node *fn, int isddd) -{ - int save_safemode; - Pkg *pkg; - - save_safemode = safemode; - - // imported functions may refer to unsafe as long as the - // package was marked safe during import (already checked). - pkg = fnpkg(fn); - if(pkg != localpkg && pkg != nil) - safemode = 0; - mkinlcall1(np, fn, isddd); - safemode = save_safemode; -} - -static Node* -tinlvar(Type *t) -{ - if(t->nname && !isblank(t->nname)) { - if(!t->nname->inlvar) - fatal("missing inlvar for %N\n", t->nname); - return t->nname->inlvar; - } - typecheck(&nblank, Erv | Easgn); - return nblank; -} - -static int inlgen; - -// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL. -// On return ninit has the parameter assignments, the nbody is the -// inlined function body and list, rlist contain the input, output -// parameters. -static void -mkinlcall1(Node **np, Node *fn, int isddd) -{ - int i; - int chkargcount; - Node *n, *call, *saveinlfn, *as, *m; - NodeList *dcl, *ll, *ninit, *body; - Type *t; - // For variadic fn. - int variadic, varargcount, multiret; - Node *vararg; - NodeList *varargs; - Type *varargtype, *vararrtype; - - if (fn->inl == nil) - return; - - if (fn == curfn || fn->defn == curfn) - return; - - if(debug['l']<2) - typecheckinl(fn); - - n = *np; - - // Bingo, we have a function node, and it has an inlineable body - if(debug['m']>1) - print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl); - else if(debug['m']) - print("%L: inlining call to %N\n", n->lineno, fn); - - if(debug['m']>2) - print("%L: Before inlining: %+N\n", n->lineno, n); - - saveinlfn = inlfn; - inlfn = fn; - - ninit = n->ninit; - -//dumplist("ninit pre", ninit); - - if(fn->defn) // local function - dcl = fn->inldcl; - else // imported function - dcl = fn->dcl; - - inlretvars = nil; - i = 0; - // Make temp names to use instead of the originals - for(ll = dcl; ll; ll=ll->next) { - if(ll->n->class == PPARAMOUT) // return values handled below. - continue; - if(ll->n->op == ONAME) { - ll->n->inlvar = inlvar(ll->n); - // Typecheck because inlvar is not necessarily a function parameter. - typecheck(&ll->n->inlvar, Erv); - if ((ll->n->class&~PHEAP) != PAUTO) - ninit = list(ninit, nod(ODCL, ll->n->inlvar, N)); // otherwise gen won't emit the allocations for heapallocs - } - } - - // temporaries for return values. - for(t = getoutargx(fn->type)->type; t; t = t->down) { - if(t != T && t->nname != N && !isblank(t->nname)) { - m = inlvar(t->nname); - typecheck(&m, Erv); - t->nname->inlvar = m; - } else { - // anonymous return values, synthesize names for use in assignment that replaces return - m = retvar(t, i++); - } - ninit = list(ninit, nod(ODCL, m, N)); - inlretvars = list(inlretvars, m); - } - - // assign receiver. - if(fn->type->thistuple && n->left->op == ODOTMETH) { - // method call with a receiver. - t = getthisx(fn->type)->type; - if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar) - fatal("missing inlvar for %N\n", t->nname); - if(!n->left->left) - fatal("method call without receiver: %+N", n); - if(t == T) - fatal("method call unknown receiver type: %+N", n); - as = nod(OAS, tinlvar(t), n->left->left); - if(as != N) { - typecheck(&as, Etop); - ninit = list(ninit, as); - } - } - - // check if inlined function is variadic. - variadic = 0; - varargtype = T; - varargcount = 0; - for(t=fn->type->type->down->down->type; t; t=t->down) { - if(t->isddd) { - variadic = 1; - varargtype = t->type; - } - } - // but if argument is dotted too forget about variadicity. - if(variadic && isddd) - variadic = 0; - - // check if argument is actually a returned tuple from call. - multiret = 0; - if(n->list && !n->list->next) { - switch(n->list->n->op) { - case OCALL: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - if(n->list->n->left->type->outtuple > 1) - multiret = n->list->n->left->type->outtuple-1; - } - } - - if(variadic) { - varargcount = count(n->list) + multiret; - if(n->left->op != ODOTMETH) - varargcount -= fn->type->thistuple; - varargcount -= fn->type->intuple - 1; - } - - // assign arguments to the parameters' temp names - as = nod(OAS2, N, N); - as->rlist = n->list; - ll = n->list; - - // TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call? - if(fn->type->thistuple && n->left->op != ODOTMETH) { - // non-method call to method - if(!n->list) - fatal("non-method call to method without first arg: %+N", n); - // append receiver inlvar to LHS. - t = getthisx(fn->type)->type; - if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar) - fatal("missing inlvar for %N\n", t->nname); - if(t == T) - fatal("method call unknown receiver type: %+N", n); - as->list = list(as->list, tinlvar(t)); - ll = ll->next; // track argument count. - } - - // append ordinary arguments to LHS. - chkargcount = n->list && n->list->next; - vararg = N; // the slice argument to a variadic call - varargs = nil; // the list of LHS names to put in vararg. - if(!chkargcount) { - // 0 or 1 expression on RHS. - for(t = getinargx(fn->type)->type; t; t=t->down) { - if(variadic && t->isddd) { - vararg = tinlvar(t); - for(i=0; ilist = list(as->list, m); - } - break; - } - as->list = list(as->list, tinlvar(t)); - } - } else { - // match arguments except final variadic (unless the call is dotted itself) - for(t = getinargx(fn->type)->type; t;) { - if(!ll) - break; - if(variadic && t->isddd) - break; - as->list = list(as->list, tinlvar(t)); - t=t->down; - ll=ll->next; - } - // match varargcount arguments with variadic parameters. - if(variadic && t && t->isddd) { - vararg = tinlvar(t); - for(i=0; ilist = list(as->list, m); - ll=ll->next; - } - if(i==varargcount) - t=t->down; - } - if(ll || t) - fatal("arg count mismatch: %#T vs %,H\n", getinargx(fn->type), n->list); - } - - if (as->rlist) { - typecheck(&as, Etop); - ninit = list(ninit, as); - } - - // turn the variadic args into a slice. - if(variadic) { - as = nod(OAS, vararg, N); - if(!varargcount) { - as->right = nodnil(); - as->right->type = varargtype; - } else { - vararrtype = typ(TARRAY); - vararrtype->type = varargtype->type; - vararrtype->bound = varargcount; - - as->right = nod(OCOMPLIT, N, typenod(varargtype)); - as->right->list = varargs; - as->right = nod(OSLICE, as->right, nod(OKEY, N, N)); - } - typecheck(&as, Etop); - ninit = list(ninit, as); - } - - // zero the outparams - for(ll = inlretvars; ll; ll=ll->next) { - as = nod(OAS, ll->n, N); - typecheck(&as, Etop); - ninit = list(ninit, as); - } - - inlretlabel = newlabel(); - inlgen++; - body = inlsubstlist(fn->inl); - - body = list(body, nod(OGOTO, inlretlabel, N)); // avoid 'not used' when function doesnt have return - body = list(body, nod(OLABEL, inlretlabel, N)); - - typechecklist(body, Etop); -//dumplist("ninit post", ninit); - - call = nod(OINLCALL, N, N); - call->ninit = ninit; - call->nbody = body; - call->rlist = inlretvars; - call->type = n->type; - call->typecheck = 1; - - setlno(call, n->lineno); -//dumplist("call body", body); - - *np = call; - - inlfn = saveinlfn; - - // transitive inlining - // TODO do this pre-expansion on fn->inl directly. requires - // either supporting exporting statemetns with complex ninits - // or saving inl and making inlinl - if(debug['l'] >= 5) { - body = fn->inl; - fn->inl = nil; // prevent infinite recursion - inlnodelist(call->nbody); - for(ll=call->nbody; ll; ll=ll->next) - if(ll->n->op == OINLCALL) - inlconv2stmt(ll->n); - fn->inl = body; - } - - if(debug['m']>2) - print("%L: After inlining %+N\n\n", n->lineno, *np); - -} - -// Every time we expand a function we generate a new set of tmpnames, -// PAUTO's in the calling functions, and link them off of the -// PPARAM's, PAUTOS and PPARAMOUTs of the called function. -static Node* -inlvar(Node *var) -{ - Node *n; - - if(debug['m']>3) - print("inlvar %+N\n", var); - - n = newname(var->sym); - n->type = var->type; - n->class = PAUTO; - n->used = 1; - n->curfn = curfn; // the calling function, not the called one - n->addrtaken = var->addrtaken; - - // Esc pass wont run if we're inlining into a iface wrapper. - // Luckily, we can steal the results from the target func. - // If inlining a function defined in another package after - // escape analysis is done, treat all local vars as escaping. - // See issue 9537. - if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME)) - addrescapes(n); - - curfn->dcl = list(curfn->dcl, n); - return n; -} - -// Synthesize a variable to store the inlined function's results in. -static Node* -retvar(Type *t, int i) -{ - Node *n; - - snprint(namebuf, sizeof(namebuf), "~r%d", i); - n = newname(lookup(namebuf)); - n->type = t->type; - n->class = PAUTO; - n->used = 1; - n->curfn = curfn; // the calling function, not the called one - curfn->dcl = list(curfn->dcl, n); - return n; -} - -// Synthesize a variable to store the inlined function's arguments -// when they come from a multiple return call. -static Node* -argvar(Type *t, int i) -{ - Node *n; - - snprint(namebuf, sizeof(namebuf), "~arg%d", i); - n = newname(lookup(namebuf)); - n->type = t->type; - n->class = PAUTO; - n->used = 1; - n->curfn = curfn; // the calling function, not the called one - curfn->dcl = list(curfn->dcl, n); - return n; -} - -static Node* -newlabel(void) -{ - Node *n; - static int label; - - label++; - snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label); - n = newname(lookup(namebuf)); - n->etype = 1; // flag 'safe' for escape analysis (no backjumps) - return n; -} - -// inlsubst and inlsubstlist recursively copy the body of the saved -// pristine ->inl body of the function while substituting references -// to input/output parameters with ones to the tmpnames, and -// substituting returns with assignments to the output. -static NodeList* -inlsubstlist(NodeList *ll) -{ - NodeList *l; - - l = nil; - for(; ll; ll=ll->next) - l = list(l, inlsubst(ll->n)); - return l; -} - -static Node* -inlsubst(Node *n) -{ - char *p; - Node *m, *as; - NodeList *ll; - - if(n == N) - return N; - - switch(n->op) { - case ONAME: - if(n->inlvar) { // These will be set during inlnode - if (debug['m']>2) - print ("substituting name %+N -> %+N\n", n, n->inlvar); - return n->inlvar; - } - if (debug['m']>2) - print ("not substituting name %+N\n", n); - return n; - - case OLITERAL: - case OTYPE: - return n; - - case ORETURN: - // Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function. - -// dump("Return before substitution", n); - m = nod(OGOTO, inlretlabel, N); - m->ninit = inlsubstlist(n->ninit); - - if(inlretvars && n->list) { - as = nod(OAS2, N, N); - // shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that. - for(ll=inlretvars; ll; ll=ll->next) - as->list = list(as->list, ll->n); - as->rlist = inlsubstlist(n->list); - typecheck(&as, Etop); - m->ninit = list(m->ninit, as); - } - - typechecklist(m->ninit, Etop); - typecheck(&m, Etop); -// dump("Return after substitution", m); - return m; - - case OGOTO: - case OLABEL: - m = nod(OXXX, N, N); - *m = *n; - m->ninit = nil; - p = smprint("%s·%d", n->left->sym->name, inlgen); - m->left = newname(lookup(p)); - free(p); - return m; - } - - - m = nod(OXXX, N, N); - *m = *n; - m->ninit = nil; - - if(n->op == OCLOSURE) - fatal("cannot inline function containing closure: %+N", n); - - m->left = inlsubst(n->left); - m->right = inlsubst(n->right); - m->list = inlsubstlist(n->list); - m->rlist = inlsubstlist(n->rlist); - m->ninit = concat(m->ninit, inlsubstlist(n->ninit)); - m->ntest = inlsubst(n->ntest); - m->nincr = inlsubst(n->nincr); - m->nbody = inlsubstlist(n->nbody); - m->nelse = inlsubstlist(n->nelse); - - return m; -} - -// Plaster over linenumbers -static void -setlnolist(NodeList *ll, int lno) -{ - for(;ll;ll=ll->next) - setlno(ll->n, lno); -} - -static void -setlno(Node *n, int lno) -{ - if(!n) - return; - - // don't clobber names, unless they're freshly synthesized - if(n->op != ONAME || n->lineno == 0) - n->lineno = lno; - - setlno(n->left, lno); - setlno(n->right, lno); - setlnolist(n->list, lno); - setlnolist(n->rlist, lno); - setlnolist(n->ninit, lno); - setlno(n->ntest, lno); - setlno(n->nincr, lno); - setlnolist(n->nbody, lno); - setlnolist(n->nelse, lno); -} diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c deleted file mode 100644 index a4b832aa0b..0000000000 --- a/src/cmd/gc/lex.c +++ /dev/null @@ -1,2590 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "y.tab.h" -#include - -#ifndef PLAN9 -#include -#endif - -#undef getc -#undef ungetc -#define getc ccgetc -#define ungetc ccungetc - -extern int yychar; -int yyprev; -int yylast; - -static int imported_unsafe; - -static void lexinit(void); -static void lexinit1(void); -static void lexfini(void); -static void yytinit(void); -static int getc(void); -static void ungetc(int); -static int32 getr(void); -static int escchar(int, int*, vlong*); -static void addidir(char*); -static int getlinepragma(void); -static char *goos, *goarch, *goroot; - -#define BOM 0xFEFF - -// Debug arguments. -// These can be specified with the -d flag, as in "-d nil" -// to set the debug_checknil variable. In general the list passed -// to -d can be comma-separated. -static struct { - char *name; - int *val; -} debugtab[] = { - {"nil", &debug_checknil}, -}; - -// Our own isdigit, isspace, isalpha, isalnum that take care -// of EOF and other out of range arguments. -static int -yy_isdigit(int c) -{ - return c >= 0 && c <= 0xFF && isdigit(c); -} - -static int -yy_isspace(int c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; -} - -static int -yy_isalpha(int c) -{ - return c >= 0 && c <= 0xFF && isalpha(c); -} - -static int -yy_isalnum(int c) -{ - return c >= 0 && c <= 0xFF && isalnum(c); -} - -// Disallow use of isdigit etc. -#undef isdigit -#undef isspace -#undef isalpha -#undef isalnum -#define isdigit use_yy_isdigit_instead_of_isdigit -#define isspace use_yy_isspace_instead_of_isspace -#define isalpha use_yy_isalpha_instead_of_isalpha -#define isalnum use_yy_isalnum_instead_of_isalnum - -#define DBG if(!debug['x']){}else print -/*c2go void DBG(char*, ...); */ - -enum -{ - EOF = -1, -}; - -void -usage(void) -{ - print("usage: %cg [options] file.go...\n", thearch.thechar); - flagprint(1); - exits("usage"); -} - -void -fault(int s) -{ - USED(s); - - // If we've already complained about things - // in the program, don't bother complaining - // about the seg fault too; let the user clean up - // the code and try again. - if(nsavederrors + nerrors > 0) - errorexit(); - fatal("fault"); -} - -#ifdef PLAN9 -void -catcher(void *v, char *s) -{ - USED(v); - - if(strncmp(s, "sys: trap: fault read", 21) == 0) { - if(nsavederrors + nerrors > 0) - errorexit(); - fatal("fault"); - } - noted(NDFLT); -} -#endif - -void -doversion(void) -{ - char *p, *sep; - - p = expstring(); - if(strcmp(p, "X:none") == 0) - p = ""; - sep = ""; - if(*p) - sep = " "; - print("%cg version %s%s%s\n", thearch.thechar, getgoversion(), sep, p); - exits(0); -} - -int -gcmain(int argc, char *argv[]) -{ - int i; - NodeList *l; - char *p; - -#ifdef SIGBUS - signal(SIGBUS, fault); - signal(SIGSEGV, fault); -#endif - -#ifdef PLAN9 - notify(catcher); - // Tell the FPU to handle all exceptions. - setfcr(FPPDBL|FPRNR); -#endif - // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix, - // but not other values. - p = getgoarch(); - if(strncmp(p, thearch.thestring, strlen(thearch.thestring)) != 0) - sysfatal("cannot use %cg with GOARCH=%s", thearch.thechar, p); - goarch = p; - - thearch.linkarchinit(); - ctxt = linknew(thearch.thelinkarch); - ctxt->diag = yyerror; - ctxt->bso = &bstdout; - Binit(&bstdout, 1, OWRITE); - - localpkg = mkpkg(newstrlit("")); - localpkg->prefix = "\"\""; - - // pseudo-package, for scoping - builtinpkg = mkpkg(newstrlit("go.builtin")); - builtinpkg->prefix = "go.builtin"; // not go%2ebuiltin - - // pseudo-package, accessed by import "unsafe" - unsafepkg = mkpkg(newstrlit("unsafe")); - unsafepkg->name = "unsafe"; - - // real package, referred to by generated runtime calls - runtimepkg = mkpkg(newstrlit("runtime")); - runtimepkg->name = "runtime"; - - // pseudo-packages used in symbol tables - gostringpkg = mkpkg(newstrlit("go.string")); - gostringpkg->name = "go.string"; - gostringpkg->prefix = "go.string"; // not go%2estring - - itabpkg = mkpkg(newstrlit("go.itab")); - itabpkg->name = "go.itab"; - itabpkg->prefix = "go.itab"; // not go%2eitab - - weaktypepkg = mkpkg(newstrlit("go.weak.type")); - weaktypepkg->name = "go.weak.type"; - weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype - - typelinkpkg = mkpkg(newstrlit("go.typelink")); - typelinkpkg->name = "go.typelink"; - typelinkpkg->prefix = "go.typelink"; // not go%2etypelink - - trackpkg = mkpkg(newstrlit("go.track")); - trackpkg->name = "go.track"; - trackpkg->prefix = "go.track"; // not go%2etrack - - typepkg = mkpkg(newstrlit("type")); - typepkg->name = "type"; - - goroot = getgoroot(); - goos = getgoos(); - - nacl = strcmp(goos, "nacl") == 0; - if(nacl) - flag_largemodel = 1; - - fmtstrinit(&pragcgobuf); - quotefmtinstall(); - - outfile = nil; - flagcount("+", "compiling runtime", &compiling_runtime); - flagcount("%", "debug non-static initializers", &debug['%']); - flagcount("A", "for bootstrapping, allow 'any' type", &debug['A']); - flagcount("B", "disable bounds checking", &debug['B']); - flagstr("D", "path: set relative path for local imports", &localimport); - flagcount("E", "debug symbol export", &debug['E']); - flagfn1("I", "dir: add dir to import search path", addidir); - flagcount("K", "debug missing line numbers", &debug['K']); - flagcount("L", "use full (long) path in error messages", &debug['L']); - flagcount("M", "debug move generation", &debug['M']); - flagcount("N", "disable optimizations", &debug['N']); - flagcount("P", "debug peephole optimizer", &debug['P']); - flagcount("R", "debug register optimizer", &debug['R']); - flagcount("S", "print assembly listing", &debug['S']); - flagfn0("V", "print compiler version", doversion); - flagcount("W", "debug parse tree after type checking", &debug['W']); - flagstr("asmhdr", "file: write assembly header to named file", &asmhdr); - flagcount("complete", "compiling complete package (no C or assembly)", &pure_go); - flagstr("d", "list: print debug information about items in list", &debugstr); - flagcount("e", "no limit on number of errors reported", &debug['e']); - flagcount("f", "debug stack frames", &debug['f']); - flagcount("g", "debug code generation", &debug['g']); - flagcount("h", "halt on error", &debug['h']); - flagcount("i", "debug line number stack", &debug['i']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagcount("j", "debug runtime-initialized variables", &debug['j']); - flagcount("l", "disable inlining", &debug['l']); - flagcount("live", "debug liveness analysis", &debuglive); - flagcount("m", "print optimization decisions", &debug['m']); - flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports); - flagstr("o", "obj: set output file", &outfile); - flagstr("p", "path: set expected package import path", &myimportpath); - flagcount("pack", "write package file instead of object file", &writearchive); - flagcount("r", "debug generated wrappers", &debug['r']); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "warn about composite literals that can be simplified", &debug['s']); - flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath); - flagcount("u", "reject unsafe code", &safemode); - flagcount("v", "increase debug verbosity", &debug['v']); - flagcount("w", "debug type checking", &debug['w']); - use_writebarrier = 1; - flagcount("wb", "enable write barrier", &use_writebarrier); - flagcount("x", "debug lexer", &debug['x']); - flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']); - if(thearch.thechar == '6') - flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel); - - flagparse(&argc, &argv, usage); - ctxt->debugasm = debug['S']; - ctxt->debugvlog = debug['v']; - - if(argc < 1) - usage(); - - if(flag_race) { - racepkg = mkpkg(newstrlit("runtime/race")); - racepkg->name = "race"; - } - - // parse -d argument - if(debugstr) { - char *f[100]; - int i, j, nf; - - nf = getfields(debugstr, f, nelem(f), 1, ","); - for(i=0; i= nelem(debugtab)) - sysfatal("unknown debug information -d '%s'\n", f[i]); - } - } - - // enable inlining. for now: - // default: inlining on. (debug['l'] == 1) - // -l: inlining off (debug['l'] == 0) - // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) - if(debug['l'] <= 1) - debug['l'] = 1 - debug['l']; - - if(thearch.thechar == '8') { - p = getgo386(); - if(strcmp(p, "387") == 0) - use_sse = 0; - else if(strcmp(p, "sse2") == 0) - use_sse = 1; - else - sysfatal("unsupported setting GO386=%s", p); - } - - fmtinstallgo(); - thearch.betypeinit(); - if(widthptr == 0) - fatal("betypeinit failed"); - - lexinit(); - typeinit(); - lexinit1(); - yytinit(); - - blockgen = 1; - dclcontext = PEXTERN; - nerrors = 0; - lexlineno = 1; - - for(i=0; iname); // final import not used checks - lexfini(); - - typecheckok = 1; - if(debug['f']) - frame(1); - - // Process top-level declarations in phases. - - // Phase 1: const, type, and names and types of funcs. - // This will gather all the information about types - // and methods but doesn't depend on any of it. - defercheckwidth(); - for(l=xtop; l; l=l->next) - if(l->n->op != ODCL && l->n->op != OAS) - typecheck(&l->n, Etop); - - // Phase 2: Variable assignments. - // To check interface assignments, depends on phase 1. - for(l=xtop; l; l=l->next) - if(l->n->op == ODCL || l->n->op == OAS) - typecheck(&l->n, Etop); - resumecheckwidth(); - - // Phase 3: Type check function bodies. - for(l=xtop; l; l=l->next) { - if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) { - curfn = l->n; - decldepth = 1; - saveerrors(); - typechecklist(l->n->nbody, Etop); - checkreturn(l->n); - if(nerrors != 0) - l->n->nbody = nil; // type errors; do not compile - } - } - - // Phase 4: Decide how to capture closed variables. - // This needs to run before escape analysis, - // because variables captured by value do not escape. - for(l=xtop; l; l=l->next) { - if(l->n->op == ODCLFUNC && l->n->closure) { - curfn = l->n; - capturevars(l->n); - } - } - - curfn = nil; - - if(nsavederrors+nerrors) - errorexit(); - - // Phase 5: Inlining - if(debug['l'] > 1) { - // Typecheck imported function bodies if debug['l'] > 1, - // otherwise lazily when used or re-exported. - for(l=importlist; l; l=l->next) - if (l->n->inl) { - saveerrors(); - typecheckinl(l->n); - } - - if(nsavederrors+nerrors) - errorexit(); - } - - if(debug['l']) { - // Find functions that can be inlined and clone them before walk expands them. - for(l=xtop; l; l=l->next) - if(l->n->op == ODCLFUNC) - caninl(l->n); - - // Expand inlineable calls in all functions - for(l=xtop; l; l=l->next) - if(l->n->op == ODCLFUNC) - inlcalls(l->n); - } - - // Phase 6: Escape analysis. - // Required for moving heap allocations onto stack, - // which in turn is required by the closure implementation, - // which stores the addresses of stack variables into the closure. - // If the closure does not escape, it needs to be on the stack - // or else the stack copier will not update it. - escapes(xtop); - - // Escape analysis moved escaped values off stack. - // Move large values off stack too. - movelarge(xtop); - - // Phase 7: Transform closure bodies to properly reference captured variables. - // This needs to happen before walk, because closures must be transformed - // before walk reaches a call of a closure. - for(l=xtop; l; l=l->next) { - if(l->n->op == ODCLFUNC && l->n->closure) { - curfn = l->n; - transformclosure(l->n); - } - } - curfn = N; - - // Phase 8: Compile top level functions. - for(l=xtop; l; l=l->next) - if(l->n->op == ODCLFUNC) - funccompile(l->n); - - if(nsavederrors+nerrors == 0) - fninit(xtop); - - // Phase 9: Check external declarations. - for(l=externdcl; l; l=l->next) - if(l->n->op == ONAME) - typecheck(&l->n, Erv); - - if(nerrors+nsavederrors) - errorexit(); - - dumpobj(); - - if(asmhdr) - dumpasmhdr(); - - if(nerrors+nsavederrors) - errorexit(); - - flusherrors(); - exits(0); - return 0; -} - -void -saveerrors(void) -{ - nsavederrors += nerrors; - nerrors = 0; -} - -static int -arsize(Biobuf *b, char *name) -{ - struct ar_hdr a; - - if(Bread(b, a.name, sizeof(a.name)) != sizeof(a.name) || - Bread(b, a.date, sizeof(a.date)) != sizeof(a.date) || - Bread(b, a.uid, sizeof(a.uid)) != sizeof(a.uid) || - Bread(b, a.gid, sizeof(a.gid)) != sizeof(a.gid) || - Bread(b, a.mode, sizeof(a.mode)) != sizeof(a.mode) || - Bread(b, a.size, sizeof(a.size)) != sizeof(a.size) || - Bread(b, a.fmag, sizeof(a.fmag)) != sizeof(a.fmag)) - return -1; - - if(strncmp(a.name, name, strlen(name)) != 0) - return -1; - - return atoi(a.size); -} - -static int -skiptopkgdef(Biobuf *b) -{ - char *p; - int sz; - - /* archive header */ - if((p = Brdline(b, '\n')) == nil) - return 0; - if(Blinelen(b) != 8) - return 0; - if(memcmp(p, "!\n", 8) != 0) - return 0; - /* symbol table may be first; skip it */ - sz = arsize(b, "__.GOSYMDEF"); - if(sz >= 0) - Bseek(b, sz, 1); - else - Bseek(b, 8, 0); - /* package export block is next */ - sz = arsize(b, "__.PKGDEF"); - if(sz <= 0) - return 0; - return 1; -} - -static void -addidir(char* dir) -{ - Idir** pp; - - if(dir == nil) - return; - - for(pp = &idirs; *pp != nil; pp = &(*pp)->link) - ; - *pp = mal(sizeof(Idir)); - (*pp)->link = nil; - (*pp)->dir = dir; -} - -// is this path a local name? begins with ./ or ../ or / -static int -islocalname(Strlit *name) -{ - if(name->len >= 1 && name->s[0] == '/') - return 1; - if(ctxt->windows && name->len >= 3 && - yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/') - return 1; - if(name->len >= 2 && strncmp(name->s, "./", 2) == 0) - return 1; - if(name->len == 1 && strncmp(name->s, ".", 1) == 0) - return 1; - if(name->len >= 3 && strncmp(name->s, "../", 3) == 0) - return 1; - if(name->len == 2 && strncmp(name->s, "..", 2) == 0) - return 1; - return 0; -} - -static int -findpkg(Strlit *name) -{ - Idir *p; - char *q, *suffix, *suffixsep; - - if(islocalname(name)) { - if(safemode || nolocalimports) - return 0; - // try .a before .6. important for building libraries: - // if there is an array.6 in the array.a library, - // want to find all of array.a, not just array.6. - snprint(namebuf, sizeof(namebuf), "%Z.a", name); - if(access(namebuf, 0) >= 0) - return 1; - snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thearch.thechar); - if(access(namebuf, 0) >= 0) - return 1; - return 0; - } - - // local imports should be canonicalized already. - // don't want to see "encoding/../encoding/base64" - // as different from "encoding/base64". - q = mal(name->len+1); - memmove(q, name->s, name->len); - q[name->len] = '\0'; - cleanname(q); - if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) { - yyerror("non-canonical import path %Z (should be %s)", name, q); - return 0; - } - - for(p = idirs; p != nil; p = p->link) { - snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name); - if(access(namebuf, 0) >= 0) - return 1; - snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thearch.thechar); - if(access(namebuf, 0) >= 0) - return 1; - } - if(goroot != nil) { - suffix = ""; - suffixsep = ""; - if(flag_installsuffix != nil) { - suffixsep = "_"; - suffix = flag_installsuffix; - } else if(flag_race) { - suffixsep = "_"; - suffix = "race"; - } - snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name); - if(access(namebuf, 0) >= 0) - return 1; - snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thearch.thechar); - if(access(namebuf, 0) >= 0) - return 1; - } - return 0; -} - -static void -fakeimport(void) -{ - importpkg = mkpkg(newstrlit("fake")); - cannedimports("fake.6", "$$\n"); -} - -void -importfile(Val *f, int line) -{ - Biobuf *imp; - char *file, *p, *q, *tag; - int32 c; - int n; - Strlit *path; - char *cleanbuf, *prefix; - - USED(line); - - if(f->ctype != CTSTR) { - yyerror("import statement not a string"); - fakeimport(); - return; - } - - if(f->u.sval->len == 0) { - yyerror("import path is empty"); - fakeimport(); - return; - } - - if(isbadimport(f->u.sval)) { - fakeimport(); - return; - } - - // The package name main is no longer reserved, - // but we reserve the import path "main" to identify - // the main package, just as we reserve the import - // path "math" to identify the standard math package. - if(strcmp(f->u.sval->s, "main") == 0) { - yyerror("cannot import \"main\""); - errorexit(); - } - - if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) { - yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval); - errorexit(); - } - - if(strcmp(f->u.sval->s, "unsafe") == 0) { - if(safemode) { - yyerror("cannot import package unsafe"); - errorexit(); - } - importpkg = mkpkg(f->u.sval); - cannedimports("unsafe.6", unsafeimport); - imported_unsafe = 1; - return; - } - - path = f->u.sval; - if(islocalname(path)) { - if(path->s[0] == '/') { - yyerror("import path cannot be absolute path"); - fakeimport(); - return; - } - prefix = ctxt->pathname; - if(localimport != nil) - prefix = localimport; - cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2); - strcpy(cleanbuf, prefix); - strcat(cleanbuf, "/"); - strcat(cleanbuf, path->s); - cleanname(cleanbuf); - path = newstrlit(cleanbuf); - - if(isbadimport(path)) { - fakeimport(); - return; - } - } - - if(!findpkg(path)) { - yyerror("can't find import: \"%Z\"", f->u.sval); - errorexit(); - } - importpkg = mkpkg(path); - - // If we already saw that package, feed a dummy statement - // to the lexer to avoid parsing export data twice. - if(importpkg->imported) { - file = strdup(namebuf); - tag = ""; - if(importpkg->safe) { - tag = "safe"; - } - p = smprint("package %s %s\n$$\n", importpkg->name, tag); - cannedimports(file, p); - return; - } - importpkg->imported = 1; - - imp = Bopen(namebuf, OREAD); - if(imp == nil) { - yyerror("can't open import: \"%Z\": %r", f->u.sval); - errorexit(); - } - file = strdup(namebuf); - - n = strlen(namebuf); - if(n > 2 && namebuf[n-2] == '.' && namebuf[n-1] == 'a') { - if(!skiptopkgdef(imp)) { - yyerror("import %s: not a package file", file); - errorexit(); - } - } - - // check object header - p = Brdstr(imp, '\n', 1); - if(strcmp(p, "empty archive") != 0) { - if(strncmp(p, "go object ", 10) != 0) { - yyerror("import %s: not a go object file", file); - errorexit(); - } - q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring()); - if(strcmp(p+10, q) != 0) { - yyerror("import %s: object is [%s] expected [%s]", file, p+10, q); - errorexit(); - } - free(q); - } - - // assume files move (get installed) - // so don't record the full path. - linehist(file + n - path->len - 2, -1, 1); // acts as #pragma lib - - /* - * position the input right - * after $$ and return - */ - pushedio = curio; - curio.bin = imp; - curio.peekc = 0; - curio.peekc1 = 0; - curio.infile = file; - curio.nlsemi = 0; - typecheckok = 1; - - for(;;) { - c = getc(); - if(c == EOF) - break; - if(c != '$') - continue; - c = getc(); - if(c == EOF) - break; - if(c != '$') - continue; - return; - } - yyerror("no import in \"%Z\"", f->u.sval); - unimportfile(); -} - -void -unimportfile(void) -{ - if(curio.bin != nil) { - Bterm(curio.bin); - curio.bin = nil; - } else - lexlineno--; // re correct sys.6 line number - - curio = pushedio; - pushedio.bin = nil; - incannedimport = 0; - typecheckok = 0; -} - -void -cannedimports(char *file, char *cp) -{ - lexlineno++; // if sys.6 is included on line 1, - - pushedio = curio; - curio.bin = nil; - curio.peekc = 0; - curio.peekc1 = 0; - curio.infile = file; - curio.cp = cp; - curio.nlsemi = 0; - curio.importsafe = 0; - - typecheckok = 1; - incannedimport = 1; -} - -static int -isfrog(int c) -{ - // complain about possibly invisible control characters - if(c < ' ') { - return !yy_isspace(c); // exclude good white space - } - if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space. - return 1; - return 0; -} - -typedef struct Loophack Loophack; -struct Loophack { - int v; - Loophack *next; -}; - -static int32 -_yylex(void) -{ - int c, c1, clen, escflag, ncp; - vlong v; - char *cp, *ep; - Rune rune; - Sym *s; - static Loophack *lstk; - Loophack *h; - - prevlineno = lineno; - -l0: - c = getc(); - if(yy_isspace(c)) { - if(c == '\n' && curio.nlsemi) { - ungetc(c); - DBG("lex: implicit semi\n"); - return ';'; - } - goto l0; - } - - lineno = lexlineno; /* start of token */ - - if(c >= Runeself) { - /* all multibyte runes are alpha */ - cp = lexbuf; - ep = lexbuf+sizeof lexbuf; - goto talph; - } - - if(yy_isalpha(c)) { - cp = lexbuf; - ep = lexbuf+sizeof lexbuf; - goto talph; - } - - if(yy_isdigit(c)) - goto tnum; - - switch(c) { - case EOF: - lineno = prevlineno; - ungetc(EOF); - return -1; - - case '_': - cp = lexbuf; - ep = lexbuf+sizeof lexbuf; - goto talph; - - case '.': - c1 = getc(); - if(yy_isdigit(c1)) { - cp = lexbuf; - ep = lexbuf+sizeof lexbuf; - *cp++ = c; - c = c1; - goto casedot; - } - if(c1 == '.') { - c1 = getc(); - if(c1 == '.') { - c = LDDD; - goto lx; - } - ungetc(c1); - c1 = '.'; - } - break; - - case '"': - /* "..." */ - strcpy(lexbuf, "\"\""); - cp = mal(8); - clen = sizeof(int32); - ncp = 8; - - for(;;) { - if(clen+UTFmax > ncp) { - cp = remal(cp, ncp, ncp); - ncp += ncp; - } - if(escchar('"', &escflag, &v)) - break; - if(v < Runeself || escflag) { - cp[clen++] = v; - } else { - rune = v; - c = runelen(rune); - runetochar(cp+clen, &rune); - clen += c; - } - } - goto strlit; - - case '`': - /* `...` */ - strcpy(lexbuf, "``"); - cp = mal(8); - clen = sizeof(int32); - ncp = 8; - - for(;;) { - if(clen+UTFmax > ncp) { - cp = remal(cp, ncp, ncp); - ncp += ncp; - } - c = getr(); - if(c == '\r') - continue; - if(c == EOF) { - yyerror("eof in string"); - break; - } - if(c == '`') - break; - rune = c; - clen += runetochar(cp+clen, &rune); - } - goto strlit; - - case '\'': - /* '.' */ - if(escchar('\'', &escflag, &v)) { - yyerror("empty character literal or unescaped ' in character literal"); - v = '\''; - } - if(!escchar('\'', &escflag, &v)) { - yyerror("missing '"); - ungetc(v); - } - yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval)); - mpmovecfix(yylval.val.u.xval, v); - yylval.val.ctype = CTRUNE; - DBG("lex: codepoint literal\n"); - strcpy(litbuf, "string literal"); - return LLITERAL; - - case '/': - c1 = getc(); - if(c1 == '*') { - int nl; - - nl = 0; - for(;;) { - c = getr(); - if(c == '\n') - nl = 1; - while(c == '*') { - c = getr(); - if(c == '/') { - if(nl) - ungetc('\n'); - goto l0; - } - if(c == '\n') - nl = 1; - } - if(c == EOF) { - yyerror("eof in comment"); - errorexit(); - } - } - } - if(c1 == '/') { - c = getlinepragma(); - for(;;) { - if(c == '\n' || c == EOF) { - ungetc(c); - goto l0; - } - c = getr(); - } - } - if(c1 == '=') { - c = ODIV; - goto asop; - } - break; - - case ':': - c1 = getc(); - if(c1 == '=') { - c = LCOLAS; - yylval.i = lexlineno; - goto lx; - } - break; - - case '*': - c1 = getc(); - if(c1 == '=') { - c = OMUL; - goto asop; - } - break; - - case '%': - c1 = getc(); - if(c1 == '=') { - c = OMOD; - goto asop; - } - break; - - case '+': - c1 = getc(); - if(c1 == '+') { - c = LINC; - goto lx; - } - if(c1 == '=') { - c = OADD; - goto asop; - } - break; - - case '-': - c1 = getc(); - if(c1 == '-') { - c = LDEC; - goto lx; - } - if(c1 == '=') { - c = OSUB; - goto asop; - } - break; - - case '>': - c1 = getc(); - if(c1 == '>') { - c = LRSH; - c1 = getc(); - if(c1 == '=') { - c = ORSH; - goto asop; - } - break; - } - if(c1 == '=') { - c = LGE; - goto lx; - } - c = LGT; - break; - - case '<': - c1 = getc(); - if(c1 == '<') { - c = LLSH; - c1 = getc(); - if(c1 == '=') { - c = OLSH; - goto asop; - } - break; - } - if(c1 == '=') { - c = LLE; - goto lx; - } - if(c1 == '-') { - c = LCOMM; - goto lx; - } - c = LLT; - break; - - case '=': - c1 = getc(); - if(c1 == '=') { - c = LEQ; - goto lx; - } - break; - - case '!': - c1 = getc(); - if(c1 == '=') { - c = LNE; - goto lx; - } - break; - - case '&': - c1 = getc(); - if(c1 == '&') { - c = LANDAND; - goto lx; - } - if(c1 == '^') { - c = LANDNOT; - c1 = getc(); - if(c1 == '=') { - c = OANDNOT; - goto asop; - } - break; - } - if(c1 == '=') { - c = OAND; - goto asop; - } - break; - - case '|': - c1 = getc(); - if(c1 == '|') { - c = LOROR; - goto lx; - } - if(c1 == '=') { - c = OOR; - goto asop; - } - break; - - case '^': - c1 = getc(); - if(c1 == '=') { - c = OXOR; - goto asop; - } - break; - - /* - * clumsy dance: - * to implement rule that disallows - * if T{1}[0] { ... } - * but allows - * if (T{1}[0]) { ... } - * the block bodies for if/for/switch/select - * begin with an LBODY token, not '{'. - * - * when we see the keyword, the next - * non-parenthesized '{' becomes an LBODY. - * loophack is normally 0. - * a keyword makes it go up to 1. - * parens push loophack onto a stack and go back to 0. - * a '{' with loophack == 1 becomes LBODY and disables loophack. - * - * i said it was clumsy. - */ - case '(': - case '[': - if(loophack || lstk != nil) { - h = malloc(sizeof *h); - if(h == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - h->v = loophack; - h->next = lstk; - lstk = h; - loophack = 0; - } - goto lx; - case ')': - case ']': - if(lstk != nil) { - h = lstk; - loophack = h->v; - lstk = h->next; - free(h); - } - goto lx; - case '{': - if(loophack == 1) { - DBG("%L lex: LBODY\n", lexlineno); - loophack = 0; - return LBODY; - } - goto lx; - - default: - goto lx; - } - ungetc(c1); - -lx: - if(c > 0xff) - DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c)); - else - DBG("%L lex: TOKEN '%c'\n", lexlineno, c); - if(isfrog(c)) { - yyerror("illegal character 0x%ux", c); - goto l0; - } - if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) { - yyerror("%s: unexpected %c", "syntax error", c); - goto l0; - } - return c; - -asop: - yylval.i = c; // rathole to hold which asop - DBG("lex: TOKEN ASOP %c\n", c); - return LASOP; - -talph: - /* - * cp is set to lexbuf and some - * prefix has been stored - */ - for(;;) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - if(c >= Runeself) { - ungetc(c); - rune = getr(); - // 0xb7 · is used for internal names - if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7)) - yyerror("invalid identifier character U+%04x", rune); - cp += runetochar(cp, &rune); - } else if(!yy_isalnum(c) && c != '_') - break; - else - *cp++ = c; - c = getc(); - } - *cp = 0; - ungetc(c); - - s = lookup(lexbuf); - switch(s->lexical) { - case LIGNORE: - goto l0; - - case LFOR: - case LIF: - case LSWITCH: - case LSELECT: - loophack = 1; // see comment about loophack above - break; - } - - DBG("lex: %S %s\n", s, lexname(s->lexical)); - yylval.sym = s; - return s->lexical; - -tnum: - cp = lexbuf; - ep = lexbuf+sizeof lexbuf; - if(c != '0') { - for(;;) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - *cp++ = c; - c = getc(); - if(yy_isdigit(c)) - continue; - goto dc; - } - } - *cp++ = c; - c = getc(); - if(c == 'x' || c == 'X') { - for(;;) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - *cp++ = c; - c = getc(); - if(yy_isdigit(c)) - continue; - if(c >= 'a' && c <= 'f') - continue; - if(c >= 'A' && c <= 'F') - continue; - if(cp == lexbuf+2) - yyerror("malformed hex constant"); - if(c == 'p') - goto caseep; - goto ncu; - } - } - - if(c == 'p') // 0p begins floating point zero - goto caseep; - - c1 = 0; - for(;;) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - if(!yy_isdigit(c)) - break; - if(c < '0' || c > '7') - c1 = 1; // not octal - *cp++ = c; - c = getc(); - } - if(c == '.') - goto casedot; - if(c == 'e' || c == 'E') - goto caseep; - if(c == 'i') - goto casei; - if(c1) - yyerror("malformed octal constant"); - goto ncu; - -dc: - if(c == '.') - goto casedot; - if(c == 'e' || c == 'E' || c == 'p' || c == 'P') - goto caseep; - if(c == 'i') - goto casei; - -ncu: - *cp = 0; - ungetc(c); - - yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval)); - mpatofix(yylval.val.u.xval, lexbuf); - if(yylval.val.u.xval->ovf) { - yyerror("overflow in constant"); - mpmovecfix(yylval.val.u.xval, 0); - } - yylval.val.ctype = CTINT; - DBG("lex: integer literal\n"); - strcpy(litbuf, "literal "); - strcat(litbuf, lexbuf); - return LLITERAL; - -casedot: - for(;;) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - *cp++ = c; - c = getc(); - if(!yy_isdigit(c)) - break; - } - if(c == 'i') - goto casei; - if(c != 'e' && c != 'E') - goto caseout; - -caseep: - *cp++ = c; - c = getc(); - if(c == '+' || c == '-') { - *cp++ = c; - c = getc(); - } - if(!yy_isdigit(c)) - yyerror("malformed fp constant exponent"); - while(yy_isdigit(c)) { - if(cp+10 >= ep) { - yyerror("identifier too long"); - errorexit(); - } - *cp++ = c; - c = getc(); - } - if(c == 'i') - goto casei; - goto caseout; - -casei: - // imaginary constant - *cp = 0; - yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval)); - mpmovecflt(&yylval.val.u.cval->real, 0.0); - mpatoflt(&yylval.val.u.cval->imag, lexbuf); - if(yylval.val.u.cval->imag.val.ovf) { - yyerror("overflow in imaginary constant"); - mpmovecflt(&yylval.val.u.cval->real, 0.0); - } - yylval.val.ctype = CTCPLX; - DBG("lex: imaginary literal\n"); - strcpy(litbuf, "literal "); - strcat(litbuf, lexbuf); - return LLITERAL; - -caseout: - *cp = 0; - ungetc(c); - - yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval)); - mpatoflt(yylval.val.u.fval, lexbuf); - if(yylval.val.u.fval->val.ovf) { - yyerror("overflow in float constant"); - mpmovecflt(yylval.val.u.fval, 0.0); - } - yylval.val.ctype = CTFLT; - DBG("lex: floating literal\n"); - strcpy(litbuf, "literal "); - strcat(litbuf, lexbuf); - return LLITERAL; - -strlit: - *(int32*)cp = clen-sizeof(int32); // length - do { - cp[clen++] = 0; - } while(clen & MAXALIGN); - yylval.val.u.sval = (Strlit*)cp; - yylval.val.ctype = CTSTR; - DBG("lex: string literal\n"); - strcpy(litbuf, "string literal"); - return LLITERAL; -} - -static void pragcgo(char*); - -static int -more(char **pp) -{ - char *p; - - p = *pp; - while(yy_isspace(*p)) - p++; - *pp = p; - return *p != '\0'; -} - -/* - * read and interpret syntax that looks like - * //line parse.y:15 - * as a discontinuity in sequential line numbers. - * the next line of input comes from parse.y:15 - */ -static int -getlinepragma(void) -{ - int i, c, n; - char *cp, *ep, *linep; - Hist *h; - - c = getr(); - if(c == 'g') - goto go; - if(c != 'l') - goto out; - for(i=1; i<5; i++) { - c = getr(); - if(c != "line "[i]) - goto out; - } - - cp = lexbuf; - ep = lexbuf+sizeof(lexbuf)-5; - linep = nil; - for(;;) { - c = getr(); - if(c == EOF) - goto out; - if(c == '\n') - break; - if(c == ' ') - continue; - if(c == ':') - linep = cp; - if(cp < ep) - *cp++ = c; - } - *cp = 0; - - if(linep == nil || linep >= ep) - goto out; - *linep++ = '\0'; - n = 0; - for(cp=linep; *cp; cp++) { - if(*cp < '0' || *cp > '9') - goto out; - n = n*10 + *cp - '0'; - if(n > 1e8) { - yyerror("line number out of range"); - errorexit(); - } - } - if(n <= 0) - goto out; - - // try to avoid allocating file name over and over - for(h=ctxt->hist; h!=nil; h=h->link) { - if(h->name != nil && strcmp(h->name, lexbuf) == 0) { - linehist(h->name, n, 0); - goto out; - } - } - linehist(strdup(lexbuf), n, 0); - goto out; - -go: - cp = lexbuf; - ep = lexbuf+sizeof(lexbuf)-5; - *cp++ = 'g'; // already read - for(;;) { - c = getr(); - if(c == EOF || c >= Runeself) - goto out; - if(c == '\n') - break; - if(cp < ep) - *cp++ = c; - } - *cp = 0; - - if(strncmp(lexbuf, "go:cgo_", 7) == 0) - pragcgo(lexbuf); - - ep = strchr(lexbuf, ' '); - if(ep != nil) - *ep = 0; - - if(strcmp(lexbuf, "go:linkname") == 0) { - if(!imported_unsafe) - yyerror("//go:linkname only allowed in Go files that import \"unsafe\""); - if(ep == nil) { - yyerror("usage: //go:linkname localname linkname"); - goto out; - } - cp = ep+1; - while(yy_isspace(*cp)) - cp++; - ep = strchr(cp, ' '); - if(ep == nil) { - yyerror("usage: //go:linkname localname linkname"); - goto out; - } - *ep++ = 0; - while(yy_isspace(*ep)) - ep++; - if(*ep == 0) { - yyerror("usage: //go:linkname localname linkname"); - goto out; - } - lookup(cp)->linkname = strdup(ep); - goto out; - } - - if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) { - nointerface = 1; - goto out; - } - if(strcmp(lexbuf, "go:noescape") == 0) { - noescape = 1; - goto out; - } - if(strcmp(lexbuf, "go:nosplit") == 0) { - nosplit = 1; - goto out; - } - if(strcmp(lexbuf, "go:nowritebarrier") == 0) { - if(!compiling_runtime) - yyerror("//go:nowritebarrier only allowed in runtime"); - nowritebarrier = 1; - goto out; - } - -out: - return c; -} - -static char* -getimpsym(char **pp) -{ - char *p, *start; - - more(pp); // skip spaces - - p = *pp; - if(*p == '\0' || *p == '"') - return nil; - - start = p; - while(*p != '\0' && !yy_isspace(*p) && *p != '"') - p++; - if(*p != '\0') - *p++ = '\0'; - - *pp = p; - return start; -} - -static char* -getquoted(char **pp) -{ - char *p, *start; - - more(pp); // skip spaces - - p = *pp; - if(*p != '"') - return nil; - p++; - - start = p; - while(*p != '"') { - if(*p == '\0') - return nil; - p++; - } - *p++ = '\0'; - *pp = p; - return start; -} - -// Copied nearly verbatim from the C compiler's #pragma parser. -// TODO: Rewrite more cleanly once the compiler is written in Go. -static void -pragcgo(char *text) -{ - char *local, *remote, *p, *q, *verb; - - for(q=text; *q != '\0' && *q != ' '; q++) - ; - if(*q == ' ') - *q++ = '\0'; - - verb = text+3; // skip "go:" - - if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) { - p = getquoted(&q); - if(p == nil) - goto err1; - fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p); - goto out; - - err1: - yyerror("usage: //go:cgo_dynamic_linker \"path\""); - goto out; - } - - if(strcmp(verb, "dynexport") == 0) - verb = "cgo_export_dynamic"; - if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) { - local = getimpsym(&q); - if(local == nil) - goto err2; - if(!more(&q)) { - fmtprint(&pragcgobuf, "%s %q\n", verb, local); - goto out; - } - remote = getimpsym(&q); - if(remote == nil) - goto err2; - fmtprint(&pragcgobuf, "%s %q %q\n", verb, local, remote); - goto out; - - err2: - yyerror("usage: //go:%s local [remote]", verb); - goto out; - } - - if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) { - local = getimpsym(&q); - if(local == nil) - goto err3; - if(!more(&q)) { - fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local); - goto out; - } - remote = getimpsym(&q); - if(remote == nil) - goto err3; - if(!more(&q)) { - fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local, remote); - goto out; - } - p = getquoted(&q); - if(p == nil) - goto err3; - fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local, remote, p); - goto out; - - err3: - yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]"); - goto out; - } - - if(strcmp(verb, "cgo_import_static") == 0) { - local = getimpsym(&q); - if(local == nil || more(&q)) - goto err4; - fmtprint(&pragcgobuf, "cgo_import_static %q\n", local); - goto out; - - err4: - yyerror("usage: //go:cgo_import_static local"); - goto out; - } - - if(strcmp(verb, "cgo_ldflag") == 0) { - p = getquoted(&q); - if(p == nil) - goto err5; - fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p); - goto out; - - err5: - yyerror("usage: //go:cgo_ldflag \"arg\""); - goto out; - } - -out:; -} - -int32 -yylex(void) -{ - int lx; - - lx = _yylex(); - - if(curio.nlsemi && lx == EOF) { - // Treat EOF as "end of line" for the purposes - // of inserting a semicolon. - lx = ';'; - } - - switch(lx) { - case LNAME: - case LLITERAL: - case LBREAK: - case LCONTINUE: - case LFALL: - case LRETURN: - case LINC: - case LDEC: - case ')': - case '}': - case ']': - curio.nlsemi = 1; - break; - default: - curio.nlsemi = 0; - break; - } - - // Track last two tokens returned by yylex. - yyprev = yylast; - yylast = lx; - return lx; -} - -static int -getc(void) -{ - int c, c1, c2; - - c = curio.peekc; - if(c != 0) { - curio.peekc = curio.peekc1; - curio.peekc1 = 0; - goto check; - } - - if(curio.bin == nil) { - c = *curio.cp & 0xff; - if(c != 0) - curio.cp++; - } else { - loop: - c = BGETC(curio.bin); - if(c == 0xef) { - c1 = BGETC(curio.bin); - c2 = BGETC(curio.bin); - if(c1 == 0xbb && c2 == 0xbf) { - yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file"); - goto loop; - } - Bungetc(curio.bin); - Bungetc(curio.bin); - } - } - -check: - switch(c) { - case 0: - if(curio.bin != nil) { - yyerror("illegal NUL byte"); - break; - } - case EOF: - // insert \n at EOF - if(curio.eofnl || curio.last == '\n') - return EOF; - curio.eofnl = 1; - c = '\n'; - case '\n': - if(pushedio.bin == nil) - lexlineno++; - break; - } - curio.last = c; - return c; -} - -static void -ungetc(int c) -{ - curio.peekc1 = curio.peekc; - curio.peekc = c; - if(c == '\n' && pushedio.bin == nil) - lexlineno--; -} - -static int32 -getr(void) -{ - int c, i; - char str[UTFmax+1]; - Rune rune; - - c = getc(); - if(c < Runeself) - return c; - i = 0; - str[i++] = c; - -loop: - c = getc(); - str[i++] = c; - if(!fullrune(str, i)) - goto loop; - c = chartorune(&rune, str); - if(rune == Runeerror && c == 1) { - lineno = lexlineno; - yyerror("illegal UTF-8 sequence"); - flusherrors(); - print("\t"); - for(c=0; c 0 ? " " : "", *(uchar*)(str+c)); - print("\n"); - } - return rune; -} - -static int -escchar(int e, int *escflg, vlong *val) -{ - int i, u, c; - vlong l; - - *escflg = 0; - - c = getr(); - switch(c) { - case EOF: - yyerror("eof in string"); - return 1; - case '\n': - yyerror("newline in string"); - return 1; - case '\\': - break; - default: - if(c == e) - return 1; - *val = c; - return 0; - } - - u = 0; - c = getr(); - switch(c) { - case 'x': - *escflg = 1; // it's a byte - i = 2; - goto hex; - - case 'u': - i = 4; - u = 1; - goto hex; - - case 'U': - i = 8; - u = 1; - goto hex; - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - *escflg = 1; // it's a byte - goto oct; - - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case '\\': c = '\\'; break; - - default: - if(c != e) - yyerror("unknown escape sequence: %c", c); - } - *val = c; - return 0; - -hex: - l = 0; - for(; i>0; i--) { - c = getc(); - if(c >= '0' && c <= '9') { - l = l*16 + c-'0'; - continue; - } - if(c >= 'a' && c <= 'f') { - l = l*16 + c-'a' + 10; - continue; - } - if(c >= 'A' && c <= 'F') { - l = l*16 + c-'A' + 10; - continue; - } - yyerror("non-hex character in escape sequence: %c", c); - ungetc(c); - break; - } - if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) { - yyerror("invalid Unicode code point in escape sequence: %#llx", l); - l = Runeerror; - } - *val = l; - return 0; - -oct: - l = c - '0'; - for(i=2; i>0; i--) { - c = getc(); - if(c >= '0' && c <= '7') { - l = l*8 + c-'0'; - continue; - } - yyerror("non-octal character in escape sequence: %c", c); - ungetc(c); - } - if(l > 255) - yyerror("octal escape value > 255: %d", l); - - *val = l; - return 0; -} - -static struct -{ - char* name; - int lexical; - int etype; - int op; -} syms[] = -{ -/* name lexical etype op - */ -/* basic types */ - {"int8", LNAME, TINT8, OXXX}, - {"int16", LNAME, TINT16, OXXX}, - {"int32", LNAME, TINT32, OXXX}, - {"int64", LNAME, TINT64, OXXX}, - - {"uint8", LNAME, TUINT8, OXXX}, - {"uint16", LNAME, TUINT16, OXXX}, - {"uint32", LNAME, TUINT32, OXXX}, - {"uint64", LNAME, TUINT64, OXXX}, - - {"float32", LNAME, TFLOAT32, OXXX}, - {"float64", LNAME, TFLOAT64, OXXX}, - - {"complex64", LNAME, TCOMPLEX64, OXXX}, - {"complex128", LNAME, TCOMPLEX128, OXXX}, - - {"bool", LNAME, TBOOL, OXXX}, - {"string", LNAME, TSTRING, OXXX}, - - {"any", LNAME, TANY, OXXX}, - - {"break", LBREAK, Txxx, OXXX}, - {"case", LCASE, Txxx, OXXX}, - {"chan", LCHAN, Txxx, OXXX}, - {"const", LCONST, Txxx, OXXX}, - {"continue", LCONTINUE, Txxx, OXXX}, - {"default", LDEFAULT, Txxx, OXXX}, - {"else", LELSE, Txxx, OXXX}, - {"defer", LDEFER, Txxx, OXXX}, - {"fallthrough", LFALL, Txxx, OXXX}, - {"for", LFOR, Txxx, OXXX}, - {"func", LFUNC, Txxx, OXXX}, - {"go", LGO, Txxx, OXXX}, - {"goto", LGOTO, Txxx, OXXX}, - {"if", LIF, Txxx, OXXX}, - {"import", LIMPORT, Txxx, OXXX}, - {"interface", LINTERFACE, Txxx, OXXX}, - {"map", LMAP, Txxx, OXXX}, - {"package", LPACKAGE, Txxx, OXXX}, - {"range", LRANGE, Txxx, OXXX}, - {"return", LRETURN, Txxx, OXXX}, - {"select", LSELECT, Txxx, OXXX}, - {"struct", LSTRUCT, Txxx, OXXX}, - {"switch", LSWITCH, Txxx, OXXX}, - {"type", LTYPE, Txxx, OXXX}, - {"var", LVAR, Txxx, OXXX}, - - {"append", LNAME, Txxx, OAPPEND}, - {"cap", LNAME, Txxx, OCAP}, - {"close", LNAME, Txxx, OCLOSE}, - {"complex", LNAME, Txxx, OCOMPLEX}, - {"copy", LNAME, Txxx, OCOPY}, - {"delete", LNAME, Txxx, ODELETE}, - {"imag", LNAME, Txxx, OIMAG}, - {"len", LNAME, Txxx, OLEN}, - {"make", LNAME, Txxx, OMAKE}, - {"new", LNAME, Txxx, ONEW}, - {"panic", LNAME, Txxx, OPANIC}, - {"print", LNAME, Txxx, OPRINT}, - {"println", LNAME, Txxx, OPRINTN}, - {"real", LNAME, Txxx, OREAL}, - {"recover", LNAME, Txxx, ORECOVER}, - - {"notwithstanding", LIGNORE, Txxx, OXXX}, - {"thetruthofthematter", LIGNORE, Txxx, OXXX}, - {"despiteallobjections", LIGNORE, Txxx, OXXX}, - {"whereas", LIGNORE, Txxx, OXXX}, - {"insofaras", LIGNORE, Txxx, OXXX}, -}; - -static void -lexinit(void) -{ - int i, lex; - Sym *s, *s1; - Type *t; - int etype; - Val v; - - /* - * initialize basic types array - * initialize known symbols - */ - for(i=0; ilexical = lex; - - etype = syms[i].etype; - if(etype != Txxx) { - if(etype < 0 || etype >= nelem(types)) - fatal("lexinit: %s bad etype", s->name); - s1 = pkglookup(syms[i].name, builtinpkg); - t = types[etype]; - if(t == T) { - t = typ(etype); - t->sym = s1; - - if(etype != TANY && etype != TSTRING) - dowidth(t); - types[etype] = t; - } - s1->lexical = LNAME; - s1->def = typenod(t); - continue; - } - - etype = syms[i].op; - if(etype != OXXX) { - s1 = pkglookup(syms[i].name, builtinpkg); - s1->lexical = LNAME; - s1->def = nod(ONAME, N, N); - s1->def->sym = s1; - s1->def->etype = etype; - s1->def->builtin = 1; - } - } - - // logically, the type of a string literal. - // types[TSTRING] is the named type string - // (the type of x in var x string or var x = "hello"). - // this is the ideal form - // (the type of x in const x = "hello"). - idealstring = typ(TSTRING); - idealbool = typ(TBOOL); - - s = pkglookup("true", builtinpkg); - s->def = nodbool(1); - s->def->sym = lookup("true"); - s->def->type = idealbool; - - s = pkglookup("false", builtinpkg); - s->def = nodbool(0); - s->def->sym = lookup("false"); - s->def->type = idealbool; - - s = lookup("_"); - s->block = -100; - s->def = nod(ONAME, N, N); - s->def->sym = s; - types[TBLANK] = typ(TBLANK); - s->def->type = types[TBLANK]; - nblank = s->def; - - s = pkglookup("_", builtinpkg); - s->block = -100; - s->def = nod(ONAME, N, N); - s->def->sym = s; - types[TBLANK] = typ(TBLANK); - s->def->type = types[TBLANK]; - - types[TNIL] = typ(TNIL); - s = pkglookup("nil", builtinpkg); - v.ctype = CTNIL; - s->def = nodlit(v); - s->def->sym = s; -} - -static void -lexinit1(void) -{ - Sym *s, *s1; - Type *t, *f, *rcvr, *in, *out; - - // t = interface { Error() string } - rcvr = typ(TSTRUCT); - rcvr->type = typ(TFIELD); - rcvr->type->type = ptrto(typ(TSTRUCT)); - rcvr->funarg = 1; - in = typ(TSTRUCT); - in->funarg = 1; - out = typ(TSTRUCT); - out->type = typ(TFIELD); - out->type->type = types[TSTRING]; - out->funarg = 1; - f = typ(TFUNC); - *getthis(f) = rcvr; - *getoutarg(f) = out; - *getinarg(f) = in; - f->thistuple = 1; - f->intuple = 0; - f->outnamed = 0; - f->outtuple = 1; - t = typ(TINTER); - t->type = typ(TFIELD); - t->type->sym = lookup("Error"); - t->type->type = f; - - // error type - s = lookup("error"); - s->lexical = LNAME; - s1 = pkglookup("error", builtinpkg); - errortype = t; - errortype->sym = s1; - s1->lexical = LNAME; - s1->def = typenod(errortype); - - // byte alias - s = lookup("byte"); - s->lexical = LNAME; - s1 = pkglookup("byte", builtinpkg); - bytetype = typ(TUINT8); - bytetype->sym = s1; - s1->lexical = LNAME; - s1->def = typenod(bytetype); - - // rune alias - s = lookup("rune"); - s->lexical = LNAME; - s1 = pkglookup("rune", builtinpkg); - runetype = typ(TINT32); - runetype->sym = s1; - s1->lexical = LNAME; - s1->def = typenod(runetype); -} - -static void -lexfini(void) -{ - Sym *s; - int lex, etype, i; - Val v; - - for(i=0; ilexical = lex; - - etype = syms[i].etype; - if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) { - s->def = typenod(types[etype]); - s->origpkg = builtinpkg; - } - - etype = syms[i].op; - if(etype != OXXX && s->def == N) { - s->def = nod(ONAME, N, N); - s->def->sym = s; - s->def->etype = etype; - s->def->builtin = 1; - s->origpkg = builtinpkg; - } - } - - // backend-specific builtin types (e.g. int). - for(i=0; thearch.typedefs[i].name; i++) { - s = lookup(thearch.typedefs[i].name); - if(s->def == N) { - s->def = typenod(types[thearch.typedefs[i].etype]); - s->origpkg = builtinpkg; - } - } - - // there's only so much table-driven we can handle. - // these are special cases. - s = lookup("byte"); - if(s->def == N) { - s->def = typenod(bytetype); - s->origpkg = builtinpkg; - } - - s = lookup("error"); - if(s->def == N) { - s->def = typenod(errortype); - s->origpkg = builtinpkg; - } - - s = lookup("rune"); - if(s->def == N) { - s->def = typenod(runetype); - s->origpkg = builtinpkg; - } - - s = lookup("nil"); - if(s->def == N) { - v.ctype = CTNIL; - s->def = nodlit(v); - s->def->sym = s; - s->origpkg = builtinpkg; - } - - s = lookup("iota"); - if(s->def == N) { - s->def = nod(OIOTA, N, N); - s->def->sym = s; - s->origpkg = builtinpkg; - } - - s = lookup("true"); - if(s->def == N) { - s->def = nodbool(1); - s->def->sym = s; - s->origpkg = builtinpkg; - } - - s = lookup("false"); - if(s->def == N) { - s->def = nodbool(0); - s->def->sym = s; - s->origpkg = builtinpkg; - } - - nodfp = nod(ONAME, N, N); - nodfp->type = types[TINT32]; - nodfp->xoffset = 0; - nodfp->class = PPARAM; - nodfp->sym = lookup(".fp"); -} - -struct -{ - int lex; - char* name; -} lexn[] = -{ - {LANDAND, "ANDAND"}, - {LANDNOT, "ANDNOT"}, - {LASOP, "ASOP"}, - {LBREAK, "BREAK"}, - {LCASE, "CASE"}, - {LCHAN, "CHAN"}, - {LCOLAS, "COLAS"}, - {LCOMM, "<-"}, - {LCONST, "CONST"}, - {LCONTINUE, "CONTINUE"}, - {LDDD, "..."}, - {LDEC, "DEC"}, - {LDEFAULT, "DEFAULT"}, - {LDEFER, "DEFER"}, - {LELSE, "ELSE"}, - {LEQ, "EQ"}, - {LFALL, "FALL"}, - {LFOR, "FOR"}, - {LFUNC, "FUNC"}, - {LGE, "GE"}, - {LGO, "GO"}, - {LGOTO, "GOTO"}, - {LGT, "GT"}, - {LIF, "IF"}, - {LIMPORT, "IMPORT"}, - {LINC, "INC"}, - {LINTERFACE, "INTERFACE"}, - {LLE, "LE"}, - {LLITERAL, "LITERAL"}, - {LLSH, "LSH"}, - {LLT, "LT"}, - {LMAP, "MAP"}, - {LNAME, "NAME"}, - {LNE, "NE"}, - {LOROR, "OROR"}, - {LPACKAGE, "PACKAGE"}, - {LRANGE, "RANGE"}, - {LRETURN, "RETURN"}, - {LRSH, "RSH"}, - {LSELECT, "SELECT"}, - {LSTRUCT, "STRUCT"}, - {LSWITCH, "SWITCH"}, - {LTYPE, "TYPE"}, - {LVAR, "VAR"}, -}; - -char* -lexname(int lex) -{ - int i; - static char buf[100]; - - for(i=0; i="}, - {"LGT", ">"}, - {"LLE", "<="}, - {"LLT", "<"}, - {"LLSH", "<<"}, - {"LRSH", ">>"}, - {"LOROR", "||"}, - {"LNE", "!="}, - - // spell out to avoid confusion with punctuation in error messages - {"';'", "semicolon or newline"}, - {"','", "comma"}, -}; - -static void -yytinit(void) -{ - int i, j; - extern char *yytname[]; - char *s, *t; - - for(i=0; yytname[i] != nil; i++) { - s = yytname[i]; - - if(strcmp(s, "LLITERAL") == 0) { - strcpy(litbuf, "literal"); - yytname[i] = litbuf; - goto loop; - } - - // apply yytfix if possible - for(j=0; js, '/'); - if(elem != nil) - elem++; - else - elem = path->s; - if(name == nil || strcmp(elem, name) == 0) - yyerrorl(lineno, "imported and not used: \"%Z\"", path); - else - yyerrorl(lineno, "imported and not used: \"%Z\" as %s", path, name); -} - -void -mkpackage(char* pkgname) -{ - Sym *s; - int32 h; - char *p, *q; - - if(localpkg->name == nil) { - if(strcmp(pkgname, "_") == 0) - yyerror("invalid package name _"); - localpkg->name = pkgname; - } else { - if(strcmp(pkgname, localpkg->name) != 0) - yyerror("package %s; expected %s", pkgname, localpkg->name); - for(h=0; hlink) { - if(s->def == N || s->pkg != localpkg) - continue; - if(s->def->op == OPACK) { - // throw away top-level package name leftover - // from previous file. - // leave s->block set to cause redeclaration - // errors if a conflicting top-level name is - // introduced by a different file. - if(!s->def->used && !nsyntaxerrors) - pkgnotused(s->def->lineno, s->def->pkg->path, s->name); - s->def = N; - continue; - } - if(s->def->sym != s) { - // throw away top-level name left over - // from previous import . "x" - if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) { - pkgnotused(s->def->pack->lineno, s->def->pack->pkg->path, nil); - s->def->pack->used = 1; - } - s->def = N; - continue; - } - } - } - } - - if(outfile == nil) { - p = strrchr(infile, '/'); - if(ctxt->windows) { - q = strrchr(infile, '\\'); - if(q > p) - p = q; - } - if(p == nil) - p = infile; - else - p = p+1; - snprint(namebuf, sizeof(namebuf), "%s", p); - p = strrchr(namebuf, '.'); - if(p != nil) - *p = 0; - outfile = smprint("%s.%c", namebuf, thearch.thechar); - } -} diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c deleted file mode 100644 index 46cb6b712d..0000000000 --- a/src/cmd/gc/md5.c +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// 64-bit MD5 (does full MD5 but returns 64 bits only). -// Translation of ../../crypto/md5/md5*.go. - -#include -#include -#include "go.h" -#include "md5.h" - -static int md5block(MD5 *dig, uchar *p, int nn); - -enum { - _Chunk = 64 -}; - -#define _Init0 0x67452301 -#define _Init1 0xEFCDAB89 -#define _Init2 0x98BADCFE -#define _Init3 0x10325476 -/*c2go -enum { - _Init0 = 0x67452301, - _Init1 = 0xEFCDAB89, - _Init2 = 0x98BADCFE, - _Init3 = 0x10325476 -}; -*/ - -void -md5reset(MD5 *d) -{ - d->s[0] = _Init0; - d->s[1] = _Init1; - d->s[2] = _Init2; - d->s[3] = _Init3; - d->nx = 0; - d->len = 0; -} - -void -md5write(MD5 *d, uchar *p, int nn) -{ - int i, n; - - d->len += nn; - if(d->nx > 0) { - n = nn; - if(n > _Chunk - d->nx) - n = _Chunk - d->nx; - for(i=0; ix[d->nx+i] = p[i]; - d->nx += n; - if(d->nx == _Chunk) { - md5block(d, d->x, _Chunk); - d->nx = 0; - } - p += n; - nn -= n; - } - n = md5block(d, p, nn); - p += n; - nn -= n; - if(nn > 0) { - for(i=0; ix[i] = p[i]; - d->nx = nn; - } -} - -uint64 -md5sum(MD5 *d, uint64 *hi) -{ - uchar tmp[64]; - int i; - uint64 len; - - // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. - len = d->len; - memset(tmp, 0, sizeof tmp); - tmp[0] = 0x80; - if(len%64 < 56) - md5write(d, tmp, 56-len%64); - else - md5write(d, tmp, 64+56-len%64); - - // Length in bits. - len <<= 3; - for(i=0; i<8; i++) - tmp[i] = len>>(8*i); - md5write(d, tmp, 8); - - if(d->nx != 0) - fatal("md5sum"); - - if(hi != nil) - *hi = d->s[2] | ((uint64)d->s[3]<<32); - return d->s[0] | ((uint64)d->s[1]<<32); -} - - -// MD5 block step. -// In its own file so that a faster assembly or C version -// can be substituted easily. - -// table[i] = int((1<<32) * abs(sin(i+1 radians))). -static uint32 table[64] = { - // round 1 - 0xd76aa478, - 0xe8c7b756, - 0x242070db, - 0xc1bdceee, - 0xf57c0faf, - 0x4787c62a, - 0xa8304613, - 0xfd469501, - 0x698098d8, - 0x8b44f7af, - 0xffff5bb1, - 0x895cd7be, - 0x6b901122, - 0xfd987193, - 0xa679438e, - 0x49b40821, - - // round 2 - 0xf61e2562, - 0xc040b340, - 0x265e5a51, - 0xe9b6c7aa, - 0xd62f105d, - 0x2441453, - 0xd8a1e681, - 0xe7d3fbc8, - 0x21e1cde6, - 0xc33707d6, - 0xf4d50d87, - 0x455a14ed, - 0xa9e3e905, - 0xfcefa3f8, - 0x676f02d9, - 0x8d2a4c8a, - - // round3 - 0xfffa3942, - 0x8771f681, - 0x6d9d6122, - 0xfde5380c, - 0xa4beea44, - 0x4bdecfa9, - 0xf6bb4b60, - 0xbebfbc70, - 0x289b7ec6, - 0xeaa127fa, - 0xd4ef3085, - 0x4881d05, - 0xd9d4d039, - 0xe6db99e5, - 0x1fa27cf8, - 0xc4ac5665, - - // round 4 - 0xf4292244, - 0x432aff97, - 0xab9423a7, - 0xfc93a039, - 0x655b59c3, - 0x8f0ccc92, - 0xffeff47d, - 0x85845dd1, - 0x6fa87e4f, - 0xfe2ce6e0, - 0xa3014314, - 0x4e0811a1, - 0xf7537e82, - 0xbd3af235, - 0x2ad7d2bb, - 0xeb86d391, -}; - -static uint32 shift1[] = { 7, 12, 17, 22 }; -static uint32 shift2[] = { 5, 9, 14, 20 }; -static uint32 shift3[] = { 4, 11, 16, 23 }; -static uint32 shift4[] = { 6, 10, 15, 21 }; - -static int -md5block(MD5 *dig, uchar *p, int nn) -{ - uint32 a, b, c, d, aa, bb, cc, dd; - int i, j, n; - uint32 X[16]; - - a = dig->s[0]; - b = dig->s[1]; - c = dig->s[2]; - d = dig->s[3]; - n = 0; - - while(nn >= _Chunk) { - aa = a; - bb = b; - cc = c; - dd = d; - - for(i=0; i<16; i++) { - j = i*4; - X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | ((uint32)p[j+3]<<24); - } - - // Round 1. - for(i=0; i<16; i++) { - uint32 x, t, s, f; - x = i; - t = i; - s = shift1[i%4]; - f = ((c ^ d) & b) ^ d; - a += f + X[x] + table[t]; - a = a<>(32-s); - a += b; - - t = d; - d = c; - c = b; - b = a; - a = t; - } - - // Round 2. - for(i=0; i<16; i++) { - uint32 x, t, s, g; - - x = (1+5*i)%16; - t = 16+i; - s = shift2[i%4]; - g = ((b ^ c) & d) ^ c; - a += g + X[x] + table[t]; - a = a<>(32-s); - a += b; - - t = d; - d = c; - c = b; - b = a; - a = t; - } - - // Round 3. - for(i=0; i<16; i++) { - uint32 x, t, s, h; - - x = (5+3*i)%16; - t = 32+i; - s = shift3[i%4]; - h = b ^ c ^ d; - a += h + X[x] + table[t]; - a = a<>(32-s); - a += b; - - t = d; - d = c; - c = b; - b = a; - a = t; - } - - // Round 4. - for(i=0; i<16; i++) { - uint32 x, s, t, ii; - - x = (7*i)%16; - s = shift4[i%4]; - t = 48+i; - ii = c ^ (b | ~d); - a += ii + X[x] + table[t]; - a = a<>(32-s); - a += b; - - t = d; - d = c; - c = b; - b = a; - a = t; - } - - a += aa; - b += bb; - c += cc; - d += dd; - - p += _Chunk; - n += _Chunk; - nn -= _Chunk; - } - - dig->s[0] = a; - dig->s[1] = b; - dig->s[2] = c; - dig->s[3] = d; - return n; -} diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h deleted file mode 100644 index 5a60106b21..0000000000 --- a/src/cmd/gc/md5.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -typedef struct MD5 MD5; -struct MD5 -{ - uint32 s[4]; - uchar x[64]; - int nx; - uint64 len; -}; - -void md5reset(MD5*); -void md5write(MD5*, uchar*, int); -uint64 md5sum(MD5*, uint64*); diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin deleted file mode 100755 index 696aa82424..0000000000 --- a/src/cmd/gc/mkbuiltin +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# Generate builtin.c from $* (runtime.go and unsafe.go). -# Run this after changing runtime.go and unsafe.go -# or after changing the export metadata format in the compiler. -# Either way, you need to have a working compiler binary first. - -set -e - -eval $(go tool dist env) -if [ -z "$GOCHAR" ]; then - echo 'missing $GOCHAR - go tool dist failed?' 1>&2 - exit 1 -fi - -GC=${GOCHAR}g -gcc -o mkbuiltin1 mkbuiltin1.c -rm -f _builtin.c -echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c -echo "#include " >>_builtin.c -echo "#include " >>_builtin.c -echo '#include "go.h"' >>_builtin.c - -for i in runtime unsafe -do - go tool $GC -A $i.go - O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c -done - -# If _builtin.c has changed vs builtin.c, -# check in the new change. -cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c -rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c deleted file mode 100644 index 69027fdf5d..0000000000 --- a/src/cmd/gc/mkbuiltin1.c +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build ignore - -// Compile .go file, import data from .6 file, and generate C string version. - -#include -#include -#include -#include -#include -#include - -void esc(char*); -void fatal(char*, ...); - -int -main(int argc, char **argv) -{ - char *name; - FILE *fin; - char buf[1024], initfunc[1024], *p, *q; - - if(argc != 2) { - fprintf(stderr, "usage: mkbuiltin1 sys\n"); - fatal("in file $1.6 s/PACKAGE/$1/"); - } - - name = argv[1]; - snprintf(initfunc, sizeof(initfunc), "init_%s_function", name); - - snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O")); - if((fin = fopen(buf, "r")) == NULL) { - fatal("open %s: %s", buf, strerror(errno)); - } - - // look for $$ that introduces imports - while(fgets(buf, sizeof buf, fin) != NULL) - if(strstr(buf, "$$")) - goto begin; - fatal("did not find beginning of imports"); - -begin: - printf("char *%simport =\n", name); - - // process imports, stopping at $$ that closes them - while(fgets(buf, sizeof buf, fin) != NULL) { - buf[strlen(buf)-1] = 0; // chop \n - if(strstr(buf, "$$")) - goto end; - - // chop leading white space - for(p=buf; *p==' ' || *p == '\t'; p++) - ; - - // cut out decl of init_$1_function - it doesn't exist - if(strstr(buf, initfunc)) - continue; - - // sys.go claims to be in package PACKAGE to avoid - // conflicts during "6g sys.go". rename PACKAGE to $2. - printf("\t\""); - while((q = strstr(p, "PACKAGE")) != NULL) { - *q = 0; - esc(p); // up to the substitution - printf("%s", name); // the sub name - p = q+7; // continue with rest - } - - esc(p); - printf("\\n\"\n"); - } - fatal("did not find end of imports"); - -end: - printf("\t\"$$\\n\";\n"); - return 0; -} - -void -esc(char *p) -{ - for(; *p; p++) { - if(*p == '\\' || *p == '\"') - printf("\\"); - putchar(*p); - } -} - -void -fatal(char *msg, ...) -{ - va_list arg; - - va_start(arg, msg); - fprintf(stderr, "fatal: "); - vfprintf(stderr, msg, arg); - fprintf(stderr, "\n"); - exit(2); -} diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames deleted file mode 100755 index d3f27e8152..0000000000 --- a/src/cmd/gc/mkopnames +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -# Copyright 2009 The Go Authors. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# Disable colored grep if user has it set to --color=always. -# (Arguably user error.) -export GREP_OPTIONS="" - -echo '// auto generated by mkopnames' -echo 'static char*' -echo 'opnames[] = ' -echo '{' -sed -n '/OXXX/,/OEND/p' go.h | - cpp | - sed 's!//.*!!; /^#/d' | - tr ' ' '\012' | - tr -d ' \011,' | - grep . | - sort | - grep -v '^OEND$' | - sed 's/O//; s/.*/ [O&] = "&",/' -echo '};' - diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c deleted file mode 100644 index 6a0eb2d6d9..0000000000 --- a/src/cmd/gc/mparith1.c +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -/// uses arithmetic - -int -mpcmpfixflt(Mpint *a, Mpflt *b) -{ - char buf[500]; - Mpflt c; - - snprint(buf, sizeof(buf), "%B", a); - mpatoflt(&c, buf); - return mpcmpfltflt(&c, b); -} - -int -mpcmpfltfix(Mpflt *a, Mpint *b) -{ - char buf[500]; - Mpflt c; - - snprint(buf, sizeof(buf), "%B", b); - mpatoflt(&c, buf); - return mpcmpfltflt(a, &c); -} - -int -mpcmpfixfix(Mpint *a, Mpint *b) -{ - Mpint c; - - mpmovefixfix(&c, a); - mpsubfixfix(&c, b); - return mptestfix(&c); -} - -int -mpcmpfixc(Mpint *b, vlong c) -{ - Mpint c1; - - mpmovecfix(&c1, c); - return mpcmpfixfix(b, &c1); -} - -int -mpcmpfltflt(Mpflt *a, Mpflt *b) -{ - Mpflt c; - - mpmovefltflt(&c, a); - mpsubfltflt(&c, b); - return mptestflt(&c); -} - -int -mpcmpfltc(Mpflt *b, double c) -{ - Mpflt a; - - mpmovecflt(&a, c); - return mpcmpfltflt(b, &a); -} - -void -mpsubfixfix(Mpint *a, Mpint *b) -{ - mpnegfix(a); - mpaddfixfix(a, b, 0); - mpnegfix(a); -} - -void -mpsubfltflt(Mpflt *a, Mpflt *b) -{ - mpnegflt(a); - mpaddfltflt(a, b); - mpnegflt(a); -} - -void -mpaddcfix(Mpint *a, vlong c) -{ - Mpint b; - - mpmovecfix(&b, c); - mpaddfixfix(a, &b, 0); -} - -void -mpaddcflt(Mpflt *a, double c) -{ - Mpflt b; - - mpmovecflt(&b, c); - mpaddfltflt(a, &b); -} - -void -mpmulcfix(Mpint *a, vlong c) -{ - Mpint b; - - mpmovecfix(&b, c); - mpmulfixfix(a, &b); -} - -void -mpmulcflt(Mpflt *a, double c) -{ - Mpflt b; - - mpmovecflt(&b, c); - mpmulfltflt(a, &b); -} - -void -mpdivfixfix(Mpint *a, Mpint *b) -{ - Mpint q, r; - - mpdivmodfixfix(&q, &r, a, b); - mpmovefixfix(a, &q); -} - -void -mpmodfixfix(Mpint *a, Mpint *b) -{ - Mpint q, r; - - mpdivmodfixfix(&q, &r, a, b); - mpmovefixfix(a, &r); -} - -void -mpcomfix(Mpint *a) -{ - Mpint b; - - mpmovecfix(&b, 1); - mpnegfix(a); - mpsubfixfix(a, &b); -} - -void -mpmovefixflt(Mpflt *a, Mpint *b) -{ - a->val = *b; - a->exp = 0; - mpnorm(a); -} - -// convert (truncate) b to a. -// return -1 (but still convert) if b was non-integer. -static int -mpexactfltfix(Mpint *a, Mpflt *b) -{ - Mpflt f; - - *a = b->val; - mpshiftfix(a, b->exp); - if(b->exp < 0) { - f.val = *a; - f.exp = 0; - mpnorm(&f); - if(mpcmpfltflt(b, &f) != 0) - return -1; - } - return 0; -} - -int -mpmovefltfix(Mpint *a, Mpflt *b) -{ - Mpflt f; - int i; - - if(mpexactfltfix(a, b) == 0) - return 0; - - // try rounding down a little - f = *b; - f.val.a[0] = 0; - if(mpexactfltfix(a, &f) == 0) - return 0; - - // try rounding up a little - for(i=1; i>1); - mpmulfltflt(a, a); - if(p & 1) - mpmulcflt(a, 10); -} - -static void -mphextofix(Mpint *a, char *s, int n) -{ - char c; - long d; - int bit, hexdigitp, end; - - while(*s == '0') { - s++; - n--; - } - - // overflow - if(4*n > Mpscale*Mpprec) { - a->ovf = 1; - return; - } - - end = n-1; - for(hexdigitp=end; hexdigitp>=0; hexdigitp--) { - c = s[hexdigitp]; - if(c >= '0' && c <= '9') - d = c-'0'; - else if(c >= 'A' && c <= 'F') - d = c-'A'+10; - else - d = c-'a'+10; - - bit = 4*(end - hexdigitp); - while(d > 0) { - if(d & 1) - a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale); - bit++; - d = d >> 1; - } - } -} - -// -// floating point input -// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] -// -void -mpatoflt(Mpflt *a, char *as) -{ - Mpflt b; - int dp, c, f, ef, ex, eb, base; - char *s, *start; - - while(*as == ' ' || *as == '\t') - as++; - - /* determine base */ - s = as; - base = -1; - while(base == -1) { - switch(*s++) { - case '-': - case '+': - break; - - case '0': - if(*s == 'x') - base = 16; - else - base = 10; - break; - - default: - base = 10; - } - } - - s = as; - dp = 0; /* digits after decimal point */ - f = 0; /* sign */ - ex = 0; /* exponent */ - eb = 0; /* binary point */ - - mpmovecflt(a, 0.0); - if(base == 16) { - start = nil; - for(;;) { - c = *s; - if(c == '-') { - f = 1; - s++; - } - else if(c == '+') { - s++; - } - else if(c == '0' && s[1] == 'x') { - s += 2; - start = s; - } - else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - s++; - } - else { - break; - } - } - if(start == nil) { - yyerror("malformed hex constant: %s", as); - goto bad; - } - - mphextofix(&a->val, start, s-start); - if(a->val.ovf) { - yyerror("constant too large: %s", as); - goto bad; - } - a->exp = 0; - mpnorm(a); - } - for(;;) { - c = *s++; - switch(c) { - default: - yyerror("malformed constant: %s (at %c)", as, c); - goto bad; - - case '-': - f = 1; - - case ' ': - case '\t': - case '+': - continue; - - case '.': - if(base == 16) { - yyerror("decimal point in hex constant: %s", as); - goto bad; - } - dp = 1; - continue; - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - mpmulcflt(a, 10); - mpaddcflt(a, c-'0'); - if(dp) - dp++; - continue; - - case 'P': - case 'p': - eb = 1; - - case 'E': - case 'e': - ex = 0; - ef = 0; - for(;;) { - c = *s++; - if(c == '+' || c == ' ' || c == '\t') - continue; - if(c == '-') { - ef = 1; - continue; - } - if(c >= '0' && c <= '9') { - ex = ex*10 + (c-'0'); - if(ex > 1e8) { - yyerror("constant exponent out of range: %s", as); - errorexit(); - } - continue; - } - break; - } - if(ef) - ex = -ex; - - case 0: - break; - } - break; - } - - if(eb) { - if(dp) { - yyerror("decimal point and binary point in constant: %s", as); - goto bad; - } - mpsetexp(a, a->exp+ex); - goto out; - } - - if(dp) - dp--; - if(mpcmpfltc(a, 0.0) != 0) { - if(ex >= dp) { - mppow10flt(&b, ex-dp); - mpmulfltflt(a, &b); - } else { - // 4 approximates least_upper_bound(log2(10)). - if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) { - mpmovecflt(a, 0.0); - } - else { - mppow10flt(&b, dp-ex); - mpdivfltflt(a, &b); - } - } - } - -out: - if(f) - mpnegflt(a); - return; - -bad: - mpmovecflt(a, 0.0); -} - -// -// fixed point input -// required syntax is [+-][0[x]]d* -// -void -mpatofix(Mpint *a, char *as) -{ - int c, f; - char *s, *s0; - - s = as; - f = 0; - mpmovecfix(a, 0); - - c = *s++; - switch(c) { - case '-': - f = 1; - - case '+': - c = *s++; - if(c != '0') - break; - - case '0': - goto oct; - } - - while(c) { - if(c >= '0' && c <= '9') { - mpmulcfix(a, 10); - mpaddcfix(a, c-'0'); - c = *s++; - continue; - } - yyerror("malformed decimal constant: %s", as); - goto bad; - } - goto out; - -oct: - c = *s++; - if(c == 'x' || c == 'X') - goto hex; - while(c) { - if(c >= '0' && c <= '7') { - mpmulcfix(a, 8); - mpaddcfix(a, c-'0'); - c = *s++; - continue; - } - yyerror("malformed octal constant: %s", as); - goto bad; - } - goto out; - -hex: - s0 = s; - c = *s; - while(c) { - if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { - s++; - c = *s; - continue; - } - yyerror("malformed hex constant: %s", as); - goto bad; - } - mphextofix(a, s0, s-s0); - if(a->ovf) { - yyerror("constant too large: %s", as); - goto bad; - } - -out: - if(f) - mpnegfix(a); - return; - -bad: - mpmovecfix(a, 0); -} - -int -Bconv(Fmt *fp) -{ - char buf[500]; - int p; - Mpint *xval, q, r, ten, sixteen; - int f, digit; - - xval = va_arg(fp->args, Mpint*); - mpmovefixfix(&q, xval); - f = 0; - if(mptestfix(&q) < 0) { - f = 1; - mpnegfix(&q); - } - - p = sizeof(buf); - buf[--p] = 0; - if(fp->flags & FmtSharp) { - // Hexadecimal - mpmovecfix(&sixteen, 16); - for(;;) { - mpdivmodfixfix(&q, &r, &q, &sixteen); - digit = mpgetfix(&r); - if(digit < 10) - buf[--p] = digit + '0'; - else - buf[--p] = digit - 10 + 'A'; - if(mptestfix(&q) <= 0) - break; - } - buf[--p] = 'x'; - buf[--p] = '0'; - } else { - // Decimal - mpmovecfix(&ten, 10); - for(;;) { - mpdivmodfixfix(&q, &r, &q, &ten); - buf[--p] = mpgetfix(&r) + '0'; - if(mptestfix(&q) <= 0) - break; - } - } - if(f) - buf[--p] = '-'; - return fmtstrcpy(fp, &buf[p]); -} - -int -Fconv(Fmt *fp) -{ - char buf[500]; - Mpflt *fvp, fv; - double d, dexp; - int exp; - - fvp = va_arg(fp->args, Mpflt*); - if(fp->flags & FmtSharp) { - // alternate form - decimal for error messages. - // for well in range, convert to double and use print's %g - exp = fvp->exp + sigfig(fvp)*Mpscale; - if(-900 < exp && exp < 900) { - d = mpgetflt(fvp); - if(d >= 0 && (fp->flags & FmtSign)) - fmtprint(fp, "+"); - return fmtprint(fp, "%g", d); - } - - // very out of range. compute decimal approximation by hand. - // decimal exponent - dexp = fvp->exp * 0.301029995663981195; // log_10(2) - exp = (int)dexp; - // decimal mantissa - fv = *fvp; - fv.val.neg = 0; - fv.exp = 0; - d = mpgetflt(&fv); - d *= pow(10, dexp-exp); - while(d >= 9.99995) { - d /= 10; - exp++; - } - if(fvp->val.neg) - fmtprint(fp, "-"); - else if(fp->flags & FmtSign) - fmtprint(fp, "+"); - return fmtprint(fp, "%.5fe+%d", d, exp); - } - - if(sigfig(fvp) == 0) { - snprint(buf, sizeof(buf), "0p+0"); - goto out; - } - fv = *fvp; - - while(fv.val.a[0] == 0) { - mpshiftfix(&fv.val, -Mpscale); - fv.exp += Mpscale; - } - while((fv.val.a[0]&1) == 0) { - mpshiftfix(&fv.val, -1); - fv.exp += 1; - } - - if(fv.exp >= 0) { - snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp); - goto out; - } - snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp); - -out: - return fmtstrcpy(fp, buf); -} diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c deleted file mode 100644 index 37aafbb5f5..0000000000 --- a/src/cmd/gc/mparith2.c +++ /dev/null @@ -1,689 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -// -// return the significant -// words of the argument -// -static int -mplen(Mpint *a) -{ - int i, n; - - n = -1; - for(i=0; ia[i] != 0) - n = i; - } - return n+1; -} - -// -// left shift mpint by one -// ignores sign -// -static void -mplsh(Mpint *a, int quiet) -{ - long x; - int i, c; - - c = 0; - for(i=0; ia[i] << 1) + c; - c = 0; - if(x >= Mpbase) { - x -= Mpbase; - c = 1; - } - a->a[i] = x; - } - a->ovf = c; - if(a->ovf && !quiet) - yyerror("constant shift overflow"); -} - -// -// left shift mpint by Mpscale -// ignores sign -// -static void -mplshw(Mpint *a, int quiet) -{ - int i; - - i = Mpprec-1; - if(a->a[i]) { - a->ovf = 1; - if(!quiet) - yyerror("constant shift overflow"); - } - for(; i > 0; i--) - a->a[i] = a->a[i-1]; - a->a[i] = 0; -} - -// -// right shift mpint by one -// ignores sign and overflow -// -static void -mprsh(Mpint *a) -{ - long x, lo; - int i, c; - - c = 0; - lo = a->a[0] & 1; - for(i=Mpprec-1; i>=0; i--) { - x = a->a[i]; - a->a[i] = (x + c) >> 1; - c = 0; - if(x & 1) - c = Mpbase; - } - if(a->neg && lo != 0) - mpaddcfix(a, -1); -} - -// -// right shift mpint by Mpscale -// ignores sign and overflow -// -static void -mprshw(Mpint *a) -{ - long lo; - int i; - - lo = a->a[0]; - for(i=0; ia[i] = a->a[i+1]; - } - a->a[i] = 0; - if(a->neg && lo != 0) - mpaddcfix(a, -1); -} - -// -// return the sign of (abs(a)-abs(b)) -// -static int -mpcmp(Mpint *a, Mpint *b) -{ - long x; - int i; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in cmp"); - return 0; - } - - for(i=Mpprec-1; i>=0; i--) { - x = a->a[i] - b->a[i]; - if(x > 0) - return +1; - if(x < 0) - return -1; - } - return 0; -} - -// -// negate a -// ignore sign and ovf -// -static void -mpneg(Mpint *a) -{ - long x; - int i, c; - - c = 0; - for(i=0; ia[i] -c; - c = 0; - if(x < 0) { - x += Mpbase; - c = 1; - } - a->a[i] = x; - } -} - -// shift left by s (or right by -s) -void -mpshiftfix(Mpint *a, int s) -{ - if(s >= 0) { - while(s >= Mpscale) { - mplshw(a, 0); - s -= Mpscale; - } - while(s > 0) { - mplsh(a, 0); - s--; - } - } else { - s = -s; - while(s >= Mpscale) { - mprshw(a); - s -= Mpscale; - } - while(s > 0) { - mprsh(a); - s--; - } - } -} - -/// implements fix arihmetic - -void -mpaddfixfix(Mpint *a, Mpint *b, int quiet) -{ - int i, c; - long x; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mpaddxx"); - a->ovf = 1; - return; - } - - c = 0; - if(a->neg != b->neg) - goto sub; - - // perform a+b - for(i=0; ia[i] + b->a[i] + c; - c = 0; - if(x >= Mpbase) { - x -= Mpbase; - c = 1; - } - a->a[i] = x; - } - a->ovf = c; - if(a->ovf && !quiet) - yyerror("constant addition overflow"); - - return; - -sub: - // perform a-b - switch(mpcmp(a, b)) { - case 0: - mpmovecfix(a, 0); - break; - - case 1: - for(i=0; ia[i] - b->a[i] - c; - c = 0; - if(x < 0) { - x += Mpbase; - c = 1; - } - a->a[i] = x; - } - break; - - case -1: - a->neg ^= 1; - for(i=0; ia[i] - a->a[i] - c; - c = 0; - if(x < 0) { - x += Mpbase; - c = 1; - } - a->a[i] = x; - } - break; - } -} - -void -mpmulfixfix(Mpint *a, Mpint *b) -{ - - int i, j, na, nb; - long x; - Mpint s, q; - Mpint *c; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mpmulfixfix"); - a->ovf = 1; - return; - } - - // pick the smaller - // to test for bits - na = mplen(a); - nb = mplen(b); - if(na > nb) { - mpmovefixfix(&s, a); - c = b; - na = nb; - } else { - mpmovefixfix(&s, b); - c = a; - } - s.neg = 0; - - mpmovecfix(&q, 0); - for(i=0; ia[i]; - for(j=0; j>= 1; - } - } - -out: - q.neg = a->neg ^ b->neg; - mpmovefixfix(a, &q); - if(a->ovf) - yyerror("constant multiplication overflow"); -} - -void -mpmulfract(Mpint *a, Mpint *b) -{ - - int i, j; - long x; - Mpint s, q; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mpmulflt"); - a->ovf = 1; - return; - } - - mpmovefixfix(&s, b); - s.neg = 0; - mpmovecfix(&q, 0); - - i = Mpprec-1; - x = a->a[i]; - if(x != 0) - yyerror("mpmulfract not normal"); - - for(i--; i >= 0; i--) { - x = a->a[i]; - if(x == 0) { - mprshw(&s); - continue; - } - for(j=0; jneg ^ b->neg; - mpmovefixfix(a, &q); - if(a->ovf) - yyerror("constant multiplication overflow"); -} - -void -mporfixfix(Mpint *a, Mpint *b) -{ - int i; - long x; - - x = 0; - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mporfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - if(a->neg) { - a->neg = 0; - mpneg(a); - } - if(b->neg) - mpneg(b); - - for(i=0; ia[i] | b->a[i]; - a->a[i] = x; - } - - if(b->neg) - mpneg(b); - if(x & Mpsign) { - a->neg = 1; - mpneg(a); - } -} - -void -mpandfixfix(Mpint *a, Mpint *b) -{ - int i; - long x; - - x = 0; - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mpandfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - if(a->neg) { - a->neg = 0; - mpneg(a); - } - if(b->neg) - mpneg(b); - - for(i=0; ia[i] & b->a[i]; - a->a[i] = x; - } - - if(b->neg) - mpneg(b); - if(x & Mpsign) { - a->neg = 1; - mpneg(a); - } -} - -void -mpandnotfixfix(Mpint *a, Mpint *b) -{ - int i; - long x; - - x = 0; - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mpandnotfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - if(a->neg) { - a->neg = 0; - mpneg(a); - } - if(b->neg) - mpneg(b); - - for(i=0; ia[i] & ~b->a[i]; - a->a[i] = x; - } - - if(b->neg) - mpneg(b); - if(x & Mpsign) { - a->neg = 1; - mpneg(a); - } -} - -void -mpxorfixfix(Mpint *a, Mpint *b) -{ - int i; - long x; - - x = 0; - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mporfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - if(a->neg) { - a->neg = 0; - mpneg(a); - } - if(b->neg) - mpneg(b); - - for(i=0; ia[i] ^ b->a[i]; - a->a[i] = x; - } - - if(b->neg) - mpneg(b); - if(x & Mpsign) { - a->neg = 1; - mpneg(a); - } -} - -void -mplshfixfix(Mpint *a, Mpint *b) -{ - vlong s; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mporfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - s = mpgetfix(b); - if(s < 0 || s >= Mpprec*Mpscale) { - yyerror("stupid shift: %lld", s); - mpmovecfix(a, 0); - return; - } - - mpshiftfix(a, s); -} - -void -mprshfixfix(Mpint *a, Mpint *b) -{ - vlong s; - - if(a->ovf || b->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("ovf in mprshfixfix"); - mpmovecfix(a, 0); - a->ovf = 1; - return; - } - s = mpgetfix(b); - if(s < 0 || s >= Mpprec*Mpscale) { - yyerror("stupid shift: %lld", s); - if(a->neg) - mpmovecfix(a, -1); - else - mpmovecfix(a, 0); - return; - } - - mpshiftfix(a, -s); -} - -void -mpnegfix(Mpint *a) -{ - a->neg ^= 1; -} - -vlong -mpgetfix(Mpint *a) -{ - vlong v; - - if(a->ovf) { - if(nsavederrors+nerrors == 0) - yyerror("constant overflow"); - return 0; - } - - v = (uvlong)a->a[0]; - v |= (uvlong)a->a[1] << Mpscale; - v |= (uvlong)a->a[2] << (Mpscale+Mpscale); - if(a->neg) - v = -(uvlong)v; - return v; -} - -void -mpmovecfix(Mpint *a, vlong c) -{ - int i; - vlong x; - - a->neg = 0; - a->ovf = 0; - - x = c; - if(x < 0) { - a->neg = 1; - x = -(uvlong)x; - } - - for(i=0; ia[i] = x&Mpmask; - x >>= Mpscale; - } -} - -void -mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d) -{ - int i, ns, ds; - - ns = n->neg; - ds = d->neg; - n->neg = 0; - d->neg = 0; - - mpmovefixfix(r, n); - mpmovecfix(q, 0); - - // shift denominator until it - // is larger than numerator - for(i=0; i 0) - break; - mplsh(d, 1); - } - - // if it never happens - // denominator is probably zero - if(i >= Mpprec*Mpscale) { - q->ovf = 1; - r->ovf = 1; - n->neg = ns; - d->neg = ds; - yyerror("constant division overflow"); - return; - } - - // shift denominator back creating - // quotient a bit at a time - // when done the remaining numerator - // will be the remainder - for(; i>0; i--) { - mplsh(q, 1); - mprsh(d); - if(mpcmp(d, r) <= 0) { - mpaddcfix(q, 1); - mpsubfixfix(r, d); - } - } - - n->neg = ns; - d->neg = ds; - r->neg = ns; - q->neg = ns^ds; -} - -static int -mpiszero(Mpint *a) -{ - int i; - - for(i=Mpprec-1; i>=0; i--) - if(a->a[i] != 0) - return 0; - return 1; -} - -void -mpdivfract(Mpint *a, Mpint *b) -{ - Mpint n, d; - int i, j, neg; - long x; - - mpmovefixfix(&n, a); // numerator - mpmovefixfix(&d, b); // denominator - - neg = n.neg ^ d.neg; - n.neg = 0; - d.neg = 0; - for(i=Mpprec-1; i >= 0; i--) { - x = 0; - for(j=0; ja[i] = x; - } - a->neg = neg; -} - -int -mptestfix(Mpint *a) -{ - Mpint b; - int r; - - mpmovecfix(&b, 0); - r = mpcmp(a, &b); - if(a->neg) { - if(r > 0) - return -1; - if(r < 0) - return +1; - } - return r; -} diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c deleted file mode 100644 index 6afd75c023..0000000000 --- a/src/cmd/gc/mparith3.c +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -/* - * returns the leading non-zero - * word of the number - */ -int -sigfig(Mpflt *a) -{ - int i; - - for(i=Mpprec-1; i>=0; i--) - if(a->val.a[i] != 0) - break; -//print("sigfig %d %d\n", i-z+1, z); - return i+1; -} - -/* - * sets the exponent. - * a too large exponent is an error. - * a too small exponent rounds the number to zero. - */ -void -mpsetexp(Mpflt *a, int exp) { - if((short)exp != exp) { - if(exp > 0) { - yyerror("float constant is too large"); - a->exp = 0x7fff; - } - else { - mpmovecflt(a, 0); - } - } - else { - a->exp = exp; - } -} - -/* - * shifts the leading non-zero - * word of the number to Mpnorm - */ -void -mpnorm(Mpflt *a) -{ - int s, os; - long x; - - os = sigfig(a); - if(os == 0) { - // zero - a->exp = 0; - a->val.neg = 0; - return; - } - - // this will normalize to the nearest word - x = a->val.a[os-1]; - s = (Mpnorm-os) * Mpscale; - - // further normalize to the nearest bit - for(;;) { - x <<= 1; - if(x & Mpbase) - break; - s++; - if(x == 0) { - // this error comes from trying to - // convert an Inf or something - // where the initial x=0x80000000 - s = (Mpnorm-os) * Mpscale; - break; - } - } - - mpshiftfix(&a->val, s); - mpsetexp(a, a->exp-s); -} - -/// implements float arihmetic - -void -mpaddfltflt(Mpflt *a, Mpflt *b) -{ - int sa, sb, s; - Mpflt c; - - if(Mpdebug) - print("\n%F + %F", a, b); - - sa = sigfig(a); - if(sa == 0) { - mpmovefltflt(a, b); - goto out; - } - - sb = sigfig(b); - if(sb == 0) - goto out; - - s = a->exp - b->exp; - if(s > 0) { - // a is larger, shift b right - mpmovefltflt(&c, b); - mpshiftfix(&c.val, -s); - mpaddfixfix(&a->val, &c.val, 0); - goto out; - } - if(s < 0) { - // b is larger, shift a right - mpshiftfix(&a->val, s); - mpsetexp(a, a->exp-s); - mpaddfixfix(&a->val, &b->val, 0); - goto out; - } - mpaddfixfix(&a->val, &b->val, 0); - -out: - mpnorm(a); - if(Mpdebug) - print(" = %F\n\n", a); -} - -void -mpmulfltflt(Mpflt *a, Mpflt *b) -{ - int sa, sb; - - if(Mpdebug) - print("%F\n * %F\n", a, b); - - sa = sigfig(a); - if(sa == 0) { - // zero - a->exp = 0; - a->val.neg = 0; - return; - } - - sb = sigfig(b); - if(sb == 0) { - // zero - mpmovefltflt(a, b); - return; - } - - mpmulfract(&a->val, &b->val); - mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1); - - mpnorm(a); - if(Mpdebug) - print(" = %F\n\n", a); -} - -void -mpdivfltflt(Mpflt *a, Mpflt *b) -{ - int sa, sb; - Mpflt c; - - if(Mpdebug) - print("%F\n / %F\n", a, b); - - sb = sigfig(b); - if(sb == 0) { - // zero and ovfl - a->exp = 0; - a->val.neg = 0; - a->val.ovf = 1; - yyerror("constant division by zero"); - return; - } - - sa = sigfig(a); - if(sa == 0) { - // zero - a->exp = 0; - a->val.neg = 0; - return; - } - - // adjust b to top - mpmovefltflt(&c, b); - mpshiftfix(&c.val, Mpscale); - - // divide - mpdivfract(&a->val, &c.val); - mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1); - - mpnorm(a); - if(Mpdebug) - print(" = %F\n\n", a); -} - -static double -mpgetfltN(Mpflt *a, int prec, int bias) -{ - int s, i, e, minexp; - uvlong v; - double f; - - if(a->val.ovf && nsavederrors+nerrors == 0) - yyerror("mpgetflt ovf"); - - s = sigfig(a); - if(s == 0) - return 0; - - if(s != Mpnorm) { - yyerror("mpgetflt norm"); - mpnorm(a); - } - - while((a->val.a[Mpnorm-1] & Mpsign) == 0) { - mpshiftfix(&a->val, 1); - mpsetexp(a, a->exp-1); // can set 'a' to zero - s = sigfig(a); - if(s == 0) - return 0; - } - - // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong - s = prec+2; - v = 0; - for(i=Mpnorm-1; s>=Mpscale; i--) { - v = (v<val.a[i]; - s -= Mpscale; - } - if(s > 0) { - v = (v<val.a[i]>>(Mpscale-s)); - if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0) - v |= 1; - i--; - } - for(; i >= 0; i--) { - if(a->val.a[i] != 0) - v |= 1; - } - - // gradual underflow - e = Mpnorm*Mpscale + a->exp - prec; - minexp = bias+1-prec+1; - if(e < minexp) { - s = minexp - e; - if(s > prec+1) - s = prec+1; - if((v & ((1ULL<>= s; - e = minexp; - } - - // round to even - v |= (v&4)>>2; - v += v&1; - v >>= 2; - - f = (double)(v); - f = ldexp(f, e); - - if(a->val.neg) - f = -f; - - return f; -} - -double -mpgetflt(Mpflt *a) -{ - return mpgetfltN(a, 53, -1023); -} - -double -mpgetflt32(Mpflt *a) -{ - return mpgetfltN(a, 24, -127); -} - -void -mpmovecflt(Mpflt *a, double c) -{ - int i; - double f; - long l; - - if(Mpdebug) - print("\nconst %g", c); - mpmovecfix(&a->val, 0); - a->exp = 0; - if(c == 0) - goto out; - if(c < 0) { - a->val.neg = 1; - c = -c; - } - - f = frexp(c, &i); - a->exp = i; - - for(i=0; i<10; i++) { - f = f*Mpbase; - l = floor(f); - f = f - l; - a->exp -= Mpscale; - a->val.a[0] = l; - if(f == 0) - break; - mpshiftfix(&a->val, Mpscale); - } - -out: - mpnorm(a); - if(Mpdebug) - print(" = %F\n", a); -} - -void -mpnegflt(Mpflt *a) -{ - a->val.neg ^= 1; -} - -int -mptestflt(Mpflt *a) -{ - int s; - - if(Mpdebug) - print("\n%F?", a); - s = sigfig(a); - if(s != 0) { - s = +1; - if(a->val.neg) - s = -1; - } - if(Mpdebug) - print(" = %d\n", s); - return s; -} diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c deleted file mode 100644 index 3983f99d6d..0000000000 --- a/src/cmd/gc/obj.c +++ /dev/null @@ -1,498 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "../ld/textflag.h" - -/* - * architecture-independent object file output - */ - -static void dumpglobls(void); - -enum -{ - ArhdrSize = 60 -}; - -static void -formathdr(char *arhdr, char *name, vlong size) -{ - snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`", - name, 0, 0, 0, 0644, size); - arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint -} - -void -dumpobj(void) -{ - NodeList *externs, *tmp; - char arhdr[ArhdrSize]; - vlong startobj, size; - Sym *zero; - - bout = Bopen(outfile, OWRITE); - if(bout == nil) { - flusherrors(); - print("can't create %s: %r\n", outfile); - errorexit(); - } - - startobj = 0; - if(writearchive) { - Bwrite(bout, "!\n", 8); - memset(arhdr, 0, sizeof arhdr); - Bwrite(bout, arhdr, sizeof arhdr); - startobj = Boffset(bout); - } - Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); - dumpexport(); - - if(writearchive) { - Bflush(bout); - size = Boffset(bout) - startobj; - if(size&1) - Bputc(bout, 0); - Bseek(bout, startobj - ArhdrSize, 0); - formathdr(arhdr, "__.PKGDEF", size); - Bwrite(bout, arhdr, ArhdrSize); - Bflush(bout); - - Bseek(bout, startobj + size + (size&1), 0); - memset(arhdr, 0, ArhdrSize); - Bwrite(bout, arhdr, ArhdrSize); - startobj = Boffset(bout); - Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); - } - - if(pragcgobuf.to > pragcgobuf.start) { - if(writearchive) { - // write empty export section; must be before cgo section - Bprint(bout, "\n$$\n\n$$\n\n"); - } - Bprint(bout, "\n$$ // cgo\n"); - Bprint(bout, "%s\n$$\n\n", fmtstrflush(&pragcgobuf)); - } - - - Bprint(bout, "\n!\n"); - - externs = nil; - if(externdcl != nil) - externs = externdcl->end; - - dumpglobls(); - dumptypestructs(); - - // Dump extra globals. - tmp = externdcl; - if(externs != nil) - externdcl = externs->next; - dumpglobls(); - externdcl = tmp; - - zero = pkglookup("zerovalue", runtimepkg); - ggloblsym(zero, zerosize, DUPOK|RODATA); - - dumpdata(); - writeobj(ctxt, bout); - - if(writearchive) { - Bflush(bout); - size = Boffset(bout) - startobj; - if(size&1) - Bputc(bout, 0); - Bseek(bout, startobj - ArhdrSize, 0); - snprint(namebuf, sizeof namebuf, "_go_.%c", thearch.thechar); - formathdr(arhdr, namebuf, size); - Bwrite(bout, arhdr, ArhdrSize); - } - Bterm(bout); -} - -static void -dumpglobls(void) -{ - Node *n; - NodeList *l; - - // add globals - for(l=externdcl; l; l=l->next) { - n = l->n; - if(n->op != ONAME) - continue; - - if(n->type == T) - fatal("external %N nil type\n", n); - if(n->class == PFUNC) - continue; - if(n->sym->pkg != localpkg) - continue; - dowidth(n->type); - - ggloblnod(n); - } - - for(l=funcsyms; l; l=l->next) { - n = l->n; - dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0); - ggloblsym(n->sym, widthptr, DUPOK|RODATA); - } - - // Do not reprocess funcsyms on next dumpglobls call. - funcsyms = nil; -} - -void -Bputname(Biobuf *b, LSym *s) -{ - Bwrite(b, s->name, strlen(s->name)+1); -} - -LSym* -linksym(Sym *s) -{ - char *p; - - if(s == nil) - return nil; - if(s->lsym != nil) - return s->lsym; - if(isblanksym(s)) - s->lsym = linklookup(ctxt, "_", 0); - else if(s->linkname != nil) - s->lsym = linklookup(ctxt, s->linkname, 0); - else { - p = smprint("%s.%s", s->pkg->prefix, s->name); - s->lsym = linklookup(ctxt, p, 0); - free(p); - } - return s->lsym; -} - -int -duintxx(Sym *s, int off, uint64 v, int wid) -{ - // Update symbol data directly instead of generating a - // DATA instruction that liblink will have to interpret later. - // This reduces compilation time and memory usage. - off = rnd(off, wid); - return setuintxx(ctxt, linksym(s), off, v, wid); -} - -int -duint8(Sym *s, int off, uint8 v) -{ - return duintxx(s, off, v, 1); -} - -int -duint16(Sym *s, int off, uint16 v) -{ - return duintxx(s, off, v, 2); -} - -int -duint32(Sym *s, int off, uint32 v) -{ - return duintxx(s, off, v, 4); -} - -int -duint64(Sym *s, int off, uint64 v) -{ - return duintxx(s, off, v, 8); -} - -int -duintptr(Sym *s, int off, uint64 v) -{ - return duintxx(s, off, v, widthptr); -} - -Sym* -stringsym(char *s, int len) -{ - static int gen; - Sym *sym; - int off, n, m; - struct { - Strlit lit; - char buf[110]; - } tmp; - Pkg *pkg; - - if(len > 100) { - // huge strings are made static to avoid long names - snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen); - pkg = localpkg; - } else { - // small strings get named by their contents, - // so that multiple modules using the same string - // can share it. - tmp.lit.len = len; - memmove(tmp.lit.s, s, len); - tmp.lit.s[len] = '\0'; - snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit); - pkg = gostringpkg; - } - sym = pkglookup(namebuf, pkg); - - // SymUniq flag indicates that data is generated already - if(sym->flags & SymUniq) - return sym; - sym->flags |= SymUniq; - sym->def = newname(sym); - - off = 0; - - // string header - off = dsymptr(sym, off, sym, widthptr+widthint); - off = duintxx(sym, off, len, widthint); - - // string data - for(n=0; n len-n) - m = len-n; - off = dsname(sym, off, s+n, m); - } - off = duint8(sym, off, 0); // terminating NUL for runtime - off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment - ggloblsym(sym, off, DUPOK|RODATA); - - return sym; -} - -void -slicebytes(Node *nam, char *s, int len) -{ - int off, n, m; - static int gen; - Sym *sym; - - snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen); - sym = pkglookup(namebuf, localpkg); - sym->def = newname(sym); - - off = 0; - for(n=0; n len-n) - m = len-n; - off = dsname(sym, off, s+n, m); - } - ggloblsym(sym, off, NOPTR); - - if(nam->op != ONAME) - fatal("slicebytes %N", nam); - off = nam->xoffset; - off = dsymptr(nam->sym, off, sym, 0); - off = duintxx(nam->sym, off, len, widthint); - duintxx(nam->sym, off, len, widthint); -} - -int -dsname(Sym *s, int off, char *t, int n) -{ - Prog *p; - - p = thearch.gins(ADATA, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.offset = off; - p->from.sym = linksym(s); - p->from3.type = TYPE_CONST; - p->from3.offset = n; - - p->to.type = TYPE_SCONST; - memmove(p->to.u.sval, t, n); - return off + n; -} - -/* - * make a refer to the data s, s+len - * emitting DATA if needed. - */ -void -datastring(char *s, int len, Addr *a) -{ - Sym *sym; - - sym = stringsym(s, len); - a->type = TYPE_MEM; - a->name = NAME_EXTERN; - a->sym = linksym(sym); - a->node = sym->def; - a->offset = widthptr+widthint; // skip header - a->etype = simtype[TINT]; -} - -/* - * make a refer to the string sval, - * emitting DATA if needed. - */ -void -datagostring(Strlit *sval, Addr *a) -{ - Sym *sym; - - sym = stringsym(sval->s, sval->len); - a->type = TYPE_MEM; - a->name = NAME_EXTERN; - a->sym = linksym(sym); - a->node = sym->def; - a->offset = 0; // header - a->etype = TSTRING; -} - -void -gdata(Node *nam, Node *nr, int wid) -{ - Prog *p; - - if(nr->op == OLITERAL) { - switch(nr->val.ctype) { - case CTCPLX: - gdatacomplex(nam, nr->val.u.cval); - return; - case CTSTR: - gdatastring(nam, nr->val.u.sval); - return; - } - } - p = thearch.gins(ADATA, nam, nr); - p->from3.type = TYPE_CONST; - p->from3.offset = wid; -} - -void -gdatacomplex(Node *nam, Mpcplx *cval) -{ - Prog *p; - int w; - - w = cplxsubtype(nam->type->etype); - w = types[w]->width; - - p = thearch.gins(ADATA, nam, N); - p->from3.type = TYPE_CONST; - p->from3.offset = w; - p->to.type = TYPE_FCONST; - p->to.u.dval = mpgetflt(&cval->real); - - p = thearch.gins(ADATA, nam, N); - p->from3.type = TYPE_CONST; - p->from3.offset = w; - p->from.offset += w; - p->to.type = TYPE_FCONST; - p->to.u.dval = mpgetflt(&cval->imag); -} - -void -gdatastring(Node *nam, Strlit *sval) -{ - Prog *p; - Node nod1; - - p = thearch.gins(ADATA, nam, N); - datastring(sval->s, sval->len, &p->to); - p->from3.type = TYPE_CONST; - p->from3.offset = types[tptr]->width; - p->to.type = TYPE_ADDR; -//print("%P\n", p); - - nodconst(&nod1, types[TINT], sval->len); - p = thearch.gins(ADATA, nam, &nod1); - p->from3.type = TYPE_CONST; - p->from3.offset = widthint; - p->from.offset += widthptr; -} - -int -dstringptr(Sym *s, int off, char *str) -{ - Prog *p; - - off = rnd(off, widthptr); - p = thearch.gins(ADATA, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.sym = linksym(s); - p->from.offset = off; - p->from3.type = TYPE_CONST; - p->from3.offset = widthptr; - - datastring(str, strlen(str)+1, &p->to); - p->to.type = TYPE_ADDR; - p->to.etype = simtype[TINT]; - off += widthptr; - - return off; -} - -int -dgostrlitptr(Sym *s, int off, Strlit *lit) -{ - Prog *p; - - if(lit == nil) - return duintptr(s, off, 0); - - off = rnd(off, widthptr); - p = thearch.gins(ADATA, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.sym = linksym(s); - p->from.offset = off; - p->from3.type = TYPE_CONST; - p->from3.offset = widthptr; - datagostring(lit, &p->to); - p->to.type = TYPE_ADDR; - p->to.etype = simtype[TINT]; - off += widthptr; - - return off; -} - -int -dgostringptr(Sym *s, int off, char *str) -{ - int n; - Strlit *lit; - - if(str == nil) - return duintptr(s, off, 0); - - n = strlen(str); - lit = mal(sizeof *lit + n); - strcpy(lit->s, str); - lit->len = n; - return dgostrlitptr(s, off, lit); -} - -int -dsymptr(Sym *s, int off, Sym *x, int xoff) -{ - Prog *p; - - off = rnd(off, widthptr); - - p = thearch.gins(ADATA, N, N); - p->from.type = TYPE_MEM; - p->from.name = NAME_EXTERN; - p->from.sym = linksym(s); - p->from.offset = off; - p->from3.type = TYPE_CONST; - p->from3.offset = widthptr; - p->to.type = TYPE_ADDR; - p->to.name = NAME_EXTERN; - p->to.sym = linksym(x); - p->to.offset = xoff; - off += widthptr; - - return off; -} diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c deleted file mode 100644 index 8e670bdc13..0000000000 --- a/src/cmd/gc/order.c +++ /dev/null @@ -1,1164 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Rewrite tree to use separate statements to enforce -// order of evaluation. Makes walk easier, because it -// can (after this runs) reorder at will within an expression. -// -// Rewrite x op= y into x = x op y. -// -// Introduce temporaries as needed by runtime routines. -// For example, the map runtime routines take the map key -// by reference, so make sure all map keys are addressable -// by copying them to temporaries as needed. -// The same is true for channel operations. -// -// Arrange that map index expressions only appear in direct -// assignments x = m[k] or m[k] = x, never in larger expressions. -// -// Arrange that receive expressions only appear in direct assignments -// x = <-c or as standalone statements <-c, never in larger expressions. - -// TODO(rsc): The temporary introduction during multiple assignments -// should be moved into this file, so that the temporaries can be cleaned -// and so that conversions implicit in the OAS2FUNC and OAS2RECV -// nodes can be made explicit and then have their temporaries cleaned. - -// TODO(rsc): Goto and multilevel break/continue can jump over -// inserted VARKILL annotations. Work out a way to handle these. -// The current implementation is safe, in that it will execute correctly. -// But it won't reuse temporaries as aggressively as it might, and -// it can result in unnecessary zeroing of those variables in the function -// prologue. - -#include -#include -#include "go.h" - -// Order holds state during the ordering process. -typedef struct Order Order; -struct Order -{ - NodeList *out; // list of generated statements - NodeList *temp; // head of stack of temporary variables - NodeList *free; // free list of NodeList* structs (for use in temp) -}; - -static void orderstmt(Node*, Order*); -static void orderstmtlist(NodeList*, Order*); -static void orderblock(NodeList **l); -static void orderexpr(Node**, Order*); -static void orderexprinplace(Node**, Order*); -static void orderexprlist(NodeList*, Order*); -static void orderexprlistinplace(NodeList*, Order*); - -// Order rewrites fn->nbody to apply the ordering constraints -// described in the comment at the top of the file. -void -order(Node *fn) -{ - char s[50]; - - if(debug['W'] > 1) { - snprint(s, sizeof(s), "\nbefore order %S", fn->nname->sym); - dumplist(s, fn->nbody); - } - - orderblock(&fn->nbody); -} - -// Ordertemp allocates a new temporary with the given type, -// pushes it onto the temp stack, and returns it. -// If clear is true, ordertemp emits code to zero the temporary. -static Node* -ordertemp(Type *t, Order *order, int clear) -{ - Node *var, *a; - NodeList *l; - - var = temp(t); - if(clear) { - a = nod(OAS, var, N); - typecheck(&a, Etop); - order->out = list(order->out, a); - } - if((l = order->free) == nil) - l = mal(sizeof *l); - order->free = l->next; - l->next = order->temp; - l->n = var; - order->temp = l; - return var; -} - -// Ordercopyexpr behaves like ordertemp but also emits -// code to initialize the temporary to the value n. -// -// The clear argument is provided for use when the evaluation -// of tmp = n turns into a function call that is passed a pointer -// to the temporary as the output space. If the call blocks before -// tmp has been written, the garbage collector will still treat the -// temporary as live, so we must zero it before entering that call. -// Today, this only happens for channel receive operations. -// (The other candidate would be map access, but map access -// returns a pointer to the result data instead of taking a pointer -// to be filled in.) -static Node* -ordercopyexpr(Node *n, Type *t, Order *order, int clear) -{ - Node *a, *var; - - var = ordertemp(t, order, clear); - a = nod(OAS, var, n); - typecheck(&a, Etop); - order->out = list(order->out, a); - return var; -} - -// Ordercheapexpr returns a cheap version of n. -// The definition of cheap is that n is a variable or constant. -// If not, ordercheapexpr allocates a new tmp, emits tmp = n, -// and then returns tmp. -static Node* -ordercheapexpr(Node *n, Order *order) -{ - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - } - return ordercopyexpr(n, n->type, order, 0); -} - -// Ordersafeexpr returns a safe version of n. -// The definition of safe is that n can appear multiple times -// without violating the semantics of the original program, -// and that assigning to the safe version has the same effect -// as assigning to the original n. -// -// The intended use is to apply to x when rewriting x += y into x = x + y. -static Node* -ordersafeexpr(Node *n, Order *order) -{ - Node *l, *r, *a; - - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - - case ODOT: - l = ordersafeexpr(n->left, order); - if(l == n->left) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->orig = a; - a->left = l; - typecheck(&a, Erv); - return a; - - case ODOTPTR: - case OIND: - l = ordercheapexpr(n->left, order); - if(l == n->left) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->orig = a; - a->left = l; - typecheck(&a, Erv); - return a; - - case OINDEX: - case OINDEXMAP: - if(isfixedarray(n->left->type)) - l = ordersafeexpr(n->left, order); - else - l = ordercheapexpr(n->left, order); - r = ordercheapexpr(n->right, order); - if(l == n->left && r == n->right) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->orig = a; - a->left = l; - a->right = r; - typecheck(&a, Erv); - return a; - } - - fatal("ordersafeexpr %O", n->op); - return nil; // not reached -} - -// Istemp reports whether n is a temporary variable. -static int -istemp(Node *n) -{ - if(n->op != ONAME) - return 0; - return strncmp(n->sym->name, "autotmp_", 8) == 0; -} - -// Isaddrokay reports whether it is okay to pass n's address to runtime routines. -// Taking the address of a variable makes the liveness and optimization analyses -// lose track of where the variable's lifetime ends. To avoid hurting the analyses -// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay, -// because we emit explicit VARKILL instructions marking the end of those -// temporaries' lifetimes. -static int -isaddrokay(Node *n) -{ - return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n)); -} - -// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines. -// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits -// tmp = *np, and then sets *np to the tmp variable. -static void -orderaddrtemp(Node **np, Order *order) -{ - Node *n; - - n = *np; - if(isaddrokay(n)) - return; - *np = ordercopyexpr(n, n->type, order, 0); -} - -// Marktemp returns the top of the temporary variable stack. -static NodeList* -marktemp(Order *order) -{ - return order->temp; -} - -// Poptemp pops temporaries off the stack until reaching the mark, -// which must have been returned by marktemp. -static void -poptemp(NodeList *mark, Order *order) -{ - NodeList *l; - - while((l = order->temp) != mark) { - order->temp = l->next; - l->next = order->free; - order->free = l; - } -} - -// Cleantempnopop emits to *out VARKILL instructions for each temporary -// above the mark on the temporary stack, but it does not pop them -// from the stack. -static void -cleantempnopop(NodeList *mark, Order *order, NodeList **out) -{ - NodeList *l; - Node *kill; - - for(l=order->temp; l != mark; l=l->next) { - kill = nod(OVARKILL, l->n, N); - typecheck(&kill, Etop); - *out = list(*out, kill); - } -} - -// Cleantemp emits VARKILL instructions for each temporary above the -// mark on the temporary stack and removes them from the stack. -static void -cleantemp(NodeList *top, Order *order) -{ - cleantempnopop(top, order, &order->out); - poptemp(top, order); -} - -// Orderstmtlist orders each of the statements in the list. -static void -orderstmtlist(NodeList *l, Order *order) -{ - for(; l; l=l->next) - orderstmt(l->n, order); -} - -// Orderblock orders the block of statements *l onto a new list, -// and then replaces *l with that list. -static void -orderblock(NodeList **l) -{ - Order order; - NodeList *mark; - - memset(&order, 0, sizeof order); - mark = marktemp(&order); - orderstmtlist(*l, &order); - cleantemp(mark, &order); - *l = order.out; -} - -// Orderexprinplace orders the side effects in *np and -// leaves them as the init list of the final *np. -static void -orderexprinplace(Node **np, Order *outer) -{ - Node *n; - NodeList **lp; - Order order; - - n = *np; - memset(&order, 0, sizeof order); - orderexpr(&n, &order); - addinit(&n, order.out); - - // insert new temporaries from order - // at head of outer list. - lp = &order.temp; - while(*lp != nil) - lp = &(*lp)->next; - *lp = outer->temp; - outer->temp = order.temp; - - *np = n; -} - -// Orderstmtinplace orders the side effects of the single statement *np -// and replaces it with the resulting statement list. -void -orderstmtinplace(Node **np) -{ - Node *n; - Order order; - NodeList *mark; - - n = *np; - memset(&order, 0, sizeof order); - mark = marktemp(&order); - orderstmt(n, &order); - cleantemp(mark, &order); - *np = liststmt(order.out); -} - -// Orderinit moves n's init list to order->out. -static void -orderinit(Node *n, Order *order) -{ - orderstmtlist(n->ninit, order); - n->ninit = nil; -} - -// Ismulticall reports whether the list l is f() for a multi-value function. -// Such an f() could appear as the lone argument to a multi-arg function. -static int -ismulticall(NodeList *l) -{ - Node *n; - - // one arg only - if(l == nil || l->next != nil) - return 0; - n = l->n; - - // must be call - switch(n->op) { - default: - return 0; - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - break; - } - - // call must return multiple values - return n->left->type->outtuple > 1; -} - -// Copyret emits t1, t2, ... = n, where n is a function call, -// and then returns the list t1, t2, .... -static NodeList* -copyret(Node *n, Order *order) -{ - Type *t; - Node *tmp, *as; - NodeList *l1, *l2; - Iter tl; - - if(n->type->etype != TSTRUCT || !n->type->funarg) - fatal("copyret %T %d", n->type, n->left->type->outtuple); - - l1 = nil; - l2 = nil; - for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) { - tmp = temp(t->type); - l1 = list(l1, tmp); - l2 = list(l2, tmp); - } - - as = nod(OAS2, N, N); - as->list = l1; - as->rlist = list1(n); - typecheck(&as, Etop); - orderstmt(as, order); - - return l2; -} - -// Ordercallargs orders the list of call arguments *l. -static void -ordercallargs(NodeList **l, Order *order) -{ - if(ismulticall(*l)) { - // return f() where f() is multiple values. - *l = copyret((*l)->n, order); - } else { - orderexprlist(*l, order); - } -} - -// Ordercall orders the call expression n. -// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY. -static void -ordercall(Node *n, Order *order) -{ - orderexpr(&n->left, order); - orderexpr(&n->right, order); // ODDDARG temp - ordercallargs(&n->list, order); -} - -// Ordermapassign appends n to order->out, introducing temporaries -// to make sure that all map assignments have the form m[k] = x, -// where x is adressable. -// (Orderexpr has already been called on n, so we know k is addressable.) -// -// If n is m[k] = x where x is not addressable, the rewrite is: -// tmp = x -// m[k] = tmp -// -// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is -// t1 = m -// t2 = k -// ...., t3, ... = x -// t1[t2] = t3 -// -// The temporaries t1, t2 are needed in case the ... being assigned -// contain m or k. They are usually unnecessary, but in the unnecessary -// cases they are also typically registerizable, so not much harm done. -// And this only applies to the multiple-assignment form. -// We could do a more precise analysis if needed, like in walk.c. -// -// Ordermapassign also inserts these temporaries if needed for -// calling writebarrierfat with a pointer to n->right. -static void -ordermapassign(Node *n, Order *order) -{ - Node *m, *a; - NodeList *l; - NodeList *post; - - switch(n->op) { - default: - fatal("ordermapassign %O", n->op); - - case OAS: - order->out = list(order->out, n); - // We call writebarrierfat only for values > 4 pointers long. See walk.c. - if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) { - m = n->left; - n->left = ordertemp(m->type, order, 0); - a = nod(OAS, m, n->left); - typecheck(&a, Etop); - order->out = list(order->out, a); - } - break; - - case OAS2: - case OAS2DOTTYPE: - case OAS2MAPR: - case OAS2FUNC: - post = nil; - for(l=n->list; l != nil; l=l->next) { - if(l->n->op == OINDEXMAP) { - m = l->n; - if(!istemp(m->left)) - m->left = ordercopyexpr(m->left, m->left->type, order, 0); - if(!istemp(m->right)) - m->right = ordercopyexpr(m->right, m->right->type, order, 0); - l->n = ordertemp(m->type, order, 0); - a = nod(OAS, m, l->n); - typecheck(&a, Etop); - post = list(post, a); - } - } - order->out = list(order->out, n); - order->out = concat(order->out, post); - break; - } -} - -// Orderstmt orders the statement n, appending to order->out. -// Temporaries created during the statement are cleaned -// up using VARKILL instructions as possible. -static void -orderstmt(Node *n, Order *order) -{ - int lno; - NodeList *l, *t, *t1; - Node *r, *tmp1, *tmp2, **np; - Type *ch, *typ; - - if(n == N) - return; - - lno = setlineno(n); - - orderinit(n, order); - - switch(n->op) { - default: - fatal("orderstmt %O", n->op); - - case OVARKILL: - order->out = list(order->out, n); - break; - - case OAS: - case OAS2: - case OCLOSE: - case OCOPY: - case OPRINT: - case OPRINTN: - case ORECOVER: - case ORECV: - t = marktemp(order); - orderexpr(&n->left, order); - orderexpr(&n->right, order); - orderexprlist(n->list, order); - orderexprlist(n->rlist, order); - switch(n->op) { - case OAS: - case OAS2: - case OAS2DOTTYPE: - ordermapassign(n, order); - break; - default: - order->out = list(order->out, n); - break; - } - cleantemp(t, order); - break; - - case OASOP: - // Special: rewrite l op= r into l = l op r. - // This simplies quite a few operations; - // most important is that it lets us separate - // out map read from map write when l is - // a map index expression. - t = marktemp(order); - orderexpr(&n->left, order); - n->left = ordersafeexpr(n->left, order); - tmp1 = treecopy(n->left); - if(tmp1->op == OINDEXMAP) - tmp1->etype = 0; // now an rvalue not an lvalue - tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0); - n->right = nod(n->etype, tmp1, n->right); - typecheck(&n->right, Erv); - orderexpr(&n->right, order); - n->etype = 0; - n->op = OAS; - ordermapassign(n, order); - cleantemp(t, order); - break; - - case OAS2MAPR: - // Special: make sure key is addressable, - // and make sure OINDEXMAP is not copied out. - t = marktemp(order); - orderexprlist(n->list, order); - r = n->rlist->n; - orderexpr(&r->left, order); - orderexpr(&r->right, order); - // See case OINDEXMAP below. - if(r->right->op == OARRAYBYTESTR) - r->right->op = OARRAYBYTESTRTMP; - orderaddrtemp(&r->right, order); - ordermapassign(n, order); - cleantemp(t, order); - break; - - case OAS2FUNC: - // Special: avoid copy of func call n->rlist->n. - t = marktemp(order); - orderexprlist(n->list, order); - ordercall(n->rlist->n, order); - ordermapassign(n, order); - cleantemp(t, order); - break; - - case OAS2DOTTYPE: - // Special: use temporary variables to hold result, - // so that assertI2Tetc can take address of temporary. - // No temporary for blank assignment. - t = marktemp(order); - orderexprlist(n->list, order); - orderexpr(&n->rlist->n->left, order); // i in i.(T) - if(isblank(n->list->n)) - order->out = list(order->out, n); - else { - typ = n->rlist->n->type; - tmp1 = ordertemp(typ, order, haspointers(typ)); - order->out = list(order->out, n); - r = nod(OAS, n->list->n, tmp1); - typecheck(&r, Etop); - ordermapassign(r, order); - n->list = list(list1(tmp1), n->list->next->n); - } - cleantemp(t, order); - break; - - case OAS2RECV: - // Special: use temporary variables to hold result, - // so that chanrecv can take address of temporary. - t = marktemp(order); - orderexprlist(n->list, order); - orderexpr(&n->rlist->n->left, order); // arg to recv - ch = n->rlist->n->left->type; - tmp1 = ordertemp(ch->type, order, haspointers(ch->type)); - if(!isblank(n->list->next->n)) - tmp2 = ordertemp(n->list->next->n->type, order, 0); - else - tmp2 = ordertemp(types[TBOOL], order, 0); - order->out = list(order->out, n); - r = nod(OAS, n->list->n, tmp1); - typecheck(&r, Etop); - ordermapassign(r, order); - r = nod(OAS, n->list->next->n, tmp2); - typecheck(&r, Etop); - ordermapassign(r, order); - n->list = list(list1(tmp1), tmp2); - cleantemp(t, order); - break; - - case OBLOCK: - case OEMPTY: - // Special: does not save n onto out. - orderstmtlist(n->list, order); - break; - - case OBREAK: - case OCONTINUE: - case ODCL: - case ODCLCONST: - case ODCLTYPE: - case OFALL: - case OXFALL: - case OGOTO: - case OLABEL: - case ORETJMP: - // Special: n->left is not an expression; save as is. - order->out = list(order->out, n); - break; - - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - // Special: handle call arguments. - t = marktemp(order); - ordercall(n, order); - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case ODEFER: - case OPROC: - // Special: order arguments to inner call but not call itself. - t = marktemp(order); - switch(n->left->op) { - case ODELETE: - // Delete will take the address of the key. - // Copy key into new temp and do not clean it - // (it persists beyond the statement). - orderexprlist(n->left->list, order); - t1 = marktemp(order); - np = &n->left->list->next->n; // map key - *np = ordercopyexpr(*np, (*np)->type, order, 0); - poptemp(t1, order); - break; - default: - ordercall(n->left, order); - break; - } - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case ODELETE: - t = marktemp(order); - orderexpr(&n->list->n, order); - orderexpr(&n->list->next->n, order); - orderaddrtemp(&n->list->next->n, order); // map key - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case OFOR: - // Clean temporaries from condition evaluation at - // beginning of loop body and after for statement. - t = marktemp(order); - orderexprinplace(&n->ntest, order); - l = nil; - cleantempnopop(t, order, &l); - n->nbody = concat(l, n->nbody); - orderblock(&n->nbody); - orderstmtinplace(&n->nincr); - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case OIF: - // Clean temporaries from condition at - // beginning of both branches. - t = marktemp(order); - orderexprinplace(&n->ntest, order); - l = nil; - cleantempnopop(t, order, &l); - n->nbody = concat(l, n->nbody); - l = nil; - cleantempnopop(t, order, &l); - n->nelse = concat(l, n->nelse); - poptemp(t, order); - orderblock(&n->nbody); - orderblock(&n->nelse); - order->out = list(order->out, n); - break; - - case OPANIC: - // Special: argument will be converted to interface using convT2E - // so make sure it is an addressable temporary. - t = marktemp(order); - orderexpr(&n->left, order); - if(!isinter(n->left->type)) - orderaddrtemp(&n->left, order); - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case ORANGE: - // n->right is the expression being ranged over. - // order it, and then make a copy if we need one. - // We almost always do, to ensure that we don't - // see any value changes made during the loop. - // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny). - // The exception is ranging over an array value (not a slice, not a pointer to array), - // which must make a copy to avoid seeing updates made during - // the range body. Ranging over an array value is uncommon though. - t = marktemp(order); - orderexpr(&n->right, order); - switch(n->type->etype) { - default: - fatal("orderstmt range %T", n->type); - case TARRAY: - // Mark []byte(str) range expression to reuse string backing storage. - // It is safe because the storage cannot be mutated. - if(n->right->op == OSTRARRAYBYTE) - n->right->op = OSTRARRAYBYTETMP; - if(count(n->list) < 2 || isblank(n->list->next->n)) { - // for i := range x will only use x once, to compute len(x). - // No need to copy it. - break; - } - // fall through - case TCHAN: - case TSTRING: - // chan, string, slice, array ranges use value multiple times. - // make copy. - r = n->right; - if(r->type->etype == TSTRING && r->type != types[TSTRING]) { - r = nod(OCONV, r, N); - r->type = types[TSTRING]; - typecheck(&r, Erv); - } - n->right = ordercopyexpr(r, r->type, order, 0); - break; - case TMAP: - // copy the map value in case it is a map literal. - // TODO(rsc): Make tmp = literal expressions reuse tmp. - // For maps tmp is just one word so it hardly matters. - r = n->right; - n->right = ordercopyexpr(r, r->type, order, 0); - // n->alloc is the temp for the iterator. - n->alloc = ordertemp(types[TUINT8], order, 1); - break; - } - for(l=n->list; l; l=l->next) - orderexprinplace(&l->n, order); - orderblock(&n->nbody); - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case ORETURN: - ordercallargs(&n->list, order); - order->out = list(order->out, n); - break; - - case OSELECT: - // Special: clean case temporaries in each block entry. - // Select must enter one of its blocks, so there is no - // need for a cleaning at the end. - // Doubly special: evaluation order for select is stricter - // than ordinary expressions. Even something like p.c - // has to be hoisted into a temporary, so that it cannot be - // reordered after the channel evaluation for a different - // case (if p were nil, then the timing of the fault would - // give this away). - t = marktemp(order); - for(l=n->list; l; l=l->next) { - if(l->n->op != OXCASE) - fatal("order select case %O", l->n->op); - r = l->n->left; - setlineno(l->n); - // Append any new body prologue to ninit. - // The next loop will insert ninit into nbody. - if(l->n->ninit != nil) - fatal("order select ninit"); - if(r != nil) { - switch(r->op) { - default: - yyerror("unknown op in select %O", r->op); - dump("select case", r); - break; - - case OSELRECV: - case OSELRECV2: - // If this is case x := <-ch or case x, y := <-ch, the case has - // the ODCL nodes to declare x and y. We want to delay that - // declaration (and possible allocation) until inside the case body. - // Delete the ODCL nodes here and recreate them inside the body below. - if(r->colas) { - t = r->ninit; - if(t != nil && t->n->op == ODCL && t->n->left == r->left) - t = t->next; - if(t != nil && t->n->op == ODCL && t->n->left == r->ntest) - t = t->next; - if(t == nil) - r->ninit = nil; - } - if(r->ninit != nil) { - yyerror("ninit on select recv"); - dumplist("ninit", r->ninit); - } - // case x = <-c - // case x, ok = <-c - // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. - // r->left == N means 'case <-c'. - // c is always evaluated; x and ok are only evaluated when assigned. - orderexpr(&r->right->left, order); - if(r->right->left->op != ONAME) - r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0); - - // Introduce temporary for receive and move actual copy into case body. - // avoids problems with target being addressed, as usual. - // NOTE: If we wanted to be clever, we could arrange for just one - // temporary per distinct type, sharing the temp among all receives - // with that temp. Similarly one ok bool could be shared among all - // the x,ok receives. Not worth doing until there's a clear need. - if(r->left != N && isblank(r->left)) - r->left = N; - if(r->left != N) { - // use channel element type for temporary to avoid conversions, - // such as in case interfacevalue = <-intchan. - // the conversion happens in the OAS instead. - tmp1 = r->left; - if(r->colas) { - tmp2 = nod(ODCL, tmp1, N); - typecheck(&tmp2, Etop); - l->n->ninit = list(l->n->ninit, tmp2); - } - r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type)); - tmp2 = nod(OAS, tmp1, r->left); - typecheck(&tmp2, Etop); - l->n->ninit = list(l->n->ninit, tmp2); - } - if(r->ntest != N && isblank(r->ntest)) - r->ntest = N; - if(r->ntest != N) { - tmp1 = r->ntest; - if(r->colas) { - tmp2 = nod(ODCL, tmp1, N); - typecheck(&tmp2, Etop); - l->n->ninit = list(l->n->ninit, tmp2); - } - r->ntest = ordertemp(tmp1->type, order, 0); - tmp2 = nod(OAS, tmp1, r->ntest); - typecheck(&tmp2, Etop); - l->n->ninit = list(l->n->ninit, tmp2); - } - orderblock(&l->n->ninit); - break; - - case OSEND: - if(r->ninit != nil) { - yyerror("ninit on select send"); - dumplist("ninit", r->ninit); - } - // case c <- x - // r->left is c, r->right is x, both are always evaluated. - orderexpr(&r->left, order); - if(!istemp(r->left)) - r->left = ordercopyexpr(r->left, r->left->type, order, 0); - orderexpr(&r->right, order); - if(!istemp(r->right)) - r->right = ordercopyexpr(r->right, r->right->type, order, 0); - break; - } - } - orderblock(&l->n->nbody); - } - // Now that we have accumulated all the temporaries, clean them. - // Also insert any ninit queued during the previous loop. - // (The temporary cleaning must follow that ninit work.) - for(l=n->list; l; l=l->next) { - cleantempnopop(t, order, &l->n->ninit); - l->n->nbody = concat(l->n->ninit, l->n->nbody); - l->n->ninit = nil; - } - order->out = list(order->out, n); - poptemp(t, order); - break; - - case OSEND: - // Special: value being sent is passed as a pointer; make it addressable. - t = marktemp(order); - orderexpr(&n->left, order); - orderexpr(&n->right, order); - orderaddrtemp(&n->right, order); - order->out = list(order->out, n); - cleantemp(t, order); - break; - - case OSWITCH: - // TODO(rsc): Clean temporaries more aggressively. - // Note that because walkswitch will rewrite some of the - // switch into a binary search, this is not as easy as it looks. - // (If we ran that code here we could invoke orderstmt on - // the if-else chain instead.) - // For now just clean all the temporaries at the end. - // In practice that's fine. - t = marktemp(order); - orderexpr(&n->ntest, order); - for(l=n->list; l; l=l->next) { - if(l->n->op != OXCASE) - fatal("order switch case %O", l->n->op); - orderexprlistinplace(l->n->list, order); - orderblock(&l->n->nbody); - } - order->out = list(order->out, n); - cleantemp(t, order); - break; - } - - lineno = lno; -} - -// Orderexprlist orders the expression list l into order. -static void -orderexprlist(NodeList *l, Order *order) -{ - for(; l; l=l->next) - orderexpr(&l->n, order); -} - -// Orderexprlist orders the expression list l but saves -// the side effects on the individual expression ninit lists. -static void -orderexprlistinplace(NodeList *l, Order *order) -{ - for(; l; l=l->next) - orderexprinplace(&l->n, order); -} - -// Orderexpr orders a single expression, appending side -// effects to order->out as needed. -static void -orderexpr(Node **np, Order *order) -{ - Node *n; - NodeList *mark, *l; - Type *t; - int lno, haslit, hasbyte; - - n = *np; - if(n == N) - return; - - lno = setlineno(n); - orderinit(n, order); - - switch(n->op) { - default: - orderexpr(&n->left, order); - orderexpr(&n->right, order); - orderexprlist(n->list, order); - orderexprlist(n->rlist, order); - break; - - case OADDSTR: - // Addition of strings turns into a function call. - // Allocate a temporary to hold the strings. - // Fewer than 5 strings use direct runtime helpers. - orderexprlist(n->list, order); - if(count(n->list) > 5) { - t = typ(TARRAY); - t->bound = count(n->list); - t->type = types[TSTRING]; - n->alloc = ordertemp(t, order, 0); - } - - // Mark string(byteSlice) arguments to reuse byteSlice backing - // buffer during conversion. String concatenation does not - // memorize the strings for later use, so it is safe. - // However, we can do it only if there is at least one non-empty string literal. - // Otherwise if all other arguments are empty strings, - // concatstrings will return the reference to the temp string - // to the caller. - hasbyte = 0; - haslit = 0; - for(l=n->list; l != nil; l=l->next) { - hasbyte |= l->n->op == OARRAYBYTESTR; - haslit |= l->n->op == OLITERAL && l->n->val.u.sval->len != 0; - } - if(haslit && hasbyte) { - for(l=n->list; l != nil; l=l->next) { - if(l->n->op == OARRAYBYTESTR) - l->n->op = OARRAYBYTESTRTMP; - } - } - break; - - case OCMPSTR: - orderexpr(&n->left, order); - orderexpr(&n->right, order); - // Mark string(byteSlice) arguments to reuse byteSlice backing - // buffer during conversion. String comparison does not - // memorize the strings for later use, so it is safe. - if(n->left->op == OARRAYBYTESTR) - n->left->op = OARRAYBYTESTRTMP; - if(n->right->op == OARRAYBYTESTR) - n->right->op = OARRAYBYTESTRTMP; - break; - - case OINDEXMAP: - // key must be addressable - orderexpr(&n->left, order); - orderexpr(&n->right, order); - - // For x = m[string(k)] where k is []byte, the allocation of - // backing bytes for the string can be avoided by reusing - // the []byte backing array. This is a special case that it - // would be nice to handle more generally, but because - // there are no []byte-keyed maps, this specific case comes - // up in important cases in practice. See issue 3512. - // Nothing can change the []byte we are not copying before - // the map index, because the map access is going to - // be forced to happen immediately following this - // conversion (by the ordercopyexpr a few lines below). - if(n->etype == 0 && n->right->op == OARRAYBYTESTR) - n->right->op = OARRAYBYTESTRTMP; - - orderaddrtemp(&n->right, order); - if(n->etype == 0) { - // use of value (not being assigned); - // make copy in temporary. - n = ordercopyexpr(n, n->type, order, 0); - } - break; - - case OCONVIFACE: - // concrete type (not interface) argument must be addressable - // temporary to pass to runtime. - orderexpr(&n->left, order); - if(!isinter(n->left->type)) - orderaddrtemp(&n->left, order); - break; - - case OANDAND: - case OOROR: - mark = marktemp(order); - orderexpr(&n->left, order); - // Clean temporaries from first branch at beginning of second. - // Leave them on the stack so that they can be killed in the outer - // context in case the short circuit is taken. - l = nil; - cleantempnopop(mark, order, &l); - n->right->ninit = concat(l, n->right->ninit); - orderexprinplace(&n->right, order); - break; - - case OAPPEND: - case OCALLFUNC: - case OCALLINTER: - case OCALLMETH: - case OCAP: - case OCOMPLEX: - case OCOPY: - case OIMAG: - case OLEN: - case OMAKECHAN: - case OMAKEMAP: - case OMAKESLICE: - case ONEW: - case OREAL: - case ORECOVER: - ordercall(n, order); - n = ordercopyexpr(n, n->type, order, 0); - break; - - case OCLOSURE: - if(n->noescape && n->cvars != nil) - n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type - break; - - case OARRAYLIT: - case OCALLPART: - orderexpr(&n->left, order); - orderexpr(&n->right, order); - orderexprlist(n->list, order); - orderexprlist(n->rlist, order); - if(n->noescape) - n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type - break; - - case ODDDARG: - if(n->noescape) { - // The ddd argument does not live beyond the call it is created for. - // Allocate a temporary that will be cleaned up when this statement - // completes. We could be more aggressive and try to arrange for it - // to be cleaned up when the call completes. - n->alloc = ordertemp(n->type->type, order, 0); - } - break; - - case ORECV: - case ODOTTYPE: - orderexpr(&n->left, order); - n = ordercopyexpr(n, n->type, order, 1); - break; - - case OEQ: - case ONE: - orderexpr(&n->left, order); - orderexpr(&n->right, order); - t = n->left->type; - if(t->etype == TSTRUCT || isfixedarray(t)) { - // for complex comparisons, we need both args to be - // addressable so we can pass them to the runtime. - orderaddrtemp(&n->left, order); - orderaddrtemp(&n->right, order); - } - break; - } - - lineno = lno; - - *np = n; -} diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c deleted file mode 100644 index 16a869181d..0000000000 --- a/src/cmd/gc/pgen.c +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// "Portable" code generation. -// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h. -// Must code to the intersection of the three back ends. - -#include -#include -#include "md5.h" -#include "go.h" -//#include "opt.h" -#include "../../runtime/funcdata.h" -#include "../ld/textflag.h" - -static void allocauto(Prog* p); -static void emitptrargsmap(void); - -static Sym* -makefuncdatasym(char *namefmt, int64 funcdatakind) -{ - Node nod; - Node *pnod; - Sym *sym; - static int32 nsym; - - snprint(namebuf, sizeof(namebuf), namefmt, nsym++); - sym = lookup(namebuf); - pnod = newname(sym); - pnod->class = PEXTERN; - nodconst(&nod, types[TINT32], funcdatakind); - thearch.gins(AFUNCDATA, &nod, pnod); - return sym; -} - -// gvardef inserts a VARDEF for n into the instruction stream. -// VARDEF is an annotation for the liveness analysis, marking a place -// where a complete initialization (definition) of a variable begins. -// Since the liveness analysis can see initialization of single-word -// variables quite easy, gvardef is usually only called for multi-word -// or 'fat' variables, those satisfying isfat(n->type). -// However, gvardef is also called when a non-fat variable is initialized -// via a block move; the only time this happens is when you have -// return f() -// for a function with multiple return values exactly matching the return -// types of the current function. -// -// A 'VARDEF x' annotation in the instruction stream tells the liveness -// analysis to behave as though the variable x is being initialized at that -// point in the instruction stream. The VARDEF must appear before the -// actual (multi-instruction) initialization, and it must also appear after -// any uses of the previous value, if any. For example, if compiling: -// -// x = x[1:] -// -// it is important to generate code like: -// -// base, len, cap = pieces of x[1:] -// VARDEF x -// x = {base, len, cap} -// -// If instead the generated code looked like: -// -// VARDEF x -// base, len, cap = pieces of x[1:] -// x = {base, len, cap} -// -// then the liveness analysis would decide the previous value of x was -// unnecessary even though it is about to be used by the x[1:] computation. -// Similarly, if the generated code looked like: -// -// base, len, cap = pieces of x[1:] -// x = {base, len, cap} -// VARDEF x -// -// then the liveness analysis will not preserve the new value of x, because -// the VARDEF appears to have "overwritten" it. -// -// VARDEF is a bit of a kludge to work around the fact that the instruction -// stream is working on single-word values but the liveness analysis -// wants to work on individual variables, which might be multi-word -// aggregates. It might make sense at some point to look into letting -// the liveness analysis work on single-word values as well, although -// there are complications around interface values, slices, and strings, -// all of which cannot be treated as individual words. -// -// VARKILL is the opposite of VARDEF: it marks a value as no longer needed, -// even if its address has been taken. That is, a VARKILL annotation asserts -// that its argument is certainly dead, for use when the liveness analysis -// would not otherwise be able to deduce that fact. - -static void -gvardefx(Node *n, int as) -{ - if(n == N) - fatal("gvardef nil"); - if(n->op != ONAME) { - yyerror("gvardef %#O; %N", n->op, n); - return; - } - switch(n->class) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - thearch.gins(as, N, n); - } -} - -void -gvardef(Node *n) -{ - gvardefx(n, AVARDEF); -} - -void -gvarkill(Node *n) -{ - gvardefx(n, AVARKILL); -} - -static void -removevardef(Prog *firstp) -{ - Prog *p; - - for(p = firstp; p != P; p = p->link) { - while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL)) - p->link = p->link->link; - if(p->to.type == TYPE_BRANCH) - while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL)) - p->to.u.branch = p->to.u.branch->link; - } -} - -static void -gcsymdup(Sym *s) -{ - LSym *ls; - uint64 lo, hi; - - ls = linksym(s); - if(ls->nr > 0) - fatal("cannot rosymdup %s with relocations", ls->name); - MD5 d; - md5reset(&d); - md5write(&d, ls->p, ls->np); - lo = md5sum(&d, &hi); - ls->name = smprint("gclocals·%016llux%016llux", lo, hi); - ls->dupok = 1; -} - -void -compile(Node *fn) -{ - Plist *pl; - Node nod1, *n; - Prog *ptxt, *p; - int32 lno; - Type *t; - Iter save; - vlong oldstksize; - NodeList *l; - Node *nam; - Sym *gcargs; - Sym *gclocals; - - if(newproc == N) { - newproc = sysfunc("newproc"); - deferproc = sysfunc("deferproc"); - deferreturn = sysfunc("deferreturn"); - panicindex = sysfunc("panicindex"); - panicslice = sysfunc("panicslice"); - throwreturn = sysfunc("throwreturn"); - } - - lno = setlineno(fn); - - curfn = fn; - dowidth(curfn->type); - - if(fn->nbody == nil) { - if(pure_go || strncmp(fn->nname->sym->name, "init.", 5) == 0) { - yyerror("missing function body", fn); - goto ret; - } - if(debug['A']) - goto ret; - emitptrargsmap(); - goto ret; - } - - saveerrors(); - - // set up domain for labels - clearlabels(); - - if(curfn->type->outnamed) { - // add clearing of the output parameters - t = structfirst(&save, getoutarg(curfn->type)); - while(t != T) { - if(t->nname != N) { - n = nod(OAS, t->nname, N); - typecheck(&n, Etop); - curfn->nbody = concat(list1(n), curfn->nbody); - } - t = structnext(&save); - } - } - - order(curfn); - if(nerrors != 0) - goto ret; - - hasdefer = 0; - walk(curfn); - if(nerrors != 0) - goto ret; - if(flag_race) - racewalk(curfn); - if(nerrors != 0) - goto ret; - - continpc = P; - breakpc = P; - - pl = newplist(); - pl->name = linksym(curfn->nname->sym); - - setlineno(curfn); - - nodconst(&nod1, types[TINT32], 0); - nam = curfn->nname; - if(isblank(nam)) - nam = N; - ptxt = thearch.gins(ATEXT, nam, &nod1); - if(fn->dupok) - ptxt->from3.offset |= DUPOK; - if(fn->wrapper) - ptxt->from3.offset |= WRAPPER; - if(fn->needctxt) - ptxt->from3.offset |= NEEDCTXT; - if(fn->nosplit) - ptxt->from3.offset |= NOSPLIT; - - // Clumsy but important. - // See test/recover.go for test cases and src/reflect/value.go - // for the actual functions being considered. - if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) { - if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0) - ptxt->from3.offset |= WRAPPER; - } - - afunclit(&ptxt->from, curfn->nname); - - thearch.ginit(); - - gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps); - gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps); - - for(t=curfn->paramfld; t; t=t->down) - gtrack(tracksym(t->type)); - - for(l=fn->dcl; l; l=l->next) { - n = l->n; - if(n->op != ONAME) // might be OTYPE or OLITERAL - continue; - switch(n->class) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - nodconst(&nod1, types[TUINTPTR], l->n->type->width); - p = thearch.gins(ATYPE, l->n, &nod1); - p->from.gotype = linksym(ngotype(l->n)); - break; - } - } - - genlist(curfn->enter); - genlist(curfn->nbody); - thearch.gclean(); - checklabels(); - if(nerrors != 0) - goto ret; - if(curfn->endlineno) - lineno = curfn->endlineno; - - if(curfn->type->outtuple != 0) - thearch.ginscall(throwreturn, 0); - - thearch.ginit(); - // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? - thearch.cgen_ret(nil); - if(hasdefer) { - // deferreturn pretends to have one uintptr argument. - // Reserve space for it so stack scanner is happy. - if(maxarg < widthptr) - maxarg = widthptr; - } - thearch.gclean(); - if(nerrors != 0) - goto ret; - - pc->as = ARET; // overwrite AEND - pc->lineno = lineno; - - fixjmp(ptxt); - if(!debug['N'] || debug['R'] || debug['P']) { - regopt(ptxt); - nilopt(ptxt); - } - thearch.expandchecks(ptxt); - - oldstksize = stksize; - allocauto(ptxt); - - if(0) - print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize); - USED(oldstksize); - - setlineno(curfn); - if((int64)stksize+maxarg > (1ULL<<31)) { - yyerror("stack frame too large (>2GB)"); - goto ret; - } - - // Emit garbage collection symbols. - liveness(curfn, ptxt, gcargs, gclocals); - gcsymdup(gcargs); - gcsymdup(gclocals); - - thearch.defframe(ptxt); - - if(debug['f']) - frame(0); - - // Remove leftover instrumentation from the instruction stream. - removevardef(ptxt); -ret: - lineno = lno; -} - -static void -emitptrargsmap(void) -{ - int nptr, nbitmap, j, off; - vlong xoffset; - Bvec *bv; - Sym *sym; - - sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name)); - - nptr = curfn->type->argwid / widthptr; - bv = bvalloc(nptr*2); - nbitmap = 1; - if(curfn->type->outtuple > 0) - nbitmap = 2; - off = duint32(sym, 0, nbitmap); - off = duint32(sym, off, bv->n); - if(curfn->type->thistuple > 0) { - xoffset = 0; - twobitwalktype1(getthisx(curfn->type), &xoffset, bv); - } - if(curfn->type->intuple > 0) { - xoffset = 0; - twobitwalktype1(getinargx(curfn->type), &xoffset, bv); - } - for(j = 0; j < bv->n; j += 32) - off = duint32(sym, off, bv->b[j/32]); - if(curfn->type->outtuple > 0) { - xoffset = 0; - twobitwalktype1(getoutargx(curfn->type), &xoffset, bv); - for(j = 0; j < bv->n; j += 32) - off = duint32(sym, off, bv->b[j/32]); - } - ggloblsym(sym, off, RODATA); - free(bv); -} - -// Sort the list of stack variables. Autos after anything else, -// within autos, unused after used, within used, things with -// pointers first, zeroed things first, and then decreasing size. -// Because autos are laid out in decreasing addresses -// on the stack, pointers first, zeroed things first and decreasing size -// really means, in memory, things with pointers needing zeroing at -// the top of the stack and increasing in size. -// Non-autos sort on offset. -static int -cmpstackvar(Node *a, Node *b) -{ - int ap, bp; - - if (a->class != b->class) { - if(a->class == PAUTO) - return +1; - return -1; - } - if (a->class != PAUTO) { - if (a->xoffset < b->xoffset) - return -1; - if (a->xoffset > b->xoffset) - return +1; - return 0; - } - if ((a->used == 0) != (b->used == 0)) - return b->used - a->used; - - ap = haspointers(a->type); - bp = haspointers(b->type); - if(ap != bp) - return bp - ap; - - ap = a->needzero; - bp = b->needzero; - if(ap != bp) - return bp - ap; - - if(a->type->width < b->type->width) - return +1; - if(a->type->width > b->type->width) - return -1; - - return strcmp(a->sym->name, b->sym->name); -} - -// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. -static void -allocauto(Prog* ptxt) -{ - NodeList *ll; - Node* n; - vlong w; - - stksize = 0; - stkptrsize = 0; - - if(curfn->dcl == nil) - return; - - // Mark the PAUTO's unused. - for(ll=curfn->dcl; ll != nil; ll=ll->next) - if (ll->n->class == PAUTO) - ll->n->used = 0; - - markautoused(ptxt); - - listsort(&curfn->dcl, cmpstackvar); - - // Unused autos are at the end, chop 'em off. - ll = curfn->dcl; - n = ll->n; - if (n->class == PAUTO && n->op == ONAME && !n->used) { - // No locals used at all - curfn->dcl = nil; - fixautoused(ptxt); - return; - } - - for(ll = curfn->dcl; ll->next != nil; ll=ll->next) { - n = ll->next->n; - if (n->class == PAUTO && n->op == ONAME && !n->used) { - ll->next = nil; - curfn->dcl->end = ll; - break; - } - } - - // Reassign stack offsets of the locals that are still there. - for(ll = curfn->dcl; ll != nil; ll=ll->next) { - n = ll->n; - if (n->class != PAUTO || n->op != ONAME) - continue; - - dowidth(n->type); - w = n->type->width; - if(w >= thearch.MAXWIDTH || w < 0) - fatal("bad width"); - stksize += w; - stksize = rnd(stksize, n->type->align); - if(haspointers(n->type)) - stkptrsize = stksize; - if(thearch.thechar == '5' || thearch.thechar == '9') - stksize = rnd(stksize, widthptr); - if(stksize >= (1ULL<<31)) { - setlineno(curfn); - yyerror("stack frame too large (>2GB)"); - } - n->stkdelta = -stksize - n->xoffset; - } - stksize = rnd(stksize, widthreg); - stkptrsize = rnd(stkptrsize, widthreg); - - fixautoused(ptxt); - - // The debug information needs accurate offsets on the symbols. - for(ll = curfn->dcl; ll != nil; ll=ll->next) { - if (ll->n->class != PAUTO || ll->n->op != ONAME) - continue; - ll->n->xoffset += ll->n->stkdelta; - ll->n->stkdelta = 0; - } -} - -static void movelargefn(Node*); - -void -movelarge(NodeList *l) -{ - for(; l; l=l->next) - if(l->n->op == ODCLFUNC) - movelargefn(l->n); -} - -static void -movelargefn(Node *fn) -{ - NodeList *l; - Node *n; - - for(l=fn->dcl; l != nil; l=l->next) { - n = l->n; - if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize) - addrescapes(n); - } -} - -void -cgen_checknil(Node *n) -{ - Node reg; - - if(disable_checknil) - return; - // Ideally we wouldn't see any integer types here, but we do. - if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) { - dump("checknil", n); - fatal("bad checknil"); - } - if(((thearch.thechar == '5' || thearch.thechar == '9') && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) { - thearch.regalloc(®, types[tptr], n); - thearch.cgen(n, ®); - thearch.gins(ACHECKNIL, ®, N); - thearch.regfree(®); - return; - } - thearch.gins(ACHECKNIL, n, N); -} diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c deleted file mode 100644 index c0d1e57932..0000000000 --- a/src/cmd/gc/plive.c +++ /dev/null @@ -1,2005 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Garbage collector liveness bitmap generation. - -// The command line flag -live causes this code to print debug information. -// The levels are: -// -// -live (aka -live=1): print liveness lists as code warnings at safe points -// -live=2: print an assembly listing with liveness annotations -// -live=3: print information during each computation phase (much chattier) -// -// Each level includes the earlier output as well. - -#include -#include -#include "go.h" -#include "../ld/textflag.h" -#include "../../runtime/funcdata.h" -#include "../../runtime/mgc0.h" - -enum { - UNVISITED = 0, - VISITED = 1, -}; - -// An ordinary basic block. -// -// Instructions are threaded together in a doubly-linked list. To iterate in -// program order follow the link pointer from the first node and stop after the -// last node has been visited -// -// for(p = bb->first;; p = p->link) { -// ... -// if(p == bb->last) -// break; -// } -// -// To iterate in reverse program order by following the opt pointer from the -// last node -// -// for(p = bb->last; p != nil; p = p->opt) { -// ... -// } -typedef struct BasicBlock BasicBlock; -struct BasicBlock { - // An array of preceding blocks. If the length of this array is 0 the - // block is probably the start block of the CFG. - Array *pred; - - // An array out succeeding blocks. If the length of this array is zero, - // the block probably ends in a return instruction. - Array *succ; - - // First instruction in the block. When part of a fully initialized - // control flow graph, the opt member will be nil. - Prog *first; - - // Last instruction in the basic block. - Prog *last; - - // The reverse post order number. This value is initialized to -1 and - // will be replaced by a non-negative value when the CFG is constructed. - // After CFG construction, if rpo is -1 this block is unreachable. - int rpo; - - // State to denote whether the block has been visited during a - // traversal. - int mark; - - // For use during livenessepilogue. - int lastbitmapindex; -}; - -// A collection of global state used by liveness analysis. -typedef struct Liveness Liveness; -struct Liveness { - // A pointer to the node corresponding to the function being analyzed. - Node *fn; - - // A linked list of instructions for this function. - Prog *ptxt; - - // A list of arguments and local variables in this function. - Array *vars; - - // A list of basic blocks that are overlayed on the instruction list. - // The blocks are roughly in the same order as the instructions - // in the function (first block has TEXT instruction, and so on). - Array *cfg; - - // Summary sets of block effects. - // The Bvec** is indexed by bb->rpo to yield a single Bvec*. - // That bit vector is indexed by variable number (same as lv->vars). - // - // Computed during livenessprologue using only the content of - // individual blocks: - // - // uevar: upward exposed variables (used before set in block) - // varkill: killed variables (set in block) - // avarinit: addrtaken variables set or used (proof of initialization) - // - // Computed during livenesssolve using control flow information: - // - // livein: variables live at block entry - // liveout: variables live at block exit - // avarinitany: addrtaken variables possibly initialized at block exit - // (initialized in block or at exit from any predecessor block) - // avarinitall: addrtaken variables certainly initialized at block exit - // (initialized in block or at exit from all predecessor blocks) - Bvec **uevar; - Bvec **varkill; - Bvec **livein; - Bvec **liveout; - Bvec **avarinit; - Bvec **avarinitany; - Bvec **avarinitall; - - // An array with a bit vector for each safe point tracking live pointers - // in the arguments and locals area, indexed by bb->rpo. - Array *argslivepointers; - Array *livepointers; -}; - -static void* -xmalloc(uintptr size) -{ - void *result; - - result = malloc(size); - if(result == nil) - fatal("malloc failed"); - return result; -} - -// Constructs a new basic block containing a single instruction. -static BasicBlock* -newblock(Prog *prog) -{ - BasicBlock *result; - - if(prog == nil) - fatal("newblock: prog cannot be nil"); - result = xmalloc(sizeof(*result)); - result->rpo = -1; - result->mark = UNVISITED; - result->first = prog; - result->last = prog; - result->pred = arraynew(2, sizeof(BasicBlock*)); - result->succ = arraynew(2, sizeof(BasicBlock*)); - return result; -} - -// Frees a basic block and all of its leaf data structures. -static void -freeblock(BasicBlock *bb) -{ - if(bb == nil) - fatal("freeblock: cannot free nil"); - arrayfree(bb->pred); - arrayfree(bb->succ); - free(bb); -} - -// Adds an edge between two basic blocks by making from a predecessor of to and -// to a successor of from. -static void -addedge(BasicBlock *from, BasicBlock *to) -{ - if(from == nil) - fatal("addedge: from is nil"); - if(to == nil) - fatal("addedge: to is nil"); - arrayadd(from->succ, &to); - arrayadd(to->pred, &from); -} - -// Inserts prev before curr in the instruction -// stream. Any control flow, such as branches or fall throughs, that target the -// existing instruction are adjusted to target the new instruction. -static void -splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr) -{ - Prog *next, tmp; - - USED(lv); - - // There may be other instructions pointing at curr, - // and we want them to now point at prev. Instead of - // trying to find all such instructions, swap the contents - // so that the problem becomes inserting next after curr. - // The "opt" field is the backward link in the linked list. - - // Overwrite curr's data with prev, but keep the list links. - tmp = *curr; - *curr = *prev; - curr->opt = tmp.opt; - curr->link = tmp.link; - - // Overwrite prev (now next) with curr's old data. - next = prev; - *next = tmp; - next->opt = nil; - next->link = nil; - - // Now insert next after curr. - next->link = curr->link; - next->opt = curr; - curr->link = next; - if(next->link && next->link->opt == curr) - next->link->opt = next; - - if(bb->last == curr) - bb->last = next; -} - -// A pretty printer for basic blocks. -static void -printblock(BasicBlock *bb) -{ - BasicBlock *pred; - BasicBlock *succ; - Prog *prog; - int i; - - print("basic block %d\n", bb->rpo); - print("\tpred:"); - for(i = 0; i < arraylength(bb->pred); i++) { - pred = *(BasicBlock**)arrayget(bb->pred, i); - print(" %d", pred->rpo); - } - print("\n"); - print("\tsucc:"); - for(i = 0; i < arraylength(bb->succ); i++) { - succ = *(BasicBlock**)arrayget(bb->succ, i); - print(" %d", succ->rpo); - } - print("\n"); - print("\tprog:\n"); - for(prog = bb->first;; prog=prog->link) { - print("\t\t%P\n", prog); - if(prog == bb->last) - break; - } -} - - -// Iterates over a basic block applying a callback to each instruction. There -// are two criteria for termination. If the end of basic block is reached a -// value of zero is returned. If the callback returns a non-zero value, the -// iteration is stopped and the value of the callback is returned. -static int -blockany(BasicBlock *bb, int (*callback)(Prog*)) -{ - Prog *p; - int result; - - for(p = bb->last; p != nil; p = p->opt) { - result = (*callback)(p); - if(result != 0) - return result; - } - return 0; -} - -// Collects and returns and array of Node*s for functions arguments and local -// variables. -static Array* -getvariables(Node *fn) -{ - Array *result; - NodeList *ll; - - result = arraynew(0, sizeof(Node*)); - for(ll = fn->dcl; ll != nil; ll = ll->next) { - if(ll->n->op == ONAME) { - // In order for GODEBUG=gcdead=1 to work, each bitmap needs - // to contain information about all variables covered by the bitmap. - // For local variables, the bitmap only covers the stkptrsize - // bytes in the frame where variables containing pointers live. - // For arguments and results, the bitmap covers all variables, - // so we must include all the variables, even the ones without - // pointers. - // - // The Node.opt field is available for use by optimization passes. - // We use it to hold the index of the node in the variables array, plus 1 - // (so that 0 means the Node is not in the variables array). - // Each pass should clear opt when done, but you never know, - // so clear them all ourselves too. - // The Node.curfn field is supposed to be set to the current function - // already, but for some compiler-introduced names it seems not to be, - // so fix that here. - // Later, when we want to find the index of a node in the variables list, - // we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1 - // is the index in the variables list. - ll->n->opt = nil; - ll->n->curfn = curfn; - switch(ll->n->class) { - case PAUTO: - if(haspointers(ll->n->type)) { - ll->n->opt = (void*)(uintptr)(arraylength(result)+1); - arrayadd(result, &ll->n); - } - break; - case PPARAM: - case PPARAMOUT: - ll->n->opt = (void*)(uintptr)(arraylength(result)+1); - arrayadd(result, &ll->n); - break; - } - } - } - return result; -} - -// A pretty printer for control flow graphs. Takes an array of BasicBlock*s. -static void -printcfg(Array *cfg) -{ - BasicBlock *bb; - int32 i; - - for(i = 0; i < arraylength(cfg); i++) { - bb = *(BasicBlock**)arrayget(cfg, i); - printblock(bb); - } -} - -// Assigns a reverse post order number to each connected basic block using the -// standard algorithm. Unconnected blocks will not be affected. -static void -reversepostorder(BasicBlock *root, int32 *rpo) -{ - BasicBlock *bb; - int i; - - root->mark = VISITED; - for(i = 0; i < arraylength(root->succ); i++) { - bb = *(BasicBlock**)arrayget(root->succ, i); - if(bb->mark == UNVISITED) - reversepostorder(bb, rpo); - } - *rpo -= 1; - root->rpo = *rpo; -} - -// Comparison predicate used for sorting basic blocks by their rpo in ascending -// order. -static int -blockrpocmp(const void *p1, const void *p2) -{ - BasicBlock *bb1; - BasicBlock *bb2; - - bb1 = *(BasicBlock**)p1; - bb2 = *(BasicBlock**)p2; - if(bb1->rpo < bb2->rpo) - return -1; - if(bb1->rpo > bb2->rpo) - return 1; - return 0; -} - -// A pattern matcher for call instructions. Returns true when the instruction -// is a call to a specific package qualified function name. -static int -iscall(Prog *prog, LSym *name) -{ - if(prog == nil) - fatal("iscall: prog is nil"); - if(name == nil) - fatal("iscall: function name is nil"); - if(prog->as != ACALL) - return 0; - return name == prog->to.sym; -} - -// Returns true for instructions that call a runtime function implementing a -// select communication clause. -static int -isselectcommcasecall(Prog *prog) -{ - static LSym* names[5]; - int32 i; - - if(names[0] == nil) { - names[0] = linksym(pkglookup("selectsend", runtimepkg)); - names[1] = linksym(pkglookup("selectrecv", runtimepkg)); - names[2] = linksym(pkglookup("selectrecv2", runtimepkg)); - names[3] = linksym(pkglookup("selectdefault", runtimepkg)); - } - for(i = 0; names[i] != nil; i++) - if(iscall(prog, names[i])) - return 1; - return 0; -} - -// Returns true for call instructions that target runtime·newselect. -static int -isnewselect(Prog *prog) -{ - static LSym *sym; - - if(sym == nil) - sym = linksym(pkglookup("newselect", runtimepkg)); - return iscall(prog, sym); -} - -// Returns true for call instructions that target runtime·selectgo. -static int -isselectgocall(Prog *prog) -{ - static LSym *sym; - - if(sym == nil) - sym = linksym(pkglookup("selectgo", runtimepkg)); - return iscall(prog, sym); -} - -static int -isdeferreturn(Prog *prog) -{ - static LSym *sym; - - if(sym == nil) - sym = linksym(pkglookup("deferreturn", runtimepkg)); - return iscall(prog, sym); -} - -// Walk backwards from a runtime·selectgo call up to its immediately dominating -// runtime·newselect call. Any successor nodes of communication clause nodes -// are implicit successors of the runtime·selectgo call node. The goal of this -// analysis is to add these missing edges to complete the control flow graph. -static void -addselectgosucc(BasicBlock *selectgo) -{ - BasicBlock *pred; - BasicBlock *succ; - - pred = selectgo; - for(;;) { - if(arraylength(pred->pred) == 0) - fatal("selectgo does not have a newselect"); - pred = *(BasicBlock**)arrayget(pred->pred, 0); - if(blockany(pred, isselectcommcasecall)) { - // A select comm case block should have exactly one - // successor. - if(arraylength(pred->succ) != 1) - fatal("select comm case has too many successors"); - succ = *(BasicBlock**)arrayget(pred->succ, 0); - // Its successor should have exactly two successors. - // The drop through should flow to the selectgo block - // and the branch should lead to the select case - // statements block. - if(arraylength(succ->succ) != 2) - fatal("select comm case successor has too many successors"); - // Add the block as a successor of the selectgo block. - addedge(selectgo, succ); - } - if(blockany(pred, isnewselect)) { - // Reached the matching newselect. - break; - } - } -} - -// The entry point for the missing selectgo control flow algorithm. Takes an -// array of BasicBlock*s containing selectgo calls. -static void -fixselectgo(Array *selectgo) -{ - BasicBlock *bb; - int32 i; - - for(i = 0; i < arraylength(selectgo); i++) { - bb = *(BasicBlock**)arrayget(selectgo, i); - addselectgosucc(bb); - } -} - -// Constructs a control flow graph from a sequence of instructions. This -// procedure is complicated by various sources of implicit control flow that are -// not accounted for using the standard cfg construction algorithm. Returns an -// array of BasicBlock*s in control flow graph form (basic blocks ordered by -// their RPO number). -static Array* -newcfg(Prog *firstp) -{ - Prog *p; - Prog *prev; - BasicBlock *bb; - Array *cfg; - Array *selectgo; - int32 i; - int32 rpo; - - // Reset the opt field of each prog to nil. In the first and second - // passes, instructions that are labels temporarily use the opt field to - // point to their basic block. In the third pass, the opt field reset - // to point to the predecessor of an instruction in its basic block. - for(p = firstp; p != P; p = p->link) - p->opt = nil; - - // Allocate an array to remember where we have seen selectgo calls. - // These blocks will be revisited to add successor control flow edges. - selectgo = arraynew(0, sizeof(BasicBlock*)); - - // Loop through all instructions identifying branch targets - // and fall-throughs and allocate basic blocks. - cfg = arraynew(0, sizeof(BasicBlock*)); - bb = newblock(firstp); - arrayadd(cfg, &bb); - for(p = firstp; p != P; p = p->link) { - if(p->to.type == TYPE_BRANCH) { - if(p->to.u.branch == nil) - fatal("prog branch to nil"); - if(p->to.u.branch->opt == nil) { - p->to.u.branch->opt = newblock(p->to.u.branch); - arrayadd(cfg, &p->to.u.branch->opt); - } - if(p->as != AJMP && p->link != nil && p->link->opt == nil) { - p->link->opt = newblock(p->link); - arrayadd(cfg, &p->link->opt); - } - } else if(isselectcommcasecall(p) || isselectgocall(p)) { - // Accommodate implicit selectgo control flow. - if(p->link->opt == nil) { - p->link->opt = newblock(p->link); - arrayadd(cfg, &p->link->opt); - } - } - } - - // Loop through all basic blocks maximally growing the list of - // contained instructions until a label is reached. Add edges - // for branches and fall-through instructions. - for(i = 0; i < arraylength(cfg); i++) { - bb = *(BasicBlock**)arrayget(cfg, i); - for(p = bb->last; p != nil; p = p->link) { - if(p->opt != nil && p != bb->last) - break; - bb->last = p; - - // Stop before an unreachable RET, to avoid creating - // unreachable control flow nodes. - if(p->link != nil && p->link->as == ARET && p->link->mode == 1) - break; - - // Collect basic blocks with selectgo calls. - if(isselectgocall(p)) - arrayadd(selectgo, &bb); - } - if(bb->last->to.type == TYPE_BRANCH) - addedge(bb, bb->last->to.u.branch->opt); - if(bb->last->link != nil) { - // Add a fall-through when the instruction is - // not an unconditional control transfer. - if(bb->last->as != AJMP && bb->last->as != ARET && bb->last->as != AUNDEF) - addedge(bb, bb->last->link->opt); - } - } - - // Add back links so the instructions in a basic block can be traversed - // backward. This is the final state of the instruction opt field. - for(i = 0; i < arraylength(cfg); i++) { - bb = *(BasicBlock**)arrayget(cfg, i); - p = bb->first; - prev = nil; - for(;;) { - p->opt = prev; - if(p == bb->last) - break; - prev = p; - p = p->link; - } - } - - // Add missing successor edges to the selectgo blocks. - if(arraylength(selectgo)) - fixselectgo(selectgo); - arrayfree(selectgo); - - // Find a depth-first order and assign a depth-first number to - // all basic blocks. - for(i = 0; i < arraylength(cfg); i++) { - bb = *(BasicBlock**)arrayget(cfg, i); - bb->mark = UNVISITED; - } - bb = *(BasicBlock**)arrayget(cfg, 0); - rpo = arraylength(cfg); - reversepostorder(bb, &rpo); - - // Sort the basic blocks by their depth first number. The - // array is now a depth-first spanning tree with the first - // node being the root. - arraysort(cfg, blockrpocmp); - bb = *(BasicBlock**)arrayget(cfg, 0); - - // Unreachable control flow nodes are indicated by a -1 in the rpo - // field. If we see these nodes something must have gone wrong in an - // upstream compilation phase. - if(bb->rpo == -1) { - print("newcfg: unreachable basic block for %P\n", bb->last); - printcfg(cfg); - fatal("newcfg: invalid control flow graph"); - } - - return cfg; -} - -// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf -// data structures. -static void -freecfg(Array *cfg) -{ - BasicBlock *bb; - BasicBlock *bb0; - Prog *p; - int32 i; - int32 n; - - n = arraylength(cfg); - if(n > 0) { - bb0 = *(BasicBlock**)arrayget(cfg, 0); - for(p = bb0->first; p != P; p = p->link) { - p->opt = nil; - } - for(i = 0; i < n; i++) { - bb = *(BasicBlock**)arrayget(cfg, i); - freeblock(bb); - } - } - arrayfree(cfg); -} - -// Returns true if the node names a variable that is otherwise uninteresting to -// the liveness computation. -static int -isfunny(Node *node) -{ - char *names[] = { ".fp", ".args", nil }; - int i; - - if(node->sym != nil && node->sym->name != nil) - for(i = 0; names[i] != nil; i++) - if(strcmp(node->sym->name, names[i]) == 0) - return 1; - return 0; -} - -// Computes the effects of an instruction on a set of -// variables. The vars argument is an array of Node*s. -// -// The output vectors give bits for variables: -// uevar - used by this instruction -// varkill - killed by this instruction -// for variables without address taken, means variable was set -// for variables with address taken, means variable was marked dead -// avarinit - initialized or referred to by this instruction, -// only for variables with address taken but not escaping to heap -// -// The avarinit output serves as a signal that the data has been -// initialized, because any use of a variable must come after its -// initialization. -static void -progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit) -{ - ProgInfo info; - Addr *from; - Addr *to; - Node *node; - int32 i; - int32 pos; - - bvresetall(uevar); - bvresetall(varkill); - bvresetall(avarinit); - - thearch.proginfo(&info, prog); - if(prog->as == ARET) { - // Return instructions implicitly read all the arguments. For - // the sake of correctness, out arguments must be read. For the - // sake of backtrace quality, we read in arguments as well. - // - // A return instruction with a p->to is a tail return, which brings - // the stack pointer back up (if it ever went down) and then jumps - // to a new function entirely. That form of instruction must read - // all the parameters for correctness, and similarly it must not - // read the out arguments - they won't be set until the new - // function runs. - for(i = 0; i < arraylength(vars); i++) { - node = *(Node**)arrayget(vars, i); - switch(node->class & ~PHEAP) { - case PPARAM: - bvset(uevar, i); - break; - case PPARAMOUT: - // If the result had its address taken, it is being tracked - // by the avarinit code, which does not use uevar. - // If we added it to uevar too, we'd not see any kill - // and decide that the varible was live entry, which it is not. - // So only use uevar in the non-addrtaken case. - // The p->to.type == thearch.D_NONE limits the bvset to - // non-tail-call return instructions; see note above - // the for loop for details. - if(!node->addrtaken && prog->to.type == TYPE_NONE) - bvset(uevar, i); - break; - } - } - return; - } - if(prog->as == ATEXT) { - // A text instruction marks the entry point to a function and - // the definition point of all in arguments. - for(i = 0; i < arraylength(vars); i++) { - node = *(Node**)arrayget(vars, i); - switch(node->class & ~PHEAP) { - case PPARAM: - if(node->addrtaken) - bvset(avarinit, i); - bvset(varkill, i); - break; - } - } - return; - } - if(info.flags & (LeftRead | LeftWrite | LeftAddr)) { - from = &prog->from; - if (from->node != nil && from->sym != nil && ((Node*)(from->node))->curfn == curfn) { - switch(((Node*)(from->node))->class & ~PHEAP) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - pos = (int)(uintptr)((Node*)(from->node))->opt - 1; // index in vars - if(pos == -1) - goto Next; - if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != from->node) - fatal("bad bookkeeping in liveness %N %d", from->node, pos); - if(((Node*)(from->node))->addrtaken) { - bvset(avarinit, pos); - } else { - if(info.flags & (LeftRead | LeftAddr)) - bvset(uevar, pos); - if(info.flags & LeftWrite) - if(from->node != nil && !isfat(((Node*)(from->node))->type)) - bvset(varkill, pos); - } - } - } - } -Next: - if(info.flags & (RightRead | RightWrite | RightAddr)) { - to = &prog->to; - if (to->node != nil && to->sym != nil && ((Node*)(to->node))->curfn == curfn) { - switch(((Node*)(to->node))->class & ~PHEAP) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - pos = (int)(uintptr)((Node*)(to->node))->opt - 1; // index in vars - if(pos == -1) - goto Next1; - if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node) - fatal("bad bookkeeping in liveness %N %d", to->node, pos); - if(((Node*)(to->node))->addrtaken) { - if(prog->as != AVARKILL) - bvset(avarinit, pos); - if(prog->as == AVARDEF || prog->as == AVARKILL) - bvset(varkill, pos); - } else { - // RightRead is a read, obviously. - // RightAddr by itself is also implicitly a read. - // - // RightAddr|RightWrite means that the address is being taken - // but only so that the instruction can write to the value. - // It is not a read. It is equivalent to RightWrite except that - // having the RightAddr bit set keeps the registerizer from - // trying to substitute a register for the memory location. - if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr) - bvset(uevar, pos); - if(info.flags & RightWrite) - if(to->node != nil && (!isfat(((Node*)(to->node))->type) || prog->as == AVARDEF)) - bvset(varkill, pos); - } - } - } - } -Next1:; -} - -// Constructs a new liveness structure used to hold the global state of the -// liveness computation. The cfg argument is an array of BasicBlock*s and the -// vars argument is an array of Node*s. -static Liveness* -newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars) -{ - Liveness *result; - int32 i; - int32 nblocks; - int32 nvars; - - result = xmalloc(sizeof(*result)); - result->fn = fn; - result->ptxt = ptxt; - result->cfg = cfg; - result->vars = vars; - - nblocks = arraylength(cfg); - result->uevar = xmalloc(sizeof(Bvec*) * nblocks); - result->varkill = xmalloc(sizeof(Bvec*) * nblocks); - result->livein = xmalloc(sizeof(Bvec*) * nblocks); - result->liveout = xmalloc(sizeof(Bvec*) * nblocks); - result->avarinit = xmalloc(sizeof(Bvec*) * nblocks); - result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks); - result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks); - - nvars = arraylength(vars); - for(i = 0; i < nblocks; i++) { - result->uevar[i] = bvalloc(nvars); - result->varkill[i] = bvalloc(nvars); - result->livein[i] = bvalloc(nvars); - result->liveout[i] = bvalloc(nvars); - result->avarinit[i] = bvalloc(nvars); - result->avarinitany[i] = bvalloc(nvars); - result->avarinitall[i] = bvalloc(nvars); - } - - result->livepointers = arraynew(0, sizeof(Bvec*)); - result->argslivepointers = arraynew(0, sizeof(Bvec*)); - return result; -} - -// Frees the liveness structure and all of its leaf data structures. -static void -freeliveness(Liveness *lv) -{ - int32 i; - - if(lv == nil) - fatal("freeliveness: cannot free nil"); - - for(i = 0; i < arraylength(lv->livepointers); i++) - free(*(Bvec**)arrayget(lv->livepointers, i)); - arrayfree(lv->livepointers); - - for(i = 0; i < arraylength(lv->argslivepointers); i++) - free(*(Bvec**)arrayget(lv->argslivepointers, i)); - arrayfree(lv->argslivepointers); - - for(i = 0; i < arraylength(lv->cfg); i++) { - free(lv->uevar[i]); - free(lv->varkill[i]); - free(lv->livein[i]); - free(lv->liveout[i]); - free(lv->avarinit[i]); - free(lv->avarinitany[i]); - free(lv->avarinitall[i]); - } - - free(lv->uevar); - free(lv->varkill); - free(lv->livein); - free(lv->liveout); - free(lv->avarinit); - free(lv->avarinitany); - free(lv->avarinitall); - - free(lv); -} - -static void -printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit) -{ - print("effects of %P", p); - print("\nuevar: "); - bvprint(uevar); - print("\nvarkill: "); - bvprint(varkill); - print("\navarinit: "); - bvprint(avarinit); - print("\n"); -} - -// Pretty print a variable node. Uses Pascal like conventions for pointers and -// addresses to avoid confusing the C like conventions used in the node variable -// names. -static void -printnode(Node *node) -{ - char *p; - char *a; - - p = ""; - if(haspointers(node->type)) - p = "^"; - a = ""; - if(node->addrtaken) - a = "@"; - print(" %N%s%s", node, p, a); -} - -// Pretty print a list of variables. The vars argument is an array of Node*s. -static void -printvars(char *name, Bvec *bv, Array *vars) -{ - int32 i; - - print("%s:", name); - for(i = 0; i < arraylength(vars); i++) - if(bvget(bv, i)) - printnode(*(Node**)arrayget(vars, i)); - print("\n"); -} - -// Prints a basic block annotated with the information computed by liveness -// analysis. -static void -livenessprintblock(Liveness *lv, BasicBlock *bb) -{ - BasicBlock *pred; - BasicBlock *succ; - Prog *prog; - Bvec *live; - int i; - int32 pos; - - print("basic block %d\n", bb->rpo); - - print("\tpred:"); - for(i = 0; i < arraylength(bb->pred); i++) { - pred = *(BasicBlock**)arrayget(bb->pred, i); - print(" %d", pred->rpo); - } - print("\n"); - - print("\tsucc:"); - for(i = 0; i < arraylength(bb->succ); i++) { - succ = *(BasicBlock**)arrayget(bb->succ, i); - print(" %d", succ->rpo); - } - print("\n"); - - printvars("\tuevar", lv->uevar[bb->rpo], lv->vars); - printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars); - printvars("\tlivein", lv->livein[bb->rpo], lv->vars); - printvars("\tliveout", lv->liveout[bb->rpo], lv->vars); - printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars); - printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars); - printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars); - - print("\tprog:\n"); - for(prog = bb->first;; prog = prog->link) { - print("\t\t%P", prog); - if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) { - pos = prog->to.offset; - live = *(Bvec**)arrayget(lv->livepointers, pos); - print(" "); - bvprint(live); - } - print("\n"); - if(prog == bb->last) - break; - } -} - -// Prints a control flow graph annotated with any information computed by -// liveness analysis. -static void -livenessprintcfg(Liveness *lv) -{ - BasicBlock *bb; - int32 i; - - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - livenessprintblock(lv, bb); - } -} - -static void -checkauto(Node *fn, Prog *p, Node *n) -{ - NodeList *l; - - for(l = fn->dcl; l != nil; l = l->next) - if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n) - return; - - if(n == nil) { - print("%L: checkauto %N: nil node in %P\n", p->lineno, curfn, p); - return; - } - print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p); - for(l = fn->dcl; l != nil; l = l->next) - print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class); - yyerror("checkauto: invariant lost"); -} - -static void -checkparam(Node *fn, Prog *p, Node *n) -{ - NodeList *l; - Node *a; - int class; - - if(isfunny(n)) - return; - for(l = fn->dcl; l != nil; l = l->next) { - a = l->n; - class = a->class & ~PHEAP; - if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n) - return; - } - - print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p); - for(l = fn->dcl; l != nil; l = l->next) - print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class); - yyerror("checkparam: invariant lost"); -} - -static void -checkprog(Node *fn, Prog *p) -{ - if(p->from.name == NAME_AUTO) - checkauto(fn, p, p->from.node); - if(p->from.name == NAME_PARAM) - checkparam(fn, p, p->from.node); - if(p->to.name == NAME_AUTO) - checkauto(fn, p, p->to.node); - if(p->to.name == NAME_PARAM) - checkparam(fn, p, p->to.node); -} - -// Check instruction invariants. We assume that the nodes corresponding to the -// sources and destinations of memory operations will be declared in the -// function. This is not strictly true, as is the case for the so-called funny -// nodes and there are special cases to skip over that stuff. The analysis will -// fail if this invariant blindly changes. -static void -checkptxt(Node *fn, Prog *firstp) -{ - Prog *p; - - if(debuglive == 0) - return; - - for(p = firstp; p != P; p = p->link) { - if(0) - print("analyzing '%P'\n", p); - if(p->as != ADATA && p->as != AGLOBL && p->as != ATYPE) - checkprog(fn, p); - } -} - -// NOTE: The bitmap for a specific type t should be cached in t after the first run -// and then simply copied into bv at the correct offset on future calls with -// the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1 -// accounts for 40% of the 6g execution time. -void -twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv) -{ - vlong fieldoffset; - vlong i; - vlong o; - Type *t1; - - if(t->align > 0 && (*xoffset & (t->align - 1)) != 0) - fatal("twobitwalktype1: invalid initial alignment, %T", t); - - switch(t->etype) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TBOOL: - case TFLOAT32: - case TFLOAT64: - case TCOMPLEX64: - case TCOMPLEX128: - for(i = 0; i < t->width; i++) { - bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar (BitsScalar) - } - *xoffset += t->width; - break; - - case TPTR32: - case TPTR64: - case TUNSAFEPTR: - case TFUNC: - case TCHAN: - case TMAP: - if((*xoffset & (widthptr-1)) != 0) - fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr (BitsPointer) - *xoffset += t->width; - break; - - case TSTRING: - // struct { byte *str; intgo len; } - if((*xoffset & (widthptr-1)) != 0) - fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) - *xoffset += t->width; - break; - - case TINTER: - // struct { Itab *tab; union { void *ptr, uintptr val } data; } - // or, when isnilinter(t)==true: - // struct { Type *type; union { void *ptr, uintptr val } data; } - if((*xoffset & (widthptr-1)) != 0) - fatal("twobitwalktype1: invalid alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 3); // 2 = live ptr in second slot (BitsPointer) - *xoffset += t->width; - break; - - case TARRAY: - // The value of t->bound is -1 for slices types and >0 for - // for fixed array types. All other values are invalid. - if(t->bound < -1) - fatal("twobitwalktype1: invalid bound, %T", t); - if(isslice(t)) { - // struct { byte *array; uintgo len; uintgo cap; } - if((*xoffset & (widthptr-1)) != 0) - fatal("twobitwalktype1: invalid TARRAY alignment, %T", t); - bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot (BitsPointer) - *xoffset += t->width; - } else - for(i = 0; i < t->bound; i++) - twobitwalktype1(t->type, xoffset, bv); - break; - - case TSTRUCT: - o = 0; - for(t1 = t->type; t1 != T; t1 = t1->down) { - fieldoffset = t1->width; - *xoffset += fieldoffset - o; - twobitwalktype1(t1->type, xoffset, bv); - o = fieldoffset + t1->type->width; - } - *xoffset += t->width - o; - break; - - default: - fatal("twobitwalktype1: unexpected type, %T", t); - } -} - -// Returns the number of words of local variables. -static int32 -localswords(void) -{ - return stkptrsize / widthptr; -} - -// Returns the number of words of in and out arguments. -static int32 -argswords(void) -{ - return curfn->type->argwid / widthptr; -} - -// Generates live pointer value maps for arguments and local variables. The -// this argument and the in arguments are always assumed live. The vars -// argument is an array of Node*s. -static void -twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals) -{ - Node *node; - Type *thisargtype; - Type *inargtype; - vlong xoffset; - int32 i; - - for(i = 0; (i = bvnext(liveout, i)) >= 0; i++) { - node = *(Node**)arrayget(vars, i); - switch(node->class) { - case PAUTO: - xoffset = node->xoffset + stkptrsize; - twobitwalktype1(node->type, &xoffset, locals); - break; - case PPARAM: - case PPARAMOUT: - xoffset = node->xoffset; - twobitwalktype1(node->type, &xoffset, args); - break; - } - } - - // The node list only contains declared names. - // If the receiver or arguments are unnamed, they will be omitted - // from the list above. Preserve those values - even though they are unused - - // in order to keep their addresses live for use in stack traces. - thisargtype = getthisx(lv->fn->type); - if(thisargtype != nil) { - xoffset = 0; - twobitwalktype1(thisargtype, &xoffset, args); - } - inargtype = getinargx(lv->fn->type); - if(inargtype != nil) { - xoffset = 0; - twobitwalktype1(inargtype, &xoffset, args); - } -} - -// Construct a disembodied instruction. -static Prog* -unlinkedprog(int as) -{ - Prog *p; - - p = mal(sizeof(*p)); - clearp(p); - p->as = as; - return p; -} - -// Construct a new PCDATA instruction associated with and for the purposes of -// covering an existing instruction. -static Prog* -newpcdataprog(Prog *prog, int32 index) -{ - Node from, to; - Prog *pcdata; - - nodconst(&from, types[TINT32], PCDATA_StackMapIndex); - nodconst(&to, types[TINT32], index); - pcdata = unlinkedprog(APCDATA); - pcdata->lineno = prog->lineno; - naddr(&from, &pcdata->from, 0); - naddr(&to, &pcdata->to, 0); - return pcdata; -} - -// Returns true for instructions that are safe points that must be annotated -// with liveness information. -static int -issafepoint(Prog *prog) -{ - return prog->as == ATEXT || prog->as == ACALL; -} - -// Initializes the sets for solving the live variables. Visits all the -// instructions in each basic block to summarizes the information at each basic -// block -static void -livenessprologue(Liveness *lv) -{ - BasicBlock *bb; - Bvec *uevar, *varkill, *avarinit; - Prog *p; - int32 i; - int32 nvars; - - nvars = arraylength(lv->vars); - uevar = bvalloc(nvars); - varkill = bvalloc(nvars); - avarinit = bvalloc(nvars); - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - // Walk the block instructions backward and update the block - // effects with the each prog effects. - for(p = bb->last; p != nil; p = p->opt) { - progeffects(p, lv->vars, uevar, varkill, avarinit); - if(debuglive >= 3) - printeffects(p, uevar, varkill, avarinit); - bvor(lv->varkill[i], lv->varkill[i], varkill); - bvandnot(lv->uevar[i], lv->uevar[i], varkill); - bvor(lv->uevar[i], lv->uevar[i], uevar); - } - // Walk the block instructions forward to update avarinit bits. - // avarinit describes the effect at the end of the block, not the beginning. - bvresetall(varkill); - for(p = bb->first;; p = p->link) { - progeffects(p, lv->vars, uevar, varkill, avarinit); - if(debuglive >= 3) - printeffects(p, uevar, varkill, avarinit); - bvandnot(lv->avarinit[i], lv->avarinit[i], varkill); - bvor(lv->avarinit[i], lv->avarinit[i], avarinit); - if(p == bb->last) - break; - } - } - free(uevar); - free(varkill); - free(avarinit); -} - -// Solve the liveness dataflow equations. -static void -livenesssolve(Liveness *lv) -{ - BasicBlock *bb, *succ, *pred; - Bvec *newlivein, *newliveout, *any, *all; - int32 rpo, i, j, change; - - // These temporary bitvectors exist to avoid successive allocations and - // frees within the loop. - newlivein = bvalloc(arraylength(lv->vars)); - newliveout = bvalloc(arraylength(lv->vars)); - any = bvalloc(arraylength(lv->vars)); - all = bvalloc(arraylength(lv->vars)); - - // Push avarinitall, avarinitany forward. - // avarinitall says the addressed var is initialized along all paths reaching the block exit. - // avarinitany says the addressed var is initialized along some path reaching the block exit. - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - rpo = bb->rpo; - if(i == 0) - bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]); - else { - bvresetall(lv->avarinitall[rpo]); - bvnot(lv->avarinitall[rpo]); - } - bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]); - } - - change = 1; - while(change != 0) { - change = 0; - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - rpo = bb->rpo; - bvresetall(any); - bvresetall(all); - for(j = 0; j < arraylength(bb->pred); j++) { - pred = *(BasicBlock**)arrayget(bb->pred, j); - if(j == 0) { - bvcopy(any, lv->avarinitany[pred->rpo]); - bvcopy(all, lv->avarinitall[pred->rpo]); - } else { - bvor(any, any, lv->avarinitany[pred->rpo]); - bvand(all, all, lv->avarinitall[pred->rpo]); - } - } - bvandnot(any, any, lv->varkill[rpo]); - bvandnot(all, all, lv->varkill[rpo]); - bvor(any, any, lv->avarinit[rpo]); - bvor(all, all, lv->avarinit[rpo]); - if(bvcmp(any, lv->avarinitany[rpo])) { - change = 1; - bvcopy(lv->avarinitany[rpo], any); - } - if(bvcmp(all, lv->avarinitall[rpo])) { - change = 1; - bvcopy(lv->avarinitall[rpo], all); - } - } - } - - // Iterate through the blocks in reverse round-robin fashion. A work - // queue might be slightly faster. As is, the number of iterations is - // so low that it hardly seems to be worth the complexity. - change = 1; - while(change != 0) { - change = 0; - // Walk blocks in the general direction of propagation. This - // improves convergence. - for(i = arraylength(lv->cfg) - 1; i >= 0; i--) { - // A variable is live on output from this block - // if it is live on input to some successor. - // - // out[b] = \bigcup_{s \in succ[b]} in[s] - bb = *(BasicBlock**)arrayget(lv->cfg, i); - rpo = bb->rpo; - bvresetall(newliveout); - for(j = 0; j < arraylength(bb->succ); j++) { - succ = *(BasicBlock**)arrayget(bb->succ, j); - bvor(newliveout, newliveout, lv->livein[succ->rpo]); - } - if(bvcmp(lv->liveout[rpo], newliveout)) { - change = 1; - bvcopy(lv->liveout[rpo], newliveout); - } - - // A variable is live on input to this block - // if it is live on output from this block and - // not set by the code in this block. - // - // in[b] = uevar[b] \cup (out[b] \setminus varkill[b]) - bvandnot(newlivein, lv->liveout[rpo], lv->varkill[rpo]); - bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]); - } - } - - free(newlivein); - free(newliveout); - free(any); - free(all); -} - -// This function is slow but it is only used for generating debug prints. -// Check whether n is marked live in args/locals. -static int -islive(Node *n, Bvec *args, Bvec *locals) -{ - int i; - - switch(n->class) { - case PPARAM: - case PPARAMOUT: - for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++) - if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i)) - return 1; - break; - case PAUTO: - for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++) - if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i)) - return 1; - break; - } - return 0; -} - -// Visits all instructions in a basic block and computes a bit vector of live -// variables at each safe point locations. -static void -livenessepilogue(Liveness *lv) -{ - BasicBlock *bb, *pred; - Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all; - Node *n; - Prog *p, *next; - int32 i, j, numlive, startmsg, nmsg, nvars, pos; - vlong xoffset; - char **msg; - Fmt fmt; - - nvars = arraylength(lv->vars); - livein = bvalloc(nvars); - liveout = bvalloc(nvars); - uevar = bvalloc(nvars); - varkill = bvalloc(nvars); - avarinit = bvalloc(nvars); - any = bvalloc(nvars); - all = bvalloc(nvars); - ambig = bvalloc(localswords() * BitsPerPointer); - msg = nil; - nmsg = 0; - startmsg = 0; - - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - - // Compute avarinitany and avarinitall for entry to block. - // This duplicates information known during livenesssolve - // but avoids storing two more vectors for each block. - bvresetall(any); - bvresetall(all); - for(j = 0; j < arraylength(bb->pred); j++) { - pred = *(BasicBlock**)arrayget(bb->pred, j); - if(j == 0) { - bvcopy(any, lv->avarinitany[pred->rpo]); - bvcopy(all, lv->avarinitall[pred->rpo]); - } else { - bvor(any, any, lv->avarinitany[pred->rpo]); - bvand(all, all, lv->avarinitall[pred->rpo]); - } - } - - // Walk forward through the basic block instructions and - // allocate liveness maps for those instructions that need them. - // Seed the maps with information about the addrtaken variables. - for(p = bb->first;; p = p->link) { - progeffects(p, lv->vars, uevar, varkill, avarinit); - bvandnot(any, any, varkill); - bvandnot(all, all, varkill); - bvor(any, any, avarinit); - bvor(all, all, avarinit); - - if(issafepoint(p)) { - // Annotate ambiguously live variables so that they can - // be zeroed at function entry. - // livein and liveout are dead here and used as temporaries. - bvresetall(livein); - bvandnot(liveout, any, all); - if(!bvisempty(liveout)) { - for(pos = 0; pos < liveout->n; pos++) { - if(!bvget(liveout, pos)) - continue; - bvset(all, pos); // silence future warnings in this block - n = *(Node**)arrayget(lv->vars, pos); - if(!n->needzero) { - n->needzero = 1; - if(debuglive >= 1) - warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n); - // Record in 'ambiguous' bitmap. - xoffset = n->xoffset + stkptrsize; - twobitwalktype1(n->type, &xoffset, ambig); - } - } - } - - // Allocate a bit vector for each class and facet of - // value we are tracking. - - // Live stuff first. - args = bvalloc(argswords() * BitsPerPointer); - arrayadd(lv->argslivepointers, &args); - locals = bvalloc(localswords() * BitsPerPointer); - arrayadd(lv->livepointers, &locals); - - if(debuglive >= 3) { - print("%P\n", p); - printvars("avarinitany", any, lv->vars); - } - - // Record any values with an "address taken" reaching - // this code position as live. Must do now instead of below - // because the any/all calculation requires walking forward - // over the block (as this loop does), while the liveout - // requires walking backward (as the next loop does). - twobitlivepointermap(lv, any, lv->vars, args, locals); - } - - if(p == bb->last) - break; - } - bb->lastbitmapindex = arraylength(lv->livepointers) - 1; - } - - for(i = 0; i < arraylength(lv->cfg); i++) { - bb = *(BasicBlock**)arrayget(lv->cfg, i); - - if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') { - nmsg = arraylength(lv->livepointers); - startmsg = nmsg; - msg = xmalloc(nmsg*sizeof msg[0]); - for(j=0; jlastbitmapindex; - if(pos < 0) { - // the first block we encounter should have the ATEXT so - // at no point should pos ever be less than zero. - fatal("livenessepilogue"); - } - - bvcopy(livein, lv->liveout[bb->rpo]); - for(p = bb->last; p != nil; p = next) { - next = p->opt; // splicebefore modifies p->opt - // Propagate liveness information - progeffects(p, lv->vars, uevar, varkill, avarinit); - bvcopy(liveout, livein); - bvandnot(livein, liveout, varkill); - bvor(livein, livein, uevar); - if(debuglive >= 3 && issafepoint(p)){ - print("%P\n", p); - printvars("uevar", uevar, lv->vars); - printvars("varkill", varkill, lv->vars); - printvars("livein", livein, lv->vars); - printvars("liveout", liveout, lv->vars); - } - if(issafepoint(p)) { - // Found an interesting instruction, record the - // corresponding liveness information. - - // Useful sanity check: on entry to the function, - // the only things that can possibly be live are the - // input parameters. - if(p->as == ATEXT) { - for(j = 0; j < liveout->n; j++) { - if(!bvget(liveout, j)) - continue; - n = *(Node**)arrayget(lv->vars, j); - if(n->class != PPARAM) - yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n); - } - } - - // Record live pointers. - args = *(Bvec**)arrayget(lv->argslivepointers, pos); - locals = *(Bvec**)arrayget(lv->livepointers, pos); - twobitlivepointermap(lv, liveout, lv->vars, args, locals); - - // Ambiguously live variables are zeroed immediately after - // function entry. Mark them live for all the non-entry bitmaps - // so that GODEBUG=gcdead=1 mode does not poison them. - if(p->as == ACALL) - bvor(locals, locals, ambig); - - // Show live pointer bitmaps. - // We're interpreting the args and locals bitmap instead of liveout so that we - // include the bits added by the avarinit logic in the - // previous loop. - if(msg != nil) { - fmtstrinit(&fmt); - fmtprint(&fmt, "%L: live at ", p->lineno); - if(p->as == ACALL && p->to.node) - fmtprint(&fmt, "call to %s:", ((Node*)(p->to.node))->sym->name); - else if(p->as == ACALL) - fmtprint(&fmt, "indirect call:"); - else - fmtprint(&fmt, "entry to %s:", ((Node*)(p->from.node))->sym->name); - numlive = 0; - for(j = 0; j < arraylength(lv->vars); j++) { - n = *(Node**)arrayget(lv->vars, j); - if(islive(n, args, locals)) { - fmtprint(&fmt, " %N", n); - numlive++; - } - } - fmtprint(&fmt, "\n"); - if(numlive == 0) // squelch message - free(fmtstrflush(&fmt)); - else - msg[--startmsg] = fmtstrflush(&fmt); - } - - // Only CALL instructions need a PCDATA annotation. - // The TEXT instruction annotation is implicit. - if(p->as == ACALL) { - if(isdeferreturn(p)) { - // runtime.deferreturn modifies its return address to return - // back to the CALL, not to the subsequent instruction. - // Because the return comes back one instruction early, - // the PCDATA must begin one instruction early too. - // The instruction before a call to deferreturn is always a - // no-op, to keep PC-specific data unambiguous. - splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt); - } else { - splicebefore(lv, bb, newpcdataprog(p, pos), p); - } - } - - pos--; - } - } - if(msg != nil) { - for(j=startmsg; jn+31)/32; - for(i=0; ib[i]; - h = (h*Hp) ^ (w&0xff); - h = (h*Hp) ^ ((w>>8)&0xff); - h = (h*Hp) ^ ((w>>16)&0xff); - h = (h*Hp) ^ ((w>>24)&0xff); - } - return h; -} - -// Compact liveness information by coalescing identical per-call-site bitmaps. -// The merging only happens for a single function, not across the entire binary. -// -// There are actually two lists of bitmaps, one list for the local variables and one -// list for the function arguments. Both lists are indexed by the same PCDATA -// index, so the corresponding pairs must be considered together when -// merging duplicates. The argument bitmaps change much less often during -// function execution than the local variable bitmaps, so it is possible that -// we could introduce a separate PCDATA index for arguments vs locals and -// then compact the set of argument bitmaps separately from the set of -// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary -// is actually a net loss: we save about 50k of argument bitmaps but the new -// PCDATA tables cost about 100k. So for now we keep using a single index for -// both bitmap lists. -static void -livenesscompact(Liveness *lv) -{ - int *table, *remap, i, j, n, tablesize, uniq; - uint32 h; - Bvec *local, *arg, *jlocal, *jarg; - Prog *p; - - // Linear probing hash table of bitmaps seen so far. - // The hash table has 4n entries to keep the linear - // scan short. An entry of -1 indicates an empty slot. - n = arraylength(lv->livepointers); - tablesize = 4*n; - table = xmalloc(tablesize*sizeof table[0]); - memset(table, 0xff, tablesize*sizeof table[0]); - - // remap[i] = the new index of the old bit vector #i. - remap = xmalloc(n*sizeof remap[0]); - memset(remap, 0xff, n*sizeof remap[0]); - uniq = 0; // unique tables found so far - - // Consider bit vectors in turn. - // If new, assign next number using uniq, - // record in remap, record in lv->livepointers and lv->argslivepointers - // under the new index, and add entry to hash table. - // If already seen, record earlier index in remap and free bitmaps. - for(i=0; ilivepointers, i); - arg = *(Bvec**)arrayget(lv->argslivepointers, i); - h = hashbitmap(hashbitmap(H0, local), arg) % tablesize; - - for(;;) { - j = table[h]; - if(j < 0) - break; - jlocal = *(Bvec**)arrayget(lv->livepointers, j); - jarg = *(Bvec**)arrayget(lv->argslivepointers, j); - if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) { - free(local); - free(arg); - remap[i] = j; - goto Next; - } - if(++h == tablesize) - h = 0; - } - table[h] = uniq; - remap[i] = uniq; - *(Bvec**)arrayget(lv->livepointers, uniq) = local; - *(Bvec**)arrayget(lv->argslivepointers, uniq) = arg; - uniq++; - Next:; - } - - // We've already reordered lv->livepointers[0:uniq] - // and lv->argslivepointers[0:uniq] and freed the bitmaps - // we don't need anymore. Clear the pointers later in the - // array so that we can tell where the coalesced bitmaps stop - // and so that we don't double-free when cleaning up. - for(j=uniq; jlivepointers, j) = nil; - *(Bvec**)arrayget(lv->argslivepointers, j) = nil; - } - - // Rewrite PCDATA instructions to use new numbering. - for(p=lv->ptxt; p != P; p=p->link) { - if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) { - i = p->to.offset; - if(i >= 0) - p->to.offset = remap[i]; - } - } - - free(table); - free(remap); -} - -static int -printbitset(int printed, char *name, Array *vars, Bvec *bits) -{ - int i, started; - Node *n; - - started = 0; - for(i=0; isym->name); - } - return printed; -} - -// Prints the computed liveness information and inputs, for debugging. -// This format synthesizes the information used during the multiple passes -// into a single presentation. -static void -livenessprintdebug(Liveness *lv) -{ - int i, j, pcdata, printed; - BasicBlock *bb; - Prog *p; - Bvec *uevar, *varkill, *avarinit, *args, *locals; - Node *n; - - print("liveness: %s\n", curfn->nname->sym->name); - - uevar = bvalloc(arraylength(lv->vars)); - varkill = bvalloc(arraylength(lv->vars)); - avarinit = bvalloc(arraylength(lv->vars)); - - pcdata = 0; - for(i = 0; i < arraylength(lv->cfg); i++) { - if(i > 0) - print("\n"); - bb = *(BasicBlock**)arrayget(lv->cfg, i); - - // bb#0 pred=1,2 succ=3,4 - print("bb#%d pred=", i); - for(j = 0; j < arraylength(bb->pred); j++) { - if(j > 0) - print(","); - print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo); - } - print(" succ="); - for(j = 0; j < arraylength(bb->succ); j++) { - if(j > 0) - print(","); - print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo); - } - print("\n"); - - // initial settings - printed = 0; - printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]); - printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]); - if(printed) - print("\n"); - - // program listing, with individual effects listed - for(p = bb->first;; p = p->link) { - print("%P\n", p); - if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) - pcdata = p->to.offset; - progeffects(p, lv->vars, uevar, varkill, avarinit); - printed = 0; - printed = printbitset(printed, "uevar", lv->vars, uevar); - printed = printbitset(printed, "varkill", lv->vars, varkill); - printed = printbitset(printed, "avarinit", lv->vars, avarinit); - if(printed) - print("\n"); - if(issafepoint(p)) { - args = *(Bvec**)arrayget(lv->argslivepointers, pcdata); - locals = *(Bvec**)arrayget(lv->livepointers, pcdata); - print("\tlive="); - printed = 0; - for(j = 0; j < arraylength(lv->vars); j++) { - n = *(Node**)arrayget(lv->vars, j); - if(islive(n, args, locals)) { - if(printed++) - print(","); - print("%N", n); - } - } - print("\n"); - } - if(p == bb->last) - break; - } - - // bb bitsets - print("end\n"); - printed = printbitset(printed, "varkill", lv->vars, lv->varkill[bb->rpo]); - printed = printbitset(printed, "liveout", lv->vars, lv->liveout[bb->rpo]); - printed = printbitset(printed, "avarinit", lv->vars, lv->avarinit[bb->rpo]); - printed = printbitset(printed, "avarinitany", lv->vars, lv->avarinitany[bb->rpo]); - printed = printbitset(printed, "avarinitall", lv->vars, lv->avarinitall[bb->rpo]); - if(printed) - print("\n"); - } - print("\n"); - - free(uevar); - free(varkill); - free(avarinit); -} - -// Dumps an array of bitmaps to a symbol as a sequence of uint32 values. The -// first word dumped is the total number of bitmaps. The second word is the -// length of the bitmaps. All bitmaps are assumed to be of equal length. The -// words that are followed are the raw bitmap words. The arr argument is an -// array of Node*s. -static void -twobitwritesymbol(Array *arr, Sym *sym) -{ - Bvec *bv; - int off, i, j, n; - uint32 word; - - n = arraylength(arr); - off = 0; - off += 4; // number of bitmaps, to fill in later - bv = *(Bvec**)arrayget(arr, 0); - off = duint32(sym, off, bv->n); // number of bits in each bitmap - for(i = 0; i < n; i++) { - // bitmap words - bv = *(Bvec**)arrayget(arr, i); - if(bv == nil) - break; - for(j = 0; j < bv->n; j += 32) { - word = bv->b[j/32]; - // Runtime reads the bitmaps as byte arrays. Oblige. - off = duint8(sym, off, word); - off = duint8(sym, off, word>>8); - off = duint8(sym, off, word>>16); - off = duint8(sym, off, word>>24); - } - } - duint32(sym, 0, i); // number of bitmaps - ggloblsym(sym, off, RODATA); -} - -static void -printprog(Prog *p) -{ - while(p != nil) { - print("%P\n", p); - p = p->link; - } -} - -// Entry pointer for liveness analysis. Constructs a complete CFG, solves for -// the liveness of pointer variables in the function, and emits a runtime data -// structure read by the garbage collector. -void -liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym) -{ - Array *cfg, *vars; - Liveness *lv; - int debugdelta; - NodeList *l; - - // Change name to dump debugging information only for a specific function. - debugdelta = 0; - if(strcmp(curfn->nname->sym->name, "!") == 0) - debugdelta = 2; - - debuglive += debugdelta; - if(debuglive >= 3) { - print("liveness: %s\n", curfn->nname->sym->name); - printprog(firstp); - } - checkptxt(fn, firstp); - - // Construct the global liveness state. - cfg = newcfg(firstp); - if(debuglive >= 3) - printcfg(cfg); - vars = getvariables(fn); - lv = newliveness(fn, firstp, cfg, vars); - - // Run the dataflow framework. - livenessprologue(lv); - if(debuglive >= 3) - livenessprintcfg(lv); - livenesssolve(lv); - if(debuglive >= 3) - livenessprintcfg(lv); - livenessepilogue(lv); - if(debuglive >= 3) - livenessprintcfg(lv); - livenesscompact(lv); - - if(debuglive >= 2) - livenessprintdebug(lv); - - // Emit the live pointer map data structures - twobitwritesymbol(lv->livepointers, livesym); - twobitwritesymbol(lv->argslivepointers, argssym); - - // Free everything. - for(l=fn->dcl; l != nil; l = l->next) - if(l->n != N) - l->n->opt = nil; - freeliveness(lv); - arrayfree(vars); - freecfg(cfg); - - debuglive -= debugdelta; -} diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c deleted file mode 100644 index b02d58e663..0000000000 --- a/src/cmd/gc/popt.c +++ /dev/null @@ -1,1022 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// "Portable" optimizations. -// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h. -// Must code to the intersection of the three back ends. - -#include -#include -#include "go.h" -#include "popt.h" - -// p is a call instruction. Does the call fail to return? -int -noreturn(Prog *p) -{ - Sym *s; - int i; - static Sym* symlist[10]; - - if(symlist[0] == S) { - symlist[0] = pkglookup("panicindex", runtimepkg); - symlist[1] = pkglookup("panicslice", runtimepkg); - symlist[2] = pkglookup("throwinit", runtimepkg); - symlist[3] = pkglookup("gopanic", runtimepkg); - symlist[4] = pkglookup("panicwrap", runtimepkg); - symlist[5] = pkglookup("throwreturn", runtimepkg); - symlist[6] = pkglookup("selectgo", runtimepkg); - symlist[7] = pkglookup("block", runtimepkg); - } - - if(p->to.node == nil) - return 0; - s = ((Node*)(p->to.node))->sym; - if(s == S) - return 0; - for(i=0; symlist[i]!=S; i++) - if(s == symlist[i]) - return 1; - return 0; -} - -// JMP chasing and removal. -// -// The code generator depends on being able to write out jump -// instructions that it can jump to now but fill in later. -// the linker will resolve them nicely, but they make the code -// longer and more difficult to follow during debugging. -// Remove them. - -/* what instruction does a JMP to p eventually land on? */ -static Prog* -chasejmp(Prog *p, int *jmploop) -{ - int n; - - n = 0; - while(p != P && p->as == AJMP && p->to.type == TYPE_BRANCH) { - if(++n > 10) { - *jmploop = 1; - break; - } - p = p->to.u.branch; - } - return p; -} - -/* - * reuse reg pointer for mark/sweep state. - * leave reg==nil at end because alive==nil. - */ -#define alive ((void*)0) -#define dead ((void*)1) -/*c2go -extern void *alive; -extern void *dead; -*/ - -/* mark all code reachable from firstp as alive */ -static void -mark(Prog *firstp) -{ - Prog *p; - - for(p=firstp; p; p=p->link) { - if(p->opt != dead) - break; - p->opt = alive; - if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch) - mark(p->to.u.branch); - if(p->as == AJMP || p->as == ARET || p->as == AUNDEF) - break; - } -} - -void -fixjmp(Prog *firstp) -{ - int jmploop; - Prog *p, *last; - - if(debug['R'] && debug['v']) - print("\nfixjmp\n"); - - // pass 1: resolve jump to jump, mark all code as dead. - jmploop = 0; - for(p=firstp; p; p=p->link) { - if(debug['R'] && debug['v']) - print("%P\n", p); - if(p->as != ACALL && p->to.type == TYPE_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) { - p->to.u.branch = chasejmp(p->to.u.branch, &jmploop); - if(debug['R'] && debug['v']) - print("->%P\n", p); - } - p->opt = dead; - } - if(debug['R'] && debug['v']) - print("\n"); - - // pass 2: mark all reachable code alive - mark(firstp); - - // pass 3: delete dead code (mostly JMPs). - last = nil; - for(p=firstp; p; p=p->link) { - if(p->opt == dead) { - if(p->link == P && p->as == ARET && last && last->as != ARET) { - // This is the final ARET, and the code so far doesn't have one. - // Let it stay. The register allocator assumes that all live code in - // the function can be traversed by starting at all the RET instructions - // and following predecessor links. If we remove the final RET, - // this assumption will not hold in the case of an infinite loop - // at the end of a function. - // Keep the RET but mark it dead for the liveness analysis. - p->mode = 1; - } else { - if(debug['R'] && debug['v']) - print("del %P\n", p); - continue; - } - } - if(last) - last->link = p; - last = p; - } - last->link = P; - - // pass 4: elide JMP to next instruction. - // only safe if there are no jumps to JMPs anymore. - if(!jmploop) { - last = nil; - for(p=firstp; p; p=p->link) { - if(p->as == AJMP && p->to.type == TYPE_BRANCH && p->to.u.branch == p->link) { - if(debug['R'] && debug['v']) - print("del %P\n", p); - continue; - } - if(last) - last->link = p; - last = p; - } - last->link = P; - } - - if(debug['R'] && debug['v']) { - print("\n"); - for(p=firstp; p; p=p->link) - print("%P\n", p); - print("\n"); - } -} - -#undef alive -#undef dead - -// Control flow analysis. The Flow structures hold predecessor and successor -// information as well as basic loop analysis. -// -// graph = flowstart(firstp, 0); -// ... use flow graph ... -// flowend(graph); // free graph -// -// Typical uses of the flow graph are to iterate over all the flow-relevant instructions: -// -// for(f = graph->start; f != nil; f = f->link) -// -// or, given an instruction f, to iterate over all the predecessors, which is -// f->p1 and this list: -// -// for(f2 = f->p2; f2 != nil; f2 = f2->p2link) -// -// The size argument to flowstart specifies an amount of zeroed memory -// to allocate in every f->data field, for use by the client. -// If size == 0, f->data will be nil. - -Graph* -flowstart(Prog *firstp, int size) -{ - int id, nf; - Flow *f, *f1, *start, *last; - Graph *graph; - Prog *p; - ProgInfo info; - char *data; - - // Count and mark instructions to annotate. - nf = 0; - for(p = firstp; p != P; p = p->link) { - p->opt = nil; // should be already, but just in case - thearch.proginfo(&info, p); - if(info.flags & Skip) - continue; - p->opt = (void*)1; - nf++; - } - - if(nf == 0) - return nil; - - if(nf >= 20000) { - // fatal("%S is too big (%d instructions)", curfn->nname->sym, nf); - return nil; - } - - // Allocate annotations and assign to instructions. - graph = calloc(sizeof *graph + sizeof(Flow)*nf + size*nf, 1); - if(graph == nil) - fatal("out of memory"); - start = (Flow*)(graph+1); - last = nil; - f = start; - data = (char*)(f+nf); - if(size == 0) - data = nil; - id = 0; - for(p = firstp; p != P; p = p->link) { - if(p->opt == nil) - continue; - p->opt = f; - f->prog = p; - if(last) - last->link = f; - last = f; - f->data = data; - f->id = id; - f++; - id++; - data += size; - } - - // Fill in pred/succ information. - for(f = start; f != nil; f = f->link) { - p = f->prog; - thearch.proginfo(&info, p); - if(!(info.flags & Break)) { - f1 = f->link; - f->s1 = f1; - f1->p1 = f; - } - if(p->to.type == TYPE_BRANCH) { - if(p->to.u.branch == P) - fatal("pnil %P", p); - f1 = p->to.u.branch->opt; - if(f1 == nil) - fatal("fnil %P / %P", p, p->to.u.branch); - if(f1 == f) { - //fatal("self loop %P", p); - continue; - } - f->s2 = f1; - f->p2link = f1->p2; - f1->p2 = f; - } - } - - graph->start = start; - graph->num = nf; - return graph; -} - -void -flowend(Graph *graph) -{ - Flow *f; - - for(f = graph->start; f != nil; f = f->link) - f->prog->opt = nil; - free(graph); -} - -/* - * find looping structure - * - * 1) find reverse postordering - * 2) find approximate dominators, - * the actual dominators if the flow graph is reducible - * otherwise, dominators plus some other non-dominators. - * See Matthew S. Hecht and Jeffrey D. Ullman, - * "Analysis of a Simple Algorithm for Global Data Flow Problems", - * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts, - * Oct. 1-3, 1973, pp. 207-217. - * 3) find all nodes with a predecessor dominated by the current node. - * such a node is a loop head. - * recursively, all preds with a greater rpo number are in the loop - */ -static int32 -postorder(Flow *r, Flow **rpo2r, int32 n) -{ - Flow *r1; - - r->rpo = 1; - r1 = r->s1; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - r1 = r->s2; - if(r1 && !r1->rpo) - n = postorder(r1, rpo2r, n); - rpo2r[n] = r; - n++; - return n; -} - -static int32 -rpolca(int32 *idom, int32 rpo1, int32 rpo2) -{ - int32 t; - - if(rpo1 == -1) - return rpo2; - while(rpo1 != rpo2){ - if(rpo1 > rpo2){ - t = rpo2; - rpo2 = rpo1; - rpo1 = t; - } - while(rpo1 < rpo2){ - t = idom[rpo2]; - if(t >= rpo2) - fatal("bad idom"); - rpo2 = t; - } - } - return rpo1; -} - -static int -doms(int32 *idom, int32 r, int32 s) -{ - while(s > r) - s = idom[s]; - return s == r; -} - -static int -loophead(int32 *idom, Flow *r) -{ - int32 src; - - src = r->rpo; - if(r->p1 != nil && doms(idom, src, r->p1->rpo)) - return 1; - for(r = r->p2; r != nil; r = r->p2link) - if(doms(idom, src, r->rpo)) - return 1; - return 0; -} - -static void -loopmark(Flow **rpo2r, int32 head, Flow *r) -{ - if(r->rpo < head || r->active == head) - return; - r->active = head; - r->loop += LOOP; - if(r->p1 != nil) - loopmark(rpo2r, head, r->p1); - for(r = r->p2; r != nil; r = r->p2link) - loopmark(rpo2r, head, r); -} - -void -flowrpo(Graph *g) -{ - Flow *r1; - int32 i, d, me, nr, *idom; - Flow **rpo2r; - - free(g->rpo); - g->rpo = calloc(g->num*sizeof g->rpo[0], 1); - idom = calloc(g->num*sizeof idom[0], 1); - if(g->rpo == nil || idom == nil) - fatal("out of memory"); - - for(r1 = g->start; r1 != nil; r1 = r1->link) - r1->active = 0; - - rpo2r = g->rpo; - d = postorder(g->start, rpo2r, 0); - nr = g->num; - if(d > nr) - fatal("too many reg nodes %d %d", d, nr); - nr = d; - for(i = 0; i < nr / 2; i++) { - r1 = rpo2r[i]; - rpo2r[i] = rpo2r[nr - 1 - i]; - rpo2r[nr - 1 - i] = r1; - } - for(i = 0; i < nr; i++) - rpo2r[i]->rpo = i; - - idom[0] = 0; - for(i = 0; i < nr; i++) { - r1 = rpo2r[i]; - me = r1->rpo; - d = -1; - // rpo2r[r->rpo] == r protects against considering dead code, - // which has r->rpo == 0. - if(r1->p1 != nil && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me) - d = r1->p1->rpo; - for(r1 = r1->p2; r1 != nil; r1 = r1->p2link) - if(rpo2r[r1->rpo] == r1 && r1->rpo < me) - d = rpolca(idom, d, r1->rpo); - idom[i] = d; - } - - for(i = 0; i < nr; i++) { - r1 = rpo2r[i]; - r1->loop++; - if(r1->p2 != nil && loophead(idom, r1)) - loopmark(rpo2r, i, r1); - } - free(idom); - - for(r1 = g->start; r1 != nil; r1 = r1->link) - r1->active = 0; -} - -Flow* -uniqp(Flow *r) -{ - Flow *r1; - - r1 = r->p1; - if(r1 == nil) { - r1 = r->p2; - if(r1 == nil || r1->p2link != nil) - return nil; - } else - if(r->p2 != nil) - return nil; - return r1; -} - -Flow* -uniqs(Flow *r) -{ - Flow *r1; - - r1 = r->s1; - if(r1 == nil) { - r1 = r->s2; - if(r1 == nil) - return nil; - } else - if(r->s2 != nil) - return nil; - return r1; -} - -// The compilers assume they can generate temporary variables -// as needed to preserve the right semantics or simplify code -// generation and the back end will still generate good code. -// This results in a large number of ephemeral temporary variables. -// Merge temps with non-overlapping lifetimes and equal types using the -// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation", -// ACM TOPLAS 1999. - -typedef struct TempVar TempVar; - -struct TempVar -{ - Node *node; - Flow *def; // definition of temp var - Flow *use; // use list, chained through Flow.data - TempVar *freelink; // next free temp in Type.opt list - TempVar *merge; // merge var with this one - vlong start; // smallest Prog.pc in live range - vlong end; // largest Prog.pc in live range - uchar addr; // address taken - no accurate end - uchar removed; // removed from program -}; - -static int -startcmp(const void *va, const void *vb) -{ - TempVar *a, *b; - - a = *(TempVar**)va; - b = *(TempVar**)vb; - - if(a->start < b->start) - return -1; - if(a->start > b->start) - return +1; - // Order what's left by id or symbol name, - // just so that sort is forced into a specific ordering, - // so that the result of the sort does not depend on - // the sort implementation. - if(a->def != b->def) - return a->def->id - b->def->id; - if(a->node != b->node) - return strcmp(a->node->sym->name, b->node->sym->name); - return 0; -} - -// Is n available for merging? -static int -canmerge(Node *n) -{ - return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0; -} - -static void mergewalk(TempVar*, Flow*, uint32); -static void varkillwalk(TempVar*, Flow*, uint32); - -void -mergetemp(Prog *firstp) -{ - int i, j, nvar, ninuse, nfree, nkill; - TempVar *var, *v, *v1, **bystart, **inuse; - Flow *f; - NodeList *l, **lp; - Node *n; - Prog *p, *p1; - Type *t; - ProgInfo info, info1; - int32 gen; - Graph *g; - - enum { debugmerge = 1 }; - - g = flowstart(firstp, 0); - if(g == nil) - return; - - // Build list of all mergeable variables. - nvar = 0; - for(l = curfn->dcl; l != nil; l = l->next) - if(canmerge(l->n)) - nvar++; - - var = calloc(nvar*sizeof var[0], 1); - nvar = 0; - for(l = curfn->dcl; l != nil; l = l->next) { - n = l->n; - if(canmerge(n)) { - v = &var[nvar++]; - n->opt = v; - v->node = n; - } - } - - // Build list of uses. - // We assume that the earliest reference to a temporary is its definition. - // This is not true of variables in general but our temporaries are all - // single-use (that's why we have so many!). - for(f = g->start; f != nil; f = f->link) { - p = f->prog; - thearch.proginfo(&info, p); - - if(p->from.node != N && ((Node*)(p->from.node))->opt && p->to.node != N && ((Node*)(p->to.node))->opt) - fatal("double node %P", p); - v = nil; - if((n = p->from.node) != N) - v = n->opt; - if(v == nil && (n = p->to.node) != N) - v = n->opt; - if(v != nil) { - if(v->def == nil) - v->def = f; - f->data = v->use; - v->use = f; - if(n == p->from.node && (info.flags & LeftAddr)) - v->addr = 1; - } - } - - if(debugmerge > 1 && debug['v']) - dumpit("before", g->start, 0); - - nkill = 0; - - // Special case. - for(i = 0; i < nvar; i++) { - v = &var[i]; - if(v->addr) - continue; - // Used in only one instruction, which had better be a write. - if((f = v->use) != nil && (Flow*)f->data == nil) { - p = f->prog; - thearch.proginfo(&info, p); - if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) { - p->as = ANOP; - p->to = zprog.to; - v->removed = 1; - if(debugmerge > 0 && debug['v']) - print("drop write-only %S\n", v->node->sym); - } else - fatal("temp used and not set: %P", p); - nkill++; - continue; - } - - // Written in one instruction, read in the next, otherwise unused, - // no jumps to the next instruction. Happens mainly in 386 compiler. - if((f = v->use) != nil && f->link == (Flow*)f->data && (Flow*)((Flow*)f->data)->data == nil && uniqp(f->link) == f) { - p = f->prog; - thearch.proginfo(&info, p); - p1 = f->link->prog; - thearch.proginfo(&info1, p1); - enum { - SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD, - }; - if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) && - !((info.flags|info1.flags) & (LeftAddr|RightAddr)) && - (info.flags & SizeAny) == (info1.flags & SizeAny)) { - p1->from = p->from; - thearch.excise(f); - v->removed = 1; - if(debugmerge > 0 && debug['v']) - print("drop immediate-use %S\n", v->node->sym); - } - nkill++; - continue; - } - } - - // Traverse live range of each variable to set start, end. - // Each flood uses a new value of gen so that we don't have - // to clear all the r->active words after each variable. - gen = 0; - for(i = 0; i < nvar; i++) { - v = &var[i]; - gen++; - for(f = v->use; f != nil; f = (Flow*)f->data) - mergewalk(v, f, gen); - if(v->addr) { - gen++; - for(f = v->use; f != nil; f = (Flow*)f->data) - varkillwalk(v, f, gen); - } - } - - // Sort variables by start. - bystart = malloc(nvar*sizeof bystart[0]); - for(i=0; i 0 && debug['v']) - print("consider %#N: removed=%d\n", v->node, v->removed); - - if(v->removed) - continue; - - // Expire no longer in use. - while(ninuse > 0 && inuse[ninuse-1]->end < v->start) { - v1 = inuse[--ninuse]; - inuse[--nfree] = v1; - } - - if(debugmerge > 0 && debug['v']) - print("consider %#N: removed=%d nfree=%d nvar=%d\n", v->node, v->removed, nfree, nvar); - // Find old temp to reuse if possible. - t = v->node->type; - for(j=nfree; j 0 && debug['v']) - print("consider %#N: maybe %#N: type=%T,%T addrtaken=%d,%d\n", v->node, v1->node, t, v1->node->type, v->node->addrtaken, v1->node->addrtaken); - // Require the types to match but also require the addrtaken bits to match. - // If a variable's address is taken, that disables registerization for the individual - // words of the variable (for example, the base,len,cap of a slice). - // We don't want to merge a non-addressed var with an addressed one and - // inhibit registerization of the former. - if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) { - inuse[j] = inuse[nfree++]; - if(v1->merge) - v->merge = v1->merge; - else - v->merge = v1; - nkill++; - break; - } - } - - // Sort v into inuse. - j = ninuse++; - while(j > 0 && inuse[j-1]->end < v->end) { - inuse[j] = inuse[j-1]; - j--; - } - inuse[j] = v; - } - - if(debugmerge > 0 && debug['v']) { - print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill); - for(i = 0; i < nvar; i++) { - v = &var[i]; - print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end); - if(v->addr) - print(" addr=1"); - if(v->removed) - print(" dead=1"); - if(v->merge) - print(" merge %#N", v->merge->node); - if(v->start == v->end && v->def != nil) - print(" %P", v->def->prog); - print("\n"); - } - - if(debugmerge > 1 && debug['v']) - dumpit("after", g->start, 0); - } - - // Update node references to use merged temporaries. - for(f = g->start; f != nil; f = f->link) { - p = f->prog; - if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil) - p->from.node = v->merge->node; - if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil) - p->to.node = v->merge->node; - } - - // Delete merged nodes from declaration list. - for(lp = &curfn->dcl; (l = *lp); ) { - curfn->dcl->end = l; - n = l->n; - v = n->opt; - if(v && (v->merge || v->removed)) { - *lp = l->next; - continue; - } - lp = &l->next; - } - - // Clear aux structures. - for(i = 0; i < nvar; i++) - var[i].node->opt = nil; - - free(var); - free(bystart); - free(inuse); - flowend(g); -} - -static void -mergewalk(TempVar *v, Flow *f0, uint32 gen) -{ - Prog *p; - Flow *f1, *f, *f2; - - for(f1 = f0; f1 != nil; f1 = f1->p1) { - if(f1->active == gen) - break; - f1->active = gen; - p = f1->prog; - if(v->end < p->pc) - v->end = p->pc; - if(f1 == v->def) { - v->start = p->pc; - break; - } - } - - for(f = f0; f != f1; f = f->p1) - for(f2 = f->p2; f2 != nil; f2 = f2->p2link) - mergewalk(v, f2, gen); -} - -static void -varkillwalk(TempVar *v, Flow *f0, uint32 gen) -{ - Prog *p; - Flow *f1, *f; - - for(f1 = f0; f1 != nil; f1 = f1->s1) { - if(f1->active == gen) - break; - f1->active = gen; - p = f1->prog; - if(v->end < p->pc) - v->end = p->pc; - if(v->start > p->pc) - v->start = p->pc; - if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node)) - break; - } - - for(f = f0; f != f1; f = f->s1) - varkillwalk(v, f->s2, gen); -} - -// Eliminate redundant nil pointer checks. -// -// The code generation pass emits a CHECKNIL for every possibly nil pointer. -// This pass removes a CHECKNIL if every predecessor path has already -// checked this value for nil. -// -// Simple backwards flood from check to definition. -// Run prog loop backward from end of program to beginning to avoid quadratic -// behavior removing a run of checks. -// -// Assume that stack variables with address not taken can be loaded multiple times -// from memory without being rechecked. Other variables need to be checked on -// each load. - -typedef struct NilVar NilVar; - -static void nilwalkback(Flow *rcheck); -static void nilwalkfwd(Flow *rcheck); - -static int killed; // f->data is either nil or &killed - -void -nilopt(Prog *firstp) -{ - Flow *f; - Prog *p; - Graph *g; - int ncheck, nkill; - - g = flowstart(firstp, 0); - if(g == nil) - return; - - if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */) - dumpit("nilopt", g->start, 0); - - ncheck = 0; - nkill = 0; - for(f = g->start; f != nil; f = f->link) { - p = f->prog; - if(p->as != ACHECKNIL || !thearch.regtyp(&p->from)) - continue; - ncheck++; - if(thearch.stackaddr(&p->from)) { - if(debug_checknil && p->lineno > 1) - warnl(p->lineno, "removed nil check of SP address"); - f->data = &killed; - continue; - } - nilwalkfwd(f); - if(f->data != nil) { - if(debug_checknil && p->lineno > 1) - warnl(p->lineno, "removed nil check before indirect"); - continue; - } - nilwalkback(f); - if(f->data != nil) { - if(debug_checknil && p->lineno > 1) - warnl(p->lineno, "removed repeated nil check"); - continue; - } - } - - for(f = g->start; f != nil; f = f->link) { - if(f->data != nil) { - nkill++; - thearch.excise(f); - } - } - - flowend(g); - - if(debug_checknil > 1) - print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck); -} - -static void -nilwalkback(Flow *fcheck) -{ - Prog *p; - ProgInfo info; - Flow *f; - - for(f = fcheck; f != nil; f = uniqp(f)) { - p = f->prog; - thearch.proginfo(&info, p); - if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) { - // Found initialization of value we're checking for nil. - // without first finding the check, so this one is unchecked. - return; - } - if(f != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from)) { - fcheck->data = &killed; - return; - } - } - - // Here is a more complex version that scans backward across branches. - // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason - // to keep the check (setting fcheck->kill = 0). - // It doesn't handle copying of aggregates as well as I would like, - // nor variables with their address taken, - // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3. - /* - for(f1 = f0; f1 != nil; f1 = f1->p1) { - if(f1->active == gen) - break; - f1->active = gen; - p = f1->prog; - - // If same check, stop this loop but still check - // alternate predecessors up to this point. - if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from)) - break; - - thearch.proginfo(&info, p); - if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) { - // Found initialization of value we're checking for nil. - // without first finding the check, so this one is unchecked. - fcheck->kill = 0; - return; - } - - if(f1->p1 == nil && f1->p2 == nil) { - print("lost pred for %P\n", fcheck->prog); - for(f1=f0; f1!=nil; f1=f1->p1) { - thearch.proginfo(&info, f1->prog); - print("\t%P %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from); - } - fatal("lost pred trail"); - } - } - - for(f = f0; f != f1; f = f->p1) - for(f2 = f->p2; f2 != nil; f2 = f2->p2link) - nilwalkback(fcheck, f2, gen); - */ -} - -static void -nilwalkfwd(Flow *fcheck) -{ - Flow *f, *last; - Prog *p; - ProgInfo info; - - // If the path down from rcheck dereferences the address - // (possibly with a small offset) before writing to memory - // and before any subsequent checks, it's okay to wait for - // that implicit check. Only consider this basic block to - // avoid problems like: - // _ = *x // should panic - // for {} // no writes but infinite loop may be considered visible - last = nil; - for(f = uniqs(fcheck); f != nil; f = uniqs(f)) { - p = f->prog; - thearch.proginfo(&info, p); - - if((info.flags & LeftRead) && thearch.smallindir(&p->from, &fcheck->prog->from)) { - fcheck->data = &killed; - return; - } - if((info.flags & (RightRead|RightWrite)) && thearch.smallindir(&p->to, &fcheck->prog->from)) { - fcheck->data = &killed; - return; - } - - // Stop if another nil check happens. - if(p->as == ACHECKNIL) - return; - // Stop if value is lost. - if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) - return; - // Stop if memory write. - if((info.flags & RightWrite) && !thearch.regtyp(&p->to)) - return; - // Stop if we jump backward. - if(last != nil && f->id <= last->id) - return; - last = f; - } -} diff --git a/src/cmd/gc/popt.h b/src/cmd/gc/popt.h deleted file mode 100644 index 4e89dbd678..0000000000 --- a/src/cmd/gc/popt.h +++ /dev/null @@ -1,152 +0,0 @@ -// Derived from Inferno utils/6c/gc.h -// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#define Z N -#define Adr Addr - -#define BLOAD(r) band(bnot(r->refbehind), r->refahead) -#define BSTORE(r) band(bnot(r->calbehind), r->calahead) -#define LOAD(r) (~r->refbehind.b[z] & r->refahead.b[z]) -#define STORE(r) (~r->calbehind.b[z] & r->calahead.b[z]) - -enum -{ - CLOAD = 5, - CREF = 5, - CINF = 1000, - LOOP = 3, -}; - -typedef struct Reg Reg; -typedef struct Rgn Rgn; - -/*c2go -extern Node *Z; - -uint32 BLOAD(Reg*); -uint32 BSTORE(Reg*); -uint64 LOAD(Reg*); -uint64 STORE(Reg*); -*/ - -// A Reg is a wrapper around a single Prog (one instruction) that holds -// register optimization information while the optimizer runs. -// r->prog is the instruction. -struct Reg -{ - Bits set; // regopt variables written by this instruction. - Bits use1; // regopt variables read by prog->from. - Bits use2; // regopt variables read by prog->to. - - // refahead/refbehind are the regopt variables whose current - // value may be used in the following/preceding instructions - // up to a CALL (or the value is clobbered). - Bits refbehind; - Bits refahead; - // calahead/calbehind are similar, but for variables in - // instructions that are reachable after hitting at least one - // CALL. - Bits calbehind; - Bits calahead; - Bits regdiff; - Bits act; - - uint64 regu; // register used bitmap -}; -#define R ((Reg*)0) -/*c2go extern Reg *R; */ - -#define NRGN 600 -/*c2go enum { NRGN = 600 }; */ - -// A Rgn represents a single regopt variable over a region of code -// where a register could potentially be dedicated to that variable. -// The code encompassed by a Rgn is defined by the flow graph, -// starting at enter, flood-filling forward while varno is refahead -// and backward while varno is refbehind, and following branches. A -// single variable may be represented by multiple disjoint Rgns and -// each Rgn may choose a different register for that variable. -// Registers are allocated to regions greedily in order of descending -// cost. -struct Rgn -{ - Flow* enter; - short cost; - short varno; - short regno; -}; - -EXTERN Reg zreg; -EXTERN Rgn region[NRGN]; -EXTERN Rgn* rgp; -EXTERN int nregion; -EXTERN int nvar; -EXTERN uint64 regbits; -EXTERN Bits externs; -EXTERN Bits params; -EXTERN Bits consts; -EXTERN Bits addrs; -EXTERN Bits ivar; -EXTERN Bits ovar; -EXTERN int change; -EXTERN int32 maxnr; - -typedef struct OptStats OptStats; -struct OptStats -{ - int32 ncvtreg; - int32 nspill; - int32 nreload; - int32 ndelmov; - int32 nvar; - int32 naddr; -}; - -EXTERN OptStats ostats; - -/* - * reg.c - */ -void regopt(Prog*); -void dumpone(Flow*, int); -void dumpit(char*, Flow*, int); - -/* - * peep.c -void peep(Prog*); -void excise(Flow*); -int copyu(Prog*, Adr*, Adr*); - */ - -/* - * prog.c - -void proginfo(ProgInfo*, Prog*); - */ diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c deleted file mode 100644 index 3aa7e36386..0000000000 --- a/src/cmd/gc/racewalk.c +++ /dev/null @@ -1,653 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The racewalk pass modifies the code tree for the function as follows: -// -// 1. It inserts a call to racefuncenter at the beginning of each function. -// 2. It inserts a call to racefuncexit at the end of each function. -// 3. It inserts a call to raceread before each memory read. -// 4. It inserts a call to racewrite before each memory write. -// -// The rewriting is not yet complete. Certain nodes are not rewritten -// but should be. - -#include -#include -#include "go.h" - -// TODO(dvyukov): do not instrument initialization as writes: -// a := make([]int, 10) - -static void racewalklist(NodeList *l, NodeList **init); -static void racewalknode(Node **np, NodeList **init, int wr, int skip); -static int callinstr(Node **n, NodeList **init, int wr, int skip); -static Node* uintptraddr(Node *n); -static void makeaddable(Node *n); -static void foreach(Node *n, void(*f)(Node*, void*), void *c); -static void hascallspred(Node *n, void *c); -static void appendinit(Node **np, NodeList *init); -static Node* detachexpr(Node *n, NodeList **init); - -// Do not instrument the following packages at all, -// at best instrumentation would cause infinite recursion. -static const char *omit_pkgs[] = {"runtime", "runtime/race"}; -// Only insert racefuncenter/racefuncexit into the following packages. -// Memory accesses in the packages are either uninteresting or will cause false positives. -static const char *noinst_pkgs[] = {"sync", "sync/atomic"}; - -static int -ispkgin(const char **pkgs, int n) -{ - int i; - - if(myimportpath) { - for(i=0; inname->sym->name, "forkAndExecInChild") == 0; -} - -void -racewalk(Node *fn) -{ - Node *nd; - Node *nodpc; - char s[1024]; - - if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn)) - return; - - if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) { - racewalklist(fn->nbody, nil); - // nothing interesting for race detector in fn->enter - racewalklist(fn->exit, nil); - } - - // nodpc is the PC of the caller as extracted by - // getcallerpc. We use -widthptr(FP) for x86. - // BUG: this will not work on arm. - nodpc = nod(OXXX, nil, nil); - *nodpc = *nodfp; - nodpc->type = types[TUINTPTR]; - nodpc->xoffset = -widthptr; - nd = mkcall("racefuncenter", T, nil, nodpc); - fn->enter = concat(list1(nd), fn->enter); - nd = mkcall("racefuncexit", T, nil); - fn->exit = list(fn->exit, nd); - - if(debug['W']) { - snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym); - dumplist(s, fn->nbody); - snprint(s, sizeof(s), "enter %S", fn->nname->sym); - dumplist(s, fn->enter); - snprint(s, sizeof(s), "exit %S", fn->nname->sym); - dumplist(s, fn->exit); - } -} - -static void -racewalklist(NodeList *l, NodeList **init) -{ - NodeList *instr; - - for(; l; l = l->next) { - instr = nil; - racewalknode(&l->n, &instr, 0, 0); - if(init == nil) - l->n->ninit = concat(l->n->ninit, instr); - else - *init = concat(*init, instr); - } -} - -// walkexpr and walkstmt combined -// walks the tree and adds calls to the -// instrumentation code to top-level (statement) nodes' init -static void -racewalknode(Node **np, NodeList **init, int wr, int skip) -{ - Node *n, *n1; - NodeList *l; - NodeList *fini; - - n = *np; - - if(n == N) - return; - - if(debug['w'] > 1) - dump("racewalk-before", n); - setlineno(n); - if(init == nil) - fatal("racewalk: bad init list"); - if(init == &n->ninit) { - // If init == &n->ninit and n->ninit is non-nil, - // racewalknode might append it to itself. - // nil it out and handle it separately before putting it back. - l = n->ninit; - n->ninit = nil; - racewalklist(l, nil); - racewalknode(&n, &l, wr, skip); // recurse with nil n->ninit - appendinit(&n, l); - *np = n; - return; - } - - racewalklist(n->ninit, nil); - - switch(n->op) { - default: - fatal("racewalk: unknown node type %O", n->op); - - case OAS: - case OAS2FUNC: - racewalknode(&n->left, init, 1, 0); - racewalknode(&n->right, init, 0, 0); - goto ret; - - case OCFUNC: - case OVARKILL: - // can't matter - goto ret; - - case OBLOCK: - if(n->list == nil) - goto ret; - - switch(n->list->n->op) { - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - // Blocks are used for multiple return function calls. - // x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]} - // We don't want to instrument between the statements because it will - // smash the results. - racewalknode(&n->list->n, &n->list->n->ninit, 0, 0); - fini = nil; - racewalklist(n->list->next, &fini); - n->list = concat(n->list, fini); - break; - - default: - // Ordinary block, for loop initialization or inlined bodies. - racewalklist(n->list, nil); - break; - } - goto ret; - - case ODEFER: - racewalknode(&n->left, init, 0, 0); - goto ret; - - case OPROC: - racewalknode(&n->left, init, 0, 0); - goto ret; - - case OCALLINTER: - racewalknode(&n->left, init, 0, 0); - goto ret; - - case OCALLFUNC: - // Instrument dst argument of runtime.writebarrier* calls - // as we do not instrument runtime code. - // typedslicecopy is instrumented in runtime. - if(n->left->sym != S && n->left->sym->pkg == runtimepkg && - (strncmp(n->left->sym->name, "writebarrier", 12) == 0 || strcmp(n->left->sym->name, "typedmemmove") == 0)) { - // Find the dst argument. - // The list can be reordered, so it's not necessary just the first or the second element. - for(l = n->list; l; l = l->next) { - if(strcmp(n->left->sym->name, "typedmemmove") == 0) { - if(l->n->left->xoffset == widthptr) - break; - } else { - if(l->n->left->xoffset == 0) - break; - } - } - if(l == nil) - fatal("racewalk: writebarrier no arg"); - if(l->n->right->op != OADDR) - fatal("racewalk: writebarrier bad arg"); - callinstr(&l->n->right->left, init, 1, 0); - } - racewalknode(&n->left, init, 0, 0); - goto ret; - - case ONOT: - case OMINUS: - case OPLUS: - case OREAL: - case OIMAG: - case OCOM: - racewalknode(&n->left, init, wr, 0); - goto ret; - - case ODOTINTER: - racewalknode(&n->left, init, 0, 0); - goto ret; - - case ODOT: - racewalknode(&n->left, init, 0, 1); - callinstr(&n, init, wr, skip); - goto ret; - - case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND - racewalknode(&n->left, init, 0, 0); - callinstr(&n, init, wr, skip); - goto ret; - - case OIND: // *p - racewalknode(&n->left, init, 0, 0); - callinstr(&n, init, wr, skip); - goto ret; - - case OSPTR: - case OLEN: - case OCAP: - racewalknode(&n->left, init, 0, 0); - if(istype(n->left->type, TMAP)) { - n1 = nod(OCONVNOP, n->left, N); - n1->type = ptrto(types[TUINT8]); - n1 = nod(OIND, n1, N); - typecheck(&n1, Erv); - callinstr(&n1, init, 0, skip); - } - goto ret; - - case OLSH: - case ORSH: - case OLROT: - case OAND: - case OANDNOT: - case OOR: - case OXOR: - case OSUB: - case OMUL: - case OHMUL: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGE: - case OGT: - case OADD: - case OCOMPLEX: - racewalknode(&n->left, init, wr, 0); - racewalknode(&n->right, init, wr, 0); - goto ret; - - case OANDAND: - case OOROR: - racewalknode(&n->left, init, wr, 0); - // walk has ensured the node has moved to a location where - // side effects are safe. - // n->right may not be executed, - // so instrumentation goes to n->right->ninit, not init. - racewalknode(&n->right, &n->right->ninit, wr, 0); - goto ret; - - case ONAME: - callinstr(&n, init, wr, skip); - goto ret; - - case OCONV: - racewalknode(&n->left, init, wr, 0); - goto ret; - - case OCONVNOP: - racewalknode(&n->left, init, wr, 0); - goto ret; - - case ODIV: - case OMOD: - racewalknode(&n->left, init, wr, 0); - racewalknode(&n->right, init, wr, 0); - goto ret; - - case OINDEX: - if(!isfixedarray(n->left->type)) - racewalknode(&n->left, init, 0, 0); - else if(!islvalue(n->left)) { - // index of unaddressable array, like Map[k][i]. - racewalknode(&n->left, init, wr, 0); - racewalknode(&n->right, init, 0, 0); - goto ret; - } - racewalknode(&n->right, init, 0, 0); - if(n->left->type->etype != TSTRING) - callinstr(&n, init, wr, skip); - goto ret; - - case OSLICE: - case OSLICEARR: - case OSLICE3: - case OSLICE3ARR: - // Seems to only lead to double instrumentation. - //racewalknode(&n->left, init, 0, 0); - goto ret; - - case OADDR: - racewalknode(&n->left, init, 0, 1); - goto ret; - - case OEFACE: - // n->left is Type* which is not interesting. - racewalknode(&n->right, init, 0, 0); - goto ret; - - case OITAB: - racewalknode(&n->left, init, 0, 0); - goto ret; - - // should not appear in AST by now - case OSEND: - case ORECV: - case OCLOSE: - case ONEW: - case OXCASE: - case OXFALL: - case OCASE: - case OPANIC: - case ORECOVER: - case OCONVIFACE: - case OCMPIFACE: - case OMAKECHAN: - case OMAKEMAP: - case OMAKESLICE: - case OCALL: - case OCOPY: - case OAPPEND: - case ORUNESTR: - case OARRAYBYTESTR: - case OARRAYRUNESTR: - case OSTRARRAYBYTE: - case OSTRARRAYRUNE: - case OINDEXMAP: // lowered to call - case OCMPSTR: - case OADDSTR: - case ODOTTYPE: - case ODOTTYPE2: - case OAS2DOTTYPE: - case OCALLPART: // lowered to PTRLIT - case OCLOSURE: // lowered to PTRLIT - case ORANGE: // lowered to ordinary for loop - case OARRAYLIT: // lowered to assignments - case OMAPLIT: - case OSTRUCTLIT: - case OAS2: - case OAS2RECV: - case OAS2MAPR: - case OASOP: - yyerror("racewalk: %O must be lowered by now", n->op); - goto ret; - - // impossible nodes: only appear in backend. - case ORROTC: - case OEXTEND: - yyerror("racewalk: %O cannot exist now", n->op); - goto ret; - - // just do generic traversal - case OFOR: - case OIF: - case OCALLMETH: - case ORETURN: - case ORETJMP: - case OSWITCH: - case OSELECT: - case OEMPTY: - case OBREAK: - case OCONTINUE: - case OFALL: - case OGOTO: - case OLABEL: - goto ret; - - // does not require instrumentation - case OPRINT: // don't bother instrumenting it - case OPRINTN: // don't bother instrumenting it - case OCHECKNIL: // always followed by a read. - case OPARAM: // it appears only in fn->exit to copy heap params back - case OCLOSUREVAR:// immutable pointer to captured variable - case ODOTMETH: // either part of CALLMETH or CALLPART (lowered to PTRLIT) - case OINDREG: // at this stage, only n(SP) nodes from nodarg - case ODCL: // declarations (without value) cannot be races - case ODCLCONST: - case ODCLTYPE: - case OTYPE: - case ONONAME: - case OLITERAL: - case OSLICESTR: // always preceded by bounds checking, avoid double instrumentation. - case OTYPESW: // ignored by code generation, do not instrument. - goto ret; - } - -ret: - if(n->op != OBLOCK) // OBLOCK is handled above in a special way. - racewalklist(n->list, init); - if(n->ntest != N) - racewalknode(&n->ntest, &n->ntest->ninit, 0, 0); - if(n->nincr != N) - racewalknode(&n->nincr, &n->nincr->ninit, 0, 0); - racewalklist(n->nbody, nil); - racewalklist(n->nelse, nil); - racewalklist(n->rlist, nil); - *np = n; -} - -static int -isartificial(Node *n) -{ - // compiler-emitted artificial things that we do not want to instrument, - // cant' possibly participate in a data race. - if(n->op == ONAME && n->sym != S && n->sym->name != nil) { - if(strcmp(n->sym->name, "_") == 0) - return 1; - // autotmp's are always local - if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0) - return 1; - // statictmp's are read-only - if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0) - return 1; - // go.itab is accessed only by the compiler and runtime (assume safe) - if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0) - return 1; - } - return 0; -} - -static int -callinstr(Node **np, NodeList **init, int wr, int skip) -{ - char *name; - Node *f, *b, *n; - Type *t; - int class, hascalls; - - n = *np; - //print("callinstr for %+N [ %O ] etype=%E class=%d\n", - // n, n->op, n->type ? n->type->etype : -1, n->class); - - if(skip || n->type == T || n->type->etype >= TIDEAL) - return 0; - t = n->type; - if(isartificial(n)) - return 0; - - b = outervalue(n); - // it skips e.g. stores to ... parameter array - if(isartificial(b)) - return 0; - class = b->class; - // BUG: we _may_ want to instrument PAUTO sometimes - // e.g. if we've got a local variable/method receiver - // that has got a pointer inside. Whether it points to - // the heap or not is impossible to know at compile time - if((class&PHEAP) || class == PPARAMREF || class == PEXTERN - || b->op == OINDEX || b->op == ODOTPTR || b->op == OIND) { - hascalls = 0; - foreach(n, hascallspred, &hascalls); - if(hascalls) { - n = detachexpr(n, init); - *np = n; - } - n = treecopy(n); - makeaddable(n); - if(t->etype == TSTRUCT || isfixedarray(t)) { - name = "racereadrange"; - if(wr) - name = "racewriterange"; - f = mkcall(name, T, init, uintptraddr(n), nodintconst(t->width)); - } else { - name = "raceread"; - if(wr) - name = "racewrite"; - f = mkcall(name, T, init, uintptraddr(n)); - } - *init = list(*init, f); - return 1; - } - return 0; -} - -// makeaddable returns a node whose memory location is the -// same as n, but which is addressable in the Go language -// sense. -// This is different from functions like cheapexpr that may make -// a copy of their argument. -static void -makeaddable(Node *n) -{ - // The arguments to uintptraddr technically have an address but - // may not be addressable in the Go sense: for example, in the case - // of T(v).Field where T is a struct type and v is - // an addressable value. - switch(n->op) { - case OINDEX: - if(isfixedarray(n->left->type)) - makeaddable(n->left); - break; - case ODOT: - case OXDOT: - // Turn T(v).Field into v.Field - if(n->left->op == OCONVNOP) - n->left = n->left->left; - makeaddable(n->left); - break; - case ODOTPTR: - default: - // nothing to do - break; - } -} - -static Node* -uintptraddr(Node *n) -{ - Node *r; - - r = nod(OADDR, n, N); - r->bounded = 1; - r = conv(r, types[TUNSAFEPTR]); - r = conv(r, types[TUINTPTR]); - return r; -} - -static Node* -detachexpr(Node *n, NodeList **init) -{ - Node *addr, *as, *ind, *l; - - addr = nod(OADDR, n, N); - l = temp(ptrto(n->type)); - as = nod(OAS, l, addr); - typecheck(&as, Etop); - walkexpr(&as, init); - *init = list(*init, as); - ind = nod(OIND, l, N); - typecheck(&ind, Erv); - walkexpr(&ind, init); - return ind; -} - -static void -foreachnode(Node *n, void(*f)(Node*, void*), void *c) -{ - if(n) - f(n, c); -} - -static void -foreachlist(NodeList *l, void(*f)(Node*, void*), void *c) -{ - for(; l; l = l->next) - foreachnode(l->n, f, c); -} - -static void -foreach(Node *n, void(*f)(Node*, void*), void *c) -{ - foreachlist(n->ninit, f, c); - foreachnode(n->left, f, c); - foreachnode(n->right, f, c); - foreachlist(n->list, f, c); - foreachnode(n->ntest, f, c); - foreachnode(n->nincr, f, c); - foreachlist(n->nbody, f, c); - foreachlist(n->nelse, f, c); - foreachlist(n->rlist, f, c); -} - -static void -hascallspred(Node *n, void *c) -{ - switch(n->op) { - case OCALL: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - (*(int*)c)++; - } -} - -// appendinit is like addinit in subr.c -// but appends rather than prepends. -static void -appendinit(Node **np, NodeList *init) -{ - Node *n; - - if(init == nil) - return; - - n = *np; - switch(n->op) { - case ONAME: - case OLITERAL: - // There may be multiple refs to this node; - // introduce OCONVNOP to hold init list. - n = nod(OCONVNOP, n, N); - n->type = n->left->type; - n->typecheck = 1; - *np = n; - break; - } - n->ninit = concat(n->ninit, init); - n->ullman = UINF; -} - diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c deleted file mode 100644 index ff9de6c349..0000000000 --- a/src/cmd/gc/range.c +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * range - */ - -#include -#include -#include "go.h" - -void -typecheckrange(Node *n) -{ - int toomany; - char *why; - Type *t, *t1, *t2; - Node *v1, *v2; - NodeList *ll; - - // Typechecking order is important here: - // 0. first typecheck range expression (slice/map/chan), - // it is evaluated only once and so logically it is not part of the loop. - // 1. typcheck produced values, - // this part can declare new vars and so it must be typechecked before body, - // because body can contain a closure that captures the vars. - // 2. decldepth++ to denote loop body. - // 3. typecheck body. - // 4. decldepth--. - - typecheck(&n->right, Erv); - if((t = n->right->type) == T) - goto out; - - // delicate little dance. see typecheckas2 - for(ll=n->list; ll; ll=ll->next) - if(ll->n->defn != n) - typecheck(&ll->n, Erv | Easgn); - - if(isptr[t->etype] && isfixedarray(t->type)) - t = t->type; - n->type = t; - - toomany = 0; - switch(t->etype) { - default: - yyerror("cannot range over %lN", n->right); - goto out; - - case TARRAY: - t1 = types[TINT]; - t2 = t->type; - break; - - case TMAP: - t1 = t->down; - t2 = t->type; - break; - - case TCHAN: - if(!(t->chan & Crecv)) { - yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type); - goto out; - } - t1 = t->type; - t2 = nil; - if(count(n->list) == 2) - toomany = 1; - break; - - case TSTRING: - t1 = types[TINT]; - t2 = runetype; - break; - } - - if(count(n->list) > 2 || toomany) - yyerror("too many variables in range"); - - v1 = N; - if(n->list) - v1 = n->list->n; - v2 = N; - if(n->list && n->list->next) - v2 = n->list->next->n; - - // this is not only a optimization but also a requirement in the spec. - // "if the second iteration variable is the blank identifier, the range - // clause is equivalent to the same clause with only the first variable - // present." - if(isblank(v2)) { - if(v1 != N) - n->list = list1(v1); - v2 = N; - } - - if(v1) { - if(v1->defn == n) - v1->type = t1; - else if(v1->type != T && assignop(t1, v1->type, &why) == 0) - yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); - checkassign(n, v1); - } - if(v2) { - if(v2->defn == n) - v2->type = t2; - else if(v2->type != T && assignop(t2, v2->type, &why) == 0) - yyerror("cannot assign type %T to %lN in range%s", t2, v2, why); - checkassign(n, v2); - } - -out: - // second half of dance - n->typecheck = 1; - for(ll=n->list; ll; ll=ll->next) - if(ll->n->typecheck == 0) - typecheck(&ll->n, Erv | Easgn); - - decldepth++; - typechecklist(n->nbody, Etop); - decldepth--; -} - -void -walkrange(Node *n) -{ - Node *ohv1, *hv1, *hv2; // hidden (old) val 1, 2 - Node *ha, *hit; // hidden aggregate, iterator - Node *hn, *hp; // hidden len, pointer - Node *hb; // hidden bool - Node *a, *v1, *v2; // not hidden aggregate, val 1, 2 - Node *fn, *tmp; - Node *keyname, *valname; - Node *key, *val; - NodeList *body, *init; - Type *th, *t; - int lno; - - t = n->type; - init = nil; - - a = n->right; - lno = setlineno(a); - - v1 = N; - if(n->list) - v1 = n->list->n; - v2 = N; - if(n->list && n->list->next && !isblank(n->list->next->n)) - v2 = n->list->next->n; - // n->list has no meaning anymore, clear it - // to avoid erroneous processing by racewalk. - n->list = nil; - hv2 = N; - - switch(t->etype) { - default: - fatal("walkrange"); - - case TARRAY: - // Lower n into runtime·memclr if possible, for - // fast zeroing of slices and arrays (issue 5373). - // Look for instances of - // - // for i := range a { - // a[i] = zero - // } - // - // in which the evaluation of a is side-effect-free. - if(!debug['N']) - if(!flag_race) - if(v1 != N) - if(v2 == N) - if(n->nbody != nil) - if(n->nbody->n != N) // at least one statement in body - if(n->nbody->next == nil) { // at most one statement in body - tmp = n->nbody->n; // first statement of body - if(tmp->op == OAS) - if(tmp->left->op == OINDEX) - if(samesafeexpr(tmp->left->left, a)) - if(samesafeexpr(tmp->left->right, v1)) - if(t->type->width > 0) - if(iszero(tmp->right)) { - // Convert to - // if len(a) != 0 { - // hp = &a[0] - // hn = len(a)*sizeof(elem(a)) - // memclr(hp, hn) - // i = len(a) - 1 - // } - n->op = OIF; - n->nbody = nil; - n->ntest = nod(ONE, nod(OLEN, a, N), nodintconst(0)); - n->nincr = nil; - - // hp = &a[0] - hp = temp(ptrto(types[TUINT8])); - tmp = nod(OINDEX, a, nodintconst(0)); - tmp->bounded = 1; - tmp = nod(OADDR, tmp, N); - tmp = nod(OCONVNOP, tmp, N); - tmp->type = ptrto(types[TUINT8]); - n->nbody = list(n->nbody, nod(OAS, hp, tmp)); - - // hn = len(a) * sizeof(elem(a)) - hn = temp(types[TUINTPTR]); - tmp = nod(OLEN, a, N); - tmp = nod(OMUL, tmp, nodintconst(t->type->width)); - tmp = conv(tmp, types[TUINTPTR]); - n->nbody = list(n->nbody, nod(OAS, hn, tmp)); - - // memclr(hp, hn) - fn = mkcall("memclr", T, nil, hp, hn); - n->nbody = list(n->nbody, fn); - - // i = len(a) - 1 - v1 = nod(OAS, v1, nod(OSUB, nod(OLEN, a, N), nodintconst(1))); - n->nbody = list(n->nbody, v1); - - typecheck(&n->ntest, Erv); - typechecklist(n->nbody, Etop); - walkstmt(&n); - lineno = lno; - return; - } - } - - // orderstmt arranged for a copy of the array/slice variable if needed. - ha = a; - hv1 = temp(types[TINT]); - hn = temp(types[TINT]); - hp = nil; - - init = list(init, nod(OAS, hv1, N)); - init = list(init, nod(OAS, hn, nod(OLEN, ha, N))); - if(v2) { - hp = temp(ptrto(n->type->type)); - tmp = nod(OINDEX, ha, nodintconst(0)); - tmp->bounded = 1; - init = list(init, nod(OAS, hp, nod(OADDR, tmp, N))); - } - - n->ntest = nod(OLT, hv1, hn); - n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); - if(v1 == N) - body = nil; - else if(v2 == N) - body = list1(nod(OAS, v1, hv1)); - else { - a = nod(OAS2, N, N); - a->list = list(list1(v1), v2); - a->rlist = list(list1(hv1), nod(OIND, hp, N)); - body = list1(a); - - // Advance pointer as part of increment. - // We used to advance the pointer before executing the loop body, - // but doing so would make the pointer point past the end of the - // array during the final iteration, possibly causing another unrelated - // piece of memory not to be garbage collected until the loop finished. - // Advancing during the increment ensures that the pointer p only points - // pass the end of the array during the final "p++; i++; if(i >= len(x)) break;", - // after which p is dead, so it cannot confuse the collector. - tmp = nod(OADD, hp, nodintconst(t->type->width)); - tmp->type = hp->type; - tmp->typecheck = 1; - tmp->right->type = types[tptr]; - tmp->right->typecheck = 1; - a = nod(OAS, hp, tmp); - typecheck(&a, Etop); - n->nincr->ninit = list1(a); - } - break; - - case TMAP: - // orderstmt allocated the iterator for us. - // we only use a once, so no copy needed. - ha = a; - th = hiter(t); - hit = n->alloc; - hit->type = th; - n->left = N; - keyname = newname(th->type->sym); // depends on layout of iterator struct. See reflect.c:hiter - valname = newname(th->type->down->sym); // ditto - - fn = syslook("mapiterinit", 1); - argtype(fn, t->down); - argtype(fn, t->type); - argtype(fn, th); - init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N))); - n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil()); - - fn = syslook("mapiternext", 1); - argtype(fn, th); - n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N)); - - key = nod(ODOT, hit, keyname); - key = nod(OIND, key, N); - if(v1 == N) - body = nil; - else if(v2 == N) { - body = list1(nod(OAS, v1, key)); - } else { - val = nod(ODOT, hit, valname); - val = nod(OIND, val, N); - a = nod(OAS2, N, N); - a->list = list(list1(v1), v2); - a->rlist = list(list1(key), val); - body = list1(a); - } - break; - - case TCHAN: - // orderstmt arranged for a copy of the channel variable. - ha = a; - n->ntest = N; - - hv1 = temp(t->type); - hv1->typecheck = 1; - if(haspointers(t->type)) - init = list(init, nod(OAS, hv1, N)); - hb = temp(types[TBOOL]); - - n->ntest = nod(ONE, hb, nodbool(0)); - a = nod(OAS2RECV, N, N); - a->typecheck = 1; - a->list = list(list1(hv1), hb); - a->rlist = list1(nod(ORECV, ha, N)); - n->ntest->ninit = list1(a); - if(v1 == N) - body = nil; - else - body = list1(nod(OAS, v1, hv1)); - break; - - case TSTRING: - // orderstmt arranged for a copy of the string variable. - ha = a; - - ohv1 = temp(types[TINT]); - - hv1 = temp(types[TINT]); - init = list(init, nod(OAS, hv1, N)); - - if(v2 == N) - a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1)); - else { - hv2 = temp(runetype); - a = nod(OAS2, N, N); - a->list = list(list1(hv1), hv2); - fn = syslook("stringiter2", 0); - a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1)); - } - n->ntest = nod(ONE, hv1, nodintconst(0)); - n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); - - - body = nil; - if(v1 != N) - body = list1(nod(OAS, v1, ohv1)); - if(v2 != N) - body = list(body, nod(OAS, v2, hv2)); - break; - } - - n->op = OFOR; - typechecklist(init, Etop); - n->ninit = concat(n->ninit, init); - typechecklist(n->ntest->ninit, Etop); - typecheck(&n->ntest, Erv); - typecheck(&n->nincr, Etop); - typechecklist(body, Etop); - n->nbody = concat(body, n->nbody); - walkstmt(&n); - - lineno = lno; -} - diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c deleted file mode 100644 index 9390ab9a86..0000000000 --- a/src/cmd/gc/reflect.c +++ /dev/null @@ -1,1609 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "../ld/textflag.h" -#include "../../runtime/mgc0.h" -#include "../../runtime/typekind.h" - -/* - * runtime interface and reflection data structures - */ - -static NodeList* signatlist; -static Sym* dtypesym(Type*); -static Sym* weaktypesym(Type*); -static Sym* dalgsym(Type*); -static int usegcprog(Type*); -static void gengcprog(Type*, Sym**, Sym**); -static void gengcmask(Type*, uint8[16]); - -static int -sigcmp(Sig *a, Sig *b) -{ - int i; - - i = strcmp(a->name, b->name); - if(i != 0) - return i; - if(a->pkg == b->pkg) - return 0; - if(a->pkg == nil) - return -1; - if(b->pkg == nil) - return +1; - return strcmp(a->pkg->path->s, b->pkg->path->s); -} - -static Sig* -lsort(Sig *l, int(*f)(Sig*, Sig*)) -{ - Sig *l1, *l2, *le; - - if(l == 0 || l->link == 0) - return l; - - l1 = l; - l2 = l; - for(;;) { - l2 = l2->link; - if(l2 == 0) - break; - l2 = l2->link; - if(l2 == 0) - break; - l1 = l1->link; - } - - l2 = l1->link; - l1->link = 0; - l1 = lsort(l, f); - l2 = lsort(l2, f); - - /* set up lead element */ - if((*f)(l1, l2) < 0) { - l = l1; - l1 = l1->link; - } else { - l = l2; - l2 = l2->link; - } - le = l; - - for(;;) { - if(l1 == 0) { - while(l2) { - le->link = l2; - le = l2; - l2 = l2->link; - } - le->link = 0; - break; - } - if(l2 == 0) { - while(l1) { - le->link = l1; - le = l1; - l1 = l1->link; - } - break; - } - if((*f)(l1, l2) < 0) { - le->link = l1; - le = l1; - l1 = l1->link; - } else { - le->link = l2; - le = l2; - l2 = l2->link; - } - } - le->link = 0; - return l; -} - -// Builds a type respresenting a Bucket structure for -// the given map type. This type is not visible to users - -// we include only enough information to generate a correct GC -// program for it. -// Make sure this stays in sync with ../../runtime/hashmap.c! -enum { - BUCKETSIZE = 8, - MAXKEYSIZE = 128, - MAXVALSIZE = 128, -}; - -static Type* -makefield(char *name, Type *t) -{ - Type *f; - - f = typ(TFIELD); - f->type = t; - f->sym = mal(sizeof(Sym)); - f->sym->name = name; - return f; -} - -Type* -mapbucket(Type *t) -{ - Type *keytype, *valtype; - Type *bucket, *arr; - Type *field[4]; - int32 n; - - if(t->bucket != T) - return t->bucket; - - bucket = typ(TSTRUCT); - keytype = t->down; - valtype = t->type; - dowidth(keytype); - dowidth(valtype); - if(keytype->width > MAXKEYSIZE) - keytype = ptrto(keytype); - if(valtype->width > MAXVALSIZE) - valtype = ptrto(valtype); - - // The first field is: uint8 topbits[BUCKETSIZE]. - arr = typ(TARRAY); - arr->type = types[TUINT8]; - arr->bound = BUCKETSIZE; - field[0] = makefield("topbits", arr); - arr = typ(TARRAY); - arr->type = keytype; - arr->bound = BUCKETSIZE; - field[1] = makefield("keys", arr); - arr = typ(TARRAY); - arr->type = valtype; - arr->bound = BUCKETSIZE; - field[2] = makefield("values", arr); - field[3] = makefield("overflow", ptrto(bucket)); - - // link up fields - bucket->noalg = 1; - bucket->local = t->local; - bucket->type = field[0]; - for(n = 0; n < nelem(field)-1; n++) - field[n]->down = field[n+1]; - field[nelem(field)-1]->down = T; - dowidth(bucket); - - // Pad to the native integer alignment. - // This is usually the same as widthptr; the exception (as usual) is amd64p32. - if(widthreg > widthptr) - bucket->width += widthreg - widthptr; - - // See comment on hmap.overflow in ../../runtime/hashmap.go. - if(!haspointers(t->type) && !haspointers(t->down) && - t->type->width <= MAXKEYSIZE && t->down->width <= MAXVALSIZE) - bucket->haspointers = 1; // no pointers - - t->bucket = bucket; - bucket->map = t; - return bucket; -} - -// Builds a type representing a Hmap structure for the given map type. -// Make sure this stays in sync with ../../runtime/hashmap.go! -Type* -hmap(Type *t) -{ - Type *h, *bucket; - Type *field[8]; - int32 n; - - if(t->hmap != T) - return t->hmap; - - bucket = mapbucket(t); - field[0] = makefield("count", types[TINT]); - field[1] = makefield("flags", types[TUINT8]); - field[2] = makefield("B", types[TUINT8]); - field[3] = makefield("hash0", types[TUINT32]); - field[4] = makefield("buckets", ptrto(bucket)); - field[5] = makefield("oldbuckets", ptrto(bucket)); - field[6] = makefield("nevacuate", types[TUINTPTR]); - field[7] = makefield("overflow", types[TUNSAFEPTR]); - - h = typ(TSTRUCT); - h->noalg = 1; - h->local = t->local; - h->type = field[0]; - for(n = 0; n < nelem(field)-1; n++) - field[n]->down = field[n+1]; - field[nelem(field)-1]->down = T; - dowidth(h); - t->hmap = h; - h->map = t; - return h; -} - -Type* -hiter(Type *t) -{ - int32 n; - Type *field[12]; - Type *i; - - if(t->hiter != T) - return t->hiter; - - // build a struct: - // hash_iter { - // key *Key - // val *Value - // t *MapType - // h *Hmap - // buckets *Bucket - // bptr *Bucket - // overflow0 unsafe.Pointer - // overflow1 unsafe.Pointer - // startBucket uintptr - // stuff uintptr - // bucket uintptr - // checkBucket uintptr - // } - // must match ../../runtime/hashmap.c:hash_iter. - field[0] = makefield("key", ptrto(t->down)); - field[1] = makefield("val", ptrto(t->type)); - field[2] = makefield("t", ptrto(types[TUINT8])); - field[3] = makefield("h", ptrto(hmap(t))); - field[4] = makefield("buckets", ptrto(mapbucket(t))); - field[5] = makefield("bptr", ptrto(mapbucket(t))); - field[6] = makefield("overflow0", types[TUNSAFEPTR]); - field[7] = makefield("overflow1", types[TUNSAFEPTR]); - field[8] = makefield("startBucket", types[TUINTPTR]); - field[9] = makefield("stuff", types[TUINTPTR]); // offset+wrapped+B+I - field[10] = makefield("bucket", types[TUINTPTR]); - field[11] = makefield("checkBucket", types[TUINTPTR]); - - // build iterator struct holding the above fields - i = typ(TSTRUCT); - i->noalg = 1; - i->type = field[0]; - for(n = 0; n < nelem(field)-1; n++) - field[n]->down = field[n+1]; - field[nelem(field)-1]->down = T; - dowidth(i); - if(i->width != 12 * widthptr) - yyerror("hash_iter size not correct %d %d", i->width, 12 * widthptr); - t->hiter = i; - i->map = t; - return i; -} - -/* - * f is method type, with receiver. - * return function type, receiver as first argument (or not). - */ -Type* -methodfunc(Type *f, Type *receiver) -{ - NodeList *in, *out; - Node *d; - Type *t; - - in = nil; - if(receiver) { - d = nod(ODCLFIELD, N, N); - d->type = receiver; - in = list(in, d); - } - for(t=getinargx(f)->type; t; t=t->down) { - d = nod(ODCLFIELD, N, N); - d->type = t->type; - d->isddd = t->isddd; - in = list(in, d); - } - - out = nil; - for(t=getoutargx(f)->type; t; t=t->down) { - d = nod(ODCLFIELD, N, N); - d->type = t->type; - out = list(out, d); - } - - t = functype(N, in, out); - if(f->nname) { - // Link to name of original method function. - t->nname = f->nname; - } - return t; -} - -/* - * return methods of non-interface type t, sorted by name. - * generates stub functions as needed. - */ -static Sig* -methods(Type *t) -{ - Type *f, *mt, *it, *this; - Sig *a, *b; - Sym *method; - - // method type - mt = methtype(t, 0); - if(mt == T) - return nil; - expandmeth(mt); - - // type stored in interface word - it = t; - if(!isdirectiface(it)) - it = ptrto(t); - - // make list of methods for t, - // generating code if necessary. - a = nil; - for(f=mt->xmethod; f; f=f->down) { - if(f->etype != TFIELD) - fatal("methods: not field %T", f); - if (f->type->etype != TFUNC || f->type->thistuple == 0) - fatal("non-method on %T method %S %T\n", mt, f->sym, f); - if (!getthisx(f->type)->type) - fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f); - if(f->nointerface) - continue; - - method = f->sym; - if(method == nil) - continue; - - // get receiver type for this particular method. - // if pointer receiver but non-pointer t and - // this is not an embedded pointer inside a struct, - // method does not apply. - this = getthisx(f->type)->type->type; - if(isptr[this->etype] && this->type == t) - continue; - if(isptr[this->etype] && !isptr[t->etype] - && f->embedded != 2 && !isifacemethod(f->type)) - continue; - - b = mal(sizeof(*b)); - b->link = a; - a = b; - - a->name = method->name; - if(!exportname(method->name)) { - if(method->pkg == nil) - fatal("methods: missing package"); - a->pkg = method->pkg; - } - a->isym = methodsym(method, it, 1); - a->tsym = methodsym(method, t, 0); - a->type = methodfunc(f->type, t); - a->mtype = methodfunc(f->type, nil); - - if(!(a->isym->flags & SymSiggen)) { - a->isym->flags |= SymSiggen; - if(!eqtype(this, it) || this->width < types[tptr]->width) { - compiling_wrappers = 1; - genwrapper(it, f, a->isym, 1); - compiling_wrappers = 0; - } - } - - if(!(a->tsym->flags & SymSiggen)) { - a->tsym->flags |= SymSiggen; - if(!eqtype(this, t)) { - compiling_wrappers = 1; - genwrapper(t, f, a->tsym, 0); - compiling_wrappers = 0; - } - } - } - - return lsort(a, sigcmp); -} - -/* - * return methods of interface type t, sorted by name. - */ -static Sig* -imethods(Type *t) -{ - Sig *a, *all, *last; - Type *f; - Sym *method, *isym; - - all = nil; - last = nil; - for(f=t->type; f; f=f->down) { - if(f->etype != TFIELD) - fatal("imethods: not field"); - if(f->type->etype != TFUNC || f->sym == nil) - continue; - method = f->sym; - a = mal(sizeof(*a)); - a->name = method->name; - if(!exportname(method->name)) { - if(method->pkg == nil) - fatal("imethods: missing package"); - a->pkg = method->pkg; - } - a->mtype = f->type; - a->offset = 0; - a->type = methodfunc(f->type, nil); - - if(last && sigcmp(last, a) >= 0) - fatal("sigcmp vs sortinter %s %s", last->name, a->name); - if(last == nil) - all = a; - else - last->link = a; - last = a; - - // Compiler can only refer to wrappers for non-blank methods. - if(isblanksym(method)) - continue; - - // NOTE(rsc): Perhaps an oversight that - // IfaceType.Method is not in the reflect data. - // Generate the method body, so that compiled - // code can refer to it. - isym = methodsym(method, t, 0); - if(!(isym->flags & SymSiggen)) { - isym->flags |= SymSiggen; - genwrapper(t, f, isym, 0); - } - } - return all; -} - -static void -dimportpath(Pkg *p) -{ - static Pkg *gopkg; - char *nam; - Node *n; - - if(p->pathsym != S) - return; - - if(gopkg == nil) { - gopkg = mkpkg(newstrlit("go")); - gopkg->name = "go"; - } - nam = smprint("importpath.%s.", p->prefix); - - n = nod(ONAME, N, N); - n->sym = pkglookup(nam, gopkg); - free(nam); - n->class = PEXTERN; - n->xoffset = 0; - p->pathsym = n->sym; - - gdatastring(n, p->path); - ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA); -} - -static int -dgopkgpath(Sym *s, int ot, Pkg *pkg) -{ - if(pkg == nil) - return dgostringptr(s, ot, nil); - - // Emit reference to go.importpath.""., which 6l will - // rewrite using the correct import path. Every package - // that imports this one directly defines the symbol. - if(pkg == localpkg) { - static Sym *ns; - - if(ns == nil) - ns = pkglookup("importpath.\"\".", mkpkg(newstrlit("go"))); - return dsymptr(s, ot, ns, 0); - } - - dimportpath(pkg); - return dsymptr(s, ot, pkg->pathsym, 0); -} - -/* - * uncommonType - * ../../runtime/type.go:/uncommonType - */ -static int -dextratype(Sym *sym, int off, Type *t, int ptroff) -{ - int ot, n; - Sym *s; - Sig *a, *m; - - m = methods(t); - if(t->sym == nil && m == nil) - return off; - - // fill in *extraType pointer in header - off = rnd(off, widthptr); - dsymptr(sym, ptroff, sym, off); - - n = 0; - for(a=m; a; a=a->link) { - dtypesym(a->type); - n++; - } - - ot = off; - s = sym; - if(t->sym) { - ot = dgostringptr(s, ot, t->sym->name); - if(t != types[t->etype] && t != errortype) - ot = dgopkgpath(s, ot, t->sym->pkg); - else - ot = dgostringptr(s, ot, nil); - } else { - ot = dgostringptr(s, ot, nil); - ot = dgostringptr(s, ot, nil); - } - - // slice header - ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint); - ot = duintxx(s, ot, n, widthint); - ot = duintxx(s, ot, n, widthint); - - // methods - for(a=m; a; a=a->link) { - // method - // ../../runtime/type.go:/method - ot = dgostringptr(s, ot, a->name); - ot = dgopkgpath(s, ot, a->pkg); - ot = dsymptr(s, ot, dtypesym(a->mtype), 0); - ot = dsymptr(s, ot, dtypesym(a->type), 0); - if(a->isym) - ot = dsymptr(s, ot, a->isym, 0); - else - ot = duintptr(s, ot, 0); - if(a->tsym) - ot = dsymptr(s, ot, a->tsym, 0); - else - ot = duintptr(s, ot, 0); - } - - return ot; -} - -static int -kinds[] = -{ - [TINT] = KindInt, - [TUINT] = KindUint, - [TINT8] = KindInt8, - [TUINT8] = KindUint8, - [TINT16] = KindInt16, - [TUINT16] = KindUint16, - [TINT32] = KindInt32, - [TUINT32] = KindUint32, - [TINT64] = KindInt64, - [TUINT64] = KindUint64, - [TUINTPTR] = KindUintptr, - [TFLOAT32] = KindFloat32, - [TFLOAT64] = KindFloat64, - [TBOOL] = KindBool, - [TSTRING] = KindString, - [TPTR32] = KindPtr, - [TPTR64] = KindPtr, - [TSTRUCT] = KindStruct, - [TINTER] = KindInterface, - [TCHAN] = KindChan, - [TMAP] = KindMap, - [TARRAY] = KindArray, - [TFUNC] = KindFunc, - [TCOMPLEX64] = KindComplex64, - [TCOMPLEX128] = KindComplex128, - [TUNSAFEPTR] = KindUnsafePointer, -}; - -int -haspointers(Type *t) -{ - Type *t1; - int ret; - - if(t->haspointers != 0) - return t->haspointers - 1; - - switch(t->etype) { - case TINT: - case TUINT: - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TUINTPTR: - case TFLOAT32: - case TFLOAT64: - case TCOMPLEX64: - case TCOMPLEX128: - case TBOOL: - ret = 0; - break; - case TARRAY: - if(t->bound < 0) { // slice - ret = 1; - break; - } - if(t->bound == 0) { // empty array - ret = 0; - break; - } - ret = haspointers(t->type); - break; - case TSTRUCT: - ret = 0; - for(t1=t->type; t1!=T; t1=t1->down) { - if(haspointers(t1->type)) { - ret = 1; - break; - } - } - break; - case TSTRING: - case TPTR32: - case TPTR64: - case TUNSAFEPTR: - case TINTER: - case TCHAN: - case TMAP: - case TFUNC: - default: - ret = 1; - break; - } - - t->haspointers = 1+ret; - return ret; -} - -/* - * commonType - * ../../runtime/type.go:/commonType - */ -static int -dcommontype(Sym *s, int ot, Type *t) -{ - int i, alg, sizeofAlg, gcprog; - Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits; - uint8 gcmask[16]; - static Sym *algarray; - uint64 x1, x2; - char *p; - - if(ot != 0) - fatal("dcommontype %d", ot); - - sizeofAlg = 2*widthptr; - if(algarray == nil) - algarray = pkglookup("algarray", runtimepkg); - dowidth(t); - alg = algtype(t); - algsym = S; - if(alg < 0 || alg == AMEM) - algsym = dalgsym(t); - - if(t->sym != nil && !isptr[t->etype]) - sptr = dtypesym(ptrto(t)); - else - sptr = weaktypesym(ptrto(t)); - - // All (non-reflect-allocated) Types share the same zero object. - // Each place in the compiler where a pointer to the zero object - // might be returned by a runtime call (map access return value, - // 2-arg type cast) declares the size of the zerovalue it needs. - // The linker magically takes the max of all the sizes. - zero = pkglookup("zerovalue", runtimepkg); - - // We use size 0 here so we get the pointer to the zero value, - // but don't allocate space for the zero value unless we need it. - // TODO: how do we get this symbol into bss? We really want - // a read-only bss, but I don't think such a thing exists. - - // ../../pkg/reflect/type.go:/^type.commonType - // actual type structure - // type commonType struct { - // size uintptr - // hash uint32 - // _ uint8 - // align uint8 - // fieldAlign uint8 - // kind uint8 - // alg unsafe.Pointer - // gc unsafe.Pointer - // string *string - // *extraType - // ptrToThis *Type - // zero unsafe.Pointer - // } - ot = duintptr(s, ot, t->width); - ot = duint32(s, ot, typehash(t)); - ot = duint8(s, ot, 0); // unused - - // runtime (and common sense) expects alignment to be a power of two. - i = t->align; - if(i == 0) - i = 1; - if((i&(i-1)) != 0) - fatal("invalid alignment %d for %T", t->align, t); - ot = duint8(s, ot, t->align); // align - ot = duint8(s, ot, t->align); // fieldAlign - - gcprog = usegcprog(t); - i = kinds[t->etype]; - if(t->etype == TARRAY && t->bound < 0) - i = KindSlice; - if(!haspointers(t)) - i |= KindNoPointers; - if(isdirectiface(t)) - i |= KindDirectIface; - if(gcprog) - i |= KindGCProg; - ot = duint8(s, ot, i); // kind - if(algsym == S) - ot = dsymptr(s, ot, algarray, alg*sizeofAlg); - else - ot = dsymptr(s, ot, algsym, 0); - // gc - if(gcprog) { - gengcprog(t, &gcprog0, &gcprog1); - if(gcprog0 != S) - ot = dsymptr(s, ot, gcprog0, 0); - else - ot = duintptr(s, ot, 0); - ot = dsymptr(s, ot, gcprog1, 0); - } else { - gengcmask(t, gcmask); - x1 = 0; - for(i=0; i<8; i++) - x1 = x1<<8 | gcmask[i]; - if(widthptr == 4) { - p = smprint("gcbits.0x%016llux", x1); - } else { - x2 = 0; - for(i=0; i<8; i++) - x2 = x2<<8 | gcmask[i+8]; - p = smprint("gcbits.0x%016llux%016llux", x1, x2); - } - sbits = pkglookup(p, runtimepkg); - if((sbits->flags & SymUniq) == 0) { - sbits->flags |= SymUniq; - for(i = 0; i < 2*widthptr; i++) - duint8(sbits, i, gcmask[i]); - ggloblsym(sbits, 2*widthptr, DUPOK|RODATA); - } - ot = dsymptr(s, ot, sbits, 0); - ot = duintptr(s, ot, 0); - } - p = smprint("%-uT", t); - //print("dcommontype: %s\n", p); - ot = dgostringptr(s, ot, p); // string - free(p); - - // skip pointer to extraType, - // which follows the rest of this type structure. - // caller will fill in if needed. - // otherwise linker will assume 0. - ot += widthptr; - - ot = dsymptr(s, ot, sptr, 0); // ptrto type - ot = dsymptr(s, ot, zero, 0); // ptr to zero value - return ot; -} - -Sym* -typesym(Type *t) -{ - char *p; - Sym *s; - - p = smprint("%-T", t); - s = pkglookup(p, typepkg); - //print("typesym: %s -> %+S\n", p, s); - free(p); - return s; -} - -Sym* -tracksym(Type *t) -{ - char *p; - Sym *s; - - p = smprint("%-T.%s", t->outer, t->sym->name); - s = pkglookup(p, trackpkg); - free(p); - return s; -} - -Sym* -typelinksym(Type *t) -{ - char *p; - Sym *s; - - // %-uT is what the generated Type's string field says. - // It uses (ambiguous) package names instead of import paths. - // %-T is the complete, unambiguous type name. - // We want the types to end up sorted by string field, - // so use that first in the name, and then add :%-T to - // disambiguate. The names are a little long but they are - // discarded by the linker and do not end up in the symbol - // table of the final binary. - p = smprint("%-uT/%-T", t, t); - s = pkglookup(p, typelinkpkg); - //print("typelinksym: %s -> %+S\n", p, s); - free(p); - return s; -} - -Sym* -typesymprefix(char *prefix, Type *t) -{ - char *p; - Sym *s; - - p = smprint("%s.%-T", prefix, t); - s = pkglookup(p, typepkg); - //print("algsym: %s -> %+S\n", p, s); - free(p); - return s; -} - -Sym* -typenamesym(Type *t) -{ - Sym *s; - Node *n; - - if(t == T || (isptr[t->etype] && t->type == T) || isideal(t)) - fatal("typename %T", t); - s = typesym(t); - if(s->def == N) { - n = nod(ONAME, N, N); - n->sym = s; - n->type = types[TUINT8]; - n->addable = 1; - n->ullman = 1; - n->class = PEXTERN; - n->xoffset = 0; - n->typecheck = 1; - s->def = n; - - signatlist = list(signatlist, typenod(t)); - } - return s->def->sym; -} - -Node* -typename(Type *t) -{ - Sym *s; - Node *n; - - s = typenamesym(t); - n = nod(OADDR, s->def, N); - n->type = ptrto(s->def->type); - n->addable = 1; - n->ullman = 2; - n->typecheck = 1; - return n; -} - -static Sym* -weaktypesym(Type *t) -{ - char *p; - Sym *s; - - p = smprint("%-T", t); - s = pkglookup(p, weaktypepkg); - //print("weaktypesym: %s -> %+S\n", p, s); - free(p); - return s; -} - -/* - * Returns 1 if t has a reflexive equality operator. - * That is, if x==x for all x of type t. - */ -static int -isreflexive(Type *t) -{ - Type *t1; - switch(t->etype) { - case TBOOL: - case TINT: - case TUINT: - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TUINTPTR: - case TPTR32: - case TPTR64: - case TUNSAFEPTR: - case TSTRING: - case TCHAN: - return 1; - case TFLOAT32: - case TFLOAT64: - case TCOMPLEX64: - case TCOMPLEX128: - case TINTER: - return 0; - case TARRAY: - if(isslice(t)) - fatal("slice can't be a map key: %T", t); - return isreflexive(t->type); - case TSTRUCT: - for(t1=t->type; t1!=T; t1=t1->down) { - if(!isreflexive(t1->type)) - return 0; - } - return 1; - default: - fatal("bad type for map key: %T", t); - return 0; - } -} - -static Sym* -dtypesym(Type *t) -{ - int ot, xt, n, isddd, dupok; - Sym *s, *s1, *s2, *s3, *s4, *slink; - Sig *a, *m; - Type *t1, *tbase, *t2; - - // Replace byte, rune aliases with real type. - // They've been separate internally to make error messages - // better, but we have to merge them in the reflect tables. - if(t == bytetype || t == runetype) - t = types[t->etype]; - - if(isideal(t)) - fatal("dtypesym %T", t); - - s = typesym(t); - if(s->flags & SymSiggen) - return s; - s->flags |= SymSiggen; - - // special case (look for runtime below): - // when compiling package runtime, - // emit the type structures for int, float, etc. - tbase = t; - if(isptr[t->etype] && t->sym == S && t->type->sym != S) - tbase = t->type; - dupok = 0; - if(tbase->sym == S) - dupok = DUPOK; - - if(compiling_runtime && - (tbase == types[tbase->etype] || - tbase == bytetype || - tbase == runetype || - tbase == errortype)) { // int, float, etc - goto ok; - } - - // named types from other files are defined only by those files - if(tbase->sym && !tbase->local) - return s; - if(isforw[tbase->etype]) - return s; - -ok: - ot = 0; - xt = 0; - switch(t->etype) { - default: - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - break; - - case TARRAY: - if(t->bound >= 0) { - // ../../runtime/type.go:/ArrayType - s1 = dtypesym(t->type); - t2 = typ(TARRAY); - t2->type = t->type; - t2->bound = -1; // slice - s2 = dtypesym(t2); - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s1, 0); - ot = dsymptr(s, ot, s2, 0); - ot = duintptr(s, ot, t->bound); - } else { - // ../../runtime/type.go:/SliceType - s1 = dtypesym(t->type); - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s1, 0); - } - break; - - case TCHAN: - // ../../runtime/type.go:/ChanType - s1 = dtypesym(t->type); - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s1, 0); - ot = duintptr(s, ot, t->chan); - break; - - case TFUNC: - for(t1=getthisx(t)->type; t1; t1=t1->down) - dtypesym(t1->type); - isddd = 0; - for(t1=getinargx(t)->type; t1; t1=t1->down) { - isddd = t1->isddd; - dtypesym(t1->type); - } - for(t1=getoutargx(t)->type; t1; t1=t1->down) - dtypesym(t1->type); - - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = duint8(s, ot, isddd); - - // two slice headers: in and out. - ot = rnd(ot, widthptr); - ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint)); - n = t->thistuple + t->intuple; - ot = duintxx(s, ot, n, widthint); - ot = duintxx(s, ot, n, widthint); - ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr); - ot = duintxx(s, ot, t->outtuple, widthint); - ot = duintxx(s, ot, t->outtuple, widthint); - - // slice data - for(t1=getthisx(t)->type; t1; t1=t1->down, n++) - ot = dsymptr(s, ot, dtypesym(t1->type), 0); - for(t1=getinargx(t)->type; t1; t1=t1->down, n++) - ot = dsymptr(s, ot, dtypesym(t1->type), 0); - for(t1=getoutargx(t)->type; t1; t1=t1->down, n++) - ot = dsymptr(s, ot, dtypesym(t1->type), 0); - break; - - case TINTER: - m = imethods(t); - n = 0; - for(a=m; a; a=a->link) { - dtypesym(a->type); - n++; - } - - // ../../runtime/type.go:/InterfaceType - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); - ot = duintxx(s, ot, n, widthint); - ot = duintxx(s, ot, n, widthint); - for(a=m; a; a=a->link) { - // ../../runtime/type.go:/imethod - ot = dgostringptr(s, ot, a->name); - ot = dgopkgpath(s, ot, a->pkg); - ot = dsymptr(s, ot, dtypesym(a->type), 0); - } - break; - - case TMAP: - // ../../runtime/type.go:/MapType - s1 = dtypesym(t->down); - s2 = dtypesym(t->type); - s3 = dtypesym(mapbucket(t)); - s4 = dtypesym(hmap(t)); - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s1, 0); - ot = dsymptr(s, ot, s2, 0); - ot = dsymptr(s, ot, s3, 0); - ot = dsymptr(s, ot, s4, 0); - if(t->down->width > MAXKEYSIZE) { - ot = duint8(s, ot, widthptr); - ot = duint8(s, ot, 1); // indirect - } else { - ot = duint8(s, ot, t->down->width); - ot = duint8(s, ot, 0); // not indirect - } - if(t->type->width > MAXVALSIZE) { - ot = duint8(s, ot, widthptr); - ot = duint8(s, ot, 1); // indirect - } else { - ot = duint8(s, ot, t->type->width); - ot = duint8(s, ot, 0); // not indirect - } - ot = duint16(s, ot, mapbucket(t)->width); - ot = duint8(s, ot, isreflexive(t->down)); - break; - - case TPTR32: - case TPTR64: - if(t->type->etype == TANY) { - // ../../runtime/type.go:/UnsafePointerType - ot = dcommontype(s, ot, t); - break; - } - // ../../runtime/type.go:/PtrType - s1 = dtypesym(t->type); - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s1, 0); - break; - - case TSTRUCT: - // ../../runtime/type.go:/StructType - // for security, only the exported fields. - n = 0; - for(t1=t->type; t1!=T; t1=t1->down) { - dtypesym(t1->type); - n++; - } - ot = dcommontype(s, ot, t); - xt = ot - 3*widthptr; - ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); - ot = duintxx(s, ot, n, widthint); - ot = duintxx(s, ot, n, widthint); - for(t1=t->type; t1!=T; t1=t1->down) { - // ../../runtime/type.go:/structField - if(t1->sym && !t1->embedded) { - ot = dgostringptr(s, ot, t1->sym->name); - if(exportname(t1->sym->name)) - ot = dgostringptr(s, ot, nil); - else - ot = dgopkgpath(s, ot, t1->sym->pkg); - } else { - ot = dgostringptr(s, ot, nil); - if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg) - ot = dgopkgpath(s, ot, localpkg); - else - ot = dgostringptr(s, ot, nil); - } - ot = dsymptr(s, ot, dtypesym(t1->type), 0); - ot = dgostrlitptr(s, ot, t1->note); - ot = duintptr(s, ot, t1->width); // field offset - } - break; - } - ot = dextratype(s, ot, t, xt); - ggloblsym(s, ot, dupok|RODATA); - - // generate typelink.foo pointing at s = type.foo. - // The linker will leave a table of all the typelinks for - // types in the binary, so reflect can find them. - // We only need the link for unnamed composites that - // we want be able to find. - if(t->sym == S) { - switch(t->etype) { - case TARRAY: - case TCHAN: - case TMAP: - slink = typelinksym(t); - dsymptr(slink, 0, s, 0); - ggloblsym(slink, widthptr, dupok|RODATA); - } - } - - return s; -} - -void -dumptypestructs(void) -{ - int i; - NodeList *l; - Node *n; - Type *t; - Pkg *p; - - // copy types from externdcl list to signatlist - for(l=externdcl; l; l=l->next) { - n = l->n; - if(n->op != OTYPE) - continue; - signatlist = list(signatlist, n); - } - - // process signatlist - for(l=signatlist; l; l=l->next) { - n = l->n; - if(n->op != OTYPE) - continue; - t = n->type; - dtypesym(t); - if(t->sym) - dtypesym(ptrto(t)); - } - - // generate import strings for imported packages - for(i=0; ilink) - if(p->direct) - dimportpath(p); - - // do basic types if compiling package runtime. - // they have to be in at least one package, - // and runtime is always loaded implicitly, - // so this is as good as any. - // another possible choice would be package main, - // but using runtime means fewer copies in .6 files. - if(compiling_runtime) { - for(i=1; i<=TBOOL; i++) - dtypesym(ptrto(types[i])); - dtypesym(ptrto(types[TSTRING])); - dtypesym(ptrto(types[TUNSAFEPTR])); - - // emit type structs for error and func(error) string. - // The latter is the type of an auto-generated wrapper. - dtypesym(ptrto(errortype)); - dtypesym(functype(nil, - list1(nod(ODCLFIELD, N, typenod(errortype))), - list1(nod(ODCLFIELD, N, typenod(types[TSTRING]))))); - - // add paths for runtime and main, which 6l imports implicitly. - dimportpath(runtimepkg); - if(flag_race) - dimportpath(racepkg); - dimportpath(mkpkg(newstrlit("main"))); - } -} - -static Sym* -dalgsym(Type *t) -{ - int ot; - Sym *s, *hash, *hashfunc, *eq, *eqfunc; - char *p; - - // dalgsym is only called for a type that needs an algorithm table, - // which implies that the type is comparable (or else it would use ANOEQ). - - if(algtype(t) == AMEM) { - // we use one algorithm table for all AMEM types of a given size - p = smprint(".alg%lld", t->width); - s = pkglookup(p, typepkg); - free(p); - if(s->flags & SymAlgGen) - return s; - s->flags |= SymAlgGen; - - // make hash closure - p = smprint(".hashfunc%lld", t->width); - hashfunc = pkglookup(p, typepkg); - free(p); - ot = 0; - ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0); - ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure - ggloblsym(hashfunc, ot, DUPOK|RODATA); - - // make equality closure - p = smprint(".eqfunc%lld", t->width); - eqfunc = pkglookup(p, typepkg); - free(p); - ot = 0; - ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0); - ot = duintxx(eqfunc, ot, t->width, widthptr); - ggloblsym(eqfunc, ot, DUPOK|RODATA); - } else { - // generate an alg table specific to this type - s = typesymprefix(".alg", t); - hash = typesymprefix(".hash", t); - eq = typesymprefix(".eq", t); - hashfunc = typesymprefix(".hashfunc", t); - eqfunc = typesymprefix(".eqfunc", t); - - genhash(hash, t); - geneq(eq, t); - - // make Go funcs (closures) for calling hash and equal from Go - dsymptr(hashfunc, 0, hash, 0); - ggloblsym(hashfunc, widthptr, DUPOK|RODATA); - dsymptr(eqfunc, 0, eq, 0); - ggloblsym(eqfunc, widthptr, DUPOK|RODATA); - } - // ../../runtime/alg.go:/typeAlg - ot = 0; - ot = dsymptr(s, ot, hashfunc, 0); - ot = dsymptr(s, ot, eqfunc, 0); - ggloblsym(s, ot, DUPOK|RODATA); - return s; -} - -static int -usegcprog(Type *t) -{ - vlong size, nptr; - - if(!haspointers(t)) - return 0; - if(t->width == BADWIDTH) - dowidth(t); - // Calculate size of the unrolled GC mask. - nptr = (t->width+widthptr-1)/widthptr; - size = nptr; - if(size%2) - size *= 2; // repeated - size = size*gcBits/8; // 4 bits per word - // Decide whether to use unrolled GC mask or GC program. - // We could use a more elaborate condition, but this seems to work well in practice. - // For small objects GC program can't give significant reduction. - // While large objects usually contain arrays; and even if it don't - // the program uses 2-bits per word while mask uses 4-bits per word, - // so the program is still smaller. - return size > 2*widthptr; -} - -// Generates sparse GC bitmask (4 bits per word). -static void -gengcmask(Type *t, uint8 *gcmask) -{ - Bvec *vec; - vlong xoffset, nptr, i, j; - int half; - uint8 bits, *pos; - - memset(gcmask, 0, 16); - if(!haspointers(t)) - return; - - // Generate compact mask as stacks use. - xoffset = 0; - vec = bvalloc(2*widthptr*8); - twobitwalktype1(t, &xoffset, vec); - - // Unfold the mask for the GC bitmap format: - // 4 bits per word, 2 high bits encode pointer info. - pos = gcmask; - nptr = (t->width+widthptr-1)/widthptr; - half = 0; - // If number of words is odd, repeat the mask. - // This makes simpler handling of arrays in runtime. - for(j=0; j<=(nptr%2); j++) { - for(i=0; is = s; - g->datasize = 0; - g->ot = 0; - memset(g->data, 0, sizeof(g->data)); -} - -static void -proggenemit(ProgGen *g, uint8 v) -{ - g->ot = duint8(g->s, g->ot, v); -} - -// Emits insData block from g->data. -static void -proggendataflush(ProgGen *g) -{ - int32 i, s; - - if(g->datasize == 0) - return; - proggenemit(g, insData); - proggenemit(g, g->datasize); - s = (g->datasize + PointersPerByte - 1)/PointersPerByte; - for(i = 0; i < s; i++) - proggenemit(g, g->data[i]); - g->datasize = 0; - memset(g->data, 0, sizeof(g->data)); -} - -static void -proggendata(ProgGen *g, uint8 d) -{ - g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer); - g->datasize++; - if(g->datasize == 255) - proggendataflush(g); -} - -// Skip v bytes due to alignment, etc. -static void -proggenskip(ProgGen *g, vlong off, vlong v) -{ - vlong i; - - for(i = off; i < off+v; i++) { - if((i%widthptr) == 0) - proggendata(g, BitsScalar); - } -} - -// Emit insArray instruction. -static void -proggenarray(ProgGen *g, vlong len) -{ - int32 i; - - proggendataflush(g); - proggenemit(g, insArray); - for(i = 0; i < widthptr; i++, len >>= 8) - proggenemit(g, len); -} - -static void -proggenarrayend(ProgGen *g) -{ - proggendataflush(g); - proggenemit(g, insArrayEnd); -} - -static vlong -proggenfini(ProgGen *g) -{ - proggendataflush(g); - proggenemit(g, insEnd); - return g->ot; -} - -static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset); - -// Generates GC program for large types. -static void -gengcprog(Type *t, Sym **pgc0, Sym **pgc1) -{ - Sym *gc0, *gc1; - vlong nptr, size, ot, xoffset; - ProgGen g; - - nptr = (t->width+widthptr-1)/widthptr; - size = nptr; - if(size%2) - size *= 2; // repeated twice - size = size*PointersPerByte/8; // 4 bits per word - size++; // unroll flag in the beginning, used by runtime (see runtime.markallocated) - // emity space in BSS for unrolled program - *pgc0 = S; - // Don't generate it if it's too large, runtime will unroll directly into GC bitmap. - if(size <= MaxGCMask) { - gc0 = typesymprefix(".gc", t); - ggloblsym(gc0, size, DUPOK|NOPTR); - *pgc0 = gc0; - } - - // program in RODATA - gc1 = typesymprefix(".gcprog", t); - proggeninit(&g, gc1); - xoffset = 0; - gengcprog1(&g, t, &xoffset); - ot = proggenfini(&g); - ggloblsym(gc1, ot, DUPOK|RODATA); - *pgc1 = gc1; -} - -// Recursively walks type t and writes GC program into g. -static void -gengcprog1(ProgGen *g, Type *t, vlong *xoffset) -{ - vlong fieldoffset, i, o, n; - Type *t1; - - switch(t->etype) { - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TBOOL: - case TFLOAT32: - case TFLOAT64: - case TCOMPLEX64: - case TCOMPLEX128: - proggenskip(g, *xoffset, t->width); - *xoffset += t->width; - break; - case TPTR32: - case TPTR64: - case TUNSAFEPTR: - case TFUNC: - case TCHAN: - case TMAP: - proggendata(g, BitsPointer); - *xoffset += t->width; - break; - case TSTRING: - proggendata(g, BitsPointer); - proggendata(g, BitsScalar); - *xoffset += t->width; - break; - case TINTER: - // Assuming IfacePointerOnly=1. - proggendata(g, BitsPointer); - proggendata(g, BitsPointer); - *xoffset += t->width; - break; - case TARRAY: - if(isslice(t)) { - proggendata(g, BitsPointer); - proggendata(g, BitsScalar); - proggendata(g, BitsScalar); - } else { - t1 = t->type; - if(t1->width == 0) { - // ignore - } if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) { - for(i = 0; i < t->bound; i++) - gengcprog1(g, t1, xoffset); - } else if(!haspointers(t1)) { - n = t->width; - n -= -*xoffset&(widthptr-1); // skip to next ptr boundary - proggenarray(g, (n+widthptr-1)/widthptr); - proggendata(g, BitsScalar); - proggenarrayend(g); - *xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width; - } else { - proggenarray(g, t->bound); - gengcprog1(g, t1, xoffset); - *xoffset += (t->bound-1)*t1->width; - proggenarrayend(g); - } - } - break; - case TSTRUCT: - o = 0; - for(t1 = t->type; t1 != T; t1 = t1->down) { - fieldoffset = t1->width; - proggenskip(g, *xoffset, fieldoffset - o); - *xoffset += fieldoffset - o; - gengcprog1(g, t1->type, xoffset); - o = fieldoffset + t1->type->width; - } - proggenskip(g, *xoffset, t->width - o); - *xoffset += t->width - o; - break; - default: - fatal("gengcprog1: unexpected type, %T", t); - } -} diff --git a/src/cmd/gc/reg.c b/src/cmd/gc/reg.c deleted file mode 100644 index 67409c2127..0000000000 --- a/src/cmd/gc/reg.c +++ /dev/null @@ -1,1233 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include -#include "go.h" -#include "popt.h" - -static Flow* firstf; -static int first = 1; - -static void addmove(Flow*, int, int, int); -static Bits mkvar(Flow*, Adr*); -static void prop(Flow*, Bits, Bits); -static void synch(Flow*, Bits); -static uint64 allreg(uint64, Rgn*); -static void paint1(Flow*, int); -static uint64 paint2(Flow*, int, int); -static void paint3(Flow*, int, uint64, int); -static void addreg(Adr*, int); - -static int -rcmp(const void *a1, const void *a2) -{ - Rgn *p1, *p2; - - p1 = (Rgn*)a1; - p2 = (Rgn*)a2; - if(p1->cost != p2->cost) - return p2->cost - p1->cost; - if(p1->varno != p2->varno) - return p2->varno - p1->varno; - if(p1->enter != p2->enter) - return p2->enter->id - p1->enter->id; - return 0; -} - -static void -setaddrs(Bits bit) -{ - int i, n; - Var *v; - Node *node; - - while(bany(&bit)) { - // convert each bit to a variable - i = bnum(bit); - node = var[i].node; - n = var[i].name; - biclr(&bit, i); - - // disable all pieces of that variable - for(i=0; inode == node && v->name == n) - v->addr = 2; - } - } -} - -static Node* regnodes[64]; - -static void walkvardef(Node *n, Flow *r, int active); - -void -regopt(Prog *firstp) -{ - Flow *f, *f1; - Reg *r; - Prog *p; - Graph *g; - ProgInfo info; - int i, z, active; - uint64 vreg, usedreg; - uint64 mask; - int nreg; - char **regnames; - Bits bit; - Rgn *rgp; - - if(first) { - fmtinstall('Q', Qconv); - first = 0; - } - - mergetemp(firstp); - - /* - * control flow is more complicated in generated go code - * than in generated c code. define pseudo-variables for - * registers, so we have complete register usage information. - */ - regnames = thearch.regnames(&nreg); - nvar = nreg; - memset(var, 0, nreg*sizeof var[0]); - for(i=0; iopt = nil; - return; - } - - firstf = g->start; - - for(f = firstf; f != nil; f = f->link) { - p = f->prog; - if(p->as == AVARDEF || p->as == AVARKILL) - continue; - thearch.proginfo(&info, p); - - // Avoid making variables for direct-called functions. - if(p->as == ACALL && p->to.type == TYPE_MEM && p->to.name == NAME_EXTERN) - continue; - - // from vs to doesn't matter for registers. - r = (Reg*)f->data; - r->use1.b[0] |= info.reguse | info.regindex; - r->set.b[0] |= info.regset; - - bit = mkvar(f, &p->from); - if(bany(&bit)) { - if(info.flags & LeftAddr) - setaddrs(bit); - if(info.flags & LeftRead) - for(z=0; zuse1.b[z] |= bit.b[z]; - if(info.flags & LeftWrite) - for(z=0; zset.b[z] |= bit.b[z]; - } - - // Compute used register for reg - if(info.flags & RegRead) - r->use1.b[0] |= thearch.RtoB(p->reg); - - // Currently we never generate three register forms. - // If we do, this will need to change. - if(p->from3.type != TYPE_NONE) - fatal("regopt not implemented for from3"); - - bit = mkvar(f, &p->to); - if(bany(&bit)) { - if(info.flags & RightAddr) - setaddrs(bit); - if(info.flags & RightRead) - for(z=0; zuse2.b[z] |= bit.b[z]; - if(info.flags & RightWrite) - for(z=0; zset.b[z] |= bit.b[z]; - } - } - - for(i=0; iaddr) { - bit = blsh(i); - for(z=0; zaddr, v->etype, v->width, v->node, v->offset); - } - - if(debug['R'] && debug['v']) - dumpit("pass1", firstf, 1); - - /* - * pass 2 - * find looping structure - */ - flowrpo(g); - - if(debug['R'] && debug['v']) - dumpit("pass2", firstf, 1); - - /* - * pass 2.5 - * iterate propagating fat vardef covering forward - * r->act records vars with a VARDEF since the last CALL. - * (r->act will be reused in pass 5 for something else, - * but we'll be done with it by then.) - */ - active = 0; - for(f = firstf; f != nil; f = f->link) { - f->active = 0; - r = (Reg*)f->data; - r->act = zbits; - } - for(f = firstf; f != nil; f = f->link) { - p = f->prog; - if(p->as == AVARDEF && isfat(((Node*)(p->to.node))->type) && ((Node*)(p->to.node))->opt != nil) { - active++; - walkvardef(p->to.node, f, active); - } - } - - /* - * pass 3 - * iterate propagating usage - * back until flow graph is complete - */ -loop1: - change = 0; - for(f = firstf; f != nil; f = f->link) - f->active = 0; - for(f = firstf; f != nil; f = f->link) - if(f->prog->as == ARET) - prop(f, zbits, zbits); -loop11: - /* pick up unreachable code */ - i = 0; - for(f = firstf; f != nil; f = f1) { - f1 = f->link; - if(f1 && f1->active && !f->active) { - prop(f, zbits, zbits); - i = 1; - } - } - if(i) - goto loop11; - if(change) - goto loop1; - - if(debug['R'] && debug['v']) - dumpit("pass3", firstf, 1); - - /* - * pass 4 - * iterate propagating register/variable synchrony - * forward until graph is complete - */ -loop2: - change = 0; - for(f = firstf; f != nil; f = f->link) - f->active = 0; - synch(firstf, zbits); - if(change) - goto loop2; - - if(debug['R'] && debug['v']) - dumpit("pass4", firstf, 1); - - /* - * pass 4.5 - * move register pseudo-variables into regu. - */ - if(nreg == 64) - mask = ~0ULL; // can't rely on C to shift by 64 - else - mask = (1ULL<link) { - r = (Reg*)f->data; - r->regu = (r->refbehind.b[0] | r->set.b[0]) & mask; - r->set.b[0] &= ~mask; - r->use1.b[0] &= ~mask; - r->use2.b[0] &= ~mask; - r->refbehind.b[0] &= ~mask; - r->refahead.b[0] &= ~mask; - r->calbehind.b[0] &= ~mask; - r->calahead.b[0] &= ~mask; - r->regdiff.b[0] &= ~mask; - r->act.b[0] &= ~mask; - } - - if(debug['R'] && debug['v']) - dumpit("pass4.5", firstf, 1); - - /* - * pass 5 - * isolate regions - * calculate costs (paint1) - */ - f = firstf; - if(f) { - r = (Reg*)f->data; - for(z=0; zrefahead.b[z] | r->calahead.b[z]) & - ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]); - if(bany(&bit) && !f->refset) { - // should never happen - all variables are preset - if(debug['w']) - print("%L: used and not set: %Q\n", f->prog->lineno, bit); - f->refset = 1; - } - } - for(f = firstf; f != nil; f = f->link) - ((Reg*)f->data)->act = zbits; - nregion = 0; - for(f = firstf; f != nil; f = f->link) { - r = (Reg*)f->data; - for(z=0; zset.b[z] & - ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]); - if(bany(&bit) && !f->refset) { - if(debug['w']) - print("%L: set and not used: %Q\n", f->prog->lineno, bit); - f->refset = 1; - thearch.excise(f); - } - for(z=0; zact.b[z] | addrs.b[z]); - while(bany(&bit)) { - i = bnum(bit); - change = 0; - paint1(f, i); - biclr(&bit, i); - if(change <= 0) - continue; - if(nregion >= NRGN) { - if(debug['R'] && debug['v']) - print("too many regions\n"); - goto brk; - } - rgp = ®ion[nregion]; - rgp->enter = f; - rgp->varno = i; - rgp->cost = change; - nregion++; - } - } -brk: - qsort(region, nregion, sizeof(region[0]), rcmp); - - if(debug['R'] && debug['v']) - dumpit("pass5", firstf, 1); - - /* - * pass 6 - * determine used registers (paint2) - * replace code (paint3) - */ - if(debug['R'] && debug['v']) - print("\nregisterizing\n"); - for(i=0; icost, rgp->varno, rgp->enter->prog->pc); - bit = blsh(rgp->varno); - usedreg = paint2(rgp->enter, rgp->varno, 0); - vreg = allreg(usedreg, rgp); - if(rgp->regno != 0) { - if(debug['R'] && debug['v']) { - Var *v; - - v = var + rgp->varno; - print("registerize %N+%lld (bit=%2d et=%E) in %R usedreg=%#llx vreg=%#llx\n", - v->node, v->offset, rgp->varno, v->etype, rgp->regno, usedreg, vreg); - } - paint3(rgp->enter, rgp->varno, vreg, rgp->regno); - } - } - - /* - * free aux structures. peep allocates new ones. - */ - for(i=0; iopt = nil; - flowend(g); - firstf = nil; - - if(debug['R'] && debug['v']) { - // Rebuild flow graph, since we inserted instructions - g = flowstart(firstp, 0); - firstf = g->start; - dumpit("pass6", firstf, 0); - flowend(g); - firstf = nil; - } - - /* - * pass 7 - * peep-hole on basic block - */ - if(!debug['R'] || debug['P']) - thearch.peep(firstp); - - /* - * eliminate nops - */ - for(p=firstp; p!=P; p=p->link) { - while(p->link != P && p->link->as == ANOP) - p->link = p->link->link; - if(p->to.type == TYPE_BRANCH) - while(p->to.u.branch != P && p->to.u.branch->as == ANOP) - p->to.u.branch = p->to.u.branch->link; - } - - if(debug['R']) { - if(ostats.ncvtreg || - ostats.nspill || - ostats.nreload || - ostats.ndelmov || - ostats.nvar || - ostats.naddr || - 0) - print("\nstats\n"); - - if(ostats.ncvtreg) - print(" %4d cvtreg\n", ostats.ncvtreg); - if(ostats.nspill) - print(" %4d spill\n", ostats.nspill); - if(ostats.nreload) - print(" %4d reload\n", ostats.nreload); - if(ostats.ndelmov) - print(" %4d delmov\n", ostats.ndelmov); - if(ostats.nvar) - print(" %4d var\n", ostats.nvar); - if(ostats.naddr) - print(" %4d addr\n", ostats.naddr); - - memset(&ostats, 0, sizeof(ostats)); - } -} - -static void -walkvardef(Node *n, Flow *f, int active) -{ - Flow *f1, *f2; - int bn; - Var *v; - - for(f1=f; f1!=nil; f1=f1->s1) { - if(f1->active == active) - break; - f1->active = active; - if(f1->prog->as == AVARKILL && f1->prog->to.node == n) - break; - for(v=n->opt; v!=nil; v=v->nextinnode) { - bn = v->id; - biset(&((Reg*)f1->data)->act, bn); - } - if(f1->prog->as == ACALL) - break; - } - - for(f2=f; f2!=f1; f2=f2->s1) - if(f2->s2 != nil) - walkvardef(n, f2->s2, active); -} - -/* - * add mov b,rn - * just after r - */ -static void -addmove(Flow *r, int bn, int rn, int f) -{ - Prog *p, *p1; - Adr *a; - Var *v; - - p1 = mal(sizeof(*p1)); - clearp(p1); - p1->pc = 9999; - - p = r->prog; - p1->link = p->link; - p->link = p1; - p1->lineno = p->lineno; - - v = var + bn; - - a = &p1->to; - a->offset = v->offset; - a->etype = v->etype; - a->type = TYPE_MEM; - a->name = v->name; - a->node = v->node; - a->sym = linksym(v->node->sym); - /* NOTE(rsc): 9g did - if(a->etype == TARRAY) - a->type = TYPE_ADDR; - else if(a->sym == nil) - a->type = TYPE_CONST; - */ - - p1->as = thearch.optoas(OAS, types[(uchar)v->etype]); - // TODO(rsc): Remove special case here. - if((thearch.thechar == '9' || thearch.thechar == '5') && v->etype == TBOOL) - p1->as = thearch.optoas(OAS, types[TUINT8]); - p1->from.type = TYPE_REG; - p1->from.reg = rn; - p1->from.name = NAME_NONE; - if(!f) { - p1->from = *a; - *a = zprog.from; - a->type = TYPE_REG; - a->reg = rn; - } - if(debug['R'] && debug['v']) - print("%P ===add=== %P\n", p, p1); - ostats.nspill++; -} - -static int -overlap(int64 o1, int w1, int64 o2, int w2) -{ - int64 t1, t2; - - t1 = o1+w1; - t2 = o2+w2; - - if(!(t1 > o2 && t2 > o1)) - return 0; - - return 1; -} - -static Bits -mkvar(Flow *f, Adr *a) -{ - Var *v; - int i, n, et, z, flag; - int64 w; - uint64 regu; - int64 o; - Bits bit; - Node *node; - Reg *r; - - - /* - * mark registers used - */ - if(a->type == TYPE_NONE) - goto none; - - r = (Reg*)f->data; - r->use1.b[0] |= thearch.doregbits(a->index); // TODO: Use RtoB - - switch(a->type) { - default: - regu = thearch.doregbits(a->reg) | thearch.RtoB(a->reg); // TODO: Use RtoB - if(regu == 0) - goto none; - bit = zbits; - bit.b[0] = regu; - return bit; - - case TYPE_ADDR: - // TODO(rsc): Remove special case here. - if(thearch.thechar == '9' || thearch.thechar == '5') - goto memcase; - a->type = TYPE_MEM; - bit = mkvar(f, a); - setaddrs(bit); - a->type = TYPE_ADDR; - ostats.naddr++; - goto none; - - case TYPE_MEM: - memcase: - if(r != R) { - r->use1.b[0] |= thearch.RtoB(a->reg); - /* NOTE: 5g did - if(r->f.prog->scond & (C_PBIT|C_WBIT)) - r->set.b[0] |= RtoB(a->reg); - */ - } - switch(a->name) { - default: - goto none; - case NAME_EXTERN: - case NAME_STATIC: - case NAME_PARAM: - case NAME_AUTO: - n = a->name; - break; - } - } - - node = a->node; - if(node == N || node->op != ONAME || node->orig == N) - goto none; - node = node->orig; - if(node->orig != node) - fatal("%D: bad node", a); - if(node->sym == S || node->sym->name[0] == '.') - goto none; - et = a->etype; - o = a->offset; - w = a->width; - if(w < 0) - fatal("bad width %lld for %D", w, a); - - flag = 0; - for(i=0; inode == node && v->name == n) { - if(v->offset == o) - if(v->etype == et) - if(v->width == w) { - // TODO(rsc): Remove special case for arm here. - if(!flag || thearch.thechar != '5') - return blsh(i); - } - - // if they overlap, disable both - if(overlap(v->offset, v->width, o, w)) { -// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et); - v->addr = 1; - flag = 1; - } - } - } - - switch(et) { - case 0: - case TFUNC: - goto none; - } - - if(nvar >= NVAR) { - if(debug['w'] > 1 && node != N) - fatal("variable not optimized: %#N", node); - - // If we're not tracking a word in a variable, mark the rest as - // having its address taken, so that we keep the whole thing - // live at all calls. otherwise we might optimize away part of - // a variable but not all of it. - for(i=0; inode == node) - v->addr = 1; - } - goto none; - } - - i = nvar; - nvar++; - v = var+i; - v->id = i; - v->offset = o; - v->name = n; - v->etype = et; - v->width = w; - v->addr = flag; // funny punning - v->node = node; - - // node->opt is the head of a linked list - // of Vars within the given Node, so that - // we can start at a Var and find all the other - // Vars in the same Go variable. - v->nextinnode = node->opt; - node->opt = v; - - bit = blsh(i); - if(n == NAME_EXTERN || n == NAME_STATIC) - for(z=0; zclass == PPARAM) - for(z=0; zclass == PPARAMOUT) - for(z=0; zaddrtaken) - v->addr = 1; - - // Disable registerization for globals, because: - // (1) we might panic at any time and we want the recovery code - // to see the latest values (issue 1304). - // (2) we don't know what pointers might point at them and we want - // loads via those pointers to see updated values and vice versa (issue 7995). - // - // Disable registerization for results if using defer, because the deferred func - // might recover and return, causing the current values to be used. - if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT)) - v->addr = 1; - - if(debug['R']) - print("bit=%2d et=%E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr); - ostats.nvar++; - - return bit; - -none: - return zbits; -} - -static void -prop(Flow *f, Bits ref, Bits cal) -{ - Flow *f1, *f2; - Reg *r, *r1; - int z, i; - Var *v, *v1; - - for(f1 = f; f1 != nil; f1 = f1->p1) { - r1 = (Reg*)f1->data; - for(z=0; zrefahead.b[z]; - if(ref.b[z] != r1->refahead.b[z]) { - r1->refahead.b[z] = ref.b[z]; - change++; - } - cal.b[z] |= r1->calahead.b[z]; - if(cal.b[z] != r1->calahead.b[z]) { - r1->calahead.b[z] = cal.b[z]; - change++; - } - } - switch(f1->prog->as) { - case ACALL: - if(noreturn(f1->prog)) - break; - - // Mark all input variables (ivar) as used, because that's what the - // liveness bitmaps say. The liveness bitmaps say that so that a - // panic will not show stale values in the parameter dump. - // Mark variables with a recent VARDEF (r1->act) as used, - // so that the optimizer flushes initializations to memory, - // so that if a garbage collection happens during this CALL, - // the collector will see initialized memory. Again this is to - // match what the liveness bitmaps say. - for(z=0; zact.b[z]; - ref.b[z] = 0; - } - - // cal.b is the current approximation of what's live across the call. - // Every bit in cal.b is a single stack word. For each such word, - // find all the other tracked stack words in the same Go variable - // (struct/slice/string/interface) and mark them live too. - // This is necessary because the liveness analysis for the garbage - // collector works at variable granularity, not at word granularity. - // It is fundamental for slice/string/interface: the garbage collector - // needs the whole value, not just some of the words, in order to - // interpret the other bits correctly. Specifically, slice needs a consistent - // ptr and cap, string needs a consistent ptr and len, and interface - // needs a consistent type word and data word. - for(z=0; z= nvar || ((cal.b[z]>>i)&1) == 0) - continue; - v = var+z*64+i; - if(v->node->opt == nil) // v represents fixed register, not Go variable - continue; - - // v->node->opt is the head of a linked list of Vars - // corresponding to tracked words from the Go variable v->node. - // Walk the list and set all the bits. - // For a large struct this could end up being quadratic: - // after the first setting, the outer loop (for z, i) would see a 1 bit - // for all of the remaining words in the struct, and for each such - // word would go through and turn on all the bits again. - // To avoid the quadratic behavior, we only turn on the bits if - // v is the head of the list or if the head's bit is not yet turned on. - // This will set the bits at most twice, keeping the overall loop linear. - v1 = v->node->opt; - if(v == v1 || !btest(&cal, v1->id)) { - for(; v1 != nil; v1 = v1->nextinnode) { - biset(&cal, v1->id); - } - } - } - } - break; - - case ATEXT: - for(z=0; zset.b[z]) | - r1->use1.b[z] | r1->use2.b[z]; - cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]); - r1->refbehind.b[z] = ref.b[z]; - r1->calbehind.b[z] = cal.b[z]; - } - if(f1->active) - break; - f1->active = 1; - } - - for(; f != f1; f = f->p1) { - r = (Reg*)f->data; - for(f2 = f->p2; f2 != nil; f2 = f2->p2link) - prop(f2, r->refbehind, r->calbehind); - } -} - -static void -synch(Flow *f, Bits dif) -{ - Flow *f1; - Reg *r1; - int z; - - for(f1 = f; f1 != nil; f1 = f1->s1) { - r1 = (Reg*)f1->data; - for(z=0; zrefbehind.b[z] & r1->refahead.b[z])) | - r1->set.b[z] | r1->regdiff.b[z]; - if(dif.b[z] != r1->regdiff.b[z]) { - r1->regdiff.b[z] = dif.b[z]; - change++; - } - } - if(f1->active) - break; - f1->active = 1; - for(z=0; zcalbehind.b[z] & r1->calahead.b[z]); - if(f1->s2 != nil) - synch(f1->s2, dif); - } -} - -static uint64 -allreg(uint64 b, Rgn *r) -{ - Var *v; - int i; - - v = var + r->varno; - r->regno = 0; - switch(v->etype) { - - default: - fatal("unknown etype %d/%E", bitno(b), v->etype); - break; - - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TBOOL: - case TPTR32: - case TPTR64: - i = thearch.BtoR(~b); - if(i && r->cost > 0) { - r->regno = i; - return thearch.RtoB(i); - } - break; - - case TFLOAT32: - case TFLOAT64: - i = thearch.BtoF(~b); - if(i && r->cost > 0) { - r->regno = i; - return thearch.FtoB(i); - } - break; - } - return 0; -} - -static void -paint1(Flow *f, int bn) -{ - Flow *f1; - Reg *r, *r1; - int z; - uint64 bb; - - z = bn/64; - bb = 1LL<<(bn%64); - r = (Reg*)f->data; - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - f1 = f->p1; - if(f1 == nil) - break; - r1 = (Reg*)f1->data; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - f = f1; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) { - change -= CLOAD * f->loop; - } - for(;;) { - r->act.b[z] |= bb; - - if(f->prog->as != ANOP) { // don't give credit for NOPs - if(r->use1.b[z] & bb) - change += CREF * f->loop; - if((r->use2.b[z]|r->set.b[z]) & bb) - change += CREF * f->loop; - } - - if(STORE(r) & r->regdiff.b[z] & bb) { - change -= CLOAD * f->loop; - } - - if(r->refbehind.b[z] & bb) - for(f1 = f->p2; f1 != nil; f1 = f1->p2link) - if(((Reg*)f1->data)->refahead.b[z] & bb) - paint1(f1, bn); - - if(!(r->refahead.b[z] & bb)) - break; - f1 = f->s2; - if(f1 != nil) - if(((Reg*)f1->data)->refbehind.b[z] & bb) - paint1(f1, bn); - f = f->s1; - if(f == nil) - break; - r = (Reg*)f->data; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -static uint64 -paint2(Flow *f, int bn, int depth) -{ - Flow *f1; - Reg *r, *r1; - int z; - uint64 bb, vreg; - - z = bn/64; - bb = 1LL << (bn%64); - vreg = regbits; - r = (Reg*)f->data; - if(!(r->act.b[z] & bb)) - return vreg; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - f1 = f->p1; - if(f1 == nil) - break; - r1 = (Reg*)f1->data; - if(!(r1->refahead.b[z] & bb)) - break; - if(!(r1->act.b[z] & bb)) - break; - f = f1; - r = r1; - } - for(;;) { - if(debug['R'] && debug['v']) - print(" paint2 %d %P\n", depth, f->prog); - - r->act.b[z] &= ~bb; - - vreg |= r->regu; - - if(r->refbehind.b[z] & bb) - for(f1 = f->p2; f1 != nil; f1 = f1->p2link) - if(((Reg*)f1->data)->refahead.b[z] & bb) - vreg |= paint2(f1, bn, depth+1); - - if(!(r->refahead.b[z] & bb)) - break; - f1 = f->s2; - if(f1 != nil) - if(((Reg*)f1->data)->refbehind.b[z] & bb) - vreg |= paint2(f1, bn, depth+1); - f = f->s1; - if(f == nil) - break; - r = (Reg*)f->data; - if(!(r->act.b[z] & bb)) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } - - return vreg; -} - -static void -paint3(Flow *f, int bn, uint64 rb, int rn) -{ - Flow *f1; - Reg *r, *r1; - Prog *p; - int z; - uint64 bb; - - z = bn/64; - bb = 1LL << (bn%64); - r = (Reg*)f->data; - if(r->act.b[z] & bb) - return; - for(;;) { - if(!(r->refbehind.b[z] & bb)) - break; - f1 = f->p1; - if(f1 == nil) - break; - r1 = (Reg*)f1->data; - if(!(r1->refahead.b[z] & bb)) - break; - if(r1->act.b[z] & bb) - break; - f = f1; - r = r1; - } - - if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) - addmove(f, bn, rn, 0); - for(;;) { - r->act.b[z] |= bb; - p = f->prog; - - if(r->use1.b[z] & bb) { - if(debug['R'] && debug['v']) - print("%P", p); - addreg(&p->from, rn); - if(debug['R'] && debug['v']) - print(" ===change== %P\n", p); - } - if((r->use2.b[z]|r->set.b[z]) & bb) { - if(debug['R'] && debug['v']) - print("%P", p); - addreg(&p->to, rn); - if(debug['R'] && debug['v']) - print(" ===change== %P\n", p); - } - - if(STORE(r) & r->regdiff.b[z] & bb) - addmove(f, bn, rn, 1); - r->regu |= rb; - - if(r->refbehind.b[z] & bb) - for(f1 = f->p2; f1 != nil; f1 = f1->p2link) - if(((Reg*)f1->data)->refahead.b[z] & bb) - paint3(f1, bn, rb, rn); - - if(!(r->refahead.b[z] & bb)) - break; - f1 = f->s2; - if(f1 != nil) - if(((Reg*)f1->data)->refbehind.b[z] & bb) - paint3(f1, bn, rb, rn); - f = f->s1; - if(f == nil) - break; - r = (Reg*)f->data; - if(r->act.b[z] & bb) - break; - if(!(r->refbehind.b[z] & bb)) - break; - } -} - -static void -addreg(Adr *a, int rn) -{ - a->sym = nil; - a->node = nil; - a->offset = 0; - a->type = TYPE_REG; - a->reg = rn; - a->name = 0; - - ostats.ncvtreg++; -} - -void -dumpone(Flow *f, int isreg) -{ - int z; - Bits bit; - Reg *r; - - print("%d:%P", f->loop, f->prog); - if(isreg) { - r = (Reg*)f->data; - for(z=0; zset.b[z] | - r->use1.b[z] | - r->use2.b[z] | - r->refbehind.b[z] | - r->refahead.b[z] | - r->calbehind.b[z] | - r->calahead.b[z] | - r->regdiff.b[z] | - r->act.b[z] | - 0; - if(bany(&bit)) { - print("\t"); - if(bany(&r->set)) - print(" s:%Q", r->set); - if(bany(&r->use1)) - print(" u1:%Q", r->use1); - if(bany(&r->use2)) - print(" u2:%Q", r->use2); - if(bany(&r->refbehind)) - print(" rb:%Q ", r->refbehind); - if(bany(&r->refahead)) - print(" ra:%Q ", r->refahead); - if(bany(&r->calbehind)) - print(" cb:%Q ", r->calbehind); - if(bany(&r->calahead)) - print(" ca:%Q ", r->calahead); - if(bany(&r->regdiff)) - print(" d:%Q ", r->regdiff); - if(bany(&r->act)) - print(" a:%Q ", r->act); - } - } - print("\n"); -} - -void -dumpit(char *str, Flow *r0, int isreg) -{ - Flow *r, *r1; - - print("\n%s\n", str); - for(r = r0; r != nil; r = r->link) { - dumpone(r, isreg); - r1 = r->p2; - if(r1 != nil) { - print(" pred:"); - for(; r1 != nil; r1 = r1->p2link) - print(" %.4ud", (int)r1->prog->pc); - if(r->p1 != nil) - print(" (and %.4ud)", (int)r->p1->prog->pc); - else - print(" (only)"); - print("\n"); - } - // Print successors if it's not just the next one - if(r->s1 != r->link || r->s2 != nil) { - print(" succ:"); - if(r->s1 != nil) - print(" %.4ud", (int)r->s1->prog->pc); - if(r->s2 != nil) - print(" %.4ud", (int)r->s2->prog->pc); - print("\n"); - } - } -} diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go deleted file mode 100644 index 0a4c1b8cbb..0000000000 --- a/src/cmd/gc/runtime.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// NOTE: If you change this file you must run "./mkbuiltin" -// to update builtin.c. This is not done automatically -// to avoid depending on having a working compiler binary. - -// +build ignore - -package PACKAGE - -// emitted by compiler, not referred to by go programs - -func newobject(typ *byte) *any -func panicindex() -func panicslice() -func panicdivide() -func throwreturn() -func throwinit() -func panicwrap(string, string, string) - -func gopanic(interface{}) -func gorecover(*int32) interface{} - -func printbool(bool) -func printfloat(float64) -func printint(int64) -func printhex(uint64) -func printuint(uint64) -func printcomplex(complex128) -func printstring(string) -func printpointer(any) -func printiface(any) -func printeface(any) -func printslice(any) -func printnl() -func printsp() -func printlock() -func printunlock() - -func concatstring2(*[32]byte, string, string) string -func concatstring3(*[32]byte, string, string, string) string -func concatstring4(*[32]byte, string, string, string, string) string -func concatstring5(*[32]byte, string, string, string, string, string) string -func concatstrings(*[32]byte, []string) string - -func cmpstring(string, string) int -func eqstring(string, string) bool -func intstring(*[4]byte, int64) string -func slicebytetostring(*[32]byte, []byte) string -func slicebytetostringtmp([]byte) string -func slicerunetostring(*[32]byte, []rune) string -func stringtoslicebyte(*[32]byte, string) []byte -func stringtoslicebytetmp(string) []byte -func stringtoslicerune(*[32]rune, string) []rune -func stringiter(string, int) int -func stringiter2(string, int) (retk int, retv rune) -func slicecopy(to any, fr any, wid uintptr) int -func slicestringcopy(to any, fr any) int - -// interface conversions -func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte) -func convI2E(elem any) (ret any) -func convI2I(typ *byte, elem any) (ret any) -func convT2E(typ *byte, elem *any) (ret any) -func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any) - -// interface type assertions x.(T) -func assertE2E(typ *byte, iface any, ret *any) -func assertE2E2(typ *byte, iface any, ret *any) bool -func assertE2I(typ *byte, iface any, ret *any) -func assertE2I2(typ *byte, iface any, ret *any) bool -func assertE2T(typ *byte, iface any, ret *any) -func assertE2T2(typ *byte, iface any, ret *any) bool -func assertI2E(typ *byte, iface any, ret *any) -func assertI2E2(typ *byte, iface any, ret *any) bool -func assertI2I(typ *byte, iface any, ret *any) -func assertI2I2(typ *byte, iface any, ret *any) bool -func assertI2T(typ *byte, iface any, ret *any) -func assertI2T2(typ *byte, iface any, ret *any) bool - -func ifaceeq(i1 any, i2 any) (ret bool) -func efaceeq(i1 any, i2 any) (ret bool) -func ifacethash(i1 any) (ret uint32) -func efacethash(i1 any) (ret uint32) - -// *byte is really *runtime.Type -func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any) -func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any) -func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any) -func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any) -func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any) -func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool) -func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) -func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) -func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool) -func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any) -func mapiterinit(mapType *byte, hmap map[any]any, hiter *any) -func mapdelete(mapType *byte, hmap map[any]any, key *any) -func mapiternext(hiter *any) - -// *byte is really *runtime.Type -func makechan(chanType *byte, hint int64) (hchan chan any) -func chanrecv1(chanType *byte, hchan <-chan any, elem *any) -func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool -func chansend1(chanType *byte, hchan chan<- any, elem *any) -func closechan(hchan any) - -// *byte is really *runtime.Type -func writebarrierptr(dst *any, src any) -func writebarrierstring(dst *any, src any) -func writebarrierslice(dst *any, src any) -func writebarrieriface(dst *any, src any) - -// The unused *byte argument makes sure that src is 2-pointer-aligned, -// which is the maximum alignment on NaCl amd64p32 -// (and possibly on 32-bit systems if we start 64-bit aligning uint64s). -// The bitmap in the name tells which words being copied are pointers. -func writebarrierfat01(dst *any, _ *byte, src any) -func writebarrierfat10(dst *any, _ *byte, src any) -func writebarrierfat11(dst *any, _ *byte, src any) -func writebarrierfat001(dst *any, _ *byte, src any) -func writebarrierfat010(dst *any, _ *byte, src any) -func writebarrierfat011(dst *any, _ *byte, src any) -func writebarrierfat100(dst *any, _ *byte, src any) -func writebarrierfat101(dst *any, _ *byte, src any) -func writebarrierfat110(dst *any, _ *byte, src any) -func writebarrierfat111(dst *any, _ *byte, src any) -func writebarrierfat0001(dst *any, _ *byte, src any) -func writebarrierfat0010(dst *any, _ *byte, src any) -func writebarrierfat0011(dst *any, _ *byte, src any) -func writebarrierfat0100(dst *any, _ *byte, src any) -func writebarrierfat0101(dst *any, _ *byte, src any) -func writebarrierfat0110(dst *any, _ *byte, src any) -func writebarrierfat0111(dst *any, _ *byte, src any) -func writebarrierfat1000(dst *any, _ *byte, src any) -func writebarrierfat1001(dst *any, _ *byte, src any) -func writebarrierfat1010(dst *any, _ *byte, src any) -func writebarrierfat1011(dst *any, _ *byte, src any) -func writebarrierfat1100(dst *any, _ *byte, src any) -func writebarrierfat1101(dst *any, _ *byte, src any) -func writebarrierfat1110(dst *any, _ *byte, src any) -func writebarrierfat1111(dst *any, _ *byte, src any) - -func typedmemmove(typ *byte, dst *any, src *any) -func typedslicecopy(typ *byte, dst any, src any) int - -func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool -func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool -func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool - -func newselect(sel *byte, selsize int64, size int32) -func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool) -func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool) -func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool) -func selectdefault(sel *byte) (selected bool) -func selectgo(sel *byte) -func block() - -func makeslice(typ *byte, nel int64, cap int64) (ary []any) -func growslice(typ *byte, old []any, n int64) (ary []any) -func memmove(to *any, frm *any, length uintptr) -func memclr(ptr *byte, length uintptr) - -func memequal(x, y *any, size uintptr) bool -func memequal8(x, y *any) bool -func memequal16(x, y *any) bool -func memequal32(x, y *any) bool -func memequal64(x, y *any) bool -func memequal128(x, y *any) bool - -// only used on 32-bit -func int64div(int64, int64) int64 -func uint64div(uint64, uint64) uint64 -func int64mod(int64, int64) int64 -func uint64mod(uint64, uint64) uint64 -func float64toint64(float64) int64 -func float64touint64(float64) uint64 -func int64tofloat64(int64) float64 -func uint64tofloat64(uint64) float64 - -func complex128div(num complex128, den complex128) (quo complex128) - -// race detection -func racefuncenter(uintptr) -func racefuncexit() -func raceread(uintptr) -func racewrite(uintptr) -func racereadrange(addr, size uintptr) -func racewriterange(addr, size uintptr) diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c deleted file mode 100644 index 537d0ca928..0000000000 --- a/src/cmd/gc/select.c +++ /dev/null @@ -1,375 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * select - */ - -#include -#include -#include "go.h" - -static Type* selecttype(int32 size); - -void -typecheckselect(Node *sel) -{ - Node *ncase, *n, *def; - NodeList *l; - int lno, count; - - def = nil; - lno = setlineno(sel); - count = 0; - typechecklist(sel->ninit, Etop); - for(l=sel->list; l; l=l->next) { - count++; - ncase = l->n; - setlineno(ncase); - if(ncase->op != OXCASE) - fatal("typecheckselect %O", ncase->op); - - if(ncase->list == nil) { - // default - if(def != N) - yyerror("multiple defaults in select (first at %L)", def->lineno); - else - def = ncase; - } else if(ncase->list->next) { - yyerror("select cases cannot be lists"); - } else { - n = typecheck(&ncase->list->n, Etop); - ncase->left = n; - ncase->list = nil; - setlineno(n); - switch(n->op) { - default: - yyerror("select case must be receive, send or assign recv"); - break; - - case OAS: - // convert x = <-c into OSELRECV(x, <-c). - // remove implicit conversions; the eventual assignment - // will reintroduce them. - if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit) - n->right = n->right->left; - - if(n->right->op != ORECV) { - yyerror("select assignment must have receive on right hand side"); - break; - } - n->op = OSELRECV; - break; - - case OAS2RECV: - // convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok - if(n->rlist->n->op != ORECV) { - yyerror("select assignment must have receive on right hand side"); - break; - } - n->op = OSELRECV2; - n->left = n->list->n; - n->ntest = n->list->next->n; - n->list = nil; - n->right = n->rlist->n; - n->rlist = nil; - break; - - case ORECV: - // convert <-c into OSELRECV(N, <-c) - n = nod(OSELRECV, N, n); - n->typecheck = 1; - ncase->left = n; - break; - - case OSEND: - break; - } - } - typechecklist(ncase->nbody, Etop); - } - sel->xoffset = count; - lineno = lno; -} - -void -walkselect(Node *sel) -{ - int lno, i; - Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch; - NodeList *l, *init; - - if(sel->list == nil && sel->xoffset != 0) - fatal("double walkselect"); // already rewrote - - lno = setlineno(sel); - i = count(sel->list); - - // optimization: zero-case select - if(i == 0) { - sel->nbody = list1(mkcall("block", nil, nil)); - goto out; - } - - // optimization: one-case select: single op. - // TODO(rsc): Reenable optimization once order.c can handle it. - // golang.org/issue/7672. - if(i == 1) { - cas = sel->list->n; - setlineno(cas); - l = cas->ninit; - if(cas->left != N) { // not default: - n = cas->left; - l = concat(l, n->ninit); - n->ninit = nil; - switch(n->op) { - default: - fatal("select %O", n->op); - - case OSEND: - // ok already - ch = n->left; - break; - - case OSELRECV: - case OSELRECV2: - ch = n->right->left; - if(n->op == OSELRECV || n->ntest == N) { - if(n->left == N) - n = n->right; - else - n->op = OAS; - break; - } - - if(n->left == N) { - typecheck(&nblank, Erv | Easgn); - n->left = nblank; - } - n->op = OAS2; - n->list = list(list1(n->left), n->ntest); - n->rlist = list1(n->right); - n->right = N; - n->left = N; - n->ntest = N; - n->typecheck = 0; - typecheck(&n, Etop); - break; - } - - // if ch == nil { block() }; n; - a = nod(OIF, N, N); - a->ntest = nod(OEQ, ch, nodnil()); - a->nbody = list1(mkcall("block", nil, &l)); - typecheck(&a, Etop); - l = list(l, a); - l = list(l, n); - } - l = concat(l, cas->nbody); - sel->nbody = l; - goto out; - } - - // convert case value arguments to addresses. - // this rewrite is used by both the general code and the next optimization. - for(l=sel->list; l; l=l->next) { - cas = l->n; - setlineno(cas); - n = cas->left; - if(n == N) - continue; - switch(n->op) { - case OSEND: - n->right = nod(OADDR, n->right, N); - typecheck(&n->right, Erv); - break; - case OSELRECV: - case OSELRECV2: - if(n->op == OSELRECV2 && n->ntest == N) - n->op = OSELRECV; - if(n->op == OSELRECV2) { - n->ntest = nod(OADDR, n->ntest, N); - typecheck(&n->ntest, Erv); - } - if(n->left == N) - n->left = nodnil(); - else { - n->left = nod(OADDR, n->left, N); - typecheck(&n->left, Erv); - } - break; - } - } - - // optimization: two-case select but one is default: single non-blocking op. - if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) { - if(sel->list->n->left == nil) { - cas = sel->list->next->n; - dflt = sel->list->n; - } else { - dflt = sel->list->next->n; - cas = sel->list->n; - } - - n = cas->left; - setlineno(n); - r = nod(OIF, N, N); - r->ninit = cas->ninit; - switch(n->op) { - default: - fatal("select %O", n->op); - - case OSEND: - // if selectnbsend(c, v) { body } else { default body } - ch = n->left; - r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type), - types[TBOOL], &r->ninit, typename(ch->type), ch, n->right); - break; - - case OSELRECV: - // if c != nil && selectnbrecv(&v, c) { body } else { default body } - r = nod(OIF, N, N); - r->ninit = cas->ninit; - ch = n->right->left; - r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type), - types[TBOOL], &r->ninit, typename(ch->type), n->left, ch); - break; - - case OSELRECV2: - // if c != nil && selectnbrecv2(&v, c) { body } else { default body } - r = nod(OIF, N, N); - r->ninit = cas->ninit; - ch = n->right->left; - r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type), - types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch); - break; - } - typecheck(&r->ntest, Erv); - r->nbody = cas->nbody; - r->nelse = concat(dflt->ninit, dflt->nbody); - sel->nbody = list1(r); - goto out; - } - - init = sel->ninit; - sel->ninit = nil; - - // generate sel-struct - setlineno(sel); - selv = temp(selecttype(sel->xoffset)); - r = nod(OAS, selv, N); - typecheck(&r, Etop); - init = list(init, r); - var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8])); - r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset)); - typecheck(&r, Etop); - init = list(init, r); - - // register cases - for(l=sel->list; l; l=l->next) { - cas = l->n; - setlineno(cas); - n = cas->left; - r = nod(OIF, N, N); - r->ninit = cas->ninit; - cas->ninit = nil; - if(n != nil) { - r->ninit = concat(r->ninit, n->ninit); - n->ninit = nil; - } - if(n == nil) { - // selectdefault(sel *byte); - r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var); - } else { - switch(n->op) { - default: - fatal("select %O", n->op); - - case OSEND: - // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); - r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL], - &r->ninit, var, n->left, n->right); - break; - - case OSELRECV: - // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); - r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL], - &r->ninit, var, n->right->left, n->left); - break; - - case OSELRECV2: - // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); - r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL], - &r->ninit, var, n->right->left, n->left, n->ntest); - break; - } - } - // selv is no longer alive after use. - r->nbody = list(r->nbody, nod(OVARKILL, selv, N)); - r->nbody = concat(r->nbody, cas->nbody); - r->nbody = list(r->nbody, nod(OBREAK, N, N)); - init = list(init, r); - } - - // run the select - setlineno(sel); - init = list(init, mkcall("selectgo", T, nil, var)); - sel->nbody = init; - -out: - sel->list = nil; - walkstmtlist(sel->nbody); - lineno = lno; -} - -// Keep in sync with src/runtime/chan.h. -static Type* -selecttype(int32 size) -{ - Node *sel, *sudog, *scase, *arr; - - // TODO(dvyukov): it's possible to generate SudoG and Scase only once - // and then cache; and also cache Select per size. - sudog = nod(OTSTRUCT, N, N); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8])))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8])))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("next")), typenod(ptrto(types[TUINT8])))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8])))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32]))); - sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8])))); - typecheck(&sudog, Etype); - sudog->type->noalg = 1; - sudog->type->local = 1; - - scase = nod(OTSTRUCT, N, N); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8])))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8])))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR]))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16]))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16]))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8])))); - scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64]))); - typecheck(&scase, Etype); - scase->type->noalg = 1; - scase->type->local = 1; - - sel = nod(OTSTRUCT, N, N); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16]))); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16]))); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8])))); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8])))); - arr = nod(OTARRAY, nodintconst(size), scase); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr)); - arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8]))); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr)); - arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16])); - sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr)); - typecheck(&sel, Etype); - sel->type->noalg = 1; - sel->type->local = 1; - - return sel->type; -} diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c deleted file mode 100644 index 1015950e41..0000000000 --- a/src/cmd/gc/sinit.c +++ /dev/null @@ -1,1502 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * static initialization - */ - -#include -#include -#include "go.h" - -enum -{ - InitNotStarted = 0, - InitDone = 1, - InitPending = 2, -}; - -static void initplan(Node*); -static NodeList *initlist; -static void init2(Node*, NodeList**); -static void init2list(NodeList*, NodeList**); -static int staticinit(Node*, NodeList**); -static Node *staticname(Type*, int); - -// init1 walks the AST starting at n, and accumulates in out -// the list of definitions needing init code in dependency order. -static void -init1(Node *n, NodeList **out) -{ - NodeList *l; - Node *nv; - - if(n == N) - return; - init1(n->left, out); - init1(n->right, out); - for(l=n->list; l; l=l->next) - init1(l->n, out); - - if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) { - // Methods called as Type.Method(receiver, ...). - // Definitions for method expressions are stored in type->nname. - init1(n->type->nname, out); - } - - if(n->op != ONAME) - return; - switch(n->class) { - case PEXTERN: - case PFUNC: - break; - default: - if(isblank(n) && n->curfn == N && n->defn != N && n->defn->initorder == InitNotStarted) { - // blank names initialization is part of init() but not - // when they are inside a function. - break; - } - return; - } - - if(n->initorder == InitDone) - return; - if(n->initorder == InitPending) { - // Since mutually recursive sets of functions are allowed, - // we don't necessarily raise an error if n depends on a node - // which is already waiting for its dependencies to be visited. - // - // initlist contains a cycle of identifiers referring to each other. - // If this cycle contains a variable, then this variable refers to itself. - // Conversely, if there exists an initialization cycle involving - // a variable in the program, the tree walk will reach a cycle - // involving that variable. - if(n->class != PFUNC) { - nv = n; - goto foundinitloop; - } - for(l=initlist; l->n!=n; l=l->next) { - if(l->n->class != PFUNC) { - nv = l->n; - goto foundinitloop; - } - } - // The loop involves only functions, ok. - return; - - foundinitloop: - // if there have already been errors printed, - // those errors probably confused us and - // there might not be a loop. let the user - // fix those first. - flusherrors(); - if(nerrors > 0) - errorexit(); - - // There is a loop involving nv. We know about - // n and initlist = n1 <- ... <- nv <- ... <- n <- ... - print("%L: initialization loop:\n", nv->lineno); - // Build back pointers in initlist. - for(l=initlist; l; l=l->next) - if(l->next != nil) - l->next->end = l; - // Print nv -> ... -> n1 -> n. - for(l=initlist; l->n!=nv; l=l->next); - for(; l; l=l->end) - print("\t%L %S refers to\n", l->n->lineno, l->n->sym); - // Print n -> ... -> nv. - for(l=initlist; l->n!=n; l=l->next); - for(; l->n != nv; l=l->end) - print("\t%L %S refers to\n", l->n->lineno, l->n->sym); - print("\t%L %S\n", nv->lineno, nv->sym); - errorexit(); - } - - // reached a new unvisited node. - n->initorder = InitPending; - l = malloc(sizeof *l); - if(l == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - l->next = initlist; - l->n = n; - l->end = nil; - initlist = l; - - // make sure that everything n depends on is initialized. - // n->defn is an assignment to n - if(n->defn != N) { - switch(n->defn->op) { - default: - goto bad; - - case ODCLFUNC: - init2list(n->defn->nbody, out); - break; - - case OAS: - if(n->defn->left != n) - goto bad; - if(isblank(n->defn->left) && candiscard(n->defn->right)) { - n->defn->op = OEMPTY; - n->defn->left = N; - n->defn->right = N; - break; - } - - init2(n->defn->right, out); - if(debug['j']) - print("%S\n", n->sym); - if(isblank(n) || !staticinit(n, out)) { - if(debug['%']) - dump("nonstatic", n->defn); - *out = list(*out, n->defn); - } - break; - - case OAS2FUNC: - case OAS2MAPR: - case OAS2DOTTYPE: - case OAS2RECV: - if(n->defn->initorder != InitNotStarted) - break; - n->defn->initorder = InitDone; - for(l=n->defn->rlist; l; l=l->next) - init1(l->n, out); - if(debug['%']) dump("nonstatic", n->defn); - *out = list(*out, n->defn); - break; - } - } - l = initlist; - initlist = l->next; - if(l->n != n) - fatal("bad initlist"); - free(l); - n->initorder = InitDone; - return; - -bad: - dump("defn", n->defn); - fatal("init1: bad defn"); -} - -// recurse over n, doing init1 everywhere. -static void -init2(Node *n, NodeList **out) -{ - if(n == N || n->initorder == InitDone) - return; - - if(n->op == ONAME && n->ninit) - fatal("name %S with ninit: %+N\n", n->sym, n); - - init1(n, out); - init2(n->left, out); - init2(n->right, out); - init2(n->ntest, out); - init2list(n->ninit, out); - init2list(n->list, out); - init2list(n->rlist, out); - init2list(n->nbody, out); - init2list(n->nelse, out); - - if(n->op == OCLOSURE) - init2list(n->closure->nbody, out); - if(n->op == ODOTMETH || n->op == OCALLPART) - init2(n->type->nname, out); -} - -static void -init2list(NodeList *l, NodeList **out) -{ - for(; l; l=l->next) - init2(l->n, out); -} - -static void -initreorder(NodeList *l, NodeList **out) -{ - Node *n; - - for(; l; l=l->next) { - n = l->n; - switch(n->op) { - case ODCLFUNC: - case ODCLCONST: - case ODCLTYPE: - continue; - } - initreorder(n->ninit, out); - n->ninit = nil; - init1(n, out); - } -} - -// initfix computes initialization order for a list l of top-level -// declarations and outputs the corresponding list of statements -// to include in the init() function body. -NodeList* -initfix(NodeList *l) -{ - NodeList *lout; - int lno; - - lout = nil; - lno = lineno; - initreorder(l, &lout); - lineno = lno; - return lout; -} - -/* - * compilation of top-level (static) assignments - * into DATA statements if at all possible. - */ - -static int staticassign(Node*, Node*, NodeList**); - -static int -staticinit(Node *n, NodeList **out) -{ - Node *l, *r; - - if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS) - fatal("staticinit"); - - lineno = n->lineno; - l = n->defn->left; - r = n->defn->right; - return staticassign(l, r, out); -} - -// like staticassign but we are copying an already -// initialized value r. -static int -staticcopy(Node *l, Node *r, NodeList **out) -{ - int i; - InitEntry *e; - InitPlan *p; - Node *a, *ll, *rr, *orig, n1; - - if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg) - return 0; - if(r->defn == N) // probably zeroed but perhaps supplied externally and of unknown value - return 0; - if(r->defn->op != OAS) - return 0; - orig = r; - r = r->defn->right; - - switch(r->op) { - case ONAME: - if(staticcopy(l, r, out)) - return 1; - *out = list(*out, nod(OAS, l, r)); - return 1; - - case OLITERAL: - if(iszero(r)) - return 1; - gdata(l, r, l->type->width); - return 1; - - case OADDR: - switch(r->left->op) { - case ONAME: - gdata(l, r, l->type->width); - return 1; - } - break; - - case OPTRLIT: - switch(r->left->op) { - default: - //dump("not static addr", r); - break; - case OARRAYLIT: - case OSTRUCTLIT: - case OMAPLIT: - // copy pointer - gdata(l, nod(OADDR, r->nname, N), l->type->width); - return 1; - } - break; - - case OARRAYLIT: - if(isslice(r->type)) { - // copy slice - a = r->nname; - n1 = *l; - n1.xoffset = l->xoffset + Array_array; - gdata(&n1, nod(OADDR, a, N), widthptr); - n1.xoffset = l->xoffset + Array_nel; - gdata(&n1, r->right, widthint); - n1.xoffset = l->xoffset + Array_cap; - gdata(&n1, r->right, widthint); - return 1; - } - // fall through - case OSTRUCTLIT: - p = r->initplan; - n1 = *l; - for(i=0; ilen; i++) { - e = &p->e[i]; - n1.xoffset = l->xoffset + e->xoffset; - n1.type = e->expr->type; - if(e->expr->op == OLITERAL) - gdata(&n1, e->expr, n1.type->width); - else { - ll = nod(OXXX, N, N); - *ll = n1; - ll->orig = ll; // completely separate copy - if(!staticassign(ll, e->expr, out)) { - // Requires computation, but we're - // copying someone else's computation. - rr = nod(OXXX, N, N); - *rr = *orig; - rr->orig = rr; // completely separate copy - rr->type = ll->type; - rr->xoffset += e->xoffset; - *out = list(*out, nod(OAS, ll, rr)); - } - } - } - return 1; - } - return 0; -} - -static int -staticassign(Node *l, Node *r, NodeList **out) -{ - Node *a, n1, nam; - Type *ta; - InitPlan *p; - InitEntry *e; - int i; - Strlit *sval; - - switch(r->op) { - default: - //dump("not static", r); - break; - - case ONAME: - if(r->class == PEXTERN && r->sym->pkg == localpkg) - return staticcopy(l, r, out); - break; - - case OLITERAL: - if(iszero(r)) - return 1; - gdata(l, r, l->type->width); - return 1; - - case OADDR: - if(stataddr(&nam, r->left)) { - n1 = *r; - n1.left = &nam; - gdata(l, &n1, l->type->width); - return 1; - } - - case OPTRLIT: - switch(r->left->op) { - default: - //dump("not static ptrlit", r); - break; - - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - // Init pointer. - a = staticname(r->left->type, 1); - r->nname = a; - gdata(l, nod(OADDR, a, N), l->type->width); - // Init underlying literal. - if(!staticassign(a, r->left, out)) - *out = list(*out, nod(OAS, a, r->left)); - return 1; - } - break; - - case OSTRARRAYBYTE: - if(l->class == PEXTERN && r->left->op == OLITERAL) { - sval = r->left->val.u.sval; - slicebytes(l, sval->s, sval->len); - return 1; - } - break; - - case OARRAYLIT: - initplan(r); - if(isslice(r->type)) { - // Init slice. - ta = typ(TARRAY); - ta->type = r->type->type; - ta->bound = mpgetfix(r->right->val.u.xval); - a = staticname(ta, 1); - r->nname = a; - n1 = *l; - n1.xoffset = l->xoffset + Array_array; - gdata(&n1, nod(OADDR, a, N), widthptr); - n1.xoffset = l->xoffset + Array_nel; - gdata(&n1, r->right, widthint); - n1.xoffset = l->xoffset + Array_cap; - gdata(&n1, r->right, widthint); - // Fall through to init underlying array. - l = a; - } - // fall through - case OSTRUCTLIT: - initplan(r); - p = r->initplan; - n1 = *l; - for(i=0; ilen; i++) { - e = &p->e[i]; - n1.xoffset = l->xoffset + e->xoffset; - n1.type = e->expr->type; - if(e->expr->op == OLITERAL) - gdata(&n1, e->expr, n1.type->width); - else { - a = nod(OXXX, N, N); - *a = n1; - a->orig = a; // completely separate copy - if(!staticassign(a, e->expr, out)) - *out = list(*out, nod(OAS, a, e->expr)); - } - } - return 1; - - case OMAPLIT: - // TODO: Table-driven map insert. - break; - } - return 0; -} - -/* - * from here down is the walk analysis - * of composite literals. - * most of the work is to generate - * data statements for the constant - * part of the composite literal. - */ - -static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init); -static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init); -static void slicelit(int ctxt, Node *n, Node *var, NodeList **init); -static void maplit(int ctxt, Node *n, Node *var, NodeList **init); - -static Node* -staticname(Type *t, int ctxt) -{ - Node *n; - - snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen); - statuniqgen++; - n = newname(lookup(namebuf)); - if(!ctxt) - n->readonly = 1; - addvar(n, t, PEXTERN); - return n; -} - -static int -isliteral(Node *n) -{ - if(n->op == OLITERAL) - if(n->val.ctype != CTNIL) - return 1; - return 0; -} - -static int -simplename(Node *n) -{ - if(n->op != ONAME) - goto no; - if(!n->addable) - goto no; - if(n->class & PHEAP) - goto no; - if(n->class == PPARAMREF) - goto no; - return 1; - -no: - return 0; -} - -static void -litas(Node *l, Node *r, NodeList **init) -{ - Node *a; - - a = nod(OAS, l, r); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); -} - -enum -{ - MODEDYNAM = 1, - MODECONST = 2, -}; - -static int -getdyn(Node *n, int top) -{ - NodeList *nl; - Node *value; - int mode; - - mode = 0; - switch(n->op) { - default: - if(isliteral(n)) - return MODECONST; - return MODEDYNAM; - case OARRAYLIT: - if(!top && n->type->bound < 0) - return MODEDYNAM; - case OSTRUCTLIT: - break; - } - - for(nl=n->list; nl; nl=nl->next) { - value = nl->n->right; - mode |= getdyn(value, 0); - if(mode == (MODEDYNAM|MODECONST)) - break; - } - return mode; -} - -static void -structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init) -{ - Node *r, *a; - NodeList *nl; - Node *index, *value; - - for(nl=n->list; nl; nl=nl->next) { - r = nl->n; - if(r->op != OKEY) - fatal("structlit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - - switch(value->op) { - case OARRAYLIT: - if(value->type->bound < 0) { - if(pass == 1 && ctxt != 0) { - a = nod(ODOT, var, newname(index->sym)); - slicelit(ctxt, value, a, init); - } else - if(pass == 2 && ctxt == 0) { - a = nod(ODOT, var, newname(index->sym)); - slicelit(ctxt, value, a, init); - } else - if(pass == 3) - break; - continue; - } - a = nod(ODOT, var, newname(index->sym)); - arraylit(ctxt, pass, value, a, init); - continue; - - case OSTRUCTLIT: - a = nod(ODOT, var, newname(index->sym)); - structlit(ctxt, pass, value, a, init); - continue; - } - - if(isliteral(value)) { - if(pass == 2) - continue; - } else - if(pass == 1) - continue; - - // build list of var.field = expr - a = nod(ODOT, var, newname(index->sym)); - a = nod(OAS, a, value); - typecheck(&a, Etop); - if(pass == 1) { - walkexpr(&a, init); // add any assignments in r to top - if(a->op != OAS) - fatal("structlit: not as"); - a->dodata = 2; - } else { - orderstmtinplace(&a); - walkstmt(&a); - } - *init = list(*init, a); - } -} - -static void -arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init) -{ - Node *r, *a; - NodeList *l; - Node *index, *value; - - for(l=n->list; l; l=l->next) { - r = l->n; - if(r->op != OKEY) - fatal("arraylit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - - switch(value->op) { - case OARRAYLIT: - if(value->type->bound < 0) { - if(pass == 1 && ctxt != 0) { - a = nod(OINDEX, var, index); - slicelit(ctxt, value, a, init); - } else - if(pass == 2 && ctxt == 0) { - a = nod(OINDEX, var, index); - slicelit(ctxt, value, a, init); - } else - if(pass == 3) - break; - continue; - } - a = nod(OINDEX, var, index); - arraylit(ctxt, pass, value, a, init); - continue; - - case OSTRUCTLIT: - a = nod(OINDEX, var, index); - structlit(ctxt, pass, value, a, init); - continue; - } - - if(isliteral(index) && isliteral(value)) { - if(pass == 2) - continue; - } else - if(pass == 1) - continue; - - // build list of var[index] = value - a = nod(OINDEX, var, index); - a = nod(OAS, a, value); - typecheck(&a, Etop); - if(pass == 1) { - walkexpr(&a, init); - if(a->op != OAS) - fatal("arraylit: not as"); - a->dodata = 2; - } else { - orderstmtinplace(&a); - walkstmt(&a); - } - *init = list(*init, a); - } -} - -static void -slicelit(int ctxt, Node *n, Node *var, NodeList **init) -{ - Node *r, *a; - NodeList *l; - Type *t; - Node *vstat, *vauto; - Node *index, *value; - int mode; - - // make an array type - t = shallow(n->type); - t->bound = mpgetfix(n->right->val.u.xval); - t->width = 0; - t->sym = nil; - t->haspointers = 0; - dowidth(t); - - if(ctxt != 0) { - // put everything into static array - vstat = staticname(t, ctxt); - arraylit(ctxt, 1, n, vstat, init); - arraylit(ctxt, 2, n, vstat, init); - - // copy static to slice - a = nod(OSLICE, vstat, nod(OKEY, N, N)); - a = nod(OAS, var, a); - typecheck(&a, Etop); - a->dodata = 2; - *init = list(*init, a); - return; - } - - // recipe for var = []t{...} - // 1. make a static array - // var vstat [...]t - // 2. assign (data statements) the constant part - // vstat = constpart{} - // 3. make an auto pointer to array and allocate heap to it - // var vauto *[...]t = new([...]t) - // 4. copy the static array to the auto array - // *vauto = vstat - // 5. assign slice of allocated heap to var - // var = [0:]*auto - // 6. for each dynamic part assign to the slice - // var[i] = dynamic part - // - // an optimization is done if there is no constant part - // 3. var vauto *[...]t = new([...]t) - // 5. var = [0:]*auto - // 6. var[i] = dynamic part - - // if the literal contains constants, - // make static initialized array (1),(2) - vstat = N; - mode = getdyn(n, 1); - if(mode & MODECONST) { - vstat = staticname(t, ctxt); - arraylit(ctxt, 1, n, vstat, init); - } - - // make new auto *array (3 declare) - vauto = temp(ptrto(t)); - - // set auto to point at new temp or heap (3 assign) - if(n->alloc != N) { - // temp allocated during order.c for dddarg - n->alloc->type = t; - if(vstat == N) { - a = nod(OAS, n->alloc, N); - typecheck(&a, Etop); - *init = list(*init, a); // zero new temp - } - a = nod(OADDR, n->alloc, N); - } else if(n->esc == EscNone) { - a = temp(t); - if(vstat == N) { - a = nod(OAS, temp(t), N); - typecheck(&a, Etop); - *init = list(*init, a); // zero new temp - a = a->left; - } - a = nod(OADDR, a, N); - } else { - a = nod(ONEW, N, N); - a->list = list1(typenod(t)); - } - a = nod(OAS, vauto, a); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - - if(vstat != N) { - // copy static to heap (4) - a = nod(OIND, vauto, N); - a = nod(OAS, a, vstat); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - } - - // make slice out of heap (5) - a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N))); - typecheck(&a, Etop); - orderstmtinplace(&a); - walkstmt(&a); - *init = list(*init, a); - - // put dynamics into slice (6) - for(l=n->list; l; l=l->next) { - r = l->n; - if(r->op != OKEY) - fatal("slicelit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - a = nod(OINDEX, var, index); - a->bounded = 1; - // TODO need to check bounds? - - switch(value->op) { - case OARRAYLIT: - if(value->type->bound < 0) - break; - arraylit(ctxt, 2, value, a, init); - continue; - - case OSTRUCTLIT: - structlit(ctxt, 2, value, a, init); - continue; - } - - if(isliteral(index) && isliteral(value)) - continue; - - // build list of var[c] = expr - a = nod(OAS, a, value); - typecheck(&a, Etop); - orderstmtinplace(&a); - walkstmt(&a); - *init = list(*init, a); - } -} - -static void -maplit(int ctxt, Node *n, Node *var, NodeList **init) -{ - Node *r, *a; - NodeList *l; - int nerr; - int64 b; - Type *t, *tk, *tv, *t1; - Node *vstat, *index, *value, *key, *val; - Sym *syma, *symb; - -USED(ctxt); -ctxt = 0; - - // make the map var - nerr = nerrors; - - a = nod(OMAKE, N, N); - a->list = list1(typenod(n->type)); - litas(var, a, init); - - // count the initializers - b = 0; - for(l=n->list; l; l=l->next) { - r = l->n; - - if(r->op != OKEY) - fatal("maplit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - - if(isliteral(index) && isliteral(value)) - b++; - } - - if(b != 0) { - // build type [count]struct { a Tindex, b Tvalue } - t = n->type; - tk = t->down; - tv = t->type; - - symb = lookup("b"); - t = typ(TFIELD); - t->type = tv; - t->sym = symb; - - syma = lookup("a"); - t1 = t; - t = typ(TFIELD); - t->type = tk; - t->sym = syma; - t->down = t1; - - t1 = t; - t = typ(TSTRUCT); - t->type = t1; - - t1 = t; - t = typ(TARRAY); - t->bound = b; - t->type = t1; - - dowidth(t); - - // make and initialize static array - vstat = staticname(t, ctxt); - b = 0; - for(l=n->list; l; l=l->next) { - r = l->n; - - if(r->op != OKEY) - fatal("maplit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - - if(isliteral(index) && isliteral(value)) { - // build vstat[b].a = key; - a = nodintconst(b); - a = nod(OINDEX, vstat, a); - a = nod(ODOT, a, newname(syma)); - a = nod(OAS, a, index); - typecheck(&a, Etop); - walkexpr(&a, init); - a->dodata = 2; - *init = list(*init, a); - - // build vstat[b].b = value; - a = nodintconst(b); - a = nod(OINDEX, vstat, a); - a = nod(ODOT, a, newname(symb)); - a = nod(OAS, a, value); - typecheck(&a, Etop); - walkexpr(&a, init); - a->dodata = 2; - *init = list(*init, a); - - b++; - } - } - - // loop adding structure elements to map - // for i = 0; i < len(vstat); i++ { - // map[vstat[i].a] = vstat[i].b - // } - index = temp(types[TINT]); - - a = nod(OINDEX, vstat, index); - a->bounded = 1; - a = nod(ODOT, a, newname(symb)); - - r = nod(OINDEX, vstat, index); - r->bounded = 1; - r = nod(ODOT, r, newname(syma)); - r = nod(OINDEX, var, r); - - r = nod(OAS, r, a); - - a = nod(OFOR, N, N); - a->nbody = list1(r); - - a->ninit = list1(nod(OAS, index, nodintconst(0))); - a->ntest = nod(OLT, index, nodintconst(t->bound)); - a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1))); - - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - } - - // put in dynamic entries one-at-a-time - key = nil; - val = nil; - for(l=n->list; l; l=l->next) { - r = l->n; - - if(r->op != OKEY) - fatal("maplit: rhs not OKEY: %N", r); - index = r->left; - value = r->right; - - if(isliteral(index) && isliteral(value)) - continue; - - // build list of var[c] = expr. - // use temporary so that mapassign1 can have addressable key, val. - if(key == nil) { - key = temp(var->type->down); - val = temp(var->type->type); - } - a = nod(OAS, key, r->left); - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - a = nod(OAS, val, r->right); - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - - a = nod(OAS, nod(OINDEX, var, key), val); - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - - if(nerr != nerrors) - break; - } - - if(key != nil) { - a = nod(OVARKILL, key, N); - typecheck(&a, Etop); - *init = list(*init, a); - a = nod(OVARKILL, val, N); - typecheck(&a, Etop); - *init = list(*init, a); - } -} - -void -anylit(int ctxt, Node *n, Node *var, NodeList **init) -{ - Type *t; - Node *a, *vstat, *r; - - t = n->type; - switch(n->op) { - default: - fatal("anylit: not lit"); - - case OPTRLIT: - if(!isptr[t->etype]) - fatal("anylit: not ptr"); - - if(n->right != N) { - r = nod(OADDR, n->right, N); - typecheck(&r, Erv); - } else { - r = nod(ONEW, N, N); - r->typecheck = 1; - r->type = t; - r->esc = n->esc; - } - walkexpr(&r, init); - a = nod(OAS, var, r); - - typecheck(&a, Etop); - *init = list(*init, a); - - var = nod(OIND, var, N); - typecheck(&var, Erv | Easgn); - anylit(ctxt, n->left, var, init); - break; - - case OSTRUCTLIT: - if(t->etype != TSTRUCT) - fatal("anylit: not struct"); - - if(simplename(var) && count(n->list) > 4) { - - if(ctxt == 0) { - // lay out static data - vstat = staticname(t, ctxt); - structlit(ctxt, 1, n, vstat, init); - - // copy static to var - a = nod(OAS, var, vstat); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - - // add expressions to automatic - structlit(ctxt, 2, n, var, init); - break; - } - structlit(ctxt, 1, n, var, init); - structlit(ctxt, 2, n, var, init); - break; - } - - // initialize of not completely specified - if(simplename(var) || count(n->list) < structcount(t)) { - a = nod(OAS, var, N); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - } - structlit(ctxt, 3, n, var, init); - break; - - case OARRAYLIT: - if(t->etype != TARRAY) - fatal("anylit: not array"); - if(t->bound < 0) { - slicelit(ctxt, n, var, init); - break; - } - - if(simplename(var) && count(n->list) > 4) { - - if(ctxt == 0) { - // lay out static data - vstat = staticname(t, ctxt); - arraylit(1, 1, n, vstat, init); - - // copy static to automatic - a = nod(OAS, var, vstat); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - - // add expressions to automatic - arraylit(ctxt, 2, n, var, init); - break; - } - arraylit(ctxt, 1, n, var, init); - arraylit(ctxt, 2, n, var, init); - break; - } - - // initialize of not completely specified - if(simplename(var) || count(n->list) < t->bound) { - a = nod(OAS, var, N); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - } - arraylit(ctxt, 3, n, var, init); - break; - - case OMAPLIT: - if(t->etype != TMAP) - fatal("anylit: not map"); - maplit(ctxt, n, var, init); - break; - } -} - -int -oaslit(Node *n, NodeList **init) -{ - int ctxt; - - if(n->left == N || n->right == N) - goto no; - if(n->left->type == T || n->right->type == T) - goto no; - if(!simplename(n->left)) - goto no; - if(!eqtype(n->left->type, n->right->type)) - goto no; - - // context is init() function. - // implies generated data executed - // exactly once and not subject to races. - ctxt = 0; -// if(n->dodata == 1) -// ctxt = 1; - - switch(n->right->op) { - default: - goto no; - - case OSTRUCTLIT: - case OARRAYLIT: - case OMAPLIT: - if(vmatch1(n->left, n->right)) - goto no; - anylit(ctxt, n->right, n->left, init); - break; - } - n->op = OEMPTY; - return 1; - -no: - // not a special composit literal assignment - return 0; -} - -static int -getlit(Node *lit) -{ - if(smallintconst(lit)) - return mpgetfix(lit->val.u.xval); - return -1; -} - -int -stataddr(Node *nam, Node *n) -{ - int l; - - if(n == N) - goto no; - - switch(n->op) { - - case ONAME: - *nam = *n; - return n->addable; - - case ODOT: - if(!stataddr(nam, n->left)) - break; - nam->xoffset += n->xoffset; - nam->type = n->type; - return 1; - - case OINDEX: - if(n->left->type->bound < 0) - break; - if(!stataddr(nam, n->left)) - break; - l = getlit(n->right); - if(l < 0) - break; - // Check for overflow. - if(n->type->width != 0 && thearch.MAXWIDTH/n->type->width <= l) - break; - nam->xoffset += l*n->type->width; - nam->type = n->type; - return 1; - } - -no: - return 0; -} - -int -gen_as_init(Node *n) -{ - Node *nr, *nl; - Node nam, nod1; - - if(n->dodata == 0) - goto no; - - nr = n->right; - nl = n->left; - if(nr == N) { - if(!stataddr(&nam, nl)) - goto no; - if(nam.class != PEXTERN) - goto no; - goto yes; - } - - if(nr->type == T || !eqtype(nl->type, nr->type)) - goto no; - - if(!stataddr(&nam, nl)) - goto no; - - if(nam.class != PEXTERN) - goto no; - - switch(nr->op) { - default: - goto no; - - case OCONVNOP: - nr = nr->left; - if(nr == N || nr->op != OSLICEARR) - goto no; - // fall through - - case OSLICEARR: - if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) { - nr = nr->left; - goto slice; - } - goto no; - - case OLITERAL: - break; - } - - switch(nr->type->etype) { - default: - goto no; - - case TBOOL: - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TPTR32: - case TPTR64: - case TFLOAT32: - case TFLOAT64: - gdata(&nam, nr, nr->type->width); - break; - - case TCOMPLEX64: - case TCOMPLEX128: - gdatacomplex(&nam, nr->val.u.cval); - break; - - case TSTRING: - gdatastring(&nam, nr->val.u.sval); - break; - } - -yes: - return 1; - -slice: - gused(N); // in case the data is the dest of a goto - nl = nr; - if(nr == N || nr->op != OADDR) - goto no; - nr = nr->left; - if(nr == N || nr->op != ONAME) - goto no; - - // nr is the array being converted to a slice - if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0) - goto no; - - nam.xoffset += Array_array; - gdata(&nam, nl, types[tptr]->width); - - nam.xoffset += Array_nel-Array_array; - nodconst(&nod1, types[TINT], nr->type->bound); - gdata(&nam, &nod1, widthint); - - nam.xoffset += Array_cap-Array_nel; - gdata(&nam, &nod1, widthint); - - goto yes; - -no: - if(n->dodata == 2) { - dump("\ngen_as_init", n); - fatal("gen_as_init couldnt make data statement"); - } - return 0; -} - -static int isvaluelit(Node*); -static InitEntry* entry(InitPlan*); -static void addvalue(InitPlan*, vlong, Node*, Node*); - -static void -initplan(Node *n) -{ - InitPlan *p; - Node *a; - NodeList *l; - - if(n->initplan != nil) - return; - p = mal(sizeof *p); - n->initplan = p; - switch(n->op) { - default: - fatal("initplan"); - case OARRAYLIT: - for(l=n->list; l; l=l->next) { - a = l->n; - if(a->op != OKEY || !smallintconst(a->left)) - fatal("initplan arraylit"); - addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right); - } - break; - case OSTRUCTLIT: - for(l=n->list; l; l=l->next) { - a = l->n; - if(a->op != OKEY || a->left->type == T) - fatal("initplan structlit"); - addvalue(p, a->left->type->width, N, a->right); - } - break; - case OMAPLIT: - for(l=n->list; l; l=l->next) { - a = l->n; - if(a->op != OKEY) - fatal("initplan maplit"); - addvalue(p, -1, a->left, a->right); - } - break; - } -} - -static void -addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n) -{ - int i; - InitPlan *q; - InitEntry *e; - - USED(key); - - // special case: zero can be dropped entirely - if(iszero(n)) { - p->zero += n->type->width; - return; - } - - // special case: inline struct and array (not slice) literals - if(isvaluelit(n)) { - initplan(n); - q = n->initplan; - for(i=0; ilen; i++) { - e = entry(p); - *e = q->e[i]; - e->xoffset += xoffset; - } - return; - } - - // add to plan - if(n->op == OLITERAL) - p->lit += n->type->width; - else - p->expr += n->type->width; - - e = entry(p); - e->xoffset = xoffset; - e->expr = n; -} - -int -iszero(Node *n) -{ - NodeList *l; - - switch(n->op) { - case OLITERAL: - switch(n->val.ctype) { - default: - dump("unexpected literal", n); - fatal("iszero"); - - case CTNIL: - return 1; - - case CTSTR: - return n->val.u.sval == nil || n->val.u.sval->len == 0; - - case CTBOOL: - return n->val.u.bval == 0; - - case CTINT: - case CTRUNE: - return mpcmpfixc(n->val.u.xval, 0) == 0; - - case CTFLT: - return mpcmpfltc(n->val.u.fval, 0) == 0; - - case CTCPLX: - return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0; - } - break; - case OARRAYLIT: - if(isslice(n->type)) - break; - // fall through - case OSTRUCTLIT: - for(l=n->list; l; l=l->next) - if(!iszero(l->n->right)) - return 0; - return 1; - } - return 0; -} - -static int -isvaluelit(Node *n) -{ - return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT; -} - -static InitEntry* -entry(InitPlan *p) -{ - if(p->len >= p->cap) { - if(p->cap == 0) - p->cap = 4; - else - p->cap *= 2; - p->e = realloc(p->e, p->cap*sizeof p->e[0]); - if(p->e == nil) - fatal("out of memory"); - } - return &p->e[p->len++]; -} diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c deleted file mode 100644 index f739a72499..0000000000 --- a/src/cmd/gc/subr.c +++ /dev/null @@ -1,3856 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "md5.h" -#include "y.tab.h" -#include "yerr.h" - -typedef struct Error Error; -struct Error -{ - int lineno; - int seq; - char *msg; -}; -static Error *err; -static int nerr; -static int merr; - -void -errorexit(void) -{ - flusherrors(); - if(outfile) - remove(outfile); - exits("error"); -} - -extern int yychar; -int -parserline(void) -{ - if(yychar != 0 && yychar != -2) // parser has one symbol lookahead - return prevlineno; - return lineno; -} - -void -adderrorname(Node *n) -{ - char *old; - - if(n->op != ODOT) - return; - old = smprint("%L: undefined: %N\n", n->lineno, n->left); - if(nerr > 0 && err[nerr-1].lineno == n->lineno && strcmp(err[nerr-1].msg, old) == 0) - err[nerr-1].msg = smprint("%L: undefined: %N in %N\n", n->lineno, n->left, n); - free(old); -} - -static void -adderr(int line, char *fmt, va_list arg) -{ - Fmt f; - Error *p; - - fmtstrinit(&f); - fmtprint(&f, "%L: ", line); - fmtvprint(&f, fmt, arg); - fmtprint(&f, "\n"); - - if(nerr >= merr) { - if(merr == 0) - merr = 16; - else - merr *= 2; - p = realloc(err, merr*sizeof err[0]); - if(p == nil) { - merr = nerr; - flusherrors(); - print("out of memory\n"); - errorexit(); - } - err = p; - } - err[nerr].seq = nerr; - err[nerr].lineno = line; - err[nerr].msg = fmtstrflush(&f); - nerr++; -} - -static int -errcmp(const void *va, const void *vb) -{ - Error *a, *b; - - a = (Error*)va; - b = (Error*)vb; - if(a->lineno != b->lineno) - return a->lineno - b->lineno; - if(a->seq != b->seq) - return a->seq - b->seq; - return strcmp(a->msg, b->msg); -} - -void -flusherrors(void) -{ - int i; - - Bflush(&bstdout); - if(nerr == 0) - return; - qsort(err, nerr, sizeof err[0], errcmp); - for(i=0; i= 10 && !debug['e']) { - flusherrors(); - print("%L: too many errors\n", line); - errorexit(); - } -} - -extern int yystate, yychar; - -void -yyerror(char *fmt, ...) -{ - int i; - static int lastsyntax; - va_list arg; - char buf[512], *p; - - if(strncmp(fmt, "syntax error", 12) == 0) { - nsyntaxerrors++; - - if(debug['x']) - print("yyerror: yystate=%d yychar=%d\n", yystate, yychar); - - // An unexpected EOF caused a syntax error. Use the previous - // line number since getc generated a fake newline character. - if(curio.eofnl) - lexlineno = prevlineno; - - // only one syntax error per line - if(lastsyntax == lexlineno) - return; - lastsyntax = lexlineno; - - if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) { - // The grammar has { and LBRACE but both show up as {. - // Rewrite syntax error referring to "{ or {" to say just "{". - strecpy(buf, buf+sizeof buf, fmt); - p = strstr(buf, "{ or {"); - if(p) - memmove(p+1, p+6, strlen(p+6)+1); - - // The grammar has ? and @ but only for reading imports. - // Silence them in ordinary errors. - p = strstr(buf, " or ?"); - if(p) - memmove(p, p+5, strlen(p+5)+1); - p = strstr(buf, " or @"); - if(p) - memmove(p, p+5, strlen(p+5)+1); - fmt = buf; - } - - // look for parse state-specific errors in list (see go.errors). - for(i=0; i= 10 && !debug['e']) { - flusherrors(); - print("%L: too many errors\n", parserline()); - errorexit(); - } -} - -void -warn(char *fmt, ...) -{ - va_list arg; - - va_start(arg, fmt); - adderr(parserline(), fmt, arg); - va_end(arg); - - hcrash(); -} - -void -warnl(int line, char *fmt, ...) -{ - va_list arg; - - va_start(arg, fmt); - adderr(line, fmt, arg); - va_end(arg); - if(debug['m']) - flusherrors(); -} - -void -fatal(char *fmt, ...) -{ - va_list arg; - - flusherrors(); - - print("%L: internal compiler error: ", lineno); - va_start(arg, fmt); - vfprint(1, fmt, arg); - va_end(arg); - print("\n"); - - // If this is a released compiler version, ask for a bug report. - if(strncmp(getgoversion(), "release", 7) == 0) { - print("\n"); - print("Please file a bug report including a short program that triggers the error.\n"); - print("https://golang.org/issue/new\n"); - } - hcrash(); - errorexit(); -} - -void -linehist(char *file, int32 off, int relative) -{ - if(debug['i']) { - if(file != nil) { - if(off < 0) - print("pragma %s", file); - else - if(off > 0) - print("line %s", file); - else - print("import %s", file); - } else - print("end of import"); - print(" at line %L\n", lexlineno); - } - - if(off < 0 && file[0] != '/' && !relative) - file = smprint("%s/%s", ctxt->pathname, file); - linklinehist(ctxt, lexlineno, file, off); -} - -int32 -setlineno(Node *n) -{ - int32 lno; - - lno = lineno; - if(n != N) - switch(n->op) { - case ONAME: - case OTYPE: - case OPACK: - case OLITERAL: - break; - default: - lineno = n->lineno; - if(lineno == 0) { - if(debug['K']) - warn("setlineno: line 0"); - lineno = lno; - } - } - return lno; -} - -uint32 -stringhash(char *p) -{ - uint32 h; - int c; - - h = 0; - for(;;) { - c = *p++; - if(c == 0) - break; - h = h*PRIME1 + c; - } - - if((int32)h < 0) { - h = -h; - if((int32)h < 0) - h = 0; - } - return h; -} - -Sym* -lookup(char *name) -{ - return pkglookup(name, localpkg); -} - -Sym* -pkglookup(char *name, Pkg *pkg) -{ - Sym *s; - uint32 h; - int c; - - h = stringhash(name) % NHASH; - c = name[0]; - for(s = hash[h]; s != S; s = s->link) { - if(s->name[0] != c || s->pkg != pkg) - continue; - if(strcmp(s->name, name) == 0) - return s; - } - - s = mal(sizeof(*s)); - s->name = mal(strlen(name)+1); - strcpy(s->name, name); - - s->pkg = pkg; - - s->link = hash[h]; - hash[h] = s; - s->lexical = LNAME; - - return s; -} - -Sym* -restrictlookup(char *name, Pkg *pkg) -{ - if(!exportname(name) && pkg != localpkg) - yyerror("cannot refer to unexported name %s.%s", pkg->name, name); - return pkglookup(name, pkg); -} - - -// find all the exported symbols in package opkg -// and make them available in the current package -void -importdot(Pkg *opkg, Node *pack) -{ - Sym *s, *s1; - uint32 h; - int n; - char *pkgerror; - - n = 0; - for(h=0; hlink) { - if(s->pkg != opkg) - continue; - if(s->def == N) - continue; - if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot - continue; - s1 = lookup(s->name); - if(s1->def != N) { - pkgerror = smprint("during import \"%Z\"", opkg->path); - redeclare(s1, pkgerror); - continue; - } - s1->def = s->def; - s1->block = s->block; - s1->def->pack = pack; - s1->origpkg = opkg; - n++; - } - } - if(n == 0) { - // can't possibly be used - there were no symbols - yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path); - } -} - -static void -gethunk(void) -{ - char *h; - int32 nh; - - nh = NHUNK; - if(thunk >= 10L*NHUNK) - nh = 10L*NHUNK; - h = (char*)malloc(nh); - if(h == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - hunk = h; - nhunk = nh; - thunk += nh; -} - -void* -mal(int32 n) -{ - void *p; - - if(n >= NHUNK) { - p = malloc(n); - if(p == nil) { - flusherrors(); - yyerror("out of memory"); - errorexit(); - } - memset(p, 0, n); - return p; - } - - while((uintptr)hunk & MAXALIGN) { - hunk++; - nhunk--; - } - if(nhunk < n) - gethunk(); - - p = hunk; - nhunk -= n; - hunk += n; - memset(p, 0, n); - return p; -} - -void* -remal(void *p, int32 on, int32 n) -{ - void *q; - - q = (uchar*)p + on; - if(q != hunk || nhunk < n) { - if(on+n >= NHUNK) { - q = mal(on+n); - memmove(q, p, on); - return q; - } - if(nhunk < on+n) - gethunk(); - memmove(hunk, p, on); - p = hunk; - hunk += on; - nhunk -= on; - } - hunk += n; - nhunk -= n; - return p; -} - -Node* -nod(int op, Node *nleft, Node *nright) -{ - Node *n; - - n = mal(sizeof(*n)); - n->op = op; - n->left = nleft; - n->right = nright; - n->lineno = parserline(); - n->xoffset = BADWIDTH; - n->orig = n; - n->curfn = curfn; - return n; -} - -void -saveorignode(Node *n) -{ - Node *norig; - - if(n->orig != N) - return; - norig = nod(n->op, N, N); - *norig = *n; - n->orig = norig; -} - -// ispaddedfield reports whether the given field -// is followed by padding. For the case where t is -// the last field, total gives the size of the enclosing struct. -static int -ispaddedfield(Type *t, vlong total) -{ - if(t->etype != TFIELD) - fatal("ispaddedfield called non-field %T", t); - if(t->down == T) - return t->width + t->type->width != total; - return t->width + t->type->width != t->down->width; -} - -int -algtype1(Type *t, Type **bad) -{ - int a, ret; - Type *t1; - - if(bad) - *bad = T; - if(t->broke) - return AMEM; - if(t->noalg) - return ANOEQ; - - switch(t->etype) { - case TANY: - case TFORW: - // will be defined later. - *bad = t; - return -1; - - case TINT8: - case TUINT8: - case TINT16: - case TUINT16: - case TINT32: - case TUINT32: - case TINT64: - case TUINT64: - case TINT: - case TUINT: - case TUINTPTR: - case TBOOL: - case TPTR32: - case TPTR64: - case TCHAN: - case TUNSAFEPTR: - return AMEM; - - case TFUNC: - case TMAP: - if(bad) - *bad = t; - return ANOEQ; - - case TFLOAT32: - return AFLOAT32; - - case TFLOAT64: - return AFLOAT64; - - case TCOMPLEX64: - return ACPLX64; - - case TCOMPLEX128: - return ACPLX128; - - case TSTRING: - return ASTRING; - - case TINTER: - if(isnilinter(t)) - return ANILINTER; - return AINTER; - - case TARRAY: - if(isslice(t)) { - if(bad) - *bad = t; - return ANOEQ; - } - a = algtype1(t->type, bad); - if(a == ANOEQ || a == AMEM) { - if(a == ANOEQ && bad) - *bad = t; - return a; - } - return -1; // needs special compare - - case TSTRUCT: - if(t->type != T && t->type->down == T && !isblanksym(t->type->sym)) { - // One-field struct is same as that one field alone. - return algtype1(t->type->type, bad); - } - ret = AMEM; - for(t1=t->type; t1!=T; t1=t1->down) { - // All fields must be comparable. - a = algtype1(t1->type, bad); - if(a == ANOEQ) - return ANOEQ; - - // Blank fields, padded fields, fields with non-memory - // equality need special compare. - if(a != AMEM || isblanksym(t1->sym) || ispaddedfield(t1, t->width)) { - ret = -1; - continue; - } - } - return ret; - } - - fatal("algtype1: unexpected type %T", t); - return 0; -} - -int -algtype(Type *t) -{ - int a; - - a = algtype1(t, nil); - if(a == AMEM || a == ANOEQ) { - if(isslice(t)) - return ASLICE; - switch(t->width) { - case 0: - return a + AMEM0 - AMEM; - case 1: - return a + AMEM8 - AMEM; - case 2: - return a + AMEM16 - AMEM; - case 4: - return a + AMEM32 - AMEM; - case 8: - return a + AMEM64 - AMEM; - case 16: - return a + AMEM128 - AMEM; - } - } - return a; -} - -Type* -maptype(Type *key, Type *val) -{ - Type *t; - Type *bad; - int atype, mtype; - - if(key != nil) { - atype = algtype1(key, &bad); - if(bad == T) - mtype = key->etype; - else - mtype = bad->etype; - switch(mtype) { - default: - if(atype == ANOEQ) - yyerror("invalid map key type %T", key); - break; - case TANY: - // will be resolved later. - break; - case TFORW: - // map[key] used during definition of key. - // postpone check until key is fully defined. - // if there are multiple uses of map[key] - // before key is fully defined, the error - // will only be printed for the first one. - // good enough. - if(key->maplineno == 0) - key->maplineno = lineno; - break; - } - } - t = typ(TMAP); - t->down = key; - t->type = val; - return t; -} - -Type* -typ(int et) -{ - Type *t; - - t = mal(sizeof(*t)); - t->etype = et; - t->width = BADWIDTH; - t->lineno = lineno; - t->orig = t; - return t; -} - -static int -methcmp(const void *va, const void *vb) -{ - Type *a, *b; - int k; - - a = *(Type**)va; - b = *(Type**)vb; - if(a->sym == S && b->sym == S) - return 0; - if(a->sym == S) - return -1; - if(b->sym == S) - return 1; - k = strcmp(a->sym->name, b->sym->name); - if(k != 0) - return k; - if(!exportname(a->sym->name)) { - k = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s); - if(k != 0) - return k; - } - return 0; -} - -Type* -sortinter(Type *t) -{ - Type *f; - int i; - Type **a; - - if(t->type == nil || t->type->down == nil) - return t; - - i=0; - for(f=t->type; f; f=f->down) - i++; - a = mal(i*sizeof f); - i = 0; - for(f=t->type; f; f=f->down) - a[i++] = f; - qsort(a, i, sizeof a[0], methcmp); - while(i-- > 0) { - a[i]->down = f; - f = a[i]; - } - t->type = f; - return t; -} - -Node* -nodintconst(int64 v) -{ - Node *c; - - c = nod(OLITERAL, N, N); - c->addable = 1; - c->val.u.xval = mal(sizeof(*c->val.u.xval)); - mpmovecfix(c->val.u.xval, v); - c->val.ctype = CTINT; - c->type = types[TIDEAL]; - ullmancalc(c); - return c; -} - -Node* -nodfltconst(Mpflt* v) -{ - Node *c; - - c = nod(OLITERAL, N, N); - c->addable = 1; - c->val.u.fval = mal(sizeof(*c->val.u.fval)); - mpmovefltflt(c->val.u.fval, v); - c->val.ctype = CTFLT; - c->type = types[TIDEAL]; - ullmancalc(c); - return c; -} - -void -nodconst(Node *n, Type *t, int64 v) -{ - memset(n, 0, sizeof(*n)); - n->op = OLITERAL; - n->addable = 1; - ullmancalc(n); - n->val.u.xval = mal(sizeof(*n->val.u.xval)); - mpmovecfix(n->val.u.xval, v); - n->val.ctype = CTINT; - n->type = t; - - if(isfloat[t->etype]) - fatal("nodconst: bad type %T", t); -} - -Node* -nodnil(void) -{ - Node *c; - - c = nodintconst(0); - c->val.ctype = CTNIL; - c->type = types[TNIL]; - return c; -} - -Node* -nodbool(int b) -{ - Node *c; - - c = nodintconst(0); - c->val.ctype = CTBOOL; - c->val.u.bval = b; - c->type = idealbool; - return c; -} - -Type* -aindex(Node *b, Type *t) -{ - Type *r; - int64 bound; - - bound = -1; // open bound - typecheck(&b, Erv); - if(b != nil) { - switch(consttype(b)) { - default: - yyerror("array bound must be an integer expression"); - break; - case CTINT: - case CTRUNE: - bound = mpgetfix(b->val.u.xval); - if(bound < 0) - yyerror("array bound must be non negative"); - break; - } - } - - // fixed array - r = typ(TARRAY); - r->type = t; - r->bound = bound; - return r; -} - -Node* -treecopy(Node *n) -{ - Node *m; - - if(n == N) - return N; - - switch(n->op) { - default: - m = nod(OXXX, N, N); - *m = *n; - m->orig = m; - m->left = treecopy(n->left); - m->right = treecopy(n->right); - m->list = listtreecopy(n->list); - if(m->defn) - abort(); - break; - - case ONONAME: - if(n->sym == lookup("iota")) { - // Not sure yet whether this is the real iota, - // but make a copy of the Node* just in case, - // so that all the copies of this const definition - // don't have the same iota value. - m = nod(OXXX, N, N); - *m = *n; - m->iota = iota; - break; - } - // fall through - case ONAME: - case OLITERAL: - case OTYPE: - m = n; - break; - } - return m; -} - - -int -isnil(Node *n) -{ - if(n == N) - return 0; - if(n->op != OLITERAL) - return 0; - if(n->val.ctype != CTNIL) - return 0; - return 1; -} - -int -isptrto(Type *t, int et) -{ - if(t == T) - return 0; - if(!isptr[t->etype]) - return 0; - t = t->type; - if(t == T) - return 0; - if(t->etype != et) - return 0; - return 1; -} - -int -istype(Type *t, int et) -{ - return t != T && t->etype == et; -} - -int -isfixedarray(Type *t) -{ - return t != T && t->etype == TARRAY && t->bound >= 0; -} - -int -isslice(Type *t) -{ - return t != T && t->etype == TARRAY && t->bound < 0; -} - -int -isblank(Node *n) -{ - if(n == N) - return 0; - return isblanksym(n->sym); -} - -int -isblanksym(Sym *s) -{ - char *p; - - if(s == S) - return 0; - p = s->name; - if(p == nil) - return 0; - return p[0] == '_' && p[1] == '\0'; -} - -int -isinter(Type *t) -{ - return t != T && t->etype == TINTER; -} - -int -isnilinter(Type *t) -{ - if(!isinter(t)) - return 0; - if(t->type != T) - return 0; - return 1; -} - -int -isideal(Type *t) -{ - if(t == T) - return 0; - if(t == idealstring || t == idealbool) - return 1; - switch(t->etype) { - case TNIL: - case TIDEAL: - return 1; - } - return 0; -} - -/* - * given receiver of type t (t == r or t == *r) - * return type to hang methods off (r). - */ -Type* -methtype(Type *t, int mustname) -{ - if(t == T) - return T; - - // strip away pointer if it's there - if(isptr[t->etype]) { - if(t->sym != S) - return T; - t = t->type; - if(t == T) - return T; - } - - // need a type name - if(t->sym == S && (mustname || t->etype != TSTRUCT)) - return T; - - // check types - if(!issimple[t->etype]) - switch(t->etype) { - default: - return T; - case TSTRUCT: - case TARRAY: - case TMAP: - case TCHAN: - case TSTRING: - case TFUNC: - break; - } - - return t; -} - -int -cplxsubtype(int et) -{ - switch(et) { - case TCOMPLEX64: - return TFLOAT32; - case TCOMPLEX128: - return TFLOAT64; - } - fatal("cplxsubtype: %E\n", et); - return 0; -} - -static int -eqnote(Strlit *a, Strlit *b) -{ - if(a == b) - return 1; - if(a == nil || b == nil) - return 0; - if(a->len != b->len) - return 0; - return memcmp(a->s, b->s, a->len) == 0; -} - -typedef struct TypePairList TypePairList; -struct TypePairList -{ - Type *t1; - Type *t2; - TypePairList *next; -}; - -static int -onlist(TypePairList *l, Type *t1, Type *t2) -{ - for(; l; l=l->next) - if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1)) - return 1; - return 0; -} - -static int eqtype1(Type*, Type*, TypePairList*); - -// Return 1 if t1 and t2 are identical, following the spec rules. -// -// Any cyclic type must go through a named type, and if one is -// named, it is only identical to the other if they are the same -// pointer (t1 == t2), so there's no chance of chasing cycles -// ad infinitum, so no need for a depth counter. -int -eqtype(Type *t1, Type *t2) -{ - return eqtype1(t1, t2, nil); -} - -static int -eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal) -{ - TypePairList l; - - if(t1 == t2) - return 1; - if(t1 == T || t2 == T || t1->etype != t2->etype) - return 0; - if(t1->sym || t2->sym) { - // Special case: we keep byte and uint8 separate - // for error messages. Treat them as equal. - switch(t1->etype) { - case TUINT8: - if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype)) - return 1; - break; - case TINT: - case TINT32: - if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype)) - return 1; - break; - } - return 0; - } - - if(onlist(assumed_equal, t1, t2)) - return 1; - l.next = assumed_equal; - l.t1 = t1; - l.t2 = t2; - - switch(t1->etype) { - case TINTER: - case TSTRUCT: - for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { - if(t1->etype != TFIELD || t2->etype != TFIELD) - fatal("struct/interface missing field: %T %T", t1, t2); - if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note)) - goto no; - } - if(t1 == T && t2 == T) - goto yes; - goto no; - - case TFUNC: - // Loop over structs: receiver, in, out. - for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) { - Type *ta, *tb; - - if(t1->etype != TSTRUCT || t2->etype != TSTRUCT) - fatal("func missing struct: %T %T", t1, t2); - - // Loop over fields in structs, ignoring argument names. - for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) { - if(ta->etype != TFIELD || tb->etype != TFIELD) - fatal("func struct missing field: %T %T", ta, tb); - if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l)) - goto no; - } - if(ta != T || tb != T) - goto no; - } - if(t1 == T && t2 == T) - goto yes; - goto no; - - case TARRAY: - if(t1->bound != t2->bound) - goto no; - break; - - case TCHAN: - if(t1->chan != t2->chan) - goto no; - break; - } - - if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l)) - goto yes; - goto no; - -yes: - return 1; - -no: - return 0; -} - -// Are t1 and t2 equal struct types when field names are ignored? -// For deciding whether the result struct from g can be copied -// directly when compiling f(g()). -int -eqtypenoname(Type *t1, Type *t2) -{ - if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT) - return 0; - - t1 = t1->type; - t2 = t2->type; - for(;;) { - if(!eqtype(t1, t2)) - return 0; - if(t1 == T) - return 1; - t1 = t1->down; - t2 = t2->down; - } -} - -// Is type src assignment compatible to type dst? -// If so, return op code to use in conversion. -// If not, return 0. -int -assignop(Type *src, Type *dst, char **why) -{ - Type *missing, *have; - int ptr; - - if(why != nil) - *why = ""; - - // TODO(rsc,lvd): This behaves poorly in the presence of inlining. - // https://golang.org/issue/2795 - if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) { - yyerror("cannot use unsafe.Pointer"); - errorexit(); - } - - if(src == dst) - return OCONVNOP; - if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T) - return 0; - - // 1. src type is identical to dst. - if(eqtype(src, dst)) - return OCONVNOP; - - // 2. src and dst have identical underlying types - // and either src or dst is not a named type or - // both are empty interface types. - // For assignable but different non-empty interface types, - // we want to recompute the itab. - if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src))) - return OCONVNOP; - - // 3. dst is an interface type and src implements dst. - if(dst->etype == TINTER && src->etype != TNIL) { - if(implements(src, dst, &missing, &have, &ptr)) - return OCONVIFACE; - - // we'll have complained about this method anyway, suppress spurious messages. - if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke)) - return OCONVIFACE; - - if(why != nil) { - if(isptrto(src, TINTER)) - *why = smprint(":\n\t%T is pointer to interface, not interface", src); - else if(have && have->sym == missing->sym && have->nointerface) - *why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')", - src, dst, missing->sym); - else if(have && have->sym == missing->sym) - *why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else if(ptr) - *why = smprint(":\n\t%T does not implement %T (%S method has pointer receiver)", - src, dst, missing->sym); - else if(have) - *why = smprint(":\n\t%T does not implement %T (missing %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else - *why = smprint(":\n\t%T does not implement %T (missing %S method)", - src, dst, missing->sym); - } - return 0; - } - if(isptrto(dst, TINTER)) { - if(why != nil) - *why = smprint(":\n\t%T is pointer to interface, not interface", dst); - return 0; - } - if(src->etype == TINTER && dst->etype != TBLANK) { - if(why != nil && implements(dst, src, &missing, &have, &ptr)) - *why = ": need type assertion"; - return 0; - } - - // 4. src is a bidirectional channel value, dst is a channel type, - // src and dst have identical element types, and - // either src or dst is not a named type. - if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN) - if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S)) - return OCONVNOP; - - // 5. src is the predeclared identifier nil and dst is a nillable type. - if(src->etype == TNIL) { - switch(dst->etype) { - case TARRAY: - if(dst->bound != -100) // not slice - break; - case TPTR32: - case TPTR64: - case TFUNC: - case TMAP: - case TCHAN: - case TINTER: - return OCONVNOP; - } - } - - // 6. rule about untyped constants - already converted by defaultlit. - - // 7. Any typed value can be assigned to the blank identifier. - if(dst->etype == TBLANK) - return OCONVNOP; - - return 0; -} - -// Can we convert a value of type src to a value of type dst? -// If so, return op code to use in conversion (maybe OCONVNOP). -// If not, return 0. -int -convertop(Type *src, Type *dst, char **why) -{ - int op; - - if(why != nil) - *why = ""; - - if(src == dst) - return OCONVNOP; - if(src == T || dst == T) - return 0; - - // 1. src can be assigned to dst. - if((op = assignop(src, dst, why)) != 0) - return op; - - // The rules for interfaces are no different in conversions - // than assignments. If interfaces are involved, stop now - // with the good message from assignop. - // Otherwise clear the error. - if(src->etype == TINTER || dst->etype == TINTER) - return 0; - if(why != nil) - *why = ""; - - // 2. src and dst have identical underlying types. - if(eqtype(src->orig, dst->orig)) - return OCONVNOP; - - // 3. src and dst are unnamed pointer types - // and their base types have identical underlying types. - if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S) - if(eqtype(src->type->orig, dst->type->orig)) - return OCONVNOP; - - // 4. src and dst are both integer or floating point types. - if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) { - if(simtype[src->etype] == simtype[dst->etype]) - return OCONVNOP; - return OCONV; - } - - // 5. src and dst are both complex types. - if(iscomplex[src->etype] && iscomplex[dst->etype]) { - if(simtype[src->etype] == simtype[dst->etype]) - return OCONVNOP; - return OCONV; - } - - // 6. src is an integer or has type []byte or []rune - // and dst is a string type. - if(isint[src->etype] && dst->etype == TSTRING) - return ORUNESTR; - - if(isslice(src) && dst->etype == TSTRING) { - if(src->type->etype == bytetype->etype) - return OARRAYBYTESTR; - if(src->type->etype == runetype->etype) - return OARRAYRUNESTR; - } - - // 7. src is a string and dst is []byte or []rune. - // String to slice. - if(src->etype == TSTRING && isslice(dst)) { - if(dst->type->etype == bytetype->etype) - return OSTRARRAYBYTE; - if(dst->type->etype == runetype->etype) - return OSTRARRAYRUNE; - } - - // 8. src is a pointer or uintptr and dst is unsafe.Pointer. - if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR) - return OCONVNOP; - - // 9. src is unsafe.Pointer and dst is a pointer or uintptr. - if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR)) - return OCONVNOP; - - return 0; -} - -// Convert node n for assignment to type t. -Node* -assignconv(Node *n, Type *t, char *context) -{ - int op; - Node *r, *old; - char *why; - - if(n == N || n->type == T || n->type->broke) - return n; - - if(t->etype == TBLANK && n->type->etype == TNIL) - yyerror("use of untyped nil"); - - old = n; - old->diag++; // silence errors about n; we'll issue one below - defaultlit(&n, t); - old->diag--; - if(t->etype == TBLANK) - return n; - - // Convert ideal bool from comparison to plain bool - // if the next step is non-bool (like interface{}). - if(n->type == idealbool && t->etype != TBOOL) { - if(n->op == ONAME || n->op == OLITERAL) { - r = nod(OCONVNOP, n, N); - r->type = types[TBOOL]; - r->typecheck = 1; - r->implicit = 1; - n = r; - } - } - - if(eqtype(n->type, t)) - return n; - - op = assignop(n->type, t, &why); - if(op == 0) { - yyerror("cannot use %lN as type %T in %s%s", n, t, context, why); - op = OCONV; - } - - r = nod(op, n, N); - r->type = t; - r->typecheck = 1; - r->implicit = 1; - r->orig = n->orig; - return r; -} - -static int -subtype(Type **stp, Type *t, int d) -{ - Type *st; - -loop: - st = *stp; - if(st == T) - return 0; - - d++; - if(d >= 10) - return 0; - - switch(st->etype) { - default: - return 0; - - case TPTR32: - case TPTR64: - case TCHAN: - case TARRAY: - stp = &st->type; - goto loop; - - case TANY: - if(!st->copyany) - return 0; - *stp = t; - break; - - case TMAP: - if(subtype(&st->down, t, d)) - break; - stp = &st->type; - goto loop; - - case TFUNC: - for(;;) { - if(subtype(&st->type, t, d)) - break; - if(subtype(&st->type->down->down, t, d)) - break; - if(subtype(&st->type->down, t, d)) - break; - return 0; - } - break; - - case TSTRUCT: - for(st=st->type; st!=T; st=st->down) - if(subtype(&st->type, t, d)) - return 1; - return 0; - } - return 1; -} - -/* - * Is this a 64-bit type? - */ -int -is64(Type *t) -{ - if(t == T) - return 0; - switch(simtype[t->etype]) { - case TINT64: - case TUINT64: - case TPTR64: - return 1; - } - return 0; -} - -/* - * Is a conversion between t1 and t2 a no-op? - */ -int -noconv(Type *t1, Type *t2) -{ - int e1, e2; - - e1 = simtype[t1->etype]; - e2 = simtype[t2->etype]; - - switch(e1) { - case TINT8: - case TUINT8: - return e2 == TINT8 || e2 == TUINT8; - - case TINT16: - case TUINT16: - return e2 == TINT16 || e2 == TUINT16; - - case TINT32: - case TUINT32: - case TPTR32: - return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32; - - case TINT64: - case TUINT64: - case TPTR64: - return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64; - - case TFLOAT32: - return e2 == TFLOAT32; - - case TFLOAT64: - return e2 == TFLOAT64; - } - return 0; -} - -void -argtype(Node *on, Type *t) -{ - dowidth(t); - if(!subtype(&on->type, t, 0)) - fatal("argtype: failed %N %T\n", on, t); -} - -Type* -shallow(Type *t) -{ - Type *nt; - - if(t == T) - return T; - nt = typ(0); - *nt = *t; - if(t->orig == t) - nt->orig = nt; - return nt; -} - -static Type* -deep(Type *t) -{ - Type *nt, *xt; - - if(t == T) - return T; - - switch(t->etype) { - default: - nt = t; // share from here down - break; - - case TANY: - nt = shallow(t); - nt->copyany = 1; - break; - - case TPTR32: - case TPTR64: - case TCHAN: - case TARRAY: - nt = shallow(t); - nt->type = deep(t->type); - break; - - case TMAP: - nt = shallow(t); - nt->down = deep(t->down); - nt->type = deep(t->type); - break; - - case TFUNC: - nt = shallow(t); - nt->type = deep(t->type); - nt->type->down = deep(t->type->down); - nt->type->down->down = deep(t->type->down->down); - break; - - case TSTRUCT: - nt = shallow(t); - nt->type = shallow(t->type); - xt = nt->type; - - for(t=t->type; t!=T; t=t->down) { - xt->type = deep(t->type); - xt->down = shallow(t->down); - xt = xt->down; - } - break; - } - return nt; -} - -Node* -syslook(char *name, int copy) -{ - Sym *s; - Node *n; - - s = pkglookup(name, runtimepkg); - if(s == S || s->def == N) - fatal("syslook: can't find runtime.%s", name); - - if(!copy) - return s->def; - - n = nod(0, N, N); - *n = *s->def; - n->type = deep(s->def->type); - - return n; -} - -/* - * compute a hash value for type t. - * if t is a method type, ignore the receiver - * so that the hash can be used in interface checks. - * %T already contains - * all the necessary logic to generate a representation - * of the type that completely describes it. - * using smprint here avoids duplicating that code. - * using md5 here is overkill, but i got tired of - * accidental collisions making the runtime think - * two types are equal when they really aren't. - */ -uint32 -typehash(Type *t) -{ - char *p; - MD5 d; - - if(t->thistuple) { - // hide method receiver from Tpretty - t->thistuple = 0; - p = smprint("%-uT", t); - t->thistuple = 1; - } else - p = smprint("%-uT", t); - //print("typehash: %s\n", p); - md5reset(&d); - md5write(&d, (uchar*)p, strlen(p)); - free(p); - return md5sum(&d, nil); -} - -Type* -ptrto(Type *t) -{ - Type *t1; - - if(tptr == 0) - fatal("ptrto: no tptr"); - t1 = typ(tptr); - t1->type = t; - t1->width = widthptr; - t1->align = widthptr; - return t1; -} - -void -frame(int context) -{ - NodeList *l; - Node *n; - vlong w; - - if(context) { - print("--- external frame ---\n"); - l = externdcl; - } else if(curfn) { - print("--- %S frame ---\n", curfn->nname->sym); - l = curfn->dcl; - } else - return; - - for(; l; l=l->next) { - n = l->n; - w = -1; - if(n->type) - w = n->type->width; - switch(n->op) { - case ONAME: - print("%O %S G%d %T width=%lld\n", n->op, n->sym, n->vargen, n->type, w); - break; - - case OTYPE: - print("%O %T width=%lld\n", n->op, n->type, w); - break; - } - } -} - -/* - * calculate sethi/ullman number - * roughly how many registers needed to - * compile a node. used to compile the - * hardest side first to minimize registers. - */ -void -ullmancalc(Node *n) -{ - int ul, ur; - - if(n == N) - return; - - if(n->ninit != nil) { - ul = UINF; - goto out; - } - - switch(n->op) { - case OREGISTER: - case OLITERAL: - case ONAME: - ul = 1; - if(n->class == PPARAMREF || (n->class & PHEAP)) - ul++; - goto out; - case OCALL: - case OCALLFUNC: - case OCALLMETH: - case OCALLINTER: - ul = UINF; - goto out; - case OANDAND: - case OOROR: - // hard with race detector - if(flag_race) { - ul = UINF; - goto out; - } - } - ul = 1; - if(n->left != N) - ul = n->left->ullman; - ur = 1; - if(n->right != N) - ur = n->right->ullman; - if(ul == ur) - ul += 1; - if(ur > ul) - ul = ur; - -out: - if(ul > 200) - ul = 200; // clamp to uchar with room to grow - n->ullman = ul; -} - -void -badtype(int o, Type *tl, Type *tr) -{ - Fmt fmt; - char *s; - - fmtstrinit(&fmt); - if(tl != T) - fmtprint(&fmt, "\n %T", tl); - if(tr != T) - fmtprint(&fmt, "\n %T", tr); - - // common mistake: *struct and *interface. - if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) { - if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER) - fmtprint(&fmt, "\n (*struct vs *interface)"); - else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT) - fmtprint(&fmt, "\n (*interface vs *struct)"); - } - s = fmtstrflush(&fmt); - yyerror("illegal types for operand: %O%s", o, s); -} - -/* - * iterator to walk a structure declaration - */ -Type* -structfirst(Iter *s, Type **nn) -{ - Type *n, *t; - - n = *nn; - if(n == T) - goto bad; - - switch(n->etype) { - default: - goto bad; - - case TSTRUCT: - case TINTER: - case TFUNC: - break; - } - - t = n->type; - if(t == T) - goto rnil; - - if(t->etype != TFIELD) - fatal("structfirst: not field %T", t); - - s->t = t; - return t; - -bad: - fatal("structfirst: not struct %T", n); - -rnil: - return T; -} - -Type* -structnext(Iter *s) -{ - Type *n, *t; - - n = s->t; - t = n->down; - if(t == T) - goto rnil; - - if(t->etype != TFIELD) - goto bad; - - s->t = t; - return t; - -bad: - fatal("structnext: not struct %T", n); - -rnil: - return T; -} - -/* - * iterator to this and inargs in a function - */ -Type* -funcfirst(Iter *s, Type *t) -{ - Type *fp; - - if(t == T) - goto bad; - - if(t->etype != TFUNC) - goto bad; - - s->tfunc = t; - s->done = 0; - fp = structfirst(s, getthis(t)); - if(fp == T) { - s->done = 1; - fp = structfirst(s, getinarg(t)); - } - return fp; - -bad: - fatal("funcfirst: not func %T", t); - return T; -} - -Type* -funcnext(Iter *s) -{ - Type *fp; - - fp = structnext(s); - if(fp == T && !s->done) { - s->done = 1; - fp = structfirst(s, getinarg(s->tfunc)); - } - return fp; -} - -Type** -getthis(Type *t) -{ - if(t->etype != TFUNC) - fatal("getthis: not a func %T", t); - return &t->type; -} - -Type** -getoutarg(Type *t) -{ - if(t->etype != TFUNC) - fatal("getoutarg: not a func %T", t); - return &t->type->down; -} - -Type** -getinarg(Type *t) -{ - if(t->etype != TFUNC) - fatal("getinarg: not a func %T", t); - return &t->type->down->down; -} - -Type* -getthisx(Type *t) -{ - return *getthis(t); -} - -Type* -getoutargx(Type *t) -{ - return *getoutarg(t); -} - -Type* -getinargx(Type *t) -{ - return *getinarg(t); -} - -/* - * return !(op) - * eg == <=> != - */ -int -brcom(int a) -{ - switch(a) { - case OEQ: return ONE; - case ONE: return OEQ; - case OLT: return OGE; - case OGT: return OLE; - case OLE: return OGT; - case OGE: return OLT; - } - fatal("brcom: no com for %O\n", a); - return a; -} - -/* - * return reverse(op) - * eg a op b <=> b r(op) a - */ -int -brrev(int a) -{ - switch(a) { - case OEQ: return OEQ; - case ONE: return ONE; - case OLT: return OGT; - case OGT: return OLT; - case OLE: return OGE; - case OGE: return OLE; - } - fatal("brcom: no rev for %O\n", a); - return a; -} - -/* - * return side effect-free n, appending side effects to init. - * result is assignable if n is. - */ -Node* -safeexpr(Node *n, NodeList **init) -{ - Node *l; - Node *r; - Node *a; - - if(n == N) - return N; - - if(n->ninit) { - walkstmtlist(n->ninit); - *init = concat(*init, n->ninit); - n->ninit = nil; - } - - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - - case ODOT: - l = safeexpr(n->left, init); - if(l == n->left) - return n; - r = nod(OXXX, N, N); - *r = *n; - r->left = l; - typecheck(&r, Erv); - walkexpr(&r, init); - return r; - - case ODOTPTR: - case OIND: - l = safeexpr(n->left, init); - if(l == n->left) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->left = l; - walkexpr(&a, init); - return a; - - case OINDEX: - case OINDEXMAP: - l = safeexpr(n->left, init); - r = safeexpr(n->right, init); - if(l == n->left && r == n->right) - return n; - a = nod(OXXX, N, N); - *a = *n; - a->left = l; - a->right = r; - walkexpr(&a, init); - return a; - } - - // make a copy; must not be used as an lvalue - if(islvalue(n)) - fatal("missing lvalue case in safeexpr: %N", n); - return cheapexpr(n, init); -} - -Node* -copyexpr(Node *n, Type *t, NodeList **init) -{ - Node *a, *l; - - l = temp(t); - a = nod(OAS, l, n); - typecheck(&a, Etop); - walkexpr(&a, init); - *init = list(*init, a); - return l; -} - -/* - * return side-effect free and cheap n, appending side effects to init. - * result may not be assignable. - */ -Node* -cheapexpr(Node *n, NodeList **init) -{ - switch(n->op) { - case ONAME: - case OLITERAL: - return n; - } - - return copyexpr(n, n->type, init); -} - -/* - * return n in a local variable of type t if it is not already. - * the value is guaranteed not to change except by direct - * assignment to it. - */ -Node* -localexpr(Node *n, Type *t, NodeList **init) -{ - if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) && - (n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) && - convertop(n->type, t, nil) == OCONVNOP) - return n; - - return copyexpr(n, t, init); -} - -void -setmaxarg(Type *t, int32 extra) -{ - int64 w; - - dowidth(t); - w = t->argwid; - if(w >= thearch.MAXWIDTH) - fatal("bad argwid %T", t); - w += extra; - if(w >= thearch.MAXWIDTH) - fatal("bad argwid %d + %T", extra, t); - if(w > maxarg) - maxarg = w; -} - -/* - * unicode-aware case-insensitive strcmp - */ - -static int -ucistrcmp(char *p, char *q) -{ - Rune rp, rq; - - while(*p || *q) { - if(*p == 0) - return +1; - if(*q == 0) - return -1; - p += chartorune(&rp, p); - q += chartorune(&rq, q); - rp = tolowerrune(rp); - rq = tolowerrune(rq); - if(rp < rq) - return -1; - if(rp > rq) - return +1; - } - return 0; -} - -/* - * code to resolve elided DOTs - * in embedded types - */ - -// search depth 0 -- -// return count of fields+methods -// found with a given name -static int -lookdot0(Sym *s, Type *t, Type **save, int ignorecase) -{ - Type *f, *u; - int c; - - u = t; - if(isptr[u->etype]) - u = u->type; - - c = 0; - if(u->etype == TSTRUCT || u->etype == TINTER) { - for(f=u->type; f!=T; f=f->down) - if(f->sym == s || (ignorecase && f->type->etype == TFUNC && f->type->thistuple > 0 && ucistrcmp(f->sym->name, s->name) == 0)) { - if(save) - *save = f; - c++; - } - } - u = methtype(t, 0); - if(u != T) { - for(f=u->method; f!=T; f=f->down) - if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) { - if(save) - *save = f; - c++; - } - } - return c; -} - -// search depth d for field/method s -- -// return count of fields+methods -// found at search depth. -// answer is in dotlist array and -// count of number of ways is returned. -int -adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase) -{ - Type *f, *u; - int c, a; - - if(t->trecur) - return 0; - t->trecur = 1; - - if(d == 0) { - c = lookdot0(s, t, save, ignorecase); - goto out; - } - - c = 0; - u = t; - if(isptr[u->etype]) - u = u->type; - if(u->etype != TSTRUCT && u->etype != TINTER) - goto out; - - d--; - for(f=u->type; f!=T; f=f->down) { - if(!f->embedded) - continue; - if(f->sym == S) - continue; - a = adddot1(s, f->type, d, save, ignorecase); - if(a != 0 && c == 0) - dotlist[d].field = f; - c += a; - } - -out: - t->trecur = 0; - return c; -} - -// in T.field -// find missing fields that -// will give shortest unique addressing. -// modify the tree with missing type names. -Node* -adddot(Node *n) -{ - Type *t; - Sym *s; - int c, d; - - typecheck(&n->left, Etype|Erv); - n->diag |= n->left->diag; - t = n->left->type; - if(t == T) - goto ret; - - if(n->left->op == OTYPE) - goto ret; - - if(n->right->op != ONAME) - goto ret; - s = n->right->sym; - if(s == S) - goto ret; - - for(d=0; d 0) - goto out; - } - goto ret; - -out: - if(c > 1) { - yyerror("ambiguous selector %N", n); - n->left = N; - return n; - } - - // rebuild elided dots - for(c=d-1; c>=0; c--) - n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym)); -ret: - return n; -} - - -/* - * code to help generate trampoline - * functions for methods on embedded - * subtypes. - * these are approx the same as - * the corresponding adddot routines - * except that they expect to be called - * with unique tasks and they return - * the actual methods. - */ - -typedef struct Symlink Symlink; -struct Symlink -{ - Type* field; - uchar good; - uchar followptr; - Symlink* link; -}; -static Symlink* slist; - -static void -expand0(Type *t, int followptr) -{ - Type *f, *u; - Symlink *sl; - - u = t; - if(isptr[u->etype]) { - followptr = 1; - u = u->type; - } - - if(u->etype == TINTER) { - for(f=u->type; f!=T; f=f->down) { - if(f->sym->flags & SymUniq) - continue; - f->sym->flags |= SymUniq; - sl = mal(sizeof(*sl)); - sl->field = f; - sl->link = slist; - sl->followptr = followptr; - slist = sl; - } - return; - } - - u = methtype(t, 0); - if(u != T) { - for(f=u->method; f!=T; f=f->down) { - if(f->sym->flags & SymUniq) - continue; - f->sym->flags |= SymUniq; - sl = mal(sizeof(*sl)); - sl->field = f; - sl->link = slist; - sl->followptr = followptr; - slist = sl; - } - } -} - -static void -expand1(Type *t, int d, int followptr) -{ - Type *f, *u; - - if(t->trecur) - return; - if(d == 0) - return; - t->trecur = 1; - - if(d != nelem(dotlist)-1) - expand0(t, followptr); - - u = t; - if(isptr[u->etype]) { - followptr = 1; - u = u->type; - } - if(u->etype != TSTRUCT && u->etype != TINTER) - goto out; - - for(f=u->type; f!=T; f=f->down) { - if(!f->embedded) - continue; - if(f->sym == S) - continue; - expand1(f->type, d-1, followptr); - } - -out: - t->trecur = 0; -} - -void -expandmeth(Type *t) -{ - Symlink *sl; - Type *f; - int c, d; - - if(t == T || t->xmethod != nil) - return; - - // mark top-level method symbols - // so that expand1 doesn't consider them. - for(f=t->method; f != nil; f=f->down) - f->sym->flags |= SymUniq; - - // generate all reachable methods - slist = nil; - expand1(t, nelem(dotlist)-1, 0); - - // check each method to be uniquely reachable - for(sl=slist; sl!=nil; sl=sl->link) { - sl->field->sym->flags &= ~SymUniq; - for(d=0; dfield->sym, t, d, &f, 0); - if(c == 0) - continue; - if(c == 1) { - // addot1 may have dug out arbitrary fields, we only want methods. - if(f->type->etype == TFUNC && f->type->thistuple > 0) { - sl->good = 1; - sl->field = f; - } - } - break; - } - } - - for(f=t->method; f != nil; f=f->down) - f->sym->flags &= ~SymUniq; - - t->xmethod = t->method; - for(sl=slist; sl!=nil; sl=sl->link) { - if(sl->good) { - // add it to the base type method list - f = typ(TFIELD); - *f = *sl->field; - f->embedded = 1; // needs a trampoline - if(sl->followptr) - f->embedded = 2; - f->down = t->xmethod; - t->xmethod = f; - } - } -} - -/* - * Given funarg struct list, return list of ODCLFIELD Node fn args. - */ -static NodeList* -structargs(Type **tl, int mustname) -{ - Iter savet; - Node *a, *n; - NodeList *args; - Type *t; - char buf[100]; - int gen; - - args = nil; - gen = 0; - for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) { - n = N; - if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) { - // invent a name so that we can refer to it in the trampoline - snprint(buf, sizeof buf, ".anon%d", gen++); - n = newname(lookup(buf)); - } else if(t->sym) - n = newname(t->sym); - a = nod(ODCLFIELD, n, typenod(t->type)); - a->isddd = t->isddd; - if(n != N) - n->isddd = t->isddd; - args = list(args, a); - } - return args; -} - -/* - * Generate a wrapper function to convert from - * a receiver of type T to a receiver of type U. - * That is, - * - * func (t T) M() { - * ... - * } - * - * already exists; this function generates - * - * func (u U) M() { - * u.M() - * } - * - * where the types T and U are such that u.M() is valid - * and calls the T.M method. - * The resulting function is for use in method tables. - * - * rcvr - U - * method - M func (t T)(), a TFIELD type struct - * newnam - the eventual mangled name of this function - */ -void -genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface) -{ - Node *this, *fn, *call, *n, *t, *pad, *dot, *as; - NodeList *l, *args, *in, *out; - Type *tpad, *methodrcvr; - int isddd; - Val v; - static int linehistdone = 0; - - if(0 && debug['r']) - print("genwrapper rcvrtype=%T method=%T newnam=%S\n", - rcvr, method, newnam); - - lexlineno++; - lineno = lexlineno; - if (linehistdone == 0) { - // All the wrappers can share the same linehist entry. - linehist("", 0, 0); - linehistdone = 1; - } - - dclcontext = PEXTERN; - markdcl(); - - this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr)); - this->left->ntype = this->right; - in = structargs(getinarg(method->type), 1); - out = structargs(getoutarg(method->type), 0); - - t = nod(OTFUNC, N, N); - l = list1(this); - if(iface && rcvr->width < types[tptr]->width) { - // Building method for interface table and receiver - // is smaller than the single pointer-sized word - // that the interface call will pass in. - // Add a dummy padding argument after the - // receiver to make up the difference. - tpad = typ(TARRAY); - tpad->type = types[TUINT8]; - tpad->bound = types[tptr]->width - rcvr->width; - pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad)); - l = list(l, pad); - } - t->list = concat(l, in); - t->rlist = out; - - fn = nod(ODCLFUNC, N, N); - fn->nname = newname(newnam); - fn->nname->defn = fn; - fn->nname->ntype = t; - declare(fn->nname, PFUNC); - funchdr(fn); - - // arg list - args = nil; - isddd = 0; - for(l=in; l; l=l->next) { - args = list(args, l->n->left); - isddd = l->n->left->isddd; - } - - methodrcvr = getthisx(method->type)->type->type; - - // generate nil pointer check for better error - if(isptr[rcvr->etype] && rcvr->type == methodrcvr) { - // generating wrapper from *T to T. - n = nod(OIF, N, N); - n->ntest = nod(OEQ, this->left, nodnil()); - // these strings are already in the reflect tables, - // so no space cost to use them here. - l = nil; - v.ctype = CTSTR; - v.u.sval = newstrlit(rcvr->type->sym->pkg->name); // package name - l = list(l, nodlit(v)); - v.u.sval = newstrlit(rcvr->type->sym->name); // type name - l = list(l, nodlit(v)); - v.u.sval = newstrlit(method->sym->name); - l = list(l, nodlit(v)); // method name - call = nod(OCALL, syslook("panicwrap", 0), N); - call->list = l; - n->nbody = list1(call); - fn->nbody = list(fn->nbody, n); - } - - dot = adddot(nod(OXDOT, this->left, newname(method->sym))); - - // generate call - if(!flag_race && isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !isifacemethod(method->type)) { - // generate tail call: adjust pointer receiver and jump to embedded method. - dot = dot->left; // skip final .M - if(!isptr[dotlist[0].field->type->etype]) - dot = nod(OADDR, dot, N); - as = nod(OAS, this->left, nod(OCONVNOP, dot, N)); - as->right->type = rcvr; - fn->nbody = list(fn->nbody, as); - n = nod(ORETJMP, N, N); - n->left = newname(methodsym(method->sym, methodrcvr, 0)); - fn->nbody = list(fn->nbody, n); - } else { - fn->wrapper = 1; // ignore frame for panic+recover matching - call = nod(OCALL, dot, N); - call->list = args; - call->isddd = isddd; - if(method->type->outtuple > 0) { - n = nod(ORETURN, N, N); - n->list = list1(call); - call = n; - } - fn->nbody = list(fn->nbody, call); - } - - if(0 && debug['r']) - dumplist("genwrapper body", fn->nbody); - - funcbody(fn); - curfn = fn; - // wrappers where T is anonymous (struct or interface) can be duplicated. - if(rcvr->etype == TSTRUCT || - rcvr->etype == TINTER || - isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT) - fn->dupok = 1; - typecheck(&fn, Etop); - typechecklist(fn->nbody, Etop); - - // Set inl_nonlocal to whether we are calling a method on a - // type defined in a different package. Checked in inlvar. - if(!methodrcvr->local) - inl_nonlocal = 1; - - inlcalls(fn); - - inl_nonlocal = 0; - - curfn = nil; - funccompile(fn); -} - -static Node* -hashmem(Type *t) -{ - Node *tfn, *n; - Sym *sym; - - sym = pkglookup("memhash", runtimepkg); - - n = newname(sym); - n->class = PFUNC; - tfn = nod(OTFUNC, N, N); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - typecheck(&tfn, Etype); - n->type = tfn->type; - return n; -} - -static Node* -hashfor(Type *t) -{ - int a; - Sym *sym; - Node *tfn, *n; - - a = algtype1(t, nil); - switch(a) { - case AMEM: - fatal("hashfor with AMEM type"); - case AINTER: - sym = pkglookup("interhash", runtimepkg); - break; - case ANILINTER: - sym = pkglookup("nilinterhash", runtimepkg); - break; - case ASTRING: - sym = pkglookup("strhash", runtimepkg); - break; - case AFLOAT32: - sym = pkglookup("f32hash", runtimepkg); - break; - case AFLOAT64: - sym = pkglookup("f64hash", runtimepkg); - break; - case ACPLX64: - sym = pkglookup("c64hash", runtimepkg); - break; - case ACPLX128: - sym = pkglookup("c128hash", runtimepkg); - break; - default: - sym = typesymprefix(".hash", t); - break; - } - - n = newname(sym); - n->class = PFUNC; - tfn = nod(OTFUNC, N, N); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); - tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR]))); - typecheck(&tfn, Etype); - n->type = tfn->type; - return n; -} - -/* - * Generate a helper function to compute the hash of a value of type t. - */ -void -genhash(Sym *sym, Type *t) -{ - Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r; - Node *hashel; - Type *first, *t1; - int old_safemode; - int64 size, mul, offend; - - if(debug['r']) - print("genhash %S %T\n", sym, t); - - lineno = 1; // less confusing than end of input - dclcontext = PEXTERN; - markdcl(); - - // func sym(p *T, h uintptr) uintptr - fn = nod(ODCLFUNC, N, N); - fn->nname = newname(sym); - fn->nname->class = PFUNC; - tfn = nod(OTFUNC, N, N); - fn->nname->ntype = tfn; - - n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); - tfn->list = list(tfn->list, n); - np = n->left; - n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR])); - tfn->list = list(tfn->list, n); - nh = n->left; - n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value - tfn->rlist = list(tfn->rlist, n); - - funchdr(fn); - typecheck(&fn->nname->ntype, Etype); - - // genhash is only called for types that have equality but - // cannot be handled by the standard algorithms, - // so t must be either an array or a struct. - switch(t->etype) { - default: - fatal("genhash %T", t); - case TARRAY: - if(isslice(t)) - fatal("genhash %T", t); - // An array of pure memory would be handled by the - // standard algorithm, so the element type must not be - // pure memory. - hashel = hashfor(t->type); - n = nod(ORANGE, N, nod(OIND, np, N)); - ni = newname(lookup("i")); - ni->type = types[TINT]; - n->list = list1(ni); - n->colas = 1; - colasdefn(n->list, n); - ni = n->list->n; - - // TODO: with aeshash we don't need these shift/mul parts - - // h = h<<3 | h>>61 - n->nbody = list(n->nbody, - nod(OAS, - nh, - nod(OOR, - nod(OLSH, nh, nodintconst(3)), - nod(ORSH, nh, nodintconst(widthptr*8-3))))); - - // h *= mul - // Same multipliers as in runtime.memhash. - if(widthptr == 4) - mul = 3267000013LL; - else - mul = 23344194077549503LL; - n->nbody = list(n->nbody, - nod(OAS, - nh, - nod(OMUL, nh, nodintconst(mul)))); - - // h = hashel(&p[i], h) - call = nod(OCALL, hashel, N); - nx = nod(OINDEX, np, ni); - nx->bounded = 1; - na = nod(OADDR, nx, N); - na->etype = 1; // no escape to heap - call->list = list(call->list, na); - call->list = list(call->list, nh); - n->nbody = list(n->nbody, nod(OAS, nh, call)); - - fn->nbody = list(fn->nbody, n); - break; - - case TSTRUCT: - // Walk the struct using memhash for runs of AMEM - // and calling specific hash functions for the others. - first = T; - offend = 0; - for(t1=t->type;; t1=t1->down) { - if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) { - offend = t1->width + t1->type->width; - if(first == T) - first = t1; - // If it's a memory field but it's padded, stop here. - if(ispaddedfield(t1, t->width)) - t1 = t1->down; - else - continue; - } - // Run memhash for fields up to this one. - if(first != T) { - size = offend - first->width; // first->width is offset - hashel = hashmem(first->type); - // h = hashel(&p.first, size, h) - call = nod(OCALL, hashel, N); - nx = nod(OXDOT, np, newname(first->sym)); // TODO: fields from other packages? - na = nod(OADDR, nx, N); - na->etype = 1; // no escape to heap - call->list = list(call->list, na); - call->list = list(call->list, nh); - call->list = list(call->list, nodintconst(size)); - fn->nbody = list(fn->nbody, nod(OAS, nh, call)); - - first = T; - } - if(t1 == T) - break; - if(isblanksym(t1->sym)) - continue; - - // Run hash for this field. - if(algtype1(t1->type, nil) == AMEM) { - hashel = hashmem(t1->type); - // h = memhash(&p.t1, h, size) - call = nod(OCALL, hashel, N); - nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages? - na = nod(OADDR, nx, N); - na->etype = 1; // no escape to heap - call->list = list(call->list, na); - call->list = list(call->list, nh); - call->list = list(call->list, nodintconst(t1->type->width)); - fn->nbody = list(fn->nbody, nod(OAS, nh, call)); - } else { - hashel = hashfor(t1->type); - // h = hashel(&p.t1, h) - call = nod(OCALL, hashel, N); - nx = nod(OXDOT, np, newname(t1->sym)); // TODO: fields from other packages? - na = nod(OADDR, nx, N); - na->etype = 1; // no escape to heap - call->list = list(call->list, na); - call->list = list(call->list, nh); - fn->nbody = list(fn->nbody, nod(OAS, nh, call)); - } - } - break; - } - r = nod(ORETURN, N, N); - r->list = list(r->list, nh); - fn->nbody = list(fn->nbody, r); - - if(debug['r']) - dumplist("genhash body", fn->nbody); - - funcbody(fn); - curfn = fn; - fn->dupok = 1; - typecheck(&fn, Etop); - typechecklist(fn->nbody, Etop); - curfn = nil; - - // Disable safemode while compiling this code: the code we - // generate internally can refer to unsafe.Pointer. - // In this case it can happen if we need to generate an == - // for a struct containing a reflect.Value, which itself has - // an unexported field of type unsafe.Pointer. - old_safemode = safemode; - safemode = 0; - funccompile(fn); - safemode = old_safemode; -} - -// Return node for -// if p.field != q.field { return false } -static Node* -eqfield(Node *p, Node *q, Node *field) -{ - Node *nif, *nx, *ny, *r; - - nx = nod(OXDOT, p, field); - ny = nod(OXDOT, q, field); - nif = nod(OIF, N, N); - nif->ntest = nod(ONE, nx, ny); - r = nod(ORETURN, N, N); - r->list = list(r->list, nodbool(0)); - nif->nbody = list(nif->nbody, r); - return nif; -} - -static Node* -eqmemfunc(vlong size, Type *type, int *needsize) -{ - char buf[30]; - Node *fn; - - switch(size) { - default: - fn = syslook("memequal", 1); - *needsize = 1; - break; - case 1: - case 2: - case 4: - case 8: - case 16: - snprint(buf, sizeof buf, "memequal%d", (int)size*8); - fn = syslook(buf, 1); - *needsize = 0; - break; - } - argtype(fn, type); - argtype(fn, type); - return fn; -} - -// Return node for -// if !memequal(&p.field, &q.field [, size]) { return false } -static Node* -eqmem(Node *p, Node *q, Node *field, vlong size) -{ - Node *nif, *nx, *ny, *call, *r; - int needsize; - - nx = nod(OADDR, nod(OXDOT, p, field), N); - nx->etype = 1; // does not escape - ny = nod(OADDR, nod(OXDOT, q, field), N); - ny->etype = 1; // does not escape - typecheck(&nx, Erv); - typecheck(&ny, Erv); - - call = nod(OCALL, eqmemfunc(size, nx->type->type, &needsize), N); - call->list = list(call->list, nx); - call->list = list(call->list, ny); - if(needsize) - call->list = list(call->list, nodintconst(size)); - - nif = nod(OIF, N, N); - nif->ninit = list(nif->ninit, call); - nif->ntest = nod(ONOT, call, N); - r = nod(ORETURN, N, N); - r->list = list(r->list, nodbool(0)); - nif->nbody = list(nif->nbody, r); - return nif; -} - -/* - * Generate a helper function to check equality of two values of type t. - */ -void -geneq(Sym *sym, Type *t) -{ - Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r; - Type *t1, *first; - int old_safemode; - int64 size; - int64 offend; - - if(debug['r']) - print("geneq %S %T\n", sym, t); - - lineno = 1; // less confusing than end of input - dclcontext = PEXTERN; - markdcl(); - - // func sym(p, q *T) bool - fn = nod(ODCLFUNC, N, N); - fn->nname = newname(sym); - fn->nname->class = PFUNC; - tfn = nod(OTFUNC, N, N); - fn->nname->ntype = tfn; - - n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t))); - tfn->list = list(tfn->list, n); - np = n->left; - n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t))); - tfn->list = list(tfn->list, n); - nq = n->left; - n = nod(ODCLFIELD, N, typenod(types[TBOOL])); - tfn->rlist = list(tfn->rlist, n); - - funchdr(fn); - - // geneq is only called for types that have equality but - // cannot be handled by the standard algorithms, - // so t must be either an array or a struct. - switch(t->etype) { - default: - fatal("geneq %T", t); - case TARRAY: - if(isslice(t)) - fatal("geneq %T", t); - // An array of pure memory would be handled by the - // standard memequal, so the element type must not be - // pure memory. Even if we unrolled the range loop, - // each iteration would be a function call, so don't bother - // unrolling. - nrange = nod(ORANGE, N, nod(OIND, np, N)); - ni = newname(lookup("i")); - ni->type = types[TINT]; - nrange->list = list1(ni); - nrange->colas = 1; - colasdefn(nrange->list, nrange); - ni = nrange->list->n; - - // if p[i] != q[i] { return false } - nx = nod(OINDEX, np, ni); - nx->bounded = 1; - ny = nod(OINDEX, nq, ni); - ny->bounded = 1; - - nif = nod(OIF, N, N); - nif->ntest = nod(ONE, nx, ny); - r = nod(ORETURN, N, N); - r->list = list(r->list, nodbool(0)); - nif->nbody = list(nif->nbody, r); - nrange->nbody = list(nrange->nbody, nif); - fn->nbody = list(fn->nbody, nrange); - break; - - case TSTRUCT: - // Walk the struct using memequal for runs of AMEM - // and calling specific equality tests for the others. - // Skip blank-named fields. - first = T; - offend = 0; - for(t1=t->type;; t1=t1->down) { - if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) { - offend = t1->width + t1->type->width; - if(first == T) - first = t1; - // If it's a memory field but it's padded, stop here. - if(ispaddedfield(t1, t->width)) - t1 = t1->down; - else - continue; - } - // Run memequal for fields up to this one. - // TODO(rsc): All the calls to newname are wrong for - // cross-package unexported fields. - if(first != T) { - if(first->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); - } else if(first->down->down == t1) { - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); - first = first->down; - if(!isblanksym(first->sym)) - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym))); - } else { - // More than two fields: use memequal. - size = offend - first->width; // first->width is offset - fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size)); - } - first = T; - } - if(t1 == T) - break; - if(isblanksym(t1->sym)) - continue; - - // Check this field, which is not just memory. - fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym))); - } - - break; - } - - // return true - r = nod(ORETURN, N, N); - r->list = list(r->list, nodbool(1)); - fn->nbody = list(fn->nbody, r); - - if(debug['r']) - dumplist("geneq body", fn->nbody); - - funcbody(fn); - curfn = fn; - fn->dupok = 1; - typecheck(&fn, Etop); - typechecklist(fn->nbody, Etop); - curfn = nil; - - // Disable safemode while compiling this code: the code we - // generate internally can refer to unsafe.Pointer. - // In this case it can happen if we need to generate an == - // for a struct containing a reflect.Value, which itself has - // an unexported field of type unsafe.Pointer. - old_safemode = safemode; - safemode = 0; - funccompile(fn); - safemode = old_safemode; -} - -static Type* -ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase) -{ - int i, c, d; - Type *m; - - *followptr = 0; - - if(t == T) - return T; - - for(d=0; d 1) { - yyerror("%T.%S is ambiguous", t, s); - return T; - } - if(c == 1) { - for(i=0; itype->etype]) { - *followptr = 1; - break; - } - } - if(m->type->etype != TFUNC || m->type->thistuple == 0) { - yyerror("%T.%S is a field, not a method", t, s); - return T; - } - return m; - } - } - return T; -} - -int -implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr) -{ - Type *t0, *im, *tm, *rcvr, *imtype; - int followptr; - - t0 = t; - if(t == T) - return 0; - - // if this is too slow, - // could sort these first - // and then do one loop. - - if(t->etype == TINTER) { - for(im=iface->type; im; im=im->down) { - for(tm=t->type; tm; tm=tm->down) { - if(tm->sym == im->sym) { - if(eqtype(tm->type, im->type)) - goto found; - *m = im; - *samename = tm; - *ptr = 0; - return 0; - } - } - *m = im; - *samename = nil; - *ptr = 0; - return 0; - found:; - } - return 1; - } - - t = methtype(t, 0); - if(t != T) - expandmeth(t); - for(im=iface->type; im; im=im->down) { - imtype = methodfunc(im->type, 0); - tm = ifacelookdot(im->sym, t, &followptr, 0); - if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) { - if(tm == T) - tm = ifacelookdot(im->sym, t, &followptr, 1); - *m = im; - *samename = tm; - *ptr = 0; - return 0; - } - // if pointer receiver in method, - // the method does not exist for value types. - rcvr = getthisx(tm->type)->type->type; - if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) { - if(0 && debug['r']) - yyerror("interface pointer mismatch"); - - *m = im; - *samename = nil; - *ptr = 1; - return 0; - } - } - return 1; -} - -/* - * even simpler simtype; get rid of ptr, bool. - * assuming that the front end has rejected - * all the invalid conversions (like ptr -> bool) - */ -int -simsimtype(Type *t) -{ - int et; - - if(t == 0) - return 0; - - et = simtype[t->etype]; - switch(et) { - case TPTR32: - et = TUINT32; - break; - case TPTR64: - et = TUINT64; - break; - case TBOOL: - et = TUINT8; - break; - } - return et; -} - -NodeList* -concat(NodeList *a, NodeList *b) -{ - if(a == nil) - return b; - if(b == nil) - return a; - - a->end->next = b; - a->end = b->end; - b->end = nil; - return a; -} - -NodeList* -list1(Node *n) -{ - NodeList *l; - - if(n == nil) - return nil; - if(n->op == OBLOCK && n->ninit == nil) { - // Flatten list and steal storage. - // Poison pointer to catch errant uses. - l = n->list; - n->list = (NodeList*)1; - return l; - } - l = mal(sizeof *l); - l->n = n; - l->end = l; - return l; -} - -NodeList* -list(NodeList *l, Node *n) -{ - return concat(l, list1(n)); -} - -void -listsort(NodeList** l, int(*f)(Node*, Node*)) -{ - NodeList *l1, *l2, *le; - - if(*l == nil || (*l)->next == nil) - return; - - l1 = *l; - l2 = *l; - for(;;) { - l2 = l2->next; - if(l2 == nil) - break; - l2 = l2->next; - if(l2 == nil) - break; - l1 = l1->next; - } - - l2 = l1->next; - l1->next = nil; - l2->end = (*l)->end; - (*l)->end = l1; - - l1 = *l; - listsort(&l1, f); - listsort(&l2, f); - - if((*f)(l1->n, l2->n) < 0) { - *l = l1; - } else { - *l = l2; - l2 = l1; - l1 = *l; - } - - // now l1 == *l; and l1 < l2 - - while ((l1 != nil) && (l2 != nil)) { - while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0) - l1 = l1->next; - - // l1 is last one from l1 that is < l2 - le = l1->next; // le is the rest of l1, first one that is >= l2 - if(le != nil) - le->end = (*l)->end; - - (*l)->end = l1; // cut *l at l1 - *l = concat(*l, l2); // glue l2 to *l's tail - - l1 = l2; // l1 is the first element of *l that is < the new l2 - l2 = le; // ... because l2 now is the old tail of l1 - } - - *l = concat(*l, l2); // any remainder -} - -NodeList* -listtreecopy(NodeList *l) -{ - NodeList *out; - - out = nil; - for(; l; l=l->next) - out = list(out, treecopy(l->n)); - return out; -} - -Node* -liststmt(NodeList *l) -{ - Node *n; - - n = nod(OBLOCK, N, N); - n->list = l; - if(l) - n->lineno = l->n->lineno; - return n; -} - -/* - * return nelem of list - */ -int -count(NodeList *l) -{ - vlong n; - - n = 0; - for(; l; l=l->next) - n++; - if((int)n != n) { // Overflow. - yyerror("too many elements in list"); - } - return n; -} - -/* - * return nelem of list - */ -int -structcount(Type *t) -{ - int v; - Iter s; - - v = 0; - for(t = structfirst(&s, &t); t != T; t = structnext(&s)) - v++; - return v; -} - -/* - * return power of 2 of the constant - * operand. -1 if it is not a power of 2. - * 1000+ if it is a -(power of 2) - */ -int -powtwo(Node *n) -{ - uvlong v, b; - int i; - - if(n == N || n->op != OLITERAL || n->type == T) - goto no; - if(!isint[n->type->etype]) - goto no; - - v = mpgetfix(n->val.u.xval); - b = 1ULL; - for(i=0; i<64; i++) { - if(b == v) - return i; - b = b<<1; - } - - if(!issigned[n->type->etype]) - goto no; - - v = -v; - b = 1ULL; - for(i=0; i<64; i++) { - if(b == v) - return i+1000; - b = b<<1; - } - -no: - return -1; -} - -/* - * return the unsigned type for - * a signed integer type. - * returns T if input is not a - * signed integer type. - */ -Type* -tounsigned(Type *t) -{ - - // this is types[et+1], but not sure - // that this relation is immutable - switch(t->etype) { - default: - print("tounsigned: unknown type %T\n", t); - t = T; - break; - case TINT: - t = types[TUINT]; - break; - case TINT8: - t = types[TUINT8]; - break; - case TINT16: - t = types[TUINT16]; - break; - case TINT32: - t = types[TUINT32]; - break; - case TINT64: - t = types[TUINT64]; - break; - } - return t; -} - -/* - * magic number for signed division - * see hacker's delight chapter 10 - */ -void -smagic(Magic *m) -{ - int p; - uint64 ad, anc, delta, q1, r1, q2, r2, t; - uint64 mask, two31; - - m->bad = 0; - switch(m->w) { - default: - m->bad = 1; - return; - case 8: - mask = 0xffLL; - break; - case 16: - mask = 0xffffLL; - break; - case 32: - mask = 0xffffffffLL; - break; - case 64: - mask = 0xffffffffffffffffULL; - break; - } - two31 = mask ^ (mask>>1); - - p = m->w-1; - ad = m->sd; - if(m->sd < 0) - ad = -(uvlong)m->sd; - - // bad denominators - if(ad == 0 || ad == 1 || ad == two31) { - m->bad = 1; - return; - } - - t = two31; - ad &= mask; - - anc = t - 1 - t%ad; - anc &= mask; - - q1 = two31/anc; - r1 = two31 - q1*anc; - q1 &= mask; - r1 &= mask; - - q2 = two31/ad; - r2 = two31 - q2*ad; - q2 &= mask; - r2 &= mask; - - for(;;) { - p++; - q1 <<= 1; - r1 <<= 1; - q1 &= mask; - r1 &= mask; - if(r1 >= anc) { - q1++; - r1 -= anc; - q1 &= mask; - r1 &= mask; - } - - q2 <<= 1; - r2 <<= 1; - q2 &= mask; - r2 &= mask; - if(r2 >= ad) { - q2++; - r2 -= ad; - q2 &= mask; - r2 &= mask; - } - - delta = ad - r2; - delta &= mask; - if(q1 < delta || (q1 == delta && r1 == 0)) { - continue; - } - break; - } - - m->sm = q2+1; - if(m->sm & two31) - m->sm |= ~mask; - m->s = p-m->w; -} - -/* - * magic number for unsigned division - * see hacker's delight chapter 10 - */ -void -umagic(Magic *m) -{ - int p; - uint64 nc, delta, q1, r1, q2, r2; - uint64 mask, two31; - - m->bad = 0; - m->ua = 0; - - switch(m->w) { - default: - m->bad = 1; - return; - case 8: - mask = 0xffLL; - break; - case 16: - mask = 0xffffLL; - break; - case 32: - mask = 0xffffffffLL; - break; - case 64: - mask = 0xffffffffffffffffULL; - break; - } - two31 = mask ^ (mask>>1); - - m->ud &= mask; - if(m->ud == 0 || m->ud == two31) { - m->bad = 1; - return; - } - nc = mask - (-m->ud&mask)%m->ud; - p = m->w-1; - - q1 = two31/nc; - r1 = two31 - q1*nc; - q1 &= mask; - r1 &= mask; - - q2 = (two31-1) / m->ud; - r2 = (two31-1) - q2*m->ud; - q2 &= mask; - r2 &= mask; - - for(;;) { - p++; - if(r1 >= nc-r1) { - q1 <<= 1; - q1++; - r1 <<= 1; - r1 -= nc; - } else { - q1 <<= 1; - r1 <<= 1; - } - q1 &= mask; - r1 &= mask; - if(r2+1 >= m->ud-r2) { - if(q2 >= two31-1) { - m->ua = 1; - } - q2 <<= 1; - q2++; - r2 <<= 1; - r2++; - r2 -= m->ud; - } else { - if(q2 >= two31) { - m->ua = 1; - } - q2 <<= 1; - r2 <<= 1; - r2++; - } - q2 &= mask; - r2 &= mask; - - delta = m->ud - 1 - r2; - delta &= mask; - - if(p < m->w+m->w) - if(q1 < delta || (q1 == delta && r1 == 0)) { - continue; - } - break; - } - m->um = q2+1; - m->s = p-m->w; -} - -Sym* -ngotype(Node *n) -{ - if(n->type != T) - return typenamesym(n->type); - return S; -} - -/* - * Convert raw string to the prefix that will be used in the symbol - * table. All control characters, space, '%' and '"', as well as - * non-7-bit clean bytes turn into %xx. The period needs escaping - * only in the last segment of the path, and it makes for happier - * users if we escape that as little as possible. - * - * If you edit this, edit ../ld/lib.c:/^pathtoprefix too. - * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too. - */ -static char* -pathtoprefix(char *s) -{ - static char hex[] = "0123456789abcdef"; - char *p, *r, *w, *l; - int n; - - // find first character past the last slash, if any. - l = s; - for(r=s; *r; r++) - if(*r == '/') - l = r+1; - - // check for chars that need escaping - n = 0; - for(r=s; *r; r++) - if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) - n++; - - // quick exit - if(n == 0) - return s; - - // escape - p = mal((r-s)+1+2*n); - for(r=s, w=p; *r; r++) { - if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) { - *w++ = '%'; - *w++ = hex[(*r>>4)&0xF]; - *w++ = hex[*r&0xF]; - } else - *w++ = *r; - } - *w = '\0'; - return p; -} - -Pkg* -mkpkg(Strlit *path) -{ - Pkg *p; - int h; - - h = stringhash(path->s) & (nelem(phash)-1); - for(p=phash[h]; p; p=p->link) - if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0) - return p; - - p = mal(sizeof *p); - p->path = path; - p->prefix = pathtoprefix(path->s); - p->link = phash[h]; - phash[h] = p; - return p; -} - -Strlit* -newstrlit(char *s) -{ - Strlit *t; - - t = mal(sizeof *t + strlen(s)); - strcpy(t->s, s); - t->len = strlen(s); - return t; -} - -void -addinit(Node **np, NodeList *init) -{ - Node *n; - - if(init == nil) - return; - - n = *np; - switch(n->op) { - case ONAME: - case OLITERAL: - // There may be multiple refs to this node; - // introduce OCONVNOP to hold init list. - n = nod(OCONVNOP, n, N); - n->type = n->left->type; - n->typecheck = 1; - *np = n; - break; - } - n->ninit = concat(init, n->ninit); - n->ullman = UINF; -} - -static char* reservedimports[] = { - "go", - "type", -}; - -int -isbadimport(Strlit *path) -{ - int i; - char *s; - Rune r; - - if(strlen(path->s) != path->len) { - yyerror("import path contains NUL"); - return 1; - } - - for(i=0; is, reservedimports[i]) == 0) { - yyerror("import path \"%s\" is reserved and cannot be used", path->s); - return 1; - } - } - - s = path->s; - while(*s) { - s += chartorune(&r, s); - if(r == Runeerror) { - yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path); - return 1; - } - if(r < 0x20 || r == 0x7f) { - yyerror("import path contains control character: \"%Z\"", path); - return 1; - } - if(r == '\\') { - yyerror("import path contains backslash; use slash: \"%Z\"", path); - return 1; - } - if(isspacerune(r)) { - yyerror("import path contains space character: \"%Z\"", path); - return 1; - } - if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) { - yyerror("import path contains invalid character '%C': \"%Z\"", r, path); - return 1; - } - } - return 0; -} - -void -checknil(Node *x, NodeList **init) -{ - Node *n; - - if(isinter(x->type)) { - x = nod(OITAB, x, N); - typecheck(&x, Erv); - } - n = nod(OCHECKNIL, x, N); - n->typecheck = 1; - *init = list(*init, n); -} - -/* - * Can this type be stored directly in an interface word? - * Yes, if the representation is a single pointer. - */ -int -isdirectiface(Type *t) -{ - switch(t->etype) { - case TPTR32: - case TPTR64: - case TCHAN: - case TMAP: - case TFUNC: - case TUNSAFEPTR: - return 1; - case TARRAY: - // Array of 1 direct iface type can be direct. - return t->bound == 1 && isdirectiface(t->type); - case TSTRUCT: - // Struct with 1 field of direct iface type can be direct. - return t->type != T && t->type->down == T && isdirectiface(t->type->type); - } - return 0; -} diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c deleted file mode 100644 index 0dc0065ed9..0000000000 --- a/src/cmd/gc/swt.c +++ /dev/null @@ -1,944 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -enum -{ - Snorm = 0, - Strue, - Sfalse, - Stype, - - Tdefault, // default case - Texprconst, // normal constant case - Texprvar, // normal variable case - Ttypenil, // case nil - Ttypeconst, // type hashes - Ttypevar, // interface type - - Ncase = 4, // count needed to split -}; - -typedef struct Case Case; -struct Case -{ - Node* node; // points at case statement - uint32 hash; // hash of a type switch - uint8 type; // type of case - uint8 diag; // suppress multiple diagnostics - uint16 ordinal; // position in switch - Case* link; // linked list to link -}; -#define C ((Case*)nil) -/*c2go Case *C; */ - -void -dumpcase(Case *c0) -{ - Case *c; - - for(c=c0; c!=C; c=c->link) { - switch(c->type) { - case Tdefault: - print("case-default\n"); - print(" ord=%d\n", c->ordinal); - break; - case Texprconst: - print("case-exprconst\n"); - print(" ord=%d\n", c->ordinal); - break; - case Texprvar: - print("case-exprvar\n"); - print(" ord=%d\n", c->ordinal); - print(" op=%O\n", c->node->left->op); - break; - case Ttypenil: - print("case-typenil\n"); - print(" ord=%d\n", c->ordinal); - break; - case Ttypeconst: - print("case-typeconst\n"); - print(" ord=%d\n", c->ordinal); - print(" hash=%ux\n", c->hash); - break; - case Ttypevar: - print("case-typevar\n"); - print(" ord=%d\n", c->ordinal); - break; - default: - print("case-???\n"); - print(" ord=%d\n", c->ordinal); - print(" op=%O\n", c->node->left->op); - print(" hash=%ux\n", c->hash); - break; - } - } - print("\n"); -} - -static int -ordlcmp(Case *c1, Case *c2) -{ - // sort default first - if(c1->type == Tdefault) - return -1; - if(c2->type == Tdefault) - return +1; - - // sort nil second - if(c1->type == Ttypenil) - return -1; - if(c2->type == Ttypenil) - return +1; - - // sort by ordinal - if(c1->ordinal > c2->ordinal) - return +1; - if(c1->ordinal < c2->ordinal) - return -1; - return 0; -} - -static int -exprcmp(Case *c1, Case *c2) -{ - int ct, n; - Node *n1, *n2; - - // sort non-constants last - if(c1->type != Texprconst) - return +1; - if(c2->type != Texprconst) - return -1; - - n1 = c1->node->left; - n2 = c2->node->left; - - // sort by type (for switches on interface) - ct = n1->val.ctype; - if(ct != n2->val.ctype) - return ct - n2->val.ctype; - if(!eqtype(n1->type, n2->type)) { - if(n1->type->vargen > n2->type->vargen) - return +1; - else - return -1; - } - - // sort by constant value - n = 0; - switch(ct) { - case CTFLT: - n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval); - break; - case CTINT: - case CTRUNE: - n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval); - break; - case CTSTR: - n = cmpslit(n1, n2); - break; - } - - return n; -} - -static int -typecmp(Case *c1, Case *c2) -{ - - // sort non-constants last - if(c1->type != Ttypeconst) - return +1; - if(c2->type != Ttypeconst) - return -1; - - // sort by hash code - if(c1->hash > c2->hash) - return +1; - if(c1->hash < c2->hash) - return -1; - - // sort by ordinal so duplicate error - // happens on later case. - if(c1->ordinal > c2->ordinal) - return +1; - if(c1->ordinal < c2->ordinal) - return -1; - return 0; -} - -static Case* -csort(Case *l, int(*f)(Case*, Case*)) -{ - Case *l1, *l2, *le; - - if(l == C || l->link == C) - return l; - - l1 = l; - l2 = l; - for(;;) { - l2 = l2->link; - if(l2 == C) - break; - l2 = l2->link; - if(l2 == C) - break; - l1 = l1->link; - } - - l2 = l1->link; - l1->link = C; - l1 = csort(l, f); - l2 = csort(l2, f); - - /* set up lead element */ - if((*f)(l1, l2) < 0) { - l = l1; - l1 = l1->link; - } else { - l = l2; - l2 = l2->link; - } - le = l; - - for(;;) { - if(l1 == C) { - while(l2) { - le->link = l2; - le = l2; - l2 = l2->link; - } - le->link = C; - break; - } - if(l2 == C) { - while(l1) { - le->link = l1; - le = l1; - l1 = l1->link; - } - break; - } - if((*f)(l1, l2) < 0) { - le->link = l1; - le = l1; - l1 = l1->link; - } else { - le->link = l2; - le = l2; - l2 = l2->link; - } - } - le->link = C; - return l; -} - -static Node* -newlabel(void) -{ - static int label; - - label++; - snprint(namebuf, sizeof(namebuf), "%.6d", label); - return newname(lookup(namebuf)); -} - -/* - * build separate list of statements and cases - * make labels between cases and statements - * deal with fallthrough, break, unreachable statements - */ -static void -casebody(Node *sw, Node *typeswvar) -{ - Node *n, *c, *last; - Node *def; - NodeList *cas, *stat, *l, *lc; - Node *go, *br; - int32 lno, needvar; - - if(sw->list == nil) - return; - - lno = setlineno(sw); - - cas = nil; // cases - stat = nil; // statements - def = N; // defaults - br = nod(OBREAK, N, N); - - for(l=sw->list; l; l=l->next) { - n = l->n; - setlineno(n); - if(n->op != OXCASE) - fatal("casebody %O", n->op); - n->op = OCASE; - needvar = count(n->list) != 1 || n->list->n->op == OLITERAL; - - go = nod(OGOTO, newlabel(), N); - if(n->list == nil) { - if(def != N) - yyerror("more than one default case"); - // reuse original default case - n->right = go; - def = n; - } - - if(n->list != nil && n->list->next == nil) { - // one case - reuse OCASE node. - c = n->list->n; - n->left = c; - n->right = go; - n->list = nil; - cas = list(cas, n); - } else { - // expand multi-valued cases - for(lc=n->list; lc; lc=lc->next) { - c = lc->n; - cas = list(cas, nod(OCASE, c, go)); - } - } - - stat = list(stat, nod(OLABEL, go->left, N)); - if(typeswvar && needvar && n->nname != N) { - NodeList *l; - - l = list1(nod(ODCL, n->nname, N)); - l = list(l, nod(OAS, n->nname, typeswvar)); - typechecklist(l, Etop); - stat = concat(stat, l); - } - stat = concat(stat, n->nbody); - - // botch - shouldn't fall thru declaration - last = stat->end->n; - if(last->xoffset == n->xoffset && last->op == OXFALL) { - if(typeswvar) { - setlineno(last); - yyerror("cannot fallthrough in type switch"); - } - if(l->next == nil) { - setlineno(last); - yyerror("cannot fallthrough final case in switch"); - } - last->op = OFALL; - } else - stat = list(stat, br); - } - - stat = list(stat, br); - if(def) - cas = list(cas, def); - - sw->list = cas; - sw->nbody = stat; - lineno = lno; -} - -static Case* -mkcaselist(Node *sw, int arg) -{ - Node *n; - Case *c, *c1, *c2; - NodeList *l; - int ord; - - c = C; - ord = 0; - - for(l=sw->list; l; l=l->next) { - n = l->n; - c1 = mal(sizeof(*c1)); - c1->link = c; - c = c1; - - ord++; - if((uint16)ord != ord) - fatal("too many cases in switch"); - c->ordinal = ord; - c->node = n; - - if(n->left == N) { - c->type = Tdefault; - continue; - } - - switch(arg) { - case Stype: - c->hash = 0; - if(n->left->op == OLITERAL) { - c->type = Ttypenil; - continue; - } - if(istype(n->left->type, TINTER)) { - c->type = Ttypevar; - continue; - } - - c->hash = typehash(n->left->type); - c->type = Ttypeconst; - continue; - - case Snorm: - case Strue: - case Sfalse: - c->type = Texprvar; - c->hash = typehash(n->left->type); - switch(consttype(n->left)) { - case CTFLT: - case CTINT: - case CTRUNE: - case CTSTR: - c->type = Texprconst; - } - continue; - } - } - - if(c == C) - return C; - - // sort by value and diagnose duplicate cases - switch(arg) { - case Stype: - c = csort(c, typecmp); - for(c1=c; c1!=C; c1=c1->link) { - for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) { - if(c1->type == Ttypenil || c1->type == Tdefault) - break; - if(c2->type == Ttypenil || c2->type == Tdefault) - break; - if(!eqtype(c1->node->left->type, c2->node->left->type)) - continue; - yyerrorl(c2->node->lineno, "duplicate case %T in type switch\n\tprevious case at %L", c2->node->left->type, c1->node->lineno); - } - } - break; - case Snorm: - case Strue: - case Sfalse: - c = csort(c, exprcmp); - for(c1=c; c1->link!=C; c1=c1->link) { - if(exprcmp(c1, c1->link) != 0) - continue; - setlineno(c1->link->node); - yyerror("duplicate case %N in switch\n\tprevious case at %L", c1->node->left, c1->node->lineno); - } - break; - } - - // put list back in processing order - c = csort(c, ordlcmp); - return c; -} - -static Node* exprname; - -static Node* -exprbsw(Case *c0, int ncase, int arg) -{ - NodeList *cas; - Node *a, *n; - Case *c; - int i, half, lno; - - cas = nil; - if(ncase < Ncase) { - for(i=0; inode; - lno = setlineno(n); - - if((arg != Strue && arg != Sfalse) || - assignop(n->left->type, exprname->type, nil) == OCONVIFACE || - assignop(exprname->type, n->left->type, nil) == OCONVIFACE) { - a = nod(OIF, N, N); - a->ntest = nod(OEQ, exprname, n->left); // if name == val - typecheck(&a->ntest, Erv); - a->nbody = list1(n->right); // then goto l - } else if(arg == Strue) { - a = nod(OIF, N, N); - a->ntest = n->left; // if val - a->nbody = list1(n->right); // then goto l - } else { // arg == Sfalse - a = nod(OIF, N, N); - a->ntest = nod(ONOT, n->left, N); // if !val - typecheck(&a->ntest, Erv); - a->nbody = list1(n->right); // then goto l - } - - cas = list(cas, a); - c0 = c0->link; - lineno = lno; - } - return liststmt(cas); - } - - // find the middle and recur - c = c0; - half = ncase>>1; - for(i=1; ilink; - a = nod(OIF, N, N); - a->ntest = nod(OLE, exprname, c->node->left); - typecheck(&a->ntest, Erv); - a->nbody = list1(exprbsw(c0, half, arg)); - a->nelse = list1(exprbsw(c->link, ncase-half, arg)); - return a; -} - -/* - * normal (expression) switch. - * rebuild case statements into if .. goto - */ -static void -exprswitch(Node *sw) -{ - Node *def; - NodeList *cas; - Node *a; - Case *c0, *c, *c1; - Type *t; - int arg, ncase; - - casebody(sw, N); - - arg = Snorm; - if(isconst(sw->ntest, CTBOOL)) { - arg = Strue; - if(sw->ntest->val.u.bval == 0) - arg = Sfalse; - } - walkexpr(&sw->ntest, &sw->ninit); - t = sw->type; - if(t == T) - return; - - /* - * convert the switch into OIF statements - */ - exprname = N; - cas = nil; - if(arg == Strue || arg == Sfalse) - exprname = nodbool(arg == Strue); - else if(consttype(sw->ntest) >= 0) - // leave constants to enable dead code elimination (issue 9608) - exprname = sw->ntest; - else { - exprname = temp(sw->ntest->type); - cas = list1(nod(OAS, exprname, sw->ntest)); - typechecklist(cas, Etop); - } - - c0 = mkcaselist(sw, arg); - if(c0 != C && c0->type == Tdefault) { - def = c0->node->right; - c0 = c0->link; - } else { - def = nod(OBREAK, N, N); - } - -loop: - if(c0 == C) { - cas = list(cas, def); - sw->nbody = concat(cas, sw->nbody); - sw->list = nil; - walkstmtlist(sw->nbody); - return; - } - - // deal with the variables one-at-a-time - if(!okforcmp[t->etype] || c0->type != Texprconst) { - a = exprbsw(c0, 1, arg); - cas = list(cas, a); - c0 = c0->link; - goto loop; - } - - // do binary search on run of constants - ncase = 1; - for(c=c0; c->link!=C; c=c->link) { - if(c->link->type != Texprconst) - break; - ncase++; - } - - // break the chain at the count - c1 = c->link; - c->link = C; - - // sort and compile constants - c0 = csort(c0, exprcmp); - a = exprbsw(c0, ncase, arg); - cas = list(cas, a); - - c0 = c1; - goto loop; - -} - -static Node* hashname; -static Node* facename; -static Node* boolname; - -static Node* -typeone(Node *t) -{ - NodeList *init; - Node *a, *b, *var; - - var = t->nname; - init = nil; - if(var == N) { - typecheck(&nblank, Erv | Easgn); - var = nblank; - } else - init = list1(nod(ODCL, var, N)); - - a = nod(OAS2, N, N); - a->list = list(list1(var), boolname); // var,bool = - b = nod(ODOTTYPE, facename, N); - b->type = t->left->type; // interface.(type) - a->rlist = list1(b); - typecheck(&a, Etop); - init = list(init, a); - - b = nod(OIF, N, N); - b->ntest = boolname; - b->nbody = list1(t->right); // if bool { goto l } - a = liststmt(list(init, b)); - return a; -} - -static Node* -typebsw(Case *c0, int ncase) -{ - NodeList *cas; - Node *a, *n; - Case *c; - int i, half; - - cas = nil; - - if(ncase < Ncase) { - for(i=0; inode; - if(c0->type != Ttypeconst) - fatal("typebsw"); - a = nod(OIF, N, N); - a->ntest = nod(OEQ, hashname, nodintconst(c0->hash)); - typecheck(&a->ntest, Erv); - a->nbody = list1(n->right); - cas = list(cas, a); - c0 = c0->link; - } - return liststmt(cas); - } - - // find the middle and recur - c = c0; - half = ncase>>1; - for(i=1; ilink; - a = nod(OIF, N, N); - a->ntest = nod(OLE, hashname, nodintconst(c->hash)); - typecheck(&a->ntest, Erv); - a->nbody = list1(typebsw(c0, half)); - a->nelse = list1(typebsw(c->link, ncase-half)); - return a; -} - -/* - * convert switch of the form - * switch v := i.(type) { case t1: ..; case t2: ..; } - * into if statements - */ -static void -typeswitch(Node *sw) -{ - Node *def; - NodeList *cas, *hash; - Node *a, *n; - Case *c, *c0, *c1; - int ncase; - Type *t; - Val v; - - if(sw->ntest == nil) - return; - if(sw->ntest->right == nil) { - setlineno(sw); - yyerror("type switch must have an assignment"); - return; - } - walkexpr(&sw->ntest->right, &sw->ninit); - if(!istype(sw->ntest->right->type, TINTER)) { - yyerror("type switch must be on an interface"); - return; - } - cas = nil; - - /* - * predeclare temporary variables - * and the boolean var - */ - facename = temp(sw->ntest->right->type); - a = nod(OAS, facename, sw->ntest->right); - typecheck(&a, Etop); - cas = list(cas, a); - - casebody(sw, facename); - - boolname = temp(types[TBOOL]); - typecheck(&boolname, Erv); - - hashname = temp(types[TUINT32]); - typecheck(&hashname, Erv); - - t = sw->ntest->right->type; - if(isnilinter(t)) - a = syslook("efacethash", 1); - else - a = syslook("ifacethash", 1); - argtype(a, t); - a = nod(OCALL, a, N); - a->list = list1(facename); - a = nod(OAS, hashname, a); - typecheck(&a, Etop); - cas = list(cas, a); - - c0 = mkcaselist(sw, Stype); - if(c0 != C && c0->type == Tdefault) { - def = c0->node->right; - c0 = c0->link; - } else { - def = nod(OBREAK, N, N); - } - - /* - * insert if statement into each case block - */ - for(c=c0; c!=C; c=c->link) { - n = c->node; - switch(c->type) { - - case Ttypenil: - v.ctype = CTNIL; - a = nod(OIF, N, N); - a->ntest = nod(OEQ, facename, nodlit(v)); - typecheck(&a->ntest, Erv); - a->nbody = list1(n->right); // if i==nil { goto l } - n->right = a; - break; - - case Ttypevar: - case Ttypeconst: - n->right = typeone(n); - break; - } - } - - /* - * generate list of if statements, binary search for constant sequences - */ - while(c0 != C) { - if(c0->type != Ttypeconst) { - n = c0->node; - cas = list(cas, n->right); - c0=c0->link; - continue; - } - - // identify run of constants - c1 = c = c0; - while(c->link!=C && c->link->type==Ttypeconst) - c = c->link; - c0 = c->link; - c->link = nil; - - // sort by hash - c1 = csort(c1, typecmp); - - // for debugging: linear search - if(0) { - for(c=c1; c!=C; c=c->link) { - n = c->node; - cas = list(cas, n->right); - } - continue; - } - - // combine adjacent cases with the same hash - ncase = 0; - for(c=c1; c!=C; c=c->link) { - ncase++; - hash = list1(c->node->right); - while(c->link != C && c->link->hash == c->hash) { - hash = list(hash, c->link->node->right); - c->link = c->link->link; - } - c->node->right = liststmt(hash); - } - - // binary search among cases to narrow by hash - cas = list(cas, typebsw(c1, ncase)); - } - if(nerrors == 0) { - cas = list(cas, def); - sw->nbody = concat(cas, sw->nbody); - sw->list = nil; - walkstmtlist(sw->nbody); - } -} - -void -walkswitch(Node *sw) -{ - /* - * reorder the body into (OLIST, cases, statements) - * cases have OGOTO into statements. - * both have inserted OBREAK statements - */ - if(sw->ntest == N) { - sw->ntest = nodbool(1); - typecheck(&sw->ntest, Erv); - } - - if(sw->ntest->op == OTYPESW) { - typeswitch(sw); -//dump("sw", sw); - return; - } - exprswitch(sw); - // Discard old AST elements after a walk. They can confuse racewealk. - sw->ntest = nil; - sw->list = nil; -} - -/* - * type check switch statement - */ -void -typecheckswitch(Node *n) -{ - int top, lno, ptr; - char *nilonly; - Type *t, *badtype, *missing, *have; - NodeList *l, *ll; - Node *ncase, *nvar; - Node *def; - - lno = lineno; - typechecklist(n->ninit, Etop); - nilonly = nil; - - if(n->ntest != N && n->ntest->op == OTYPESW) { - // type switch - top = Etype; - typecheck(&n->ntest->right, Erv); - t = n->ntest->right->type; - if(t != T && t->etype != TINTER) - yyerror("cannot type switch on non-interface value %lN", n->ntest->right); - } else { - // value switch - top = Erv; - if(n->ntest) { - typecheck(&n->ntest, Erv); - defaultlit(&n->ntest, T); - t = n->ntest->type; - } else - t = types[TBOOL]; - if(t) { - if(!okforeq[t->etype]) - yyerror("cannot switch on %lN", n->ntest); - else if(t->etype == TARRAY && !isfixedarray(t)) - nilonly = "slice"; - else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ) - yyerror("cannot switch on %lN", n->ntest); - else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ) - yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype); - else if(t->etype == TFUNC) - nilonly = "func"; - else if(t->etype == TMAP) - nilonly = "map"; - } - } - n->type = t; - - def = N; - for(l=n->list; l; l=l->next) { - ncase = l->n; - setlineno(n); - if(ncase->list == nil) { - // default - if(def != N) - yyerror("multiple defaults in switch (first at %L)", def->lineno); - else - def = ncase; - } else { - for(ll=ncase->list; ll; ll=ll->next) { - setlineno(ll->n); - typecheck(&ll->n, Erv | Etype); - if(ll->n->type == T || t == T) - continue; - setlineno(ncase); - switch(top) { - case Erv: // expression switch - defaultlit(&ll->n, t); - if(ll->n->op == OTYPE) - yyerror("type %T is not an expression", ll->n->type); - else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) { - if(n->ntest) - yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t); - else - yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type); - } else if(nilonly && !isconst(ll->n, CTNIL)) { - yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest); - } - break; - case Etype: // type switch - if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) { - ; - } else if(ll->n->op != OTYPE && ll->n->type != T) { // should this be ||? - yyerror("%lN is not a type", ll->n); - // reset to original type - ll->n = n->ntest->right; - } else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) { - if(have && !missing->broke && !have->broke) - yyerror("impossible type switch case: %lN cannot have dynamic type %T" - " (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT", - n->ntest->right, ll->n->type, missing->sym, have->sym, have->type, - missing->sym, missing->type); - else if(!missing->broke) - yyerror("impossible type switch case: %lN cannot have dynamic type %T" - " (missing %S method)", n->ntest->right, ll->n->type, missing->sym); - } - break; - } - } - } - if(top == Etype && n->type != T) { - ll = ncase->list; - nvar = ncase->nname; - if(nvar != N) { - if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) { - // single entry type switch - nvar->ntype = typenod(ll->n->type); - } else { - // multiple entry type switch or default - nvar->ntype = typenod(n->type); - } - typecheck(&nvar, Erv | Easgn); - ncase->nname = nvar; - } - } - typechecklist(ncase->nbody, Etop); - } - - lineno = lno; -} diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c deleted file mode 100644 index 649f1c5120..0000000000 --- a/src/cmd/gc/typecheck.c +++ /dev/null @@ -1,3649 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - * type check the whole tree of an expression. - * calculates expression types. - * evaluates compile time constants. - * marks variables that escape the local frame. - * rewrites n->op to be more specific in some cases. - */ - -#include -#include -#include "go.h" - -static void implicitstar(Node**); -static int onearg(Node*, char*, ...); -static int twoarg(Node*); -static int lookdot(Node*, Type*, int); -static int looktypedot(Node*, Type*, int); -static void typecheckaste(int, Node*, int, Type*, NodeList*, char*); -static Type* lookdot1(Node*, Sym *s, Type *t, Type *f, int); -static int nokeys(NodeList*); -static void typecheckcomplit(Node**); -static void typecheckas2(Node*); -static void typecheckas(Node*); -static void typecheckfunc(Node*); -static void checklvalue(Node*, char*); -static void checkassignlist(Node*, NodeList*); -static void stringtoarraylit(Node**); -static Node* resolve(Node*); -static void checkdefergo(Node*); -static int checkmake(Type*, char*, Node*); -static int checksliceindex(Node*, Node*, Type*); -static int checksliceconst(Node*, Node*); - -static NodeList* typecheckdefstack; - -/* - * resolve ONONAME to definition, if any. - */ -static Node* -resolve(Node *n) -{ - Node *r; - - if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) { - if(r->op != OIOTA) - n = r; - else if(n->iota >= 0) - n = nodintconst(n->iota); - } - return n; -} - -void -typechecklist(NodeList *l, int top) -{ - for(; l; l=l->next) - typecheck(&l->n, top); -} - -static char* _typekind[] = { - [TINT] = "int", - [TUINT] = "uint", - [TINT8] = "int8", - [TUINT8] = "uint8", - [TINT16] = "int16", - [TUINT16] = "uint16", - [TINT32] = "int32", - [TUINT32] = "uint32", - [TINT64] = "int64", - [TUINT64] = "uint64", - [TUINTPTR] = "uintptr", - [TCOMPLEX64] = "complex64", - [TCOMPLEX128] = "complex128", - [TFLOAT32] = "float32", - [TFLOAT64] = "float64", - [TBOOL] = "bool", - [TSTRING] = "string", - [TPTR32] = "pointer", - [TPTR64] = "pointer", - [TUNSAFEPTR] = "unsafe.Pointer", - [TSTRUCT] = "struct", - [TINTER] = "interface", - [TCHAN] = "chan", - [TMAP] = "map", - [TARRAY] = "array", - [TFUNC] = "func", - [TNIL] = "nil", - [TIDEAL] = "untyped number", -}; - -static char* -typekind(Type *t) -{ - int et; - static char buf[50]; - char *s; - - if(isslice(t)) - return "slice"; - et = t->etype; - if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil) - return s; - snprint(buf, sizeof buf, "etype=%d", et); - return buf; -} - -/* - * sprint_depchain prints a dependency chain - * of nodes into fmt. - * It is used by typecheck in the case of OLITERAL nodes - * to print constant definition loops. - */ -static void -sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first) -{ - NodeList *l; - - for(l = stack; l; l=l->next) { - if(l->n->op == cur->op) { - if(l->n != first) - sprint_depchain(fmt, l->next, l->n, first); - fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur); - return; - } - } -} - -/* - * type check node *np. - * replaces *np with a new pointer in some cases. - * returns the final value of *np as a convenience. - */ -static void typecheck1(Node **, int); -Node* -typecheck(Node **np, int top) -{ - Node *n; - int lno; - Fmt fmt; - NodeList *l; - static NodeList *tcstack, *tcfree; - - // cannot type check until all the source has been parsed - if(!typecheckok) - fatal("early typecheck"); - - n = *np; - if(n == N) - return N; - - lno = setlineno(n); - - // Skip over parens. - while(n->op == OPAREN) - n = n->left; - - // Resolve definition of name and value of iota lazily. - n = resolve(n); - - *np = n; - - // Skip typecheck if already done. - // But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed. - if(n->typecheck == 1) { - switch(n->op) { - case ONAME: - case OTYPE: - case OLITERAL: - case OPACK: - break; - default: - lineno = lno; - return n; - } - } - - if(n->typecheck == 2) { - // Typechecking loop. Trying printing a meaningful message, - // otherwise a stack trace of typechecking. - switch(n->op) { - case ONAME: - // We can already diagnose variables used as types. - if((top & (Erv|Etype)) == Etype) - yyerror("%N is not a type", n); - break; - case OLITERAL: - if((top & (Erv|Etype)) == Etype) { - yyerror("%N is not a type", n); - break; - } - fmtstrinit(&fmt); - sprint_depchain(&fmt, tcstack, n, n); - yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt)); - break; - } - if(nsavederrors+nerrors == 0) { - fmtstrinit(&fmt); - for(l=tcstack; l; l=l->next) - fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n); - yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt)); - } - lineno = lno; - return n; - } - n->typecheck = 2; - - if(tcfree != nil) { - l = tcfree; - tcfree = l->next; - } else - l = mal(sizeof *l); - l->next = tcstack; - l->n = n; - tcstack = l; - - typecheck1(&n, top); - *np = n; - n->typecheck = 1; - - if(tcstack != l) - fatal("typecheck stack out of sync"); - tcstack = l->next; - l->next = tcfree; - tcfree = l; - - lineno = lno; - return n; -} - -/* - * does n contain a call or receive operation? - */ -static int callrecvlist(NodeList*); - -static int -callrecv(Node *n) -{ - if(n == nil) - return 0; - - switch(n->op) { - case OCALL: - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - case ORECV: - case OCAP: - case OLEN: - case OCOPY: - case ONEW: - case OAPPEND: - case ODELETE: - return 1; - } - - return callrecv(n->left) || - callrecv(n->right) || - callrecv(n->ntest) || - callrecv(n->nincr) || - callrecvlist(n->ninit) || - callrecvlist(n->nbody) || - callrecvlist(n->nelse) || - callrecvlist(n->list) || - callrecvlist(n->rlist); -} - -static int -callrecvlist(NodeList *l) -{ - for(; l; l=l->next) - if(callrecv(l->n)) - return 1; - return 0; -} - -// indexlit implements typechecking of untyped values as -// array/slice indexes. It is equivalent to defaultlit -// except for constants of numerical kind, which are acceptable -// whenever they can be represented by a value of type int. -static void -indexlit(Node **np) -{ - Node *n; - - n = *np; - if(n == N || !isideal(n->type)) - return; - switch(consttype(n)) { - case CTINT: - case CTRUNE: - case CTFLT: - case CTCPLX: - defaultlit(np, types[TINT]); - break; - } - defaultlit(np, T); -} - -static void -typecheck1(Node **np, int top) -{ - int et, aop, op, ptr; - Node *n, *l, *r, *lo, *mid, *hi; - NodeList *args; - int ok, ntop; - Type *t, *tp, *missing, *have, *badtype; - Val v; - char *why, *desc, descbuf[64]; - vlong x; - - n = *np; - - if(n->sym) { - if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) { - yyerror("use of builtin %S not in function call", n->sym); - goto error; - } - - typecheckdef(n); - if(n->op == ONONAME) - goto error; - } - *np = n; - -reswitch: - ok = 0; - switch(n->op) { - default: - // until typecheck is complete, do nothing. - dump("typecheck", n); - fatal("typecheck %O", n->op); - - /* - * names - */ - case OLITERAL: - ok |= Erv; - if(n->type == T && n->val.ctype == CTSTR) - n->type = idealstring; - goto ret; - - case ONONAME: - ok |= Erv; - goto ret; - - case ONAME: - if(n->decldepth == 0) - n->decldepth = decldepth; - if(n->etype != 0) { - ok |= Ecall; - goto ret; - } - if(!(top & Easgn)) { - // not a write to the variable - if(isblank(n)) { - yyerror("cannot use _ as value"); - goto error; - } - n->used = 1; - } - if(!(top &Ecall) && isunsafebuiltin(n)) { - yyerror("%N is not an expression, must be called", n); - goto error; - } - ok |= Erv; - goto ret; - - case OPACK: - yyerror("use of package %S without selector", n->sym); - goto error; - - case ODDD: - break; - - /* - * types (OIND is with exprs) - */ - case OTYPE: - ok |= Etype; - if(n->type == T) - goto error; - break; - - case OTARRAY: - ok |= Etype; - t = typ(TARRAY); - l = n->left; - r = n->right; - if(l == nil) { - t->bound = -1; // slice - } else if(l->op == ODDD) { - t->bound = -100; // to be filled in - if(!(top&Ecomplit) && !n->diag) { - t->broke = 1; - n->diag = 1; - yyerror("use of [...] array outside of array literal"); - } - } else { - l = typecheck(&n->left, Erv); - switch(consttype(l)) { - case CTINT: - case CTRUNE: - v = l->val; - break; - case CTFLT: - v = toint(l->val); - break; - default: - if(l->type != T && isint[l->type->etype] && l->op != OLITERAL) - yyerror("non-constant array bound %N", l); - else - yyerror("invalid array bound %N", l); - goto error; - } - t->bound = mpgetfix(v.u.xval); - if(doesoverflow(v, types[TINT])) { - yyerror("array bound is too large"); - goto error; - } else if(t->bound < 0) { - yyerror("array bound must be non-negative"); - goto error; - } - } - typecheck(&r, Etype); - if(r->type == T) - goto error; - t->type = r->type; - n->op = OTYPE; - n->type = t; - n->left = N; - n->right = N; - if(t->bound != -100) - checkwidth(t); - break; - - case OTMAP: - ok |= Etype; - l = typecheck(&n->left, Etype); - r = typecheck(&n->right, Etype); - if(l->type == T || r->type == T) - goto error; - n->op = OTYPE; - n->type = maptype(l->type, r->type); - n->left = N; - n->right = N; - break; - - case OTCHAN: - ok |= Etype; - l = typecheck(&n->left, Etype); - if(l->type == T) - goto error; - t = typ(TCHAN); - t->type = l->type; - t->chan = n->etype; - n->op = OTYPE; - n->type = t; - n->left = N; - n->etype = 0; - break; - - case OTSTRUCT: - ok |= Etype; - n->op = OTYPE; - n->type = tostruct(n->list); - if(n->type == T || n->type->broke) - goto error; - n->list = nil; - break; - - case OTINTER: - ok |= Etype; - n->op = OTYPE; - n->type = tointerface(n->list); - if(n->type == T) - goto error; - break; - - case OTFUNC: - ok |= Etype; - n->op = OTYPE; - n->type = functype(n->left, n->list, n->rlist); - if(n->type == T) - goto error; - break; - - /* - * type or expr - */ - case OIND: - ntop = Erv | Etype; - if(!(top & Eaddr)) // The *x in &*x is not an indirect. - ntop |= Eindir; - ntop |= top & Ecomplit; - l = typecheck(&n->left, ntop); - if((t = l->type) == T) - goto error; - if(l->op == OTYPE) { - ok |= Etype; - n->op = OTYPE; - n->type = ptrto(l->type); - n->left = N; - goto ret; - } - if(!isptr[t->etype]) { - if(top & (Erv | Etop)) { - yyerror("invalid indirect of %lN", n->left); - goto error; - } - goto ret; - } - ok |= Erv; - n->type = t->type; - goto ret; - - /* - * arithmetic exprs - */ - case OASOP: - ok |= Etop; - l = typecheck(&n->left, Erv); - r = typecheck(&n->right, Erv); - checkassign(n, n->left); - if(l->type == T || r->type == T) - goto error; - op = n->etype; - goto arith; - - case OADD: - case OAND: - case OANDAND: - case OANDNOT: - case ODIV: - case OEQ: - case OGE: - case OGT: - case OLE: - case OLT: - case OLSH: - case ORSH: - case OMOD: - case OMUL: - case ONE: - case OOR: - case OOROR: - case OSUB: - case OXOR: - ok |= Erv; - l = typecheck(&n->left, Erv | (top & Eiota)); - r = typecheck(&n->right, Erv | (top & Eiota)); - if(l->type == T || r->type == T) - goto error; - op = n->op; - goto arith; - - case OCOM: - case OMINUS: - case ONOT: - case OPLUS: - ok |= Erv; - l = typecheck(&n->left, Erv | (top & Eiota)); - if((t = l->type) == T) - goto error; - if(!okfor[n->op][t->etype]) { - yyerror("invalid operation: %O %T", n->op, t); - goto error; - } - n->type = t; - goto ret; - - /* - * exprs - */ - case OADDR: - ok |= Erv; - typecheck(&n->left, Erv | Eaddr); - if(n->left->type == T) - goto error; - checklvalue(n->left, "take the address of"); - r = outervalue(n->left); - for(l = n->left; l != r; l = l->left) { - l->addrtaken = 1; - if(l->closure) - l->closure->addrtaken = 1; - } - if(l->orig != l && l->op == ONAME) - fatal("found non-orig name node %N", l); - l->addrtaken = 1; - if(l->closure) - l->closure->addrtaken = 1; - defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) - goto error; - n->type = ptrto(t); - goto ret; - - case OCOMPLIT: - ok |= Erv; - typecheckcomplit(&n); - if(n->type == T) - goto error; - goto ret; - - case OXDOT: - n = adddot(n); - n->op = ODOT; - if(n->left == N) - goto error; - // fall through - case ODOT: - typecheck(&n->left, Erv|Etype); - defaultlit(&n->left, T); - if(n->right->op != ONAME) { - yyerror("rhs of . must be a name"); // impossible - goto error; - } - if((t = n->left->type) == T) { - adderrorname(n); - goto error; - } - r = n->right; - - if(n->left->op == OTYPE) { - if(!looktypedot(n, t, 0)) { - if(looktypedot(n, t, 1)) - yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym); - else - yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym); - goto error; - } - if(n->type->etype != TFUNC || n->type->thistuple != 1) { - yyerror("type %T has no method %hS", n->left->type, n->right->sym); - n->type = T; - goto error; - } - n->op = ONAME; - n->sym = n->right->sym; - n->type = methodfunc(n->type, n->left->type); - n->xoffset = 0; - n->class = PFUNC; - ok = Erv; - goto ret; - } - if(isptr[t->etype] && t->type->etype != TINTER) { - t = t->type; - if(t == T) - goto error; - n->op = ODOTPTR; - checkwidth(t); - } - if(isblank(n->right)) { - yyerror("cannot refer to blank field or method"); - goto error; - } - if(!lookdot(n, t, 0)) { - if(lookdot(n, t, 1)) - yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym); - else - yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym); - goto error; - } - switch(n->op) { - case ODOTINTER: - case ODOTMETH: - if(top&Ecall) - ok |= Ecall; - else { - typecheckpartialcall(n, r); - ok |= Erv; - } - break; - default: - ok |= Erv; - break; - } - goto ret; - - case ODOTTYPE: - ok |= Erv; - typecheck(&n->left, Erv); - defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) - goto error; - if(!isinter(t)) { - yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t); - goto error; - } - if(n->right != N) { - typecheck(&n->right, Etype); - n->type = n->right->type; - n->right = N; - if(n->type == T) - goto error; - } - if(n->type != T && n->type->etype != TINTER) - if(!implements(n->type, t, &missing, &have, &ptr)) { - if(have && have->sym == missing->sym) - yyerror("impossible type assertion:\n\t%T does not implement %T (wrong type for %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else if(ptr) - yyerror("impossible type assertion:\n\t%T does not implement %T (%S method has pointer receiver)", - n->type, t, missing->sym); - else if(have) - yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)\n" - "\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym, - have->sym, have->type, missing->sym, missing->type); - else - yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)", - n->type, t, missing->sym); - goto error; - } - goto ret; - - case OINDEX: - ok |= Erv; - typecheck(&n->left, Erv); - defaultlit(&n->left, T); - implicitstar(&n->left); - l = n->left; - typecheck(&n->right, Erv); - r = n->right; - if((t = l->type) == T || r->type == T) - goto error; - switch(t->etype) { - default: - yyerror("invalid operation: %N (type %T does not support indexing)", n, t); - goto error; - - - case TSTRING: - case TARRAY: - indexlit(&n->right); - if(t->etype == TSTRING) - n->type = types[TUINT8]; - else - n->type = t->type; - why = "string"; - if(t->etype == TARRAY) { - if(isfixedarray(t)) - why = "array"; - else - why = "slice"; - } - if(n->right->type != T && !isint[n->right->type->etype]) { - yyerror("non-integer %s index %N", why, n->right); - break; - } - if(isconst(n->right, CTINT)) { - x = mpgetfix(n->right->val.u.xval); - if(x < 0) - yyerror("invalid %s index %N (index must be non-negative)", why, n->right); - else if(isfixedarray(t) && t->bound > 0 && x >= t->bound) - yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound); - else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len) - yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len); - else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0) - yyerror("invalid %s index %N (index too large)", why, n->right); - } - break; - - case TMAP: - n->etype = 0; - defaultlit(&n->right, t->down); - if(n->right->type != T) - n->right = assignconv(n->right, t->down, "map index"); - n->type = t->type; - n->op = OINDEXMAP; - break; - } - goto ret; - - case ORECV: - ok |= Etop | Erv; - typecheck(&n->left, Erv); - defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) - goto error; - if(t->etype != TCHAN) { - yyerror("invalid operation: %N (receive from non-chan type %T)", n, t); - goto error; - } - if(!(t->chan & Crecv)) { - yyerror("invalid operation: %N (receive from send-only type %T)", n, t); - goto error; - } - n->type = t->type; - goto ret; - - case OSEND: - ok |= Etop; - l = typecheck(&n->left, Erv); - typecheck(&n->right, Erv); - defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) - goto error; - if(t->etype != TCHAN) { - yyerror("invalid operation: %N (send to non-chan type %T)", n, t); - goto error; - } - if(!(t->chan & Csend)) { - yyerror("invalid operation: %N (send to receive-only type %T)", n, t); - goto error; - } - defaultlit(&n->right, t->type); - r = n->right; - if(r->type == T) - goto error; - n->right = assignconv(r, l->type->type, "send"); - // TODO: more aggressive - n->etype = 0; - n->type = T; - goto ret; - - case OSLICE: - ok |= Erv; - typecheck(&n->left, top); - typecheck(&n->right->left, Erv); - typecheck(&n->right->right, Erv); - defaultlit(&n->left, T); - indexlit(&n->right->left); - indexlit(&n->right->right); - l = n->left; - if(isfixedarray(l->type)) { - if(!islvalue(n->left)) { - yyerror("invalid operation %N (slice of unaddressable value)", n); - goto error; - } - n->left = nod(OADDR, n->left, N); - n->left->implicit = 1; - typecheck(&n->left, Erv); - l = n->left; - } - if((t = l->type) == T) - goto error; - tp = nil; - if(istype(t, TSTRING)) { - n->type = t; - n->op = OSLICESTR; - } else if(isptr[t->etype] && isfixedarray(t->type)) { - tp = t->type; - n->type = typ(TARRAY); - n->type->type = tp->type; - n->type->bound = -1; - dowidth(n->type); - n->op = OSLICEARR; - } else if(isslice(t)) { - n->type = t; - } else { - yyerror("cannot slice %N (type %T)", l, t); - goto error; - } - if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) - goto error; - if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0) - goto error; - if(checksliceconst(lo, hi) < 0) - goto error; - goto ret; - - case OSLICE3: - ok |= Erv; - typecheck(&n->left, top); - typecheck(&n->right->left, Erv); - typecheck(&n->right->right->left, Erv); - typecheck(&n->right->right->right, Erv); - defaultlit(&n->left, T); - indexlit(&n->right->left); - indexlit(&n->right->right->left); - indexlit(&n->right->right->right); - l = n->left; - if(isfixedarray(l->type)) { - if(!islvalue(n->left)) { - yyerror("invalid operation %N (slice of unaddressable value)", n); - goto error; - } - n->left = nod(OADDR, n->left, N); - n->left->implicit = 1; - typecheck(&n->left, Erv); - l = n->left; - } - if((t = l->type) == T) - goto error; - tp = nil; - if(istype(t, TSTRING)) { - yyerror("invalid operation %N (3-index slice of string)", n); - goto error; - } - if(isptr[t->etype] && isfixedarray(t->type)) { - tp = t->type; - n->type = typ(TARRAY); - n->type->type = tp->type; - n->type->bound = -1; - dowidth(n->type); - n->op = OSLICE3ARR; - } else if(isslice(t)) { - n->type = t; - } else { - yyerror("cannot slice %N (type %T)", l, t); - goto error; - } - if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0) - goto error; - if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0) - goto error; - if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0) - goto error; - if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0) - goto error; - goto ret; - - /* - * call and call like - */ - case OCALL: - l = n->left; - if(l->op == ONAME && (r = unsafenmagic(n)) != N) { - if(n->isddd) - yyerror("invalid use of ... with builtin %N", l); - n = r; - goto reswitch; - } - typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc)); - n->diag |= n->left->diag; - l = n->left; - if(l->op == ONAME && l->etype != 0) { - if(n->isddd && l->etype != OAPPEND) - yyerror("invalid use of ... with builtin %N", l); - // builtin: OLEN, OCAP, etc. - n->op = l->etype; - n->left = n->right; - n->right = N; - goto reswitch; - } - defaultlit(&n->left, T); - l = n->left; - if(l->op == OTYPE) { - if(n->isddd || l->type->bound == -100) { - if(!l->type->broke) - yyerror("invalid use of ... in type conversion", l); - n->diag = 1; - } - // pick off before type-checking arguments - ok |= Erv; - // turn CALL(type, arg) into CONV(arg) w/ type - n->left = N; - n->op = OCONV; - n->type = l->type; - if(onearg(n, "conversion to %T", l->type) < 0) - goto error; - goto doconv; - } - - if(count(n->list) == 1 && !n->isddd) - typecheck(&n->list->n, Erv | Efnstruct); - else - typechecklist(n->list, Erv); - if((t = l->type) == T) - goto error; - checkwidth(t); - - switch(l->op) { - case ODOTINTER: - n->op = OCALLINTER; - break; - - case ODOTMETH: - n->op = OCALLMETH; - // typecheckaste was used here but there wasn't enough - // information further down the call chain to know if we - // were testing a method receiver for unexported fields. - // It isn't necessary, so just do a sanity check. - tp = getthisx(t)->type->type; - if(l->left == N || !eqtype(l->left->type, tp)) - fatal("method receiver"); - break; - - default: - n->op = OCALLFUNC; - if(t->etype != TFUNC) { - yyerror("cannot call non-function %N (type %T)", l, t); - goto error; - } - break; - } - if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf) - desc = descbuf; - else - desc = "function argument"; - typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc); - ok |= Etop; - if(t->outtuple == 0) - goto ret; - ok |= Erv; - if(t->outtuple == 1) { - t = getoutargx(l->type)->type; - if(t == T) - goto error; - if(t->etype == TFIELD) - t = t->type; - n->type = t; - goto ret; - } - // multiple return - if(!(top & (Efnstruct | Etop))) { - yyerror("multiple-value %N() in single-value context", l); - goto ret; - } - n->type = getoutargx(l->type); - goto ret; - - case OCAP: - case OLEN: - case OREAL: - case OIMAG: - ok |= Erv; - if(onearg(n, "%O", n->op) < 0) - goto error; - typecheck(&n->left, Erv); - defaultlit(&n->left, T); - implicitstar(&n->left); - l = n->left; - t = l->type; - if(t == T) - goto error; - switch(n->op) { - case OCAP: - if(!okforcap[t->etype]) - goto badcall1; - break; - case OLEN: - if(!okforlen[t->etype]) - goto badcall1; - break; - case OREAL: - case OIMAG: - if(!iscomplex[t->etype]) - goto badcall1; - if(isconst(l, CTCPLX)){ - r = n; - if(n->op == OREAL) - n = nodfltconst(&l->val.u.cval->real); - else - n = nodfltconst(&l->val.u.cval->imag); - n->orig = r; - } - n->type = types[cplxsubtype(t->etype)]; - goto ret; - } - // might be constant - switch(t->etype) { - case TSTRING: - if(isconst(l, CTSTR)) { - r = nod(OXXX, N, N); - nodconst(r, types[TINT], l->val.u.sval->len); - r->orig = n; - n = r; - } - break; - case TARRAY: - if(t->bound < 0) // slice - break; - if(callrecv(l)) // has call or receive - break; - r = nod(OXXX, N, N); - nodconst(r, types[TINT], t->bound); - r->orig = n; - n = r; - break; - } - n->type = types[TINT]; - goto ret; - - case OCOMPLEX: - ok |= Erv; - if(count(n->list) == 1) { - typechecklist(n->list, Efnstruct); - if(n->list->n->op != OCALLFUNC && n->list->n->op != OCALLMETH) { - yyerror("invalid operation: complex expects two arguments"); - goto error; - } - t = n->list->n->left->type; - if(t->outtuple != 2) { - yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple); - goto error; - } - t = n->list->n->type->type; - l = t->nname; - r = t->down->nname; - } else { - if(twoarg(n) < 0) - goto error; - l = typecheck(&n->left, Erv | (top & Eiota)); - r = typecheck(&n->right, Erv | (top & Eiota)); - if(l->type == T || r->type == T) - goto error; - defaultlit2(&l, &r, 0); - if(l->type == T || r->type == T) - goto error; - n->left = l; - n->right = r; - } - if(!eqtype(l->type, r->type)) { - yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); - goto error; - } - switch(l->type->etype) { - default: - yyerror("invalid operation: %N (arguments have type %T, expected floating-point)", n, l->type, r->type); - goto error; - case TIDEAL: - t = types[TIDEAL]; - break; - case TFLOAT32: - t = types[TCOMPLEX64]; - break; - case TFLOAT64: - t = types[TCOMPLEX128]; - break; - } - if(l->op == OLITERAL && r->op == OLITERAL) { - // make it a complex literal - r = nodcplxlit(l->val, r->val); - r->orig = n; - n = r; - } - n->type = t; - goto ret; - - case OCLOSE: - if(onearg(n, "%O", n->op) < 0) - goto error; - typecheck(&n->left, Erv); - defaultlit(&n->left, T); - l = n->left; - if((t = l->type) == T) - goto error; - if(t->etype != TCHAN) { - yyerror("invalid operation: %N (non-chan type %T)", n, t); - goto error; - } - if(!(t->chan & Csend)) { - yyerror("invalid operation: %N (cannot close receive-only channel)", n); - goto error; - } - ok |= Etop; - goto ret; - - case ODELETE: - args = n->list; - if(args == nil) { - yyerror("missing arguments to delete"); - goto error; - } - if(args->next == nil) { - yyerror("missing second (key) argument to delete"); - goto error; - } - if(args->next->next != nil) { - yyerror("too many arguments to delete"); - goto error; - } - ok |= Etop; - typechecklist(args, Erv); - l = args->n; - r = args->next->n; - if(l->type != T && l->type->etype != TMAP) { - yyerror("first argument to delete must be map; have %lT", l->type); - goto error; - } - args->next->n = assignconv(r, l->type->down, "delete"); - goto ret; - - case OAPPEND: - ok |= Erv; - args = n->list; - if(args == nil) { - yyerror("missing arguments to append"); - goto error; - } - - if(count(args) == 1 && !n->isddd) - typecheck(&args->n, Erv | Efnstruct); - else - typechecklist(args, Erv); - - if((t = args->n->type) == T) - goto error; - - // Unpack multiple-return result before type-checking. - if(istype(t, TSTRUCT) && t->funarg) { - t = t->type; - if(istype(t, TFIELD)) - t = t->type; - } - - n->type = t; - if(!isslice(t)) { - if(isconst(args->n, CTNIL)) { - yyerror("first argument to append must be typed slice; have untyped nil", t); - goto error; - } - yyerror("first argument to append must be slice; have %lT", t); - goto error; - } - - if(n->isddd) { - if(args->next == nil) { - yyerror("cannot use ... on first argument to append"); - goto error; - } - if(args->next->next != nil) { - yyerror("too many arguments to append"); - goto error; - } - if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) { - defaultlit(&args->next->n, types[TSTRING]); - goto ret; - } - args->next->n = assignconv(args->next->n, t->orig, "append"); - goto ret; - } - for(args=args->next; args != nil; args=args->next) { - if(args->n->type == T) - continue; - args->n = assignconv(args->n, t->type, "append"); - } - goto ret; - - case OCOPY: - ok |= Etop|Erv; - args = n->list; - if(args == nil || args->next == nil) { - yyerror("missing arguments to copy"); - goto error; - } - if(args->next->next != nil) { - yyerror("too many arguments to copy"); - goto error; - } - n->left = args->n; - n->right = args->next->n; - n->list = nil; - n->type = types[TINT]; - typecheck(&n->left, Erv); - typecheck(&n->right, Erv); - if(n->left->type == T || n->right->type == T) - goto error; - defaultlit(&n->left, T); - defaultlit(&n->right, T); - if(n->left->type == T || n->right->type == T) - goto error; - - // copy([]byte, string) - if(isslice(n->left->type) && n->right->type->etype == TSTRING) { - if(eqtype(n->left->type->type, bytetype)) - goto ret; - yyerror("arguments to copy have different element types: %lT and string", n->left->type); - goto error; - } - - if(!isslice(n->left->type) || !isslice(n->right->type)) { - if(!isslice(n->left->type) && !isslice(n->right->type)) - yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type); - else if(!isslice(n->left->type)) - yyerror("first argument to copy should be slice; have %lT", n->left->type); - else - yyerror("second argument to copy should be slice or string; have %lT", n->right->type); - goto error; - } - if(!eqtype(n->left->type->type, n->right->type->type)) { - yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type); - goto error; - } - goto ret; - - case OCONV: - goto doconv; - - case OMAKE: - ok |= Erv; - args = n->list; - if(args == nil) { - yyerror("missing argument to make"); - goto error; - } - n->list = nil; - l = args->n; - args = args->next; - typecheck(&l, Etype); - if((t = l->type) == T) - goto error; - - switch(t->etype) { - default: - yyerror("cannot make type %T", t); - goto error; - - case TARRAY: - if(!isslice(t)) { - yyerror("cannot make type %T", t); - goto error; - } - if(args == nil) { - yyerror("missing len argument to make(%T)", t); - goto error; - } - l = args->n; - args = args->next; - typecheck(&l, Erv); - r = N; - if(args != nil) { - r = args->n; - args = args->next; - typecheck(&r, Erv); - } - if(l->type == T || (r && r->type == T)) - goto error; - et = checkmake(t, "len", l) < 0; - et |= r && checkmake(t, "cap", r) < 0; - if(et) - goto error; - if(isconst(l, CTINT) && r && isconst(r, CTINT) && mpcmpfixfix(l->val.u.xval, r->val.u.xval) > 0) { - yyerror("len larger than cap in make(%T)", t); - goto error; - } - n->left = l; - n->right = r; - n->op = OMAKESLICE; - break; - - case TMAP: - if(args != nil) { - l = args->n; - args = args->next; - typecheck(&l, Erv); - defaultlit(&l, types[TINT]); - if(l->type == T) - goto error; - if(checkmake(t, "size", l) < 0) - goto error; - n->left = l; - } else - n->left = nodintconst(0); - n->op = OMAKEMAP; - break; - - case TCHAN: - l = N; - if(args != nil) { - l = args->n; - args = args->next; - typecheck(&l, Erv); - defaultlit(&l, types[TINT]); - if(l->type == T) - goto error; - if(checkmake(t, "buffer", l) < 0) - goto error; - n->left = l; - } else - n->left = nodintconst(0); - n->op = OMAKECHAN; - break; - } - if(args != nil) { - yyerror("too many arguments to make(%T)", t); - n->op = OMAKE; - goto error; - } - n->type = t; - goto ret; - - case ONEW: - ok |= Erv; - args = n->list; - if(args == nil) { - yyerror("missing argument to new"); - goto error; - } - l = args->n; - typecheck(&l, Etype); - if((t = l->type) == T) - goto error; - if(args->next != nil) { - yyerror("too many arguments to new(%T)", t); - goto error; - } - n->left = l; - n->type = ptrto(t); - goto ret; - - case OPRINT: - case OPRINTN: - ok |= Etop; - typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape - for(args=n->list; args; args=args->next) { - // Special case for print: int constant is int64, not int. - if(isconst(args->n, CTINT)) - defaultlit(&args->n, types[TINT64]); - else - defaultlit(&args->n, T); - } - goto ret; - - case OPANIC: - ok |= Etop; - if(onearg(n, "panic") < 0) - goto error; - typecheck(&n->left, Erv); - defaultlit(&n->left, types[TINTER]); - if(n->left->type == T) - goto error; - goto ret; - - case ORECOVER: - ok |= Erv|Etop; - if(n->list != nil) { - yyerror("too many arguments to recover"); - goto error; - } - n->type = types[TINTER]; - goto ret; - - case OCLOSURE: - ok |= Erv; - typecheckclosure(n, top); - if(n->type == T) - goto error; - goto ret; - - case OITAB: - ok |= Erv; - typecheck(&n->left, Erv); - if((t = n->left->type) == T) - goto error; - if(t->etype != TINTER) - fatal("OITAB of %T", t); - n->type = ptrto(types[TUINTPTR]); - goto ret; - - case OSPTR: - ok |= Erv; - typecheck(&n->left, Erv); - if((t = n->left->type) == T) - goto error; - if(!isslice(t) && t->etype != TSTRING) - fatal("OSPTR of %T", t); - if(t->etype == TSTRING) - n->type = ptrto(types[TUINT8]); - else - n->type = ptrto(t->type); - goto ret; - - case OCLOSUREVAR: - ok |= Erv; - goto ret; - - case OCFUNC: - ok |= Erv; - typecheck(&n->left, Erv); - n->type = types[TUINTPTR]; - goto ret; - - case OCONVNOP: - ok |= Erv; - typecheck(&n->left, Erv); - goto ret; - - /* - * statements - */ - case OAS: - ok |= Etop; - typecheckas(n); - // Code that creates temps does not bother to set defn, so do it here. - if(n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0) - n->left->defn = n; - goto ret; - - case OAS2: - ok |= Etop; - typecheckas2(n); - goto ret; - - case OBREAK: - case OCONTINUE: - case ODCL: - case OEMPTY: - case OGOTO: - case OXFALL: - case OVARKILL: - ok |= Etop; - goto ret; - - case OLABEL: - ok |= Etop; - decldepth++; - goto ret; - - case ODEFER: - ok |= Etop; - typecheck(&n->left, Etop|Erv); - if(!n->left->diag) - checkdefergo(n); - goto ret; - - case OPROC: - ok |= Etop; - typecheck(&n->left, Etop|Eproc|Erv); - checkdefergo(n); - goto ret; - - case OFOR: - ok |= Etop; - typechecklist(n->ninit, Etop); - decldepth++; - typecheck(&n->ntest, Erv); - if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL) - yyerror("non-bool %lN used as for condition", n->ntest); - typecheck(&n->nincr, Etop); - typechecklist(n->nbody, Etop); - decldepth--; - goto ret; - - case OIF: - ok |= Etop; - typechecklist(n->ninit, Etop); - typecheck(&n->ntest, Erv); - if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL) - yyerror("non-bool %lN used as if condition", n->ntest); - typechecklist(n->nbody, Etop); - typechecklist(n->nelse, Etop); - goto ret; - - case ORETURN: - ok |= Etop; - if(count(n->list) == 1) - typechecklist(n->list, Erv | Efnstruct); - else - typechecklist(n->list, Erv); - if(curfn == N) { - yyerror("return outside function"); - goto error; - } - if(curfn->type->outnamed && n->list == nil) - goto ret; - typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument"); - goto ret; - - case ORETJMP: - ok |= Etop; - goto ret; - - case OSELECT: - ok |= Etop; - typecheckselect(n); - goto ret; - - case OSWITCH: - ok |= Etop; - typecheckswitch(n); - goto ret; - - case ORANGE: - ok |= Etop; - typecheckrange(n); - goto ret; - - case OTYPESW: - yyerror("use of .(type) outside type switch"); - goto error; - - case OXCASE: - ok |= Etop; - typechecklist(n->list, Erv); - typechecklist(n->nbody, Etop); - goto ret; - - case ODCLFUNC: - ok |= Etop; - typecheckfunc(n); - goto ret; - - case ODCLCONST: - ok |= Etop; - typecheck(&n->left, Erv); - goto ret; - - case ODCLTYPE: - ok |= Etop; - typecheck(&n->left, Etype); - if(!incannedimport) - checkwidth(n->left->type); - goto ret; - } - goto ret; - -arith: - if(op == OLSH || op == ORSH) - goto shift; - // ideal mixed with non-ideal - defaultlit2(&l, &r, 0); - n->left = l; - n->right = r; - if(l->type == T || r->type == T) - goto error; - t = l->type; - if(t->etype == TIDEAL) - t = r->type; - et = t->etype; - if(et == TIDEAL) - et = TINT; - aop = 0; - if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) { - // comparison is okay as long as one side is - // assignable to the other. convert so they have - // the same type. - // - // the only conversion that isn't a no-op is concrete == interface. - // in that case, check comparability of the concrete type. - // The conversion allocates, so only do it if the concrete type is huge. - if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) { - if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) { - yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type)); - goto error; - } - dowidth(l->type); - if(isinter(r->type) == isinter(l->type) || l->type->width >= 1<<16) { - l = nod(aop, l, N); - l->type = r->type; - l->typecheck = 1; - n->left = l; - } - t = r->type; - goto converted; - } - if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) { - if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) { - yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type)); - goto error; - } - dowidth(r->type); - if(isinter(r->type) == isinter(l->type) || r->type->width >= 1<<16) { - r = nod(aop, r, N); - r->type = l->type; - r->typecheck = 1; - n->right = r; - } - t = l->type; - } - converted: - et = t->etype; - } - if(t->etype != TIDEAL && !eqtype(l->type, r->type)) { - defaultlit2(&l, &r, 1); - if(n->op == OASOP && n->implicit) { - yyerror("invalid operation: %N (non-numeric type %T)", n, l->type); - goto error; - } - if(isinter(r->type) == isinter(l->type) || aop == 0) { - yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type); - goto error; - } - } - if(!okfor[op][et]) { - yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t)); - goto error; - } - // okfor allows any array == array, map == map, func == func. - // restrict to slice/map/func == nil and nil == slice/map/func. - if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) { - yyerror("invalid operation: %N (%T cannot be compared)", n, l->type); - goto error; - } - if(isslice(l->type) && !isnil(l) && !isnil(r)) { - yyerror("invalid operation: %N (slice can only be compared to nil)", n); - goto error; - } - if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) { - yyerror("invalid operation: %N (map can only be compared to nil)", n); - goto error; - } - if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) { - yyerror("invalid operation: %N (func can only be compared to nil)", n); - goto error; - } - if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) { - yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype); - goto error; - } - - t = l->type; - if(iscmp[n->op]) { - evconst(n); - t = idealbool; - if(n->op != OLITERAL) { - defaultlit2(&l, &r, 1); - n->left = l; - n->right = r; - } - } else if(n->op == OANDAND || n->op == OOROR) { - if(l->type == r->type) - t = l->type; - else if(l->type == idealbool) - t = r->type; - else if(r->type == idealbool) - t = l->type; - // non-comparison operators on ideal bools should make them lose their ideal-ness - } else if(t == idealbool) - t = types[TBOOL]; - - if(et == TSTRING) { - if(iscmp[n->op]) { - n->etype = n->op; - n->op = OCMPSTR; - } else if(n->op == OADD) { - // create OADDSTR node with list of strings in x + y + z + (w + v) + ... - n->op = OADDSTR; - if(l->op == OADDSTR) - n->list = l->list; - else - n->list = list1(l); - if(r->op == OADDSTR) - n->list = concat(n->list, r->list); - else - n->list = list(n->list, r); - n->left = N; - n->right = N; - } - } - if(et == TINTER) { - if(l->op == OLITERAL && l->val.ctype == CTNIL) { - // swap for back end - n->left = r; - n->right = l; - } else if(r->op == OLITERAL && r->val.ctype == CTNIL) { - // leave alone for back end - } else if(isinter(r->type) == isinter(l->type)) { - n->etype = n->op; - n->op = OCMPIFACE; - } - } - - if((op == ODIV || op == OMOD) && isconst(r, CTINT)) - if(mpcmpfixc(r->val.u.xval, 0) == 0) { - yyerror("division by zero"); - goto error; - } - - n->type = t; - goto ret; - -shift: - defaultlit(&r, types[TUINT]); - n->right = r; - t = r->type; - if(!isint[t->etype] || issigned[t->etype]) { - yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type); - goto error; - } - t = l->type; - if(t != T && t->etype != TIDEAL && !isint[t->etype]) { - yyerror("invalid operation: %N (shift of type %T)", n, t); - goto error; - } - // no defaultlit for left - // the outer context gives the type - n->type = l->type; - goto ret; - -doconv: - ok |= Erv; - saveorignode(n); - typecheck(&n->left, Erv | (top & (Eindir | Eiota))); - convlit1(&n->left, n->type, 1); - if((t = n->left->type) == T || n->type == T) - goto error; - if((n->op = convertop(t, n->type, &why)) == 0) { - if(!n->diag && !n->type->broke) { - yyerror("cannot convert %lN to type %T%s", n->left, n->type, why); - n->diag = 1; - } - n->op = OCONV; - } - switch(n->op) { - case OCONVNOP: - if(n->left->op == OLITERAL && n->type != types[TBOOL]) { - r = nod(OXXX, N, N); - n->op = OCONV; - n->orig = r; - *r = *n; - n->op = OLITERAL; - n->val = n->left->val; - } - break; - case OSTRARRAYBYTE: - // do not use stringtoarraylit. - // generated code and compiler memory footprint is better without it. - break; - case OSTRARRAYRUNE: - if(n->left->op == OLITERAL) - stringtoarraylit(&n); - break; - } - goto ret; - -ret: - t = n->type; - if(t && !t->funarg && n->op != OTYPE) { - switch(t->etype) { - case TFUNC: // might have TANY; wait until its called - case TANY: - case TFORW: - case TIDEAL: - case TNIL: - case TBLANK: - break; - default: - checkwidth(t); - } - } - - if(safemode && !incannedimport && !importpkg && !compiling_wrappers && t && t->etype == TUNSAFEPTR) - yyerror("cannot use unsafe.Pointer"); - - evconst(n); - if(n->op == OTYPE && !(top & Etype)) { - yyerror("type %T is not an expression", n->type); - goto error; - } - if((top & (Erv|Etype)) == Etype && n->op != OTYPE) { - yyerror("%N is not a type", n); - goto error; - } - // TODO(rsc): simplify - if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) { - yyerror("%N used as value", n); - goto error; - } - if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) { - if(n->diag == 0) { - yyerror("%N evaluated but not used", n); - n->diag = 1; - } - goto error; - } - - /* TODO - if(n->type == T) - fatal("typecheck nil type"); - */ - goto out; - -badcall1: - yyerror("invalid argument %lN for %O", n->left, n->op); - goto error; - -error: - n->type = T; - -out: - *np = n; -} - -static int -checksliceindex(Node *l, Node *r, Type *tp) -{ - Type *t; - - if((t = r->type) == T) - return -1; - if(!isint[t->etype]) { - yyerror("invalid slice index %N (type %T)", r, t); - return -1; - } - if(r->op == OLITERAL) { - if(mpgetfix(r->val.u.xval) < 0) { - yyerror("invalid slice index %N (index must be non-negative)", r); - return -1; - } else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) { - yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound); - return -1; - } else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) { - yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len); - return -1; - } else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) { - yyerror("invalid slice index %N (index too large)", r); - return -1; - } - } - return 0; -} - -static int -checksliceconst(Node *lo, Node *hi) -{ - if(lo != N && hi != N && lo->op == OLITERAL && hi->op == OLITERAL - && mpcmpfixfix(lo->val.u.xval, hi->val.u.xval) > 0) { - yyerror("invalid slice index: %N > %N", lo, hi); - return -1; - } - return 0; -} - -static void -checkdefergo(Node *n) -{ - char *what; - - what = "defer"; - if(n->op == OPROC) - what = "go"; - - switch(n->left->op) { - case OCALLINTER: - case OCALLMETH: - case OCALLFUNC: - case OCLOSE: - case OCOPY: - case ODELETE: - case OPANIC: - case OPRINT: - case OPRINTN: - case ORECOVER: - // ok - return; - case OAPPEND: - case OCAP: - case OCOMPLEX: - case OIMAG: - case OLEN: - case OMAKE: - case OMAKESLICE: - case OMAKECHAN: - case OMAKEMAP: - case ONEW: - case OREAL: - case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof - if(n->left->orig != N && n->left->orig->op == OCONV) - break; - yyerror("%s discards result of %N", what, n->left); - return; - } - - // type is broken or missing, most likely a method call on a broken type - // we will warn about the broken type elsewhere. no need to emit a potentially confusing error - if(n->left->type == T || n->left->type->broke) - return; - - if(!n->diag) { - // The syntax made sure it was a call, so this must be - // a conversion. - n->diag = 1; - yyerror("%s requires function call, not conversion", what); - } -} - -static void -implicitstar(Node **nn) -{ - Type *t; - Node *n; - - // insert implicit * if needed for fixed array - n = *nn; - t = n->type; - if(t == T || !isptr[t->etype]) - return; - t = t->type; - if(t == T) - return; - if(!isfixedarray(t)) - return; - n = nod(OIND, n, N); - n->implicit = 1; - typecheck(&n, Erv); - *nn = n; -} - -static int -onearg(Node *n, char *f, ...) -{ - va_list arg; - char *p; - - if(n->left != N) - return 0; - if(n->list == nil) { - va_start(arg, f); - p = vsmprint(f, arg); - va_end(arg); - yyerror("missing argument to %s: %N", p, n); - return -1; - } - if(n->list->next != nil) { - va_start(arg, f); - p = vsmprint(f, arg); - va_end(arg); - yyerror("too many arguments to %s: %N", p, n); - n->left = n->list->n; - n->list = nil; - return -1; - } - n->left = n->list->n; - n->list = nil; - return 0; -} - -static int -twoarg(Node *n) -{ - if(n->left != N) - return 0; - if(n->list == nil) { - yyerror("missing argument to %O - %N", n->op, n); - return -1; - } - n->left = n->list->n; - if(n->list->next == nil) { - yyerror("missing argument to %O - %N", n->op, n); - n->list = nil; - return -1; - } - if(n->list->next->next != nil) { - yyerror("too many arguments to %O - %N", n->op, n); - n->list = nil; - return -1; - } - n->right = n->list->next->n; - n->list = nil; - return 0; -} - -static Type* -lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp) -{ - Type *r; - - r = T; - for(; f!=T; f=f->down) { - if(dostrcmp && strcmp(f->sym->name, s->name) == 0) - return f; - if(f->sym != s) - continue; - if(r != T) { - if(errnode) - yyerror("ambiguous selector %N", errnode); - else if(isptr[t->etype]) - yyerror("ambiguous selector (%T).%S", t, s); - else - yyerror("ambiguous selector %T.%S", t, s); - break; - } - r = f; - } - return r; -} - -static int -looktypedot(Node *n, Type *t, int dostrcmp) -{ - Type *f1, *f2; - Sym *s; - - s = n->right->sym; - - if(t->etype == TINTER) { - f1 = lookdot1(n, s, t, t->type, dostrcmp); - if(f1 == T) - return 0; - - n->right = methodname(n->right, t); - n->xoffset = f1->width; - n->type = f1->type; - n->op = ODOTINTER; - return 1; - } - - // Find the base type: methtype will fail if t - // is not of the form T or *T. - f2 = methtype(t, 0); - if(f2 == T) - return 0; - - expandmeth(f2); - f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp); - if(f2 == T) - return 0; - - // disallow T.m if m requires *T receiver - if(isptr[getthisx(f2->type)->type->type->etype] - && !isptr[t->etype] - && f2->embedded != 2 - && !isifacemethod(f2->type)) { - yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym); - return 0; - } - - n->right = methodname(n->right, t); - n->xoffset = f2->width; - n->type = f2->type; - n->op = ODOTMETH; - return 1; -} - -static Type* -derefall(Type* t) -{ - while(t && t->etype == tptr) - t = t->type; - return t; -} - -static int -lookdot(Node *n, Type *t, int dostrcmp) -{ - Type *f1, *f2, *tt, *rcvr; - Sym *s; - - s = n->right->sym; - - dowidth(t); - f1 = T; - if(t->etype == TSTRUCT || t->etype == TINTER) - f1 = lookdot1(n, s, t, t->type, dostrcmp); - - f2 = T; - if(n->left->type == t || n->left->type->sym == S) { - f2 = methtype(t, 0); - if(f2 != T) { - // Use f2->method, not f2->xmethod: adddot has - // already inserted all the necessary embedded dots. - f2 = lookdot1(n, s, f2, f2->method, dostrcmp); - } - } - - if(f1 != T) { - if(f2 != T) - yyerror("%S is both field and method", - n->right->sym); - if(f1->width == BADWIDTH) - fatal("lookdot badwidth %T %p", f1, f1); - n->xoffset = f1->width; - n->type = f1->type; - n->paramfld = f1; - if(t->etype == TINTER) { - if(isptr[n->left->type->etype]) { - n->left = nod(OIND, n->left, N); // implicitstar - n->left->implicit = 1; - typecheck(&n->left, Erv); - } - n->op = ODOTINTER; - } - return 1; - } - - if(f2 != T) { - tt = n->left->type; - dowidth(tt); - rcvr = getthisx(f2->type)->type->type; - if(!eqtype(rcvr, tt)) { - if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) { - checklvalue(n->left, "call pointer method on"); - n->left = nod(OADDR, n->left, N); - n->left->implicit = 1; - typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) { - n->left = nod(OIND, n->left, N); - n->left->implicit = 1; - typecheck(&n->left, Etype|Erv); - } else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) { - yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left); - while(tt->etype == tptr) { - // Stop one level early for method with pointer receiver. - if(rcvr->etype == tptr && tt->type->etype != tptr) - break; - n->left = nod(OIND, n->left, N); - n->left->implicit = 1; - typecheck(&n->left, Etype|Erv); - tt = tt->type; - } - } else { - fatal("method mismatch: %T for %T", rcvr, tt); - } - } - n->right = methodname(n->right, n->left->type); - n->xoffset = f2->width; - n->type = f2->type; -// print("lookdot found [%p] %T\n", f2->type, f2->type); - n->op = ODOTMETH; - return 1; - } - - return 0; -} - -static int -nokeys(NodeList *l) -{ - for(; l; l=l->next) - if(l->n->op == OKEY) - return 0; - return 1; -} - -static int -hasddd(Type *t) -{ - Type *tl; - - for(tl=t->type; tl; tl=tl->down) { - if(tl->isddd) - return 1; - } - return 0; -} - -static int -downcount(Type *t) -{ - Type *tl; - int n; - - n = 0; - for(tl=t->type; tl; tl=tl->down) { - n++; - } - return n; -} - -/* - * typecheck assignment: type list = expression list - */ -static void -typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc) -{ - Type *t, *tl, *tn; - Node *n; - int lno; - char *why; - int n1, n2; - - lno = lineno; - - if(tstruct->broke) - goto out; - - n = N; - if(nl != nil && nl->next == nil && (n = nl->n)->type != T) - if(n->type->etype == TSTRUCT && n->type->funarg) { - if(!hasddd(tstruct)) { - n1 = downcount(tstruct); - n2 = downcount(n->type); - if(n2 > n1) - goto toomany; - if(n2 < n1) - goto notenough; - } - - tn = n->type->type; - for(tl=tstruct->type; tl; tl=tl->down) { - if(tl->isddd) { - for(; tn; tn=tn->down) { - if(assignop(tn->type, tl->type->type, &why) == 0) { - if(call != N) - yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type->type, call, why); - else - yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why); - } - } - goto out; - } - if(tn == T) - goto notenough; - if(assignop(tn->type, tl->type, &why) == 0) { - if(call != N) - yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why); - else - yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why); - } - tn = tn->down; - } - if(tn != T) - goto toomany; - goto out; - } - - n1 = downcount(tstruct); - n2 = count(nl); - if(!hasddd(tstruct)) { - if(n2 > n1) - goto toomany; - if(n2 < n1) - goto notenough; - } - else { - if(!isddd) { - if(n2 < n1-1) - goto notenough; - } else { - if(n2 > n1) - goto toomany; - if(n2 < n1) - goto notenough; - } - } - - for(tl=tstruct->type; tl; tl=tl->down) { - t = tl->type; - if(tl->isddd) { - if(isddd) { - if(nl == nil) - goto notenough; - if(nl->next != nil) - goto toomany; - n = nl->n; - setlineno(n); - if(n->type != T) - nl->n = assignconv(n, t, desc); - goto out; - } - for(; nl; nl=nl->next) { - n = nl->n; - setlineno(nl->n); - if(n->type != T) - nl->n = assignconv(n, t->type, desc); - } - goto out; - } - if(nl == nil) - goto notenough; - n = nl->n; - setlineno(n); - if(n->type != T) - nl->n = assignconv(n, t, desc); - nl = nl->next; - } - if(nl != nil) - goto toomany; - if(isddd) { - if(call != N) - yyerror("invalid use of ... in call to %N", call); - else - yyerror("invalid use of ... in %O", op); - } - -out: - lineno = lno; - return; - -notenough: - if(n == N || !n->diag) { - if(call != N) - yyerror("not enough arguments in call to %N", call); - else - yyerror("not enough arguments to %O", op); - if(n != N) - n->diag = 1; - } - goto out; - -toomany: - if(call != N) - yyerror("too many arguments in call to %N", call); - else - yyerror("too many arguments to %O", op); - goto out; -} - -/* - * type check composite - */ - -static void -fielddup(Node *n, Node **hash, ulong nhash) -{ - uint h; - char *s; - Node *a; - - if(n->op != ONAME) - fatal("fielddup: not ONAME"); - s = n->sym->name; - h = stringhash(s)%nhash; - for(a=hash[h]; a!=N; a=a->ntest) { - if(strcmp(a->sym->name, s) == 0) { - yyerror("duplicate field name in struct literal: %s", s); - return; - } - } - n->ntest = hash[h]; - hash[h] = n; -} - -static void -keydup(Node *n, Node **hash, ulong nhash) -{ - uint h; - ulong b; - double d; - int i; - Node *a, *orign; - Node cmp; - char *s; - - orign = n; - if(n->op == OCONVIFACE) - n = n->left; - evconst(n); - if(n->op != OLITERAL) - return; // we dont check variables - - switch(n->val.ctype) { - default: // unknown, bool, nil - b = 23; - break; - case CTINT: - case CTRUNE: - b = mpgetfix(n->val.u.xval); - break; - case CTFLT: - d = mpgetflt(n->val.u.fval); - s = (char*)&d; - b = 0; - for(i=sizeof(d); i>0; i--) - b = b*PRIME1 + *s++; - break; - case CTSTR: - b = 0; - s = n->val.u.sval->s; - for(i=n->val.u.sval->len; i>0; i--) - b = b*PRIME1 + *s++; - break; - } - - h = b%nhash; - memset(&cmp, 0, sizeof(cmp)); - for(a=hash[h]; a!=N; a=a->ntest) { - cmp.op = OEQ; - cmp.left = n; - b = 0; - if(a->op == OCONVIFACE && orign->op == OCONVIFACE) { - if(eqtype(a->left->type, n->type)) { - cmp.right = a->left; - evconst(&cmp); - b = cmp.val.u.bval; - } - } else if(eqtype(a->type, n->type)) { - cmp.right = a; - evconst(&cmp); - b = cmp.val.u.bval; - } - if(b) { - yyerror("duplicate key %N in map literal", n); - return; - } - } - orign->ntest = hash[h]; - hash[h] = orign; -} - -static void -indexdup(Node *n, Node **hash, ulong nhash) -{ - uint h; - Node *a; - ulong b, c; - - if(n->op != OLITERAL) - fatal("indexdup: not OLITERAL"); - - b = mpgetfix(n->val.u.xval); - h = b%nhash; - for(a=hash[h]; a!=N; a=a->ntest) { - c = mpgetfix(a->val.u.xval); - if(b == c) { - yyerror("duplicate index in array literal: %ld", b); - return; - } - } - n->ntest = hash[h]; - hash[h] = n; -} - -static int -prime(ulong h, ulong sr) -{ - ulong n; - - for(n=3; n<=sr; n+=2) - if(h%n == 0) - return 0; - return 1; -} - -static ulong -inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash) -{ - ulong h, sr; - NodeList *ll; - int i; - - // count the number of entries - h = 0; - for(ll=n->list; ll; ll=ll->next) - h++; - - // if the auto hash table is - // large enough use it. - if(h <= nautohash) { - *hash = autohash; - memset(*hash, 0, nautohash * sizeof(**hash)); - return nautohash; - } - - // make hash size odd and 12% larger than entries - h += h/8; - h |= 1; - - // calculate sqrt of h - sr = h/2; - for(i=0; i<5; i++) - sr = (sr + h/sr)/2; - - // check for primeality - while(!prime(h, sr)) - h += 2; - - // build and return a throw-away hash table - *hash = mal(h * sizeof(**hash)); - memset(*hash, 0, h * sizeof(**hash)); - return h; -} - -static int -iscomptype(Type *t) -{ - switch(t->etype) { - case TARRAY: - case TSTRUCT: - case TMAP: - return 1; - case TPTR32: - case TPTR64: - switch(t->type->etype) { - case TARRAY: - case TSTRUCT: - case TMAP: - return 1; - } - break; - } - return 0; -} - -static void -pushtype(Node *n, Type *t) -{ - if(n == N || n->op != OCOMPLIT || !iscomptype(t)) - return; - - if(n->right == N) { - n->right = typenod(t); - n->implicit = 1; // don't print - n->right->implicit = 1; // * is okay - } - else if(debug['s']) { - typecheck(&n->right, Etype); - if(n->right->type != T && eqtype(n->right->type, t)) - print("%L: redundant type: %T\n", n->lineno, t); - } -} - -static void -typecheckcomplit(Node **np) -{ - int bad, i, nerr; - int64 length; - Node *l, *n, *norig, *r, **hash; - NodeList *ll; - Type *t, *f; - Sym *s, *s1; - int32 lno; - ulong nhash; - Node *autohash[101]; - - n = *np; - lno = lineno; - - if(n->right == N) { - if(n->list != nil) - setlineno(n->list->n); - yyerror("missing type in composite literal"); - goto error; - } - - // Save original node (including n->right) - norig = nod(n->op, N, N); - *norig = *n; - - setlineno(n->right); - l = typecheck(&n->right /* sic */, Etype|Ecomplit); - if((t = l->type) == T) - goto error; - nerr = nerrors; - n->type = t; - - if(isptr[t->etype]) { - // For better or worse, we don't allow pointers as the composite literal type, - // except when using the &T syntax, which sets implicit on the OIND. - if(!n->right->implicit) { - yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type); - goto error; - } - // Also, the underlying type must be a struct, map, slice, or array. - if(!iscomptype(t)) { - yyerror("invalid pointer type %T for composite literal", t); - goto error; - } - t = t->type; - } - - switch(t->etype) { - default: - yyerror("invalid type for composite literal: %T", t); - n->type = T; - break; - - case TARRAY: - nhash = inithash(n, &hash, autohash, nelem(autohash)); - - length = 0; - i = 0; - for(ll=n->list; ll; ll=ll->next) { - l = ll->n; - setlineno(l); - if(l->op != OKEY) { - l = nod(OKEY, nodintconst(i), l); - l->left->type = types[TINT]; - l->left->typecheck = 1; - ll->n = l; - } - - typecheck(&l->left, Erv); - evconst(l->left); - i = nonnegconst(l->left); - if(i < 0 && !l->left->diag) { - yyerror("array index must be non-negative integer constant"); - l->left->diag = 1; - i = -(1<<30); // stay negative for a while - } - if(i >= 0) - indexdup(l->left, hash, nhash); - i++; - if(i > length) { - length = i; - if(t->bound >= 0 && length > t->bound) { - setlineno(l); - yyerror("array index %lld out of bounds [0:%lld]", length-1, t->bound); - t->bound = -1; // no more errors - } - } - - r = l->right; - pushtype(r, t->type); - typecheck(&r, Erv); - defaultlit(&r, t->type); - l->right = assignconv(r, t->type, "array element"); - } - if(t->bound == -100) - t->bound = length; - if(t->bound < 0) - n->right = nodintconst(length); - n->op = OARRAYLIT; - break; - - case TMAP: - nhash = inithash(n, &hash, autohash, nelem(autohash)); - - for(ll=n->list; ll; ll=ll->next) { - l = ll->n; - setlineno(l); - if(l->op != OKEY) { - typecheck(&ll->n, Erv); - yyerror("missing key in map literal"); - continue; - } - - typecheck(&l->left, Erv); - defaultlit(&l->left, t->down); - l->left = assignconv(l->left, t->down, "map key"); - if (l->left->op != OCONV) - keydup(l->left, hash, nhash); - - r = l->right; - pushtype(r, t->type); - typecheck(&r, Erv); - defaultlit(&r, t->type); - l->right = assignconv(r, t->type, "map value"); - } - n->op = OMAPLIT; - break; - - case TSTRUCT: - bad = 0; - if(n->list != nil && nokeys(n->list)) { - // simple list of variables - f = t->type; - for(ll=n->list; ll; ll=ll->next) { - setlineno(ll->n); - typecheck(&ll->n, Erv); - if(f == nil) { - if(!bad++) - yyerror("too many values in struct initializer"); - continue; - } - s = f->sym; - if(s != nil && !exportname(s->name) && s->pkg != localpkg) - yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t); - // No pushtype allowed here. Must name fields for that. - ll->n = assignconv(ll->n, f->type, "field value"); - ll->n = nod(OKEY, newname(f->sym), ll->n); - ll->n->left->type = f; - ll->n->left->typecheck = 1; - f = f->down; - } - if(f != nil) - yyerror("too few values in struct initializer"); - } else { - nhash = inithash(n, &hash, autohash, nelem(autohash)); - - // keyed list - for(ll=n->list; ll; ll=ll->next) { - l = ll->n; - setlineno(l); - if(l->op != OKEY) { - if(!bad++) - yyerror("mixture of field:value and value initializers"); - typecheck(&ll->n, Erv); - continue; - } - s = l->left->sym; - if(s == S) { - yyerror("invalid field name %N in struct initializer", l->left); - typecheck(&l->right, Erv); - continue; - } - - // Sym might have resolved to name in other top-level - // package, because of import dot. Redirect to correct sym - // before we do the lookup. - if(s->pkg != localpkg && exportname(s->name)) { - s1 = lookup(s->name); - if(s1->origpkg == s->pkg) - s = s1; - } - f = lookdot1(nil, s, t, t->type, 0); - if(f == nil) { - yyerror("unknown %T field '%S' in struct literal", t, s); - continue; - } - l->left = newname(s); - l->left->typecheck = 1; - l->left->type = f; - s = f->sym; - fielddup(newname(s), hash, nhash); - r = l->right; - // No pushtype allowed here. Tried and rejected. - typecheck(&r, Erv); - l->right = assignconv(r, f->type, "field value"); - } - } - n->op = OSTRUCTLIT; - break; - } - if(nerr != nerrors) - goto error; - - n->orig = norig; - if(isptr[n->type->etype]) { - n = nod(OPTRLIT, n, N); - n->typecheck = 1; - n->type = n->left->type; - n->left->type = t; - n->left->typecheck = 1; - } - - n->orig = norig; - *np = n; - lineno = lno; - return; - -error: - n->type = T; - *np = n; - lineno = lno; -} - -/* - * lvalue etc - */ -int -islvalue(Node *n) -{ - switch(n->op) { - case OINDEX: - if(isfixedarray(n->left->type)) - return islvalue(n->left); - if(n->left->type != T && n->left->type->etype == TSTRING) - return 0; - // fall through - case OIND: - case ODOTPTR: - case OCLOSUREVAR: - case OPARAM: - return 1; - case ODOT: - return islvalue(n->left); - case ONAME: - if(n->class == PFUNC) - return 0; - return 1; - } - return 0; -} - -static void -checklvalue(Node *n, char *verb) -{ - if(!islvalue(n)) - yyerror("cannot %s %N", verb, n); -} - -void -checkassign(Node *stmt, Node *n) -{ - Node *r, *l; - - // Variables declared in ORANGE are assigned on every iteration. - if(n->defn != stmt || stmt->op == ORANGE) { - r = outervalue(n); - for(l = n; l != r; l = l->left) { - l->assigned = 1; - if(l->closure) - l->closure->assigned = 1; - } - l->assigned = 1; - if(l->closure) - l->closure->assigned = 1; - } - - if(islvalue(n)) - return; - if(n->op == OINDEXMAP) { - n->etype = 1; - return; - } - - // have already complained about n being undefined - if(n->op == ONONAME) - return; - - yyerror("cannot assign to %N", n); -} - -static void -checkassignlist(Node *stmt, NodeList *l) -{ - for(; l; l=l->next) - checkassign(stmt, l->n); -} - -// Check whether l and r are the same side effect-free expression, -// so that it is safe to reuse one instead of computing both. -int -samesafeexpr(Node *l, Node *r) -{ - if(l->op != r->op || !eqtype(l->type, r->type)) - return 0; - - switch(l->op) { - case ONAME: - case OCLOSUREVAR: - return l == r; - - case ODOT: - case ODOTPTR: - return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left); - - case OIND: - return samesafeexpr(l->left, r->left); - - case OINDEX: - return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right); - } - - return 0; -} - -/* - * type check assignment. - * if this assignment is the definition of a var on the left side, - * fill in the var's type. - */ - -static void -typecheckas(Node *n) -{ - // delicate little dance. - // the definition of n may refer to this assignment - // as its definition, in which case it will call typecheckas. - // in that case, do not call typecheck back, or it will cycle. - // if the variable has a type (ntype) then typechecking - // will not look at defn, so it is okay (and desirable, - // so that the conversion below happens). - n->left = resolve(n->left); - if(n->left->defn != n || n->left->ntype) - typecheck(&n->left, Erv | Easgn); - - typecheck(&n->right, Erv); - checkassign(n, n->left); - if(n->right && n->right->type != T) { - if(n->left->type != T) - n->right = assignconv(n->right, n->left->type, "assignment"); - } - if(n->left->defn == n && n->left->ntype == N) { - defaultlit(&n->right, T); - n->left->type = n->right->type; - } - - // second half of dance. - // now that right is done, typecheck the left - // just to get it over with. see dance above. - n->typecheck = 1; - if(n->left->typecheck == 0) - typecheck(&n->left, Erv | Easgn); - - // Recognize slices being updated in place, for better code generation later. - // Don't rewrite if using race detector, to avoid needing to teach race detector - // about this optimization. - if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) { - switch(n->right->op) { - case OSLICE: - case OSLICE3: - case OSLICESTR: - // For x = x[0:y], x can be updated in place, without touching pointer. - // TODO(rsc): Reenable once it is actually updated in place without touching the pointer. - if(0 && samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left))) - n->right->reslice = 1; - break; - - case OAPPEND: - // For x = append(x, ...), x can be updated in place when there is capacity, - // without touching the pointer; otherwise the emitted code to growslice - // can take care of updating the pointer, and only in that case. - // TODO(rsc): Reenable once the emitted code does update the pointer. - if(0 && n->right->list != nil && samesafeexpr(n->left, n->right->list->n)) - n->right->reslice = 1; - break; - } - } -} - -static void -checkassignto(Type *src, Node *dst) -{ - char *why; - - if(assignop(src, dst->type, &why) == 0) { - yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why); - return; - } -} - -static void -typecheckas2(Node *n) -{ - int cl, cr; - NodeList *ll, *lr; - Node *l, *r; - Iter s; - Type *t; - - for(ll=n->list; ll; ll=ll->next) { - // delicate little dance. - ll->n = resolve(ll->n); - if(ll->n->defn != n || ll->n->ntype) - typecheck(&ll->n, Erv | Easgn); - } - cl = count(n->list); - cr = count(n->rlist); - if(cl > 1 && cr == 1) - typecheck(&n->rlist->n, Erv | Efnstruct); - else - typechecklist(n->rlist, Erv); - checkassignlist(n, n->list); - - if(cl == cr) { - // easy - for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) { - if(ll->n->type != T && lr->n->type != T) - lr->n = assignconv(lr->n, ll->n->type, "assignment"); - if(ll->n->defn == n && ll->n->ntype == N) { - defaultlit(&lr->n, T); - ll->n->type = lr->n->type; - } - } - goto out; - } - - - l = n->list->n; - r = n->rlist->n; - - // x,y,z = f() - if(cr == 1) { - if(r->type == T) - goto out; - switch(r->op) { - case OCALLMETH: - case OCALLINTER: - case OCALLFUNC: - if(r->type->etype != TSTRUCT || r->type->funarg == 0) - break; - cr = structcount(r->type); - if(cr != cl) - goto mismatch; - n->op = OAS2FUNC; - t = structfirst(&s, &r->type); - for(ll=n->list; ll; ll=ll->next) { - if(t->type != T && ll->n->type != T) - checkassignto(t->type, ll->n); - if(ll->n->defn == n && ll->n->ntype == N) - ll->n->type = t->type; - t = structnext(&s); - } - goto out; - } - } - - // x, ok = y - if(cl == 2 && cr == 1) { - if(r->type == T) - goto out; - switch(r->op) { - case OINDEXMAP: - case ORECV: - case ODOTTYPE: - switch(r->op) { - case OINDEXMAP: - n->op = OAS2MAPR; - break; - case ORECV: - n->op = OAS2RECV; - break; - case ODOTTYPE: - n->op = OAS2DOTTYPE; - r->op = ODOTTYPE2; - break; - } - if(l->type != T) - checkassignto(r->type, l); - if(l->defn == n) - l->type = r->type; - l = n->list->next->n; - if(l->type != T && l->type->etype != TBOOL) - checkassignto(types[TBOOL], l); - if(l->defn == n && l->ntype == N) - l->type = types[TBOOL]; - goto out; - } - } - -mismatch: - yyerror("assignment count mismatch: %d = %d", cl, cr); - -out: - // second half of dance - n->typecheck = 1; - for(ll=n->list; ll; ll=ll->next) - if(ll->n->typecheck == 0) - typecheck(&ll->n, Erv | Easgn); -} - -/* - * type check function definition - */ -static void -typecheckfunc(Node *n) -{ - Type *t, *rcvr; - NodeList *l; - - typecheck(&n->nname, Erv | Easgn); - if((t = n->nname->type) == T) - return; - n->type = t; - t->nname = n->nname; - rcvr = getthisx(t)->type; - if(rcvr != nil && n->shortname != N && !isblank(n->shortname)) - addmethod(n->shortname->sym, t, 1, n->nname->nointerface); - - for(l=n->dcl; l; l=l->next) - if(l->n->op == ONAME && (l->n->class == PPARAM || l->n->class == PPARAMOUT)) - l->n->decldepth = 1; -} - -static void -stringtoarraylit(Node **np) -{ - int32 i; - NodeList *l; - Strlit *s; - char *p, *ep; - Rune r; - Node *nn, *n; - - n = *np; - if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR) - fatal("stringtoarraylit %N", n); - - s = n->left->val.u.sval; - l = nil; - p = s->s; - ep = s->s + s->len; - i = 0; - if(n->type->type->etype == TUINT8) { - // raw []byte - while(p < ep) - l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++))); - } else { - // utf-8 []rune - while(p < ep) { - p += chartorune(&r, p); - l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r))); - } - } - nn = nod(OCOMPLIT, N, typenod(n->type)); - nn->list = l; - typecheck(&nn, Erv); - *np = nn; -} - - -static int ntypecheckdeftype; -static NodeList *methodqueue; - -static void -domethod(Node *n) -{ - Node *nt; - Type *t; - - nt = n->type->nname; - typecheck(&nt, Etype); - if(nt->type == T) { - // type check failed; leave empty func - n->type->etype = TFUNC; - n->type->nod = N; - return; - } - - // If we have - // type I interface { - // M(_ int) - // } - // then even though I.M looks like it doesn't care about the - // value of its argument, a specific implementation of I may - // care. The _ would suppress the assignment to that argument - // while generating a call, so remove it. - for(t=getinargx(nt->type)->type; t; t=t->down) { - if(t->sym != nil && strcmp(t->sym->name, "_") == 0) - t->sym = nil; - } - - *n->type = *nt->type; - n->type->nod = N; - checkwidth(n->type); -} - -static NodeList *mapqueue; - -void -copytype(Node *n, Type *t) -{ - int maplineno, embedlineno, lno; - NodeList *l; - - if(t->etype == TFORW) { - // This type isn't computed yet; when it is, update n. - t->copyto = list(t->copyto, n); - return; - } - - maplineno = n->type->maplineno; - embedlineno = n->type->embedlineno; - - l = n->type->copyto; - *n->type = *t; - - t = n->type; - t->sym = n->sym; - t->local = n->local; - t->vargen = n->vargen; - t->siggen = 0; - t->method = nil; - t->xmethod = nil; - t->nod = N; - t->printed = 0; - t->deferwidth = 0; - t->copyto = nil; - - // Update nodes waiting on this type. - for(; l; l=l->next) - copytype(l->n, t); - - // Double-check use of type as embedded type. - lno = lineno; - if(embedlineno) { - lineno = embedlineno; - if(isptr[t->etype]) - yyerror("embedded type cannot be a pointer"); - } - lineno = lno; - - // Queue check for map until all the types are done settling. - if(maplineno) { - t->maplineno = maplineno; - mapqueue = list(mapqueue, n); - } -} - -static void -typecheckdeftype(Node *n) -{ - int lno; - Type *t; - NodeList *l; - - ntypecheckdeftype++; - lno = lineno; - setlineno(n); - n->type->sym = n->sym; - n->typecheck = 1; - typecheck(&n->ntype, Etype); - if((t = n->ntype->type) == T) { - n->diag = 1; - n->type = T; - goto ret; - } - if(n->type == T) { - n->diag = 1; - goto ret; - } - - // copy new type and clear fields - // that don't come along. - // anything zeroed here must be zeroed in - // typedcl2 too. - copytype(n, t); - -ret: - lineno = lno; - - // if there are no type definitions going on, it's safe to - // try to resolve the method types for the interfaces - // we just read. - if(ntypecheckdeftype == 1) { - while((l = methodqueue) != nil) { - methodqueue = nil; - for(; l; l=l->next) - domethod(l->n); - } - for(l=mapqueue; l; l=l->next) { - lineno = l->n->type->maplineno; - maptype(l->n->type, types[TBOOL]); - } - lineno = lno; - } - ntypecheckdeftype--; -} - -void -queuemethod(Node *n) -{ - if(ntypecheckdeftype == 0) { - domethod(n); - return; - } - methodqueue = list(methodqueue, n); -} - -Node* -typecheckdef(Node *n) -{ - int lno, nerrors0; - Node *e; - Type *t; - NodeList *l; - - lno = lineno; - setlineno(n); - - if(n->op == ONONAME) { - if(!n->diag) { - n->diag = 1; - if(n->lineno != 0) - lineno = n->lineno; - // Note: adderrorname looks for this string and - // adds context about the outer expression - yyerror("undefined: %S", n->sym); - } - return n; - } - - if(n->walkdef == 1) - return n; - - l = mal(sizeof *l); - l->n = n; - l->next = typecheckdefstack; - typecheckdefstack = l; - - if(n->walkdef == 2) { - flusherrors(); - print("typecheckdef loop:"); - for(l=typecheckdefstack; l; l=l->next) - print(" %S", l->n->sym); - print("\n"); - fatal("typecheckdef loop"); - } - n->walkdef = 2; - - if(n->type != T || n->sym == S) // builtin or no name - goto ret; - - switch(n->op) { - default: - fatal("typecheckdef %O", n->op); - - case OGOTO: - case OLABEL: - // not really syms - break; - - case OLITERAL: - if(n->ntype != N) { - typecheck(&n->ntype, Etype); - n->type = n->ntype->type; - n->ntype = N; - if(n->type == T) { - n->diag = 1; - goto ret; - } - } - e = n->defn; - n->defn = N; - if(e == N) { - lineno = n->lineno; - dump("typecheckdef nil defn", n); - yyerror("xxx"); - } - typecheck(&e, Erv | Eiota); - if(isconst(e, CTNIL)) { - yyerror("const initializer cannot be nil"); - goto ret; - } - if(e->type != T && e->op != OLITERAL || !isgoconst(e)) { - if(!e->diag) { - yyerror("const initializer %N is not a constant", e); - e->diag = 1; - } - goto ret; - } - t = n->type; - if(t != T) { - if(!okforconst[t->etype]) { - yyerror("invalid constant type %T", t); - goto ret; - } - if(!isideal(e->type) && !eqtype(t, e->type)) { - yyerror("cannot use %lN as type %T in const initializer", e, t); - goto ret; - } - convlit(&e, t); - } - n->val = e->val; - n->type = e->type; - break; - - case ONAME: - if(n->ntype != N) { - typecheck(&n->ntype, Etype); - n->type = n->ntype->type; - - if(n->type == T) { - n->diag = 1; - goto ret; - } - } - if(n->type != T) - break; - if(n->defn == N) { - if(n->etype != 0) // like OPRINTN - break; - if(nsavederrors+nerrors > 0) { - // Can have undefined variables in x := foo - // that make x have an n->ndefn == nil. - // If there are other errors anyway, don't - // bother adding to the noise. - break; - } - fatal("var without type, init: %S", n->sym); - } - if(n->defn->op == ONAME) { - typecheck(&n->defn, Erv); - n->type = n->defn->type; - break; - } - typecheck(&n->defn, Etop); // fills in n->type - break; - - case OTYPE: - if(curfn) - defercheckwidth(); - n->walkdef = 1; - n->type = typ(TFORW); - n->type->sym = n->sym; - nerrors0 = nerrors; - typecheckdeftype(n); - if(n->type->etype == TFORW && nerrors > nerrors0) { - // Something went wrong during type-checking, - // but it was reported. Silence future errors. - n->type->broke = 1; - } - if(curfn) - resumecheckwidth(); - break; - - case OPACK: - // nothing to see here - break; - } - -ret: - if(n->op != OLITERAL && n->type != T && isideal(n->type)) - fatal("got %T for %N", n->type, n); - if(typecheckdefstack->n != n) - fatal("typecheckdefstack mismatch"); - l = typecheckdefstack; - typecheckdefstack = l->next; - - lineno = lno; - n->walkdef = 1; - return n; -} - -static int -checkmake(Type *t, char *arg, Node *n) -{ - if(n->op == OLITERAL) { - switch(n->val.ctype) { - case CTINT: - case CTRUNE: - case CTFLT: - case CTCPLX: - n->val = toint(n->val); - if(mpcmpfixc(n->val.u.xval, 0) < 0) { - yyerror("negative %s argument in make(%T)", arg, t); - return -1; - } - if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) { - yyerror("%s argument too large in make(%T)", arg, t); - return -1; - } - - // Delay defaultlit until after we've checked range, to avoid - // a redundant "constant NNN overflows int" error. - defaultlit(&n, types[TINT]); - return 0; - default: - break; - } - } - - if(!isint[n->type->etype] && n->type->etype != TIDEAL) { - yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type); - return -1; - } - - // Defaultlit still necessary for non-constant: n might be 1<op) { - case OBREAK: - if(n->left == N) { - if(implicit) - implicit->hasbreak = 1; - } else { - lab = n->left->sym->label; - if(lab != L) - lab->def->hasbreak = 1; - } - break; - - case OFOR: - case OSWITCH: - case OTYPESW: - case OSELECT: - case ORANGE: - implicit = n; - // fall through - - default: - markbreak(n->left, implicit); - markbreak(n->right, implicit); - markbreak(n->ntest, implicit); - markbreak(n->nincr, implicit); - markbreaklist(n->ninit, implicit); - markbreaklist(n->nbody, implicit); - markbreaklist(n->nelse, implicit); - markbreaklist(n->list, implicit); - markbreaklist(n->rlist, implicit); - break; - } -} - -static void -markbreaklist(NodeList *l, Node *implicit) -{ - Node *n; - Label *lab; - - for(; l; l=l->next) { - n = l->n; - if(n->op == OLABEL && l->next && n->defn == l->next->n) { - switch(n->defn->op) { - case OFOR: - case OSWITCH: - case OTYPESW: - case OSELECT: - case ORANGE: - lab = mal(sizeof *lab); - lab->def = n->defn; - n->left->sym->label = lab; - markbreak(n->defn, n->defn); - n->left->sym->label = L; - l = l->next; - continue; - } - } - markbreak(n, implicit); - } -} - -static int -isterminating(NodeList *l, int top) -{ - int def; - Node *n; - - if(l == nil) - return 0; - if(top) { - while(l->next && l->n->op != OLABEL) - l = l->next; - markbreaklist(l, nil); - } - while(l->next) - l = l->next; - n = l->n; - - if(n == N) - return 0; - - switch(n->op) { - // NOTE: OLABEL is treated as a separate statement, - // not a separate prefix, so skipping to the last statement - // in the block handles the labeled statement case by - // skipping over the label. No case OLABEL here. - - case OBLOCK: - return isterminating(n->list, 0); - - case OGOTO: - case ORETURN: - case ORETJMP: - case OPANIC: - case OXFALL: - return 1; - - case OFOR: - if(n->ntest != N) - return 0; - if(n->hasbreak) - return 0; - return 1; - - case OIF: - return isterminating(n->nbody, 0) && isterminating(n->nelse, 0); - - case OSWITCH: - case OTYPESW: - case OSELECT: - if(n->hasbreak) - return 0; - def = 0; - for(l=n->list; l; l=l->next) { - if(!isterminating(l->n->nbody, 0)) - return 0; - if(l->n->list == nil) // default - def = 1; - } - if(n->op != OSELECT && !def) - return 0; - return 1; - } - - return 0; -} - -void -checkreturn(Node *fn) -{ - if(fn->type->outtuple && fn->nbody != nil) - if(!isterminating(fn->nbody, 1)) - yyerrorl(fn->endlineno, "missing return at end of function"); -} diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c deleted file mode 100644 index 95d212e92b..0000000000 --- a/src/cmd/gc/unsafe.c +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" - -/* - * look for - * unsafe.Sizeof - * unsafe.Offsetof - * unsafe.Alignof - * rewrite with a constant - */ -Node* -unsafenmagic(Node *nn) -{ - Node *r, *n, *base, *r1; - Sym *s; - Type *t, *tr; - vlong v; - Val val; - Node *fn; - NodeList *args; - - fn = nn->left; - args = nn->list; - - if(safemode || fn == N || fn->op != ONAME) - goto no; - if((s = fn->sym) == S) - goto no; - if(s->pkg != unsafepkg) - goto no; - - if(args == nil) { - yyerror("missing argument for %S", s); - goto no; - } - r = args->n; - - if(strcmp(s->name, "Sizeof") == 0) { - typecheck(&r, Erv); - defaultlit(&r, T); - tr = r->type; - if(tr == T) - goto bad; - dowidth(tr); - v = tr->width; - goto yes; - } - if(strcmp(s->name, "Offsetof") == 0) { - // must be a selector. - if(r->op != OXDOT) - goto bad; - // Remember base of selector to find it back after dot insertion. - // Since r->left may be mutated by typechecking, check it explicitly - // first to track it correctly. - typecheck(&r->left, Erv); - base = r->left; - typecheck(&r, Erv); - switch(r->op) { - case ODOT: - case ODOTPTR: - break; - case OCALLPART: - yyerror("invalid expression %N: argument is a method value", nn); - v = 0; - goto ret; - default: - goto bad; - } - v = 0; - // add offsets for inserted dots. - for(r1=r; r1->left!=base; r1=r1->left) { - switch(r1->op) { - case ODOT: - v += r1->xoffset; - break; - case ODOTPTR: - yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left); - goto ret; - default: - dump("unsafenmagic", r); - fatal("impossible %#O node after dot insertion", r1->op); - goto bad; - } - } - v += r1->xoffset; - goto yes; - } - if(strcmp(s->name, "Alignof") == 0) { - typecheck(&r, Erv); - defaultlit(&r, T); - tr = r->type; - if(tr == T) - goto bad; - - // make struct { byte; T; } - t = typ(TSTRUCT); - t->type = typ(TFIELD); - t->type->type = types[TUINT8]; - t->type->down = typ(TFIELD); - t->type->down->type = tr; - // compute struct widths - dowidth(t); - - // the offset of T is its required alignment - v = t->type->down->width; - goto yes; - } - -no: - return N; - -bad: - yyerror("invalid expression %N", nn); - v = 0; - goto ret; - -yes: - if(args->next != nil) - yyerror("extra arguments for %S", s); -ret: - // any side effects disappear; ignore init - val.ctype = CTINT; - val.u.xval = mal(sizeof(*n->val.u.xval)); - mpmovecfix(val.u.xval, v); - n = nod(OLITERAL, N, N); - n->orig = nn; - n->val = val; - n->type = types[TUINTPTR]; - nn->type = types[TUINTPTR]; - return n; -} - -int -isunsafebuiltin(Node *n) -{ - if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg) - return 0; - if(strcmp(n->sym->name, "Sizeof") == 0) - return 1; - if(strcmp(n->sym->name, "Offsetof") == 0) - return 1; - if(strcmp(n->sym->name, "Alignof") == 0) - return 1; - return 0; -} diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go deleted file mode 100644 index c3c627815a..0000000000 --- a/src/cmd/gc/unsafe.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// NOTE: If you change this file you must run "./mkbuiltin" -// to update builtin.c.boot. This is not done automatically -// to avoid depending on having a working compiler binary. - -// +build ignore - -package PACKAGE - -type Pointer uintptr // not really; filled in by compiler - -// return types here are ignored; see unsafe.c -func Offsetof(any) uintptr -func Sizeof(any) uintptr -func Alignof(any) uintptr diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c deleted file mode 100644 index 50dae8ca68..0000000000 --- a/src/cmd/gc/walk.c +++ /dev/null @@ -1,4189 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include -#include -#include "go.h" -#include "../ld/textflag.h" -#include "../../runtime/mgc0.h" - -static Node* walkprint(Node*, NodeList**); -static Node* writebarrierfn(char*, Type*, Type*); -static Node* applywritebarrier(Node*, NodeList**); -static Node* mapfn(char*, Type*); -static Node* mapfndel(char*, Type*); -static Node* ascompatee1(int, Node*, Node*, NodeList**); -static NodeList* ascompatee(int, NodeList*, NodeList*, NodeList**); -static NodeList* ascompatet(int, NodeList*, Type**, int, NodeList**); -static NodeList* ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**); -static Node* convas(Node*, NodeList**); -static void heapmoves(void); -static NodeList* paramstoheap(Type **argin, int out); -static NodeList* reorder1(NodeList*); -static NodeList* reorder3(NodeList*); -static Node* addstr(Node*, NodeList**); -static Node* appendslice(Node*, NodeList**); -static Node* append(Node*, NodeList**); -static Node* copyany(Node*, NodeList**, int); -static Node* sliceany(Node*, NodeList**); -static void walkcompare(Node**, NodeList**); -static void walkrotate(Node**); -static void walkmul(Node**, NodeList**); -static void walkdiv(Node**, NodeList**); -static int bounded(Node*, int64); -static Mpint mpzero; -static void walkprintfunc(Node**, NodeList**); - -// The constant is known to runtime. -enum -{ - tmpstringbufsize = 32, -}; - -void -walk(Node *fn) -{ - char s[50]; - NodeList *l; - int lno; - - curfn = fn; - - if(debug['W']) { - snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym); - dumplist(s, curfn->nbody); - } - - lno = lineno; - - // Final typecheck for any unused variables. - // It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below. - for(l=fn->dcl; l; l=l->next) - if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO) - typecheck(&l->n, Erv | Easgn); - - // Propagate the used flag for typeswitch variables up to the NONAME in it's definition. - for(l=fn->dcl; l; l=l->next) - if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used) - l->n->defn->left->used++; - - for(l=fn->dcl; l; l=l->next) { - if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used) - continue; - if(l->n->defn && l->n->defn->op == OTYPESW) { - if(l->n->defn->left->used) - continue; - lineno = l->n->defn->left->lineno; - yyerror("%S declared and not used", l->n->sym); - l->n->defn->left->used = 1; // suppress repeats - } else { - lineno = l->n->lineno; - yyerror("%S declared and not used", l->n->sym); - } - } - - lineno = lno; - if(nerrors != 0) - return; - walkstmtlist(curfn->nbody); - if(debug['W']) { - snprint(s, sizeof(s), "after walk %S", curfn->nname->sym); - dumplist(s, curfn->nbody); - } - heapmoves(); - if(debug['W'] && curfn->enter != nil) { - snprint(s, sizeof(s), "enter %S", curfn->nname->sym); - dumplist(s, curfn->enter); - } -} - - -void -walkstmtlist(NodeList *l) -{ - for(; l; l=l->next) - walkstmt(&l->n); -} - -static int -samelist(NodeList *a, NodeList *b) -{ - for(; a && b; a=a->next, b=b->next) - if(a->n != b->n) - return 0; - return a == b; -} - -static int -paramoutheap(Node *fn) -{ - NodeList *l; - - for(l=fn->dcl; l; l=l->next) { - switch(l->n->class) { - case PPARAMOUT: - case PPARAMOUT|PHEAP: - return l->n->addrtaken; - case PAUTO: - case PAUTO|PHEAP: - // stop early - parameters are over - return 0; - } - } - return 0; -} - -// adds "adjust" to all the argument locations for the call n. -// n must be a defer or go node that has already been walked. -static void -adjustargs(Node *n, int adjust) -{ - Node *callfunc, *arg, *lhs; - NodeList *args; - - callfunc = n->left; - for(args = callfunc->list; args != 0; args = args->next) { - arg = args->n; - if(arg->op != OAS) - yyerror("call arg not assignment"); - lhs = arg->left; - if(lhs->op == ONAME) { - // This is a temporary introduced by reorder1. - // The real store to the stack appears later in the arg list. - continue; - } - if(lhs->op != OINDREG) { - yyerror("call argument store does not use OINDREG"); - } - // can't really check this in machine-indep code. - //if(lhs->val.u.reg != D_SP) - // yyerror("call arg assign not indreg(SP)"); - lhs->xoffset += adjust; - } -} - -void -walkstmt(Node **np) -{ - NodeList *init; - NodeList *ll, *rl; - int cl; - Node *n, *f; - - n = *np; - if(n == N) - return; - if(n->dodata == 2) // don't walk, generated by anylit. - return; - - setlineno(n); - - walkstmtlist(n->ninit); - - switch(n->op) { - default: - if(n->op == ONAME) - yyerror("%S is not a top level statement", n->sym); - else - yyerror("%O is not a top level statement", n->op); - dump("nottop", n); - break; - - case OAS: - case OASOP: - case OAS2: - case OAS2DOTTYPE: - case OAS2RECV: - case OAS2FUNC: - case OAS2MAPR: - case OCLOSE: - case OCOPY: - case OCALLMETH: - case OCALLINTER: - case OCALL: - case OCALLFUNC: - case ODELETE: - case OSEND: - case OPRINT: - case OPRINTN: - case OPANIC: - case OEMPTY: - case ORECOVER: - if(n->typecheck == 0) - fatal("missing typecheck: %+N", n); - init = n->ninit; - n->ninit = nil; - walkexpr(&n, &init); - addinit(&n, init); - if((*np)->op == OCOPY && n->op == OCONVNOP) - n->op = OEMPTY; // don't leave plain values as statements. - break; - - case ORECV: - // special case for a receive where we throw away - // the value received. - if(n->typecheck == 0) - fatal("missing typecheck: %+N", n); - init = n->ninit; - n->ninit = nil; - - walkexpr(&n->left, &init); - n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil()); - walkexpr(&n, &init); - - addinit(&n, init); - break; - - case OBREAK: - case ODCL: - case OCONTINUE: - case OFALL: - case OGOTO: - case OLABEL: - case ODCLCONST: - case ODCLTYPE: - case OCHECKNIL: - case OVARKILL: - break; - - case OBLOCK: - walkstmtlist(n->list); - break; - - case OXCASE: - yyerror("case statement out of place"); - n->op = OCASE; - case OCASE: - walkstmt(&n->right); - break; - - case ODEFER: - hasdefer = 1; - switch(n->left->op) { - case OPRINT: - case OPRINTN: - walkprintfunc(&n->left, &n->ninit); - break; - case OCOPY: - n->left = copyany(n->left, &n->ninit, 1); - break; - default: - walkexpr(&n->left, &n->ninit); - break; - } - // make room for size & fn arguments. - adjustargs(n, 2 * widthptr); - break; - - case OFOR: - if(n->ntest != N) { - walkstmtlist(n->ntest->ninit); - init = n->ntest->ninit; - n->ntest->ninit = nil; - walkexpr(&n->ntest, &init); - addinit(&n->ntest, init); - } - walkstmt(&n->nincr); - walkstmtlist(n->nbody); - break; - - case OIF: - walkexpr(&n->ntest, &n->ninit); - walkstmtlist(n->nbody); - walkstmtlist(n->nelse); - break; - - case OPROC: - switch(n->left->op) { - case OPRINT: - case OPRINTN: - walkprintfunc(&n->left, &n->ninit); - break; - case OCOPY: - n->left = copyany(n->left, &n->ninit, 1); - break; - default: - walkexpr(&n->left, &n->ninit); - break; - } - // make room for size & fn arguments. - adjustargs(n, 2 * widthptr); - break; - - case ORETURN: - walkexprlist(n->list, &n->ninit); - if(n->list == nil) - break; - if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) { - // assign to the function out parameters, - // so that reorder3 can fix up conflicts - rl = nil; - for(ll=curfn->dcl; ll != nil; ll=ll->next) { - cl = ll->n->class & ~PHEAP; - if(cl == PAUTO) - break; - if(cl == PPARAMOUT) - rl = list(rl, ll->n); - } - if(samelist(rl, n->list)) { - // special return in disguise - n->list = nil; - break; - } - if(count(n->list) == 1 && count(rl) > 1) { - // OAS2FUNC in disguise - f = n->list->n; - if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER) - fatal("expected return of call, have %N", f); - n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit)); - break; - } - - // move function calls out, to make reorder3's job easier. - walkexprlistsafe(n->list, &n->ninit); - ll = ascompatee(n->op, rl, n->list, &n->ninit); - n->list = reorder3(ll); - break; - } - ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit); - n->list = ll; - break; - - case ORETJMP: - break; - - case OSELECT: - walkselect(n); - break; - - case OSWITCH: - walkswitch(n); - break; - - case ORANGE: - walkrange(n); - break; - - case OXFALL: - yyerror("fallthrough statement out of place"); - n->op = OFALL; - break; - } - - if(n->op == ONAME) - fatal("walkstmt ended up with name: %+N", n); - - *np = n; -} - - -/* - * walk the whole tree of the body of an - * expression or simple statement. - * the types expressions are calculated. - * compile-time constants are evaluated. - * complex side effects like statements are appended to init - */ - -void -walkexprlist(NodeList *l, NodeList **init) -{ - for(; l; l=l->next) - walkexpr(&l->n, init); -} - -void -walkexprlistsafe(NodeList *l, NodeList **init) -{ - for(; l; l=l->next) { - l->n = safeexpr(l->n, init); - walkexpr(&l->n, init); - } -} - -void -walkexprlistcheap(NodeList *l, NodeList **init) -{ - for(; l; l=l->next) { - l->n = cheapexpr(l->n, init); - walkexpr(&l->n, init); - } -} - -void -walkexpr(Node **np, NodeList **init) -{ - Node *r, *l, *var, *a, *ok; - Node *map, *key; - NodeList *ll, *lr; - Type *t; - int et, old_safemode; - int64 v; - int32 lno; - Node *n, *fn, *n1, *n2; - Sym *sym; - char buf[100], *p, *from, *to; - - n = *np; - - if(n == N) - return; - - if(init == &n->ninit) { - // not okay to use n->ninit when walking n, - // because we might replace n with some other node - // and would lose the init list. - fatal("walkexpr init == &n->ninit"); - } - - if(n->ninit != nil) { - walkstmtlist(n->ninit); - *init = concat(*init, n->ninit); - n->ninit = nil; - } - - // annoying case - not typechecked - if(n->op == OKEY) { - walkexpr(&n->left, init); - walkexpr(&n->right, init); - return; - } - - lno = setlineno(n); - - if(debug['w'] > 1) - dump("walk-before", n); - - if(n->typecheck != 1) - fatal("missed typecheck: %+N\n", n); - - switch(n->op) { - default: - dump("walk", n); - fatal("walkexpr: switch 1 unknown op %+hN", n); - break; - - case OTYPE: - case ONONAME: - case OINDREG: - case OEMPTY: - case OPARAM: - goto ret; - - case ONOT: - case OMINUS: - case OPLUS: - case OCOM: - case OREAL: - case OIMAG: - case ODOTMETH: - case ODOTINTER: - walkexpr(&n->left, init); - goto ret; - - case OIND: - walkexpr(&n->left, init); - goto ret; - - case ODOT: - usefield(n); - walkexpr(&n->left, init); - goto ret; - - case ODOTPTR: - usefield(n); - if(n->op == ODOTPTR && n->left->type->type->width == 0) { - // No actual copy will be generated, so emit an explicit nil check. - n->left = cheapexpr(n->left, init); - checknil(n->left, init); - } - walkexpr(&n->left, init); - goto ret; - - case OEFACE: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - goto ret; - - case OSPTR: - case OITAB: - walkexpr(&n->left, init); - goto ret; - - case OLEN: - case OCAP: - walkexpr(&n->left, init); - - // replace len(*[10]int) with 10. - // delayed until now to preserve side effects. - t = n->left->type; - if(isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) { - safeexpr(n->left, init); - nodconst(n, n->type, t->bound); - n->typecheck = 1; - } - goto ret; - - case OLSH: - case ORSH: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - t = n->left->type; - n->bounded = bounded(n->right, 8*t->width); - if(debug['m'] && n->etype && !isconst(n->right, CTINT)) - warn("shift bounds check elided"); - goto ret; - - case OAND: - case OSUB: - case OHMUL: - case OLT: - case OLE: - case OGE: - case OGT: - case OADD: - case OCOMPLEX: - case OLROT: - // Use results from call expression as arguments for complex. - if(n->op == OCOMPLEX && n->left == N && n->right == N) { - n->left = n->list->n; - n->right = n->list->next->n; - } - walkexpr(&n->left, init); - walkexpr(&n->right, init); - goto ret; - - case OOR: - case OXOR: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - walkrotate(&n); - goto ret; - - case OEQ: - case ONE: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - // Disable safemode while compiling this code: the code we - // generate internally can refer to unsafe.Pointer. - // In this case it can happen if we need to generate an == - // for a struct containing a reflect.Value, which itself has - // an unexported field of type unsafe.Pointer. - old_safemode = safemode; - safemode = 0; - walkcompare(&n, init); - safemode = old_safemode; - goto ret; - - case OANDAND: - case OOROR: - walkexpr(&n->left, init); - // cannot put side effects from n->right on init, - // because they cannot run before n->left is checked. - // save elsewhere and store on the eventual n->right. - ll = nil; - walkexpr(&n->right, &ll); - addinit(&n->right, ll); - goto ret; - - case OPRINT: - case OPRINTN: - walkexprlist(n->list, init); - n = walkprint(n, init); - goto ret; - - case OPANIC: - n = mkcall("gopanic", T, init, n->left); - goto ret; - - case ORECOVER: - n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N)); - goto ret; - - case OLITERAL: - n->addable = 1; - goto ret; - - case OCLOSUREVAR: - case OCFUNC: - n->addable = 1; - goto ret; - - case ONAME: - if(!(n->class & PHEAP) && n->class != PPARAMREF) - n->addable = 1; - goto ret; - - case OCALLINTER: - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - walkexpr(&n->left, init); - walkexprlist(n->list, init); - ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); - n->list = reorder1(ll); - goto ret; - - case OCALLFUNC: - if(n->left->op == OCLOSURE) { - // Transform direct call of a closure to call of a normal function. - // transformclosure already did all preparation work. - - // Append captured variables to argument list. - n->list = concat(n->list, n->left->enter); - n->left->enter = nil; - // Replace OCLOSURE with ONAME/PFUNC. - n->left = n->left->closure->nname; - // Update type of OCALLFUNC node. - // Output arguments had not changed, but their offsets could. - if(n->left->type->outtuple == 1) { - t = getoutargx(n->left->type)->type; - if(t->etype == TFIELD) - t = t->type; - n->type = t; - } else - n->type = getoutargx(n->left->type); - } - - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - - walkexpr(&n->left, init); - walkexprlist(n->list, init); - - ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); - n->list = reorder1(ll); - goto ret; - - case OCALLMETH: - t = n->left->type; - if(n->list && n->list->n->op == OAS) - goto ret; - walkexpr(&n->left, init); - walkexprlist(n->list, init); - ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init); - lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init); - ll = concat(ll, lr); - n->left->left = N; - ullmancalc(n->left); - n->list = reorder1(ll); - goto ret; - - case OAS: - *init = concat(*init, n->ninit); - n->ninit = nil; - - walkexpr(&n->left, init); - n->left = safeexpr(n->left, init); - - if(oaslit(n, init)) - goto ret; - - if(n->right == N || iszero(n->right) && !flag_race) - goto ret; - - switch(n->right->op) { - default: - walkexpr(&n->right, init); - break; - - case ODOTTYPE: - // x = i.(T); n->left is x, n->right->left is i. - // orderstmt made sure x is addressable. - walkexpr(&n->right->left, init); - n1 = nod(OADDR, n->left, N); - r = n->right; // i.(T) - - from = "I"; - to = "T"; - if(isnilinter(r->left->type)) - from = "E"; - if(isnilinter(r->type)) - to = "E"; - else if(isinter(r->type)) - to = "I"; - - snprint(buf, sizeof buf, "assert%s2%s", from, to); - - fn = syslook(buf, 1); - argtype(fn, r->left->type); - argtype(fn, r->type); - - n = mkcall1(fn, T, init, typename(r->type), r->left, n1); - walkexpr(&n, init); - goto ret; - - case ORECV: - // x = <-c; n->left is x, n->right->left is c. - // orderstmt made sure x is addressable. - walkexpr(&n->right->left, init); - n1 = nod(OADDR, n->left, N); - r = n->right->left; // the channel - n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1); - walkexpr(&n, init); - goto ret; - } - - if(n->left != N && n->right != N) { - r = convas(nod(OAS, n->left, n->right), init); - r->dodata = n->dodata; - n = r; - n = applywritebarrier(n, init); - } - - goto ret; - - case OAS2: - *init = concat(*init, n->ninit); - n->ninit = nil; - walkexprlistsafe(n->list, init); - walkexprlistsafe(n->rlist, init); - ll = ascompatee(OAS, n->list, n->rlist, init); - ll = reorder3(ll); - for(lr = ll; lr != nil; lr = lr->next) - lr->n = applywritebarrier(lr->n, init); - n = liststmt(ll); - goto ret; - - case OAS2FUNC: - // a,b,... = fn() - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r, init); - - ll = ascompatet(n->op, n->list, &r->type, 0, init); - for(lr = ll; lr != nil; lr = lr->next) - lr->n = applywritebarrier(lr->n, init); - n = liststmt(concat(list1(r), ll)); - goto ret; - - case OAS2RECV: - // x, y = <-c - // orderstmt made sure x is addressable. - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r->left, init); - if(isblank(n->list->n)) - n1 = nodnil(); - else - n1 = nod(OADDR, n->list->n, N); - n1->etype = 1; // addr does not escape - fn = chanfn("chanrecv2", 2, r->left->type); - r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1); - n = nod(OAS, n->list->next->n, r); - typecheck(&n, Etop); - goto ret; - - case OAS2MAPR: - // a,b = m[i]; - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r->left, init); - walkexpr(&r->right, init); - t = r->left->type; - p = nil; - if(t->type->width <= 128) { // Check ../../runtime/hashmap.go:maxValueSize before changing. - switch(simsimtype(t->down)) { - case TINT32: - case TUINT32: - p = "mapaccess2_fast32"; - break; - case TINT64: - case TUINT64: - p = "mapaccess2_fast64"; - break; - case TSTRING: - p = "mapaccess2_faststr"; - break; - } - } - if(p != nil) { - // fast versions take key by value - key = r->right; - } else { - // standard version takes key by reference - // orderexpr made sure key is addressable. - key = nod(OADDR, r->right, N); - p = "mapaccess2"; - } - - // from: - // a,b = m[i] - // to: - // var,b = mapaccess2*(t, m, i) - // a = *var - a = n->list->n; - fn = mapfn(p, t); - r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key); - - // mapaccess2* returns a typed bool, but due to spec changes, - // the boolean result of i.(T) is now untyped so we make it the - // same type as the variable on the lhs. - if(!isblank(n->list->next->n)) - r->type->type->down->type = n->list->next->n->type; - n->rlist = list1(r); - n->op = OAS2FUNC; - - // don't generate a = *var if a is _ - if(!isblank(a)) { - var = temp(ptrto(t->type)); - var->typecheck = 1; - n->list->n = var; - walkexpr(&n, init); - *init = list(*init, n); - n = nod(OAS, a, nod(OIND, var, N)); - } - - typecheck(&n, Etop); - walkexpr(&n, init); - // mapaccess needs a zero value to be at least this big. - if(zerosize < t->type->width) - zerosize = t->type->width; - // TODO: ptr is always non-nil, so disable nil check for this OIND op. - goto ret; - - case ODELETE: - *init = concat(*init, n->ninit); - n->ninit = nil; - map = n->list->n; - key = n->list->next->n; - walkexpr(&map, init); - walkexpr(&key, init); - // orderstmt made sure key is addressable. - key = nod(OADDR, key, N); - t = map->type; - n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key); - goto ret; - - case OAS2DOTTYPE: - // a,b = i.(T) - // orderstmt made sure a is addressable. - *init = concat(*init, n->ninit); - n->ninit = nil; - r = n->rlist->n; - walkexprlistsafe(n->list, init); - walkexpr(&r->left, init); - if(isblank(n->list->n)) - n1 = nodnil(); - else - n1 = nod(OADDR, n->list->n, N); - n1->etype = 1; // addr does not escape - - from = "I"; - to = "T"; - if(isnilinter(r->left->type)) - from = "E"; - if(isnilinter(r->type)) - to = "E"; - else if(isinter(r->type)) - to = "I"; - snprint(buf, sizeof buf, "assert%s2%s2", from, to); - - fn = syslook(buf, 1); - argtype(fn, r->left->type); - argtype(fn, r->type); - - t = types[TBOOL]; - ok = n->list->next->n; - if(!isblank(ok)) - t = ok->type; - r = mkcall1(fn, t, init, typename(r->type), r->left, n1); - n = nod(OAS, ok, r); - typecheck(&n, Etop); - goto ret; - - case ODOTTYPE: - case ODOTTYPE2: - fatal("walkexpr ODOTTYPE"); // should see inside OAS or OAS2 only - - case OCONVIFACE: - walkexpr(&n->left, init); - - // Optimize convT2E as a two-word copy when T is pointer-shaped. - if(isnilinter(n->type) && isdirectiface(n->left->type)) { - l = nod(OEFACE, typename(n->left->type), n->left); - l->type = n->type; - l->typecheck = n->typecheck; - n = l; - goto ret; - } - - // Build name of function: convI2E etc. - // Not all names are possible - // (e.g., we'll never generate convE2E or convE2I). - from = "T"; - to = "I"; - if(isnilinter(n->left->type)) - from = "E"; - else if(isinter(n->left->type)) - from = "I"; - if(isnilinter(n->type)) - to = "E"; - snprint(buf, sizeof buf, "conv%s2%s", from, to); - - fn = syslook(buf, 1); - ll = nil; - if(!isinter(n->left->type)) - ll = list(ll, typename(n->left->type)); - if(!isnilinter(n->type)) - ll = list(ll, typename(n->type)); - if(!isinter(n->left->type) && !isnilinter(n->type)){ - sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg); - if(sym->def == N) { - l = nod(ONAME, N, N); - l->sym = sym; - l->type = ptrto(types[TUINT8]); - l->addable = 1; - l->class = PEXTERN; - l->xoffset = 0; - sym->def = l; - ggloblsym(sym, widthptr, DUPOK|NOPTR); - } - l = nod(OADDR, sym->def, N); - l->addable = 1; - ll = list(ll, l); - - if(isdirectiface(n->left->type)) { - /* For pointer types, we can make a special form of optimization - * - * These statements are put onto the expression init list: - * Itab *tab = atomicloadtype(&cache); - * if(tab == nil) - * tab = typ2Itab(type, itype, &cache); - * - * The CONVIFACE expression is replaced with this: - * OEFACE{tab, ptr}; - */ - l = temp(ptrto(types[TUINT8])); - - n1 = nod(OAS, l, sym->def); - typecheck(&n1, Etop); - *init = list(*init, n1); - - fn = syslook("typ2Itab", 1); - n1 = nod(OCALL, fn, N); - n1->list = ll; - typecheck(&n1, Erv); - walkexpr(&n1, init); - - n2 = nod(OIF, N, N); - n2->ntest = nod(OEQ, l, nodnil()); - n2->nbody = list1(nod(OAS, l, n1)); - n2->likely = -1; - typecheck(&n2, Etop); - *init = list(*init, n2); - - l = nod(OEFACE, l, n->left); - l->typecheck = n->typecheck; - l->type = n->type; - n = l; - goto ret; - } - } - if(isinter(n->left->type)) { - ll = list(ll, n->left); - } else { - // regular types are passed by reference to avoid C vararg calls - // orderexpr arranged for n->left to be a temporary for all - // the conversions it could see. comparison of an interface - // with a non-interface, especially in a switch on interface value - // with non-interface cases, is not visible to orderstmt, so we - // have to fall back on allocating a temp here. - if(islvalue(n->left)) - ll = list(ll, nod(OADDR, n->left, N)); - else - ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N)); - } - argtype(fn, n->left->type); - argtype(fn, n->type); - dowidth(fn->type); - n = nod(OCALL, fn, N); - n->list = ll; - typecheck(&n, Erv); - walkexpr(&n, init); - goto ret; - - case OCONV: - case OCONVNOP: - if(thearch.thechar == '5') { - if(isfloat[n->left->type->etype]) { - if(n->type->etype == TINT64) { - n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64])); - goto ret; - } - if(n->type->etype == TUINT64) { - n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64])); - goto ret; - } - } - if(isfloat[n->type->etype]) { - if(n->left->type->etype == TINT64) { - n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64])); - goto ret; - } - if(n->left->type->etype == TUINT64) { - n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64])); - goto ret; - } - } - } - walkexpr(&n->left, init); - goto ret; - - case OANDNOT: - walkexpr(&n->left, init); - n->op = OAND; - n->right = nod(OCOM, n->right, N); - typecheck(&n->right, Erv); - walkexpr(&n->right, init); - goto ret; - - case OMUL: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - walkmul(&n, init); - goto ret; - - case ODIV: - case OMOD: - walkexpr(&n->left, init); - walkexpr(&n->right, init); - /* - * rewrite complex div into function call. - */ - et = n->left->type->etype; - if(iscomplex[et] && n->op == ODIV) { - t = n->type; - n = mkcall("complex128div", types[TCOMPLEX128], init, - conv(n->left, types[TCOMPLEX128]), - conv(n->right, types[TCOMPLEX128])); - n = conv(n, t); - goto ret; - } - // Nothing to do for float divisions. - if(isfloat[et]) - goto ret; - - // Try rewriting as shifts or magic multiplies. - walkdiv(&n, init); - - /* - * rewrite 64-bit div and mod into function calls - * on 32-bit architectures. - */ - switch(n->op) { - case OMOD: - case ODIV: - if(widthreg >= 8 || (et != TUINT64 && et != TINT64)) - goto ret; - if(et == TINT64) - strcpy(namebuf, "int64"); - else - strcpy(namebuf, "uint64"); - if(n->op == ODIV) - strcat(namebuf, "div"); - else - strcat(namebuf, "mod"); - n = mkcall(namebuf, n->type, init, - conv(n->left, types[et]), conv(n->right, types[et])); - break; - default: - break; - } - goto ret; - - case OINDEX: - walkexpr(&n->left, init); - // save the original node for bounds checking elision. - // If it was a ODIV/OMOD walk might rewrite it. - r = n->right; - walkexpr(&n->right, init); - - // if range of type cannot exceed static array bound, - // disable bounds check. - if(n->bounded) - goto ret; - t = n->left->type; - if(t != T && isptr[t->etype]) - t = t->type; - if(isfixedarray(t)) { - n->bounded = bounded(r, t->bound); - if(debug['m'] && n->bounded && !isconst(n->right, CTINT)) - warn("index bounds check elided"); - if(smallintconst(n->right) && !n->bounded) - yyerror("index out of bounds"); - } else if(isconst(n->left, CTSTR)) { - n->bounded = bounded(r, n->left->val.u.sval->len); - if(debug['m'] && n->bounded && !isconst(n->right, CTINT)) - warn("index bounds check elided"); - if(smallintconst(n->right)) { - if(!n->bounded) - yyerror("index out of bounds"); - else { - // replace "abc"[1] with 'b'. - // delayed until now because "abc"[1] is not - // an ideal constant. - v = mpgetfix(n->right->val.u.xval); - nodconst(n, n->type, n->left->val.u.sval->s[v]); - n->typecheck = 1; - } - } - } - - if(isconst(n->right, CTINT)) - if(mpcmpfixfix(n->right->val.u.xval, &mpzero) < 0 || - mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0) - yyerror("index out of bounds"); - goto ret; - - case OINDEXMAP: - if(n->etype == 1) - goto ret; - walkexpr(&n->left, init); - walkexpr(&n->right, init); - - t = n->left->type; - p = nil; - if(t->type->width <= 128) { // Check ../../runtime/hashmap.go:maxValueSize before changing. - switch(simsimtype(t->down)) { - case TINT32: - case TUINT32: - p = "mapaccess1_fast32"; - break; - case TINT64: - case TUINT64: - p = "mapaccess1_fast64"; - break; - case TSTRING: - p = "mapaccess1_faststr"; - break; - } - } - if(p != nil) { - // fast versions take key by value - key = n->right; - } else { - // standard version takes key by reference. - // orderexpr made sure key is addressable. - key = nod(OADDR, n->right, N); - p = "mapaccess1"; - } - n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key); - n = nod(OIND, n, N); - n->type = t->type; - n->typecheck = 1; - // mapaccess needs a zero value to be at least this big. - if(zerosize < t->type->width) - zerosize = t->type->width; - goto ret; - - case ORECV: - fatal("walkexpr ORECV"); // should see inside OAS only - - case OSLICE: - if(n->right != N && n->right->left == N && n->right->right == N) { // noop - walkexpr(&n->left, init); - n = n->left; - goto ret; - } - // fallthrough - case OSLICEARR: - case OSLICESTR: - if(n->right == N) // already processed - goto ret; - - walkexpr(&n->left, init); - // cgen_slice can't handle string literals as source - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX)) - n->left = copyexpr(n->left, n->left->type, init); - else - n->left = safeexpr(n->left, init); - walkexpr(&n->right->left, init); - n->right->left = safeexpr(n->right->left, init); - walkexpr(&n->right->right, init); - n->right->right = safeexpr(n->right->right, init); - n = sliceany(n, init); // chops n->right, sets n->list - goto ret; - - case OSLICE3: - case OSLICE3ARR: - if(n->right == N) // already processed - goto ret; - - walkexpr(&n->left, init); - // TODO the OINDEX case is a bug elsewhere that needs to be traced. it causes a crash on ([2][]int{ ... })[1][lo:hi] - // TODO the comment on the previous line was copied from case OSLICE. it might not even be true. - if(n->left->op == OINDEX) - n->left = copyexpr(n->left, n->left->type, init); - else - n->left = safeexpr(n->left, init); - walkexpr(&n->right->left, init); - n->right->left = safeexpr(n->right->left, init); - walkexpr(&n->right->right->left, init); - n->right->right->left = safeexpr(n->right->right->left, init); - walkexpr(&n->right->right->right, init); - n->right->right->right = safeexpr(n->right->right->right, init); - n = sliceany(n, init); // chops n->right, sets n->list - goto ret; - - case OADDR: - walkexpr(&n->left, init); - goto ret; - - case ONEW: - if(n->esc == EscNone && n->type->type->width < (1<<16)) { - r = temp(n->type->type); - r = nod(OAS, r, N); // zero temp - typecheck(&r, Etop); - *init = list(*init, r); - r = nod(OADDR, r->left, N); - typecheck(&r, Erv); - n = r; - } else { - n = callnew(n->type->type); - } - goto ret; - - case OCMPSTR: - // If one argument to the comparison is an empty string, - // comparing the lengths instead will yield the same result - // without the function call. - if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) || - (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) { - r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N)); - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; - n = r; - goto ret; - } - - // s + "badgerbadgerbadger" == "badgerbadgerbadger" - if((n->etype == OEQ || n->etype == ONE) && - isconst(n->right, CTSTR) && - n->left->op == OADDSTR && count(n->left->list) == 2 && - isconst(n->left->list->next->n, CTSTR) && - cmpslit(n->right, n->left->list->next->n) == 0) { - r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0)); - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; - n = r; - goto ret; - } - - if(n->etype == OEQ || n->etype == ONE) { - // prepare for rewrite below - n->left = cheapexpr(n->left, init); - n->right = cheapexpr(n->right, init); - - r = mkcall("eqstring", types[TBOOL], init, - conv(n->left, types[TSTRING]), - conv(n->right, types[TSTRING])); - - // quick check of len before full compare for == or != - // eqstring assumes that the lengths are equal - if(n->etype == OEQ) { - // len(left) == len(right) && eqstring(left, right) - r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); - } else { - // len(left) != len(right) || !eqstring(left, right) - r = nod(ONOT, r, N); - r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r); - } - typecheck(&r, Erv); - walkexpr(&r, nil); - } else { - // sys_cmpstring(s1, s2) :: 0 - r = mkcall("cmpstring", types[TINT], init, - conv(n->left, types[TSTRING]), - conv(n->right, types[TSTRING])); - r = nod(n->etype, r, nodintconst(0)); - } - - typecheck(&r, Erv); - if(n->type->etype != TBOOL) fatal("cmp %T", n->type); - r->type = n->type; - n = r; - goto ret; - - case OADDSTR: - n = addstr(n, init); - goto ret; - - case OAPPEND: - if(n->isddd) - n = appendslice(n, init); // also works for append(slice, string). - else - n = append(n, init); - goto ret; - - case OCOPY: - n = copyany(n, init, flag_race); - goto ret; - - case OCLOSE: - // cannot use chanfn - closechan takes any, not chan any - fn = syslook("closechan", 1); - argtype(fn, n->left->type); - n = mkcall1(fn, T, init, n->left); - goto ret; - - case OMAKECHAN: - n = mkcall1(chanfn("makechan", 1, n->type), n->type, init, - typename(n->type), - conv(n->left, types[TINT64])); - goto ret; - - case OMAKEMAP: - t = n->type; - - fn = syslook("makemap", 1); - - a = nodnil(); // hmap buffer - r = nodnil(); // bucket buffer - if(n->esc == EscNone) { - // Allocate hmap buffer on stack. - var = temp(hmap(t)); - a = nod(OAS, var, N); // zero temp - typecheck(&a, Etop); - *init = list(*init, a); - a = nod(OADDR, var, N); - - // Allocate one bucket on stack. - // Maximum key/value size is 128 bytes, larger objects - // are stored with an indirection. So max bucket size is 2048+eps. - var = temp(mapbucket(t)); - r = nod(OAS, var, N); // zero temp - typecheck(&r, Etop); - *init = list(*init, r); - r = nod(OADDR, var, N); - } - - argtype(fn, hmap(t)); // hmap buffer - argtype(fn, mapbucket(t)); // bucket buffer - argtype(fn, t->down); // key type - argtype(fn, t->type); // value type - n = mkcall1(fn, n->type, init, typename(n->type), conv(n->left, types[TINT64]), a, r); - goto ret; - - case OMAKESLICE: - l = n->left; - r = n->right; - if(r == nil) - l = r = safeexpr(l, init); - t = n->type; - if(n->esc == EscNone - && smallintconst(l) && smallintconst(r) - && (t->type->width == 0 || mpgetfix(r->val.u.xval) < (1ULL<<16) / t->type->width)) { - // var arr [r]T - // n = arr[:l] - t = aindex(r, t->type); // [r]T - var = temp(t); - a = nod(OAS, var, N); // zero temp - typecheck(&a, Etop); - *init = list(*init, a); - r = nod(OSLICE, var, nod(OKEY, N, l)); // arr[:l] - r = conv(r, n->type); // in case n->type is named. - typecheck(&r, Erv); - walkexpr(&r, init); - n = r; - } else { - // makeslice(t *Type, nel int64, max int64) (ary []any) - fn = syslook("makeslice", 1); - argtype(fn, t->type); // any-1 - n = mkcall1(fn, n->type, init, - typename(n->type), - conv(l, types[TINT64]), - conv(r, types[TINT64])); - } - goto ret; - - case ORUNESTR: - a = nodnil(); - if(n->esc == EscNone) { - t = aindex(nodintconst(4), types[TUINT8]); - var = temp(t); - a = nod(OADDR, var, N); - } - // intstring(*[4]byte, rune) - n = mkcall("intstring", n->type, init, a, conv(n->left, types[TINT64])); - goto ret; - - case OARRAYBYTESTR: - a = nodnil(); - if(n->esc == EscNone) { - // Create temporary buffer for string on stack. - t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]); - a = nod(OADDR, temp(t), N); - } - // slicebytetostring(*[32]byte, []byte) string; - n = mkcall("slicebytetostring", n->type, init, a, n->left); - goto ret; - - case OARRAYBYTESTRTMP: - // slicebytetostringtmp([]byte) string; - n = mkcall("slicebytetostringtmp", n->type, init, n->left); - goto ret; - - case OARRAYRUNESTR: - // slicerunetostring(*[32]byte, []rune) string; - a = nodnil(); - if(n->esc == EscNone) { - // Create temporary buffer for string on stack. - t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]); - a = nod(OADDR, temp(t), N); - } - n = mkcall("slicerunetostring", n->type, init, a, n->left); - goto ret; - - case OSTRARRAYBYTE: - // stringtoslicebyte(*32[byte], string) []byte; - a = nodnil(); - if(n->esc == EscNone) { - // Create temporary buffer for slice on stack. - t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]); - a = nod(OADDR, temp(t), N); - } - n = mkcall("stringtoslicebyte", n->type, init, a, conv(n->left, types[TSTRING])); - goto ret; - - case OSTRARRAYBYTETMP: - // stringtoslicebytetmp(string) []byte; - n = mkcall("stringtoslicebytetmp", n->type, init, conv(n->left, types[TSTRING])); - goto ret; - - case OSTRARRAYRUNE: - // stringtoslicerune(*[32]rune, string) []rune - a = nodnil(); - if(n->esc == EscNone) { - // Create temporary buffer for slice on stack. - t = aindex(nodintconst(tmpstringbufsize), types[TINT32]); - a = nod(OADDR, temp(t), N); - } - n = mkcall("stringtoslicerune", n->type, init, a, n->left); - goto ret; - - case OCMPIFACE: - // ifaceeq(i1 any-1, i2 any-2) (ret bool); - if(!eqtype(n->left->type, n->right->type)) - fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type); - if(isnilinter(n->left->type)) - fn = syslook("efaceeq", 1); - else - fn = syslook("ifaceeq", 1); - - n->right = cheapexpr(n->right, init); - n->left = cheapexpr(n->left, init); - argtype(fn, n->right->type); - argtype(fn, n->left->type); - r = mkcall1(fn, n->type, init, n->left, n->right); - if(n->etype == ONE) - r = nod(ONOT, r, N); - - // check itable/type before full compare. - if(n->etype == OEQ) - r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r); - else - r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r); - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; - n = r; - goto ret; - - case OARRAYLIT: - case OMAPLIT: - case OSTRUCTLIT: - case OPTRLIT: - var = temp(n->type); - anylit(0, n, var, init); - n = var; - goto ret; - - case OSEND: - n1 = n->right; - n1 = assignconv(n1, n->left->type->type, "chan send"); - walkexpr(&n1, init); - n1 = nod(OADDR, n1, N); - n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1); - goto ret; - - case OCLOSURE: - n = walkclosure(n, init); - goto ret; - - case OCALLPART: - n = walkpartialcall(n, init); - goto ret; - } - fatal("missing switch %O", n->op); - -ret: - // Expressions that are constant at run time but not - // considered const by the language spec are not turned into - // constants until walk. For example, if n is y%1 == 0, the - // walk of y%1 may have replaced it by 0. - // Check whether n with its updated args is itself now a constant. - t = n->type; - evconst(n); - n->type = t; - if(n->op == OLITERAL) - typecheck(&n, Erv); - - ullmancalc(n); - - if(debug['w'] && n != N) - dump("walk", n); - - lineno = lno; - *np = n; -} - -static Node* -ascompatee1(int op, Node *l, Node *r, NodeList **init) -{ - Node *n; - USED(op); - - // convas will turn map assigns into function calls, - // making it impossible for reorder3 to work. - n = nod(OAS, l, r); - if(l->op == OINDEXMAP) - return n; - - return convas(n, init); -} - -static NodeList* -ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init) -{ - NodeList *ll, *lr, *nn; - - /* - * check assign expression list to - * a expression list. called in - * expr-list = expr-list - */ - - // ensure order of evaluation for function calls - for(ll=nl; ll; ll=ll->next) - ll->n = safeexpr(ll->n, init); - for(lr=nr; lr; lr=lr->next) - lr->n = safeexpr(lr->n, init); - - nn = nil; - for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) { - // Do not generate 'x = x' during return. See issue 4014. - if(op == ORETURN && ll->n == lr->n) - continue; - nn = list(nn, ascompatee1(op, ll->n, lr->n, init)); - } - - // cannot happen: caller checked that lists had same length - if(ll || lr) - yyerror("error in shape across %+H %O %+H / %d %d [%s]", nl, op, nr, count(nl), count(nr), curfn->nname->sym->name); - return nn; -} - -/* - * l is an lv and rt is the type of an rv - * return 1 if this implies a function call - * evaluating the lv or a function call - * in the conversion of the types - */ -static int -fncall(Node *l, Type *rt) -{ - Node r; - - if(l->ullman >= UINF || l->op == OINDEXMAP) - return 1; - memset(&r, 0, sizeof r); - if(needwritebarrier(l, &r)) - return 1; - if(eqtype(l->type, rt)) - return 0; - return 1; -} - -static NodeList* -ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init) -{ - Node *l, *tmp, *a; - NodeList *ll; - Type *r; - Iter saver; - int ucount; - NodeList *nn, *mm; - - USED(op); - - /* - * check assign type list to - * a expression list. called in - * expr-list = func() - */ - r = structfirst(&saver, nr); - nn = nil; - mm = nil; - ucount = 0; - for(ll=nl; ll; ll=ll->next) { - if(r == T) - break; - l = ll->n; - if(isblank(l)) { - r = structnext(&saver); - continue; - } - - // any lv that causes a fn call must be - // deferred until all the return arguments - // have been pulled from the output arguments - if(fncall(l, r->type)) { - tmp = temp(r->type); - typecheck(&tmp, Erv); - a = nod(OAS, l, tmp); - a = convas(a, init); - mm = list(mm, a); - l = tmp; - } - - a = nod(OAS, l, nodarg(r, fp)); - a = convas(a, init); - ullmancalc(a); - if(a->ullman >= UINF) { - dump("ascompatet ucount", a); - ucount++; - } - nn = list(nn, a); - r = structnext(&saver); - } - - if(ll != nil || r != T) - yyerror("ascompatet: assignment count mismatch: %d = %d", - count(nl), structcount(*nr)); - - if(ucount) - fatal("ascompatet: too many function calls evaluating parameters"); - return concat(nn, mm); -} - - /* - * package all the arguments that match a ... T parameter into a []T. - */ -static NodeList* -mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd) -{ - Node *a, *n; - Type *tslice; - int esc; - - esc = EscUnknown; - if(ddd != nil) - esc = ddd->esc; - - tslice = typ(TARRAY); - tslice->type = l->type->type; - tslice->bound = -1; - - if(count(lr0) == 0) { - n = nodnil(); - n->type = tslice; - } else { - n = nod(OCOMPLIT, N, typenod(tslice)); - if(ddd != nil) - n->alloc = ddd->alloc; // temporary to use - n->list = lr0; - n->esc = esc; - typecheck(&n, Erv); - if(n->type == T) - fatal("mkdotargslice: typecheck failed"); - walkexpr(&n, init); - } - - a = nod(OAS, nodarg(l, fp), n); - nn = list(nn, convas(a, init)); - return nn; -} - -/* - * helpers for shape errors - */ -static char* -dumptypes(Type **nl, char *what) -{ - int first; - Type *l; - Iter savel; - Fmt fmt; - - fmtstrinit(&fmt); - fmtprint(&fmt, "\t"); - first = 1; - for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) { - if(first) - first = 0; - else - fmtprint(&fmt, ", "); - fmtprint(&fmt, "%T", l); - } - if(first) - fmtprint(&fmt, "[no arguments %s]", what); - return fmtstrflush(&fmt); -} - -static char* -dumpnodetypes(NodeList *l, char *what) -{ - int first; - Node *r; - Fmt fmt; - - fmtstrinit(&fmt); - fmtprint(&fmt, "\t"); - first = 1; - for(; l; l=l->next) { - r = l->n; - if(first) - first = 0; - else - fmtprint(&fmt, ", "); - fmtprint(&fmt, "%T", r->type); - } - if(first) - fmtprint(&fmt, "[no arguments %s]", what); - return fmtstrflush(&fmt); -} - -/* - * check assign expression list to - * a type list. called in - * return expr-list - * func(expr-list) - */ -static NodeList* -ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init) -{ - Type *l, *ll; - Node *r, *a; - NodeList *nn, *lr0, *alist; - Iter savel; - char *l1, *l2; - - lr0 = lr; - l = structfirst(&savel, nl); - r = N; - if(lr) - r = lr->n; - nn = nil; - - // f(g()) where g has multiple return values - if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) { - // optimization - can do block copy - if(eqtypenoname(r->type, *nl)) { - a = nodarg(*nl, fp); - r = nod(OCONVNOP, r, N); - r->type = a->type; - nn = list1(convas(nod(OAS, a, r), init)); - goto ret; - } - - // conversions involved. - // copy into temporaries. - alist = nil; - for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) { - a = temp(l->type); - alist = list(alist, a); - } - a = nod(OAS2, N, N); - a->list = alist; - a->rlist = lr; - typecheck(&a, Etop); - walkstmt(&a); - *init = list(*init, a); - lr = alist; - r = lr->n; - l = structfirst(&savel, nl); - } - -loop: - if(l != T && l->isddd) { - // the ddd parameter must be last - ll = structnext(&savel); - if(ll != T) - yyerror("... must be last argument"); - - // special case -- - // only if we are assigning a single ddd - // argument to a ddd parameter then it is - // passed thru unencapsulated - if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) { - a = nod(OAS, nodarg(l, fp), r); - a = convas(a, init); - nn = list(nn, a); - goto ret; - } - - // normal case -- make a slice of all - // remaining arguments and pass it to - // the ddd parameter. - nn = mkdotargslice(lr, nn, l, fp, init, call->right); - goto ret; - } - - if(l == T || r == N) { - if(l != T || r != N) { - l1 = dumptypes(nl, "expected"); - l2 = dumpnodetypes(lr0, "given"); - if(l != T) - yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2); - else - yyerror("too many arguments to %O\n%s\n%s", op, l1, l2); - } - goto ret; - } - - a = nod(OAS, nodarg(l, fp), r); - a = convas(a, init); - nn = list(nn, a); - - l = structnext(&savel); - r = N; - lr = lr->next; - if(lr != nil) - r = lr->n; - goto loop; - -ret: - for(lr=nn; lr; lr=lr->next) - lr->n->typecheck = 1; - return nn; -} - -// generate code for print -static Node* -walkprint(Node *nn, NodeList **init) -{ - Node *r; - Node *n; - NodeList *l, *all; - Node *on; - Type *t; - int notfirst, et, op; - NodeList *calls; - - op = nn->op; - all = nn->list; - calls = nil; - notfirst = 0; - - // Hoist all the argument evaluation up before the lock. - walkexprlistcheap(all, init); - - calls = list(calls, mkcall("printlock", T, init)); - - for(l=all; l; l=l->next) { - if(notfirst) { - calls = list(calls, mkcall("printsp", T, init)); - } - notfirst = op == OPRINTN; - - n = l->n; - if(n->op == OLITERAL) { - switch(n->val.ctype) { - case CTRUNE: - defaultlit(&n, runetype); - break; - case CTINT: - defaultlit(&n, types[TINT64]); - break; - case CTFLT: - defaultlit(&n, types[TFLOAT64]); - break; - } - } - if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL) - defaultlit(&n, types[TINT64]); - defaultlit(&n, nil); - l->n = n; - if(n->type == T || n->type->etype == TFORW) - continue; - - t = n->type; - et = n->type->etype; - if(isinter(n->type)) { - if(isnilinter(n->type)) - on = syslook("printeface", 1); - else - on = syslook("printiface", 1); - argtype(on, n->type); // any-1 - } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) { - on = syslook("printpointer", 1); - argtype(on, n->type); // any-1 - } else if(isslice(n->type)) { - on = syslook("printslice", 1); - argtype(on, n->type); // any-1 - } else if(isint[et]) { - if(et == TUINT64) { - if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0) - on = syslook("printhex", 0); - else - on = syslook("printuint", 0); - } else - on = syslook("printint", 0); - } else if(isfloat[et]) { - on = syslook("printfloat", 0); - } else if(iscomplex[et]) { - on = syslook("printcomplex", 0); - } else if(et == TBOOL) { - on = syslook("printbool", 0); - } else if(et == TSTRING) { - on = syslook("printstring", 0); - } else { - badtype(OPRINT, n->type, T); - continue; - } - - t = *getinarg(on->type); - if(t != nil) - t = t->type; - if(t != nil) - t = t->type; - - if(!eqtype(t, n->type)) { - n = nod(OCONV, n, N); - n->type = t; - } - - r = nod(OCALL, on, N); - r->list = list1(n); - calls = list(calls, r); - } - - if(op == OPRINTN) - calls = list(calls, mkcall("printnl", T, nil)); - - calls = list(calls, mkcall("printunlock", T, init)); - - typechecklist(calls, Etop); - walkexprlist(calls, init); - - r = nod(OEMPTY, N, N); - typecheck(&r, Etop); - walkexpr(&r, init); - r->ninit = calls; - return r; -} - -Node* -callnew(Type *t) -{ - Node *fn; - - dowidth(t); - fn = syslook("newobject", 1); - argtype(fn, t); - return mkcall1(fn, ptrto(t), nil, typename(t)); -} - -static int -isstack(Node *n) -{ - Node *defn; - - n = outervalue(n); - - // If n is *autotmp and autotmp = &foo, replace n with foo. - // We introduce such temps when initializing struct literals. - if(n->op == OIND && n->left->op == ONAME && strncmp(n->left->sym->name, "autotmp_", 8) == 0) { - defn = n->left->defn; - if(defn != N && defn->op == OAS && defn->right->op == OADDR) - n = defn->right->left; - } - - switch(n->op) { - case OINDREG: - // OINDREG only ends up in walk if it's indirect of SP. - return 1; - - case ONAME: - switch(n->class) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - return 1; - } - break; - } - - return 0; -} - -static int -isglobal(Node *n) -{ - n = outervalue(n); - - switch(n->op) { - case ONAME: - switch(n->class) { - case PEXTERN: - return 1; - } - break; - } - - return 0; -} - -// Do we need a write barrier for the assignment l = r? -int -needwritebarrier(Node *l, Node *r) -{ - if(!use_writebarrier) - return 0; - - if(l == N || isblank(l)) - return 0; - - // No write barrier for write of non-pointers. - dowidth(l->type); - if(!haspointers(l->type)) - return 0; - - // No write barrier for write to stack. - if(isstack(l)) - return 0; - - // No write barrier for implicit or explicit zeroing. - if(r == N || iszero(r)) - return 0; - - // No write barrier for initialization to constant. - if(r->op == OLITERAL) - return 0; - - // No write barrier for storing static (read-only) data. - if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0) - return 0; - - // No write barrier for storing address of stack values, - // which are guaranteed only to be written to the stack. - if(r->op == OADDR && isstack(r->left)) - return 0; - - // No write barrier for storing address of global, which - // is live no matter what. - if(r->op == OADDR && isglobal(r->left)) - return 0; - - // No write barrier for reslice: x = x[0:y] or x = append(x, ...). - // Both are compiled to modify x directly. - // In the case of append, a write barrier may still be needed - // if the underlying array grows, but the append code can - // generate the write barrier directly in that case. - // (It does not yet, but the cost of the write barrier will be - // small compared to the cost of the allocation.) - if(r->reslice) { - switch(r->op) { - case OSLICE: - case OSLICE3: - case OSLICESTR: - case OAPPEND: - break; - default: - dump("bad reslice-l", l); - dump("bad reslice-r", r); - break; - } - return 0; - } - - // Otherwise, be conservative and use write barrier. - return 1; -} - -// TODO(rsc): Perhaps componentgen should run before this. -static Node* -applywritebarrier(Node *n, NodeList **init) -{ - Node *l, *r; - Type *t; - vlong x; - static Bvec *bv; - char name[32]; - - if(n->left && n->right && needwritebarrier(n->left, n->right)) { - if(curfn && curfn->nowritebarrier) - yyerror("write barrier prohibited"); - t = n->left->type; - l = nod(OADDR, n->left, N); - l->etype = 1; // addr does not escape - if(t->width == widthptr) { - n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init, - l, n->right); - } else if(t->etype == TSTRING) { - n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init, - l, n->right); - } else if(isslice(t)) { - n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init, - l, n->right); - } else if(isinter(t)) { - n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init, - l, n->right); - } else if(t->width <= 4*widthptr) { - x = 0; - if(bv == nil) - bv = bvalloc(BitsPerPointer*4); - bvresetall(bv); - twobitwalktype1(t, &x, bv); - // The bvgets are looking for BitsPointer in successive slots. - enum { - PtrBit = 1, - }; - if(BitsPointer != (1<width/widthptr) { - default: - fatal("found writebarrierfat for %d-byte object of type %T", (int)t->width, t); - case 2: - snprint(name, sizeof name, "writebarrierfat%d%d", - bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit)); - break; - case 3: - snprint(name, sizeof name, "writebarrierfat%d%d%d", - bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit)); - break; - case 4: - snprint(name, sizeof name, "writebarrierfat%d%d%d%d", - bvget(bv, PtrBit), bvget(bv, BitsPerPointer+PtrBit), bvget(bv, 2*BitsPerPointer+PtrBit), bvget(bv, 3*BitsPerPointer+PtrBit)); - break; - } - n = mkcall1(writebarrierfn(name, t, n->right->type), T, init, - l, nodnil(), n->right); - } else { - r = n->right; - while(r->op == OCONVNOP) - r = r->left; - r = nod(OADDR, r, N); - r->etype = 1; // addr does not escape - //warnl(n->lineno, "typedmemmove %T %N", t, r); - n = mkcall1(writebarrierfn("typedmemmove", t, r->left->type), T, init, - typename(t), l, r); - } - } - return n; -} - -static Node* -convas(Node *n, NodeList **init) -{ - Type *lt, *rt; - Node *map, *key, *val; - - if(n->op != OAS) - fatal("convas: not OAS %O", n->op); - - n->typecheck = 1; - - if(n->left == N || n->right == N) - goto out; - - lt = n->left->type; - rt = n->right->type; - if(lt == T || rt == T) - goto out; - - if(isblank(n->left)) { - defaultlit(&n->right, T); - goto out; - } - - if(n->left->op == OINDEXMAP) { - map = n->left->left; - key = n->left->right; - val = n->right; - walkexpr(&map, init); - walkexpr(&key, init); - walkexpr(&val, init); - // orderexpr made sure key and val are addressable. - key = nod(OADDR, key, N); - val = nod(OADDR, val, N); - n = mkcall1(mapfn("mapassign1", map->type), T, init, - typename(map->type), map, key, val); - goto out; - } - - if(!eqtype(lt, rt)) { - n->right = assignconv(n->right, lt, "assignment"); - walkexpr(&n->right, init); - } - -out: - ullmancalc(n); - return n; -} - -/* - * from ascompat[te] - * evaluating actual function arguments. - * f(a,b) - * if there is exactly one function expr, - * then it is done first. otherwise must - * make temp variables - */ -static NodeList* -reorder1(NodeList *all) -{ - Node *f, *a, *n; - NodeList *l, *r, *g; - int c, d, t; - - c = 0; // function calls - t = 0; // total parameters - - for(l=all; l; l=l->next) { - n = l->n; - t++; - ullmancalc(n); - if(n->ullman >= UINF) - c++; - } - if(c == 0 || t == 1) - return all; - - g = nil; // fncalls assigned to tempnames - f = N; // last fncall assigned to stack - r = nil; // non fncalls and tempnames assigned to stack - d = 0; - for(l=all; l; l=l->next) { - n = l->n; - if(n->ullman < UINF) { - r = list(r, n); - continue; - } - d++; - if(d == c) { - f = n; - continue; - } - - // make assignment of fncall to tempname - a = temp(n->right->type); - a = nod(OAS, a, n->right); - g = list(g, a); - - // put normal arg assignment on list - // with fncall replaced by tempname - n->right = a->left; - r = list(r, n); - } - - if(f != N) - g = list(g, f); - return concat(g, r); -} - -static void reorder3save(Node**, NodeList*, NodeList*, NodeList**); -static int aliased(Node*, NodeList*, NodeList*); - -/* - * from ascompat[ee] - * a,b = c,d - * simultaneous assignment. there cannot - * be later use of an earlier lvalue. - * - * function calls have been removed. - */ -static NodeList* -reorder3(NodeList *all) -{ - NodeList *list, *early, *mapinit; - Node *l; - - // If a needed expression may be affected by an - // earlier assignment, make an early copy of that - // expression and use the copy instead. - early = nil; - mapinit = nil; - for(list=all; list; list=list->next) { - l = list->n->left; - - // Save subexpressions needed on left side. - // Drill through non-dereferences. - for(;;) { - if(l->op == ODOT || l->op == OPAREN) { - l = l->left; - continue; - } - if(l->op == OINDEX && isfixedarray(l->left->type)) { - reorder3save(&l->right, all, list, &early); - l = l->left; - continue; - } - break; - } - switch(l->op) { - default: - fatal("reorder3 unexpected lvalue %#O", l->op); - case ONAME: - break; - case OINDEX: - case OINDEXMAP: - reorder3save(&l->left, all, list, &early); - reorder3save(&l->right, all, list, &early); - if(l->op == OINDEXMAP) - list->n = convas(list->n, &mapinit); - break; - case OIND: - case ODOTPTR: - reorder3save(&l->left, all, list, &early); - } - - // Save expression on right side. - reorder3save(&list->n->right, all, list, &early); - } - - early = concat(mapinit, early); - return concat(early, all); -} - -static int vmatch2(Node*, Node*); -static int varexpr(Node*); - -/* - * if the evaluation of *np would be affected by the - * assignments in all up to but not including stop, - * copy into a temporary during *early and - * replace *np with that temp. - */ -static void -reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early) -{ - Node *n, *q; - - n = *np; - if(!aliased(n, all, stop)) - return; - - q = temp(n->type); - q = nod(OAS, q, n); - typecheck(&q, Etop); - *early = list(*early, q); - *np = q->left; -} - -/* - * what's the outer value that a write to n affects? - * outer value means containing struct or array. - */ -Node* -outervalue(Node *n) -{ - for(;;) { - if(n->op == OXDOT) - fatal("OXDOT in walk"); - if(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP) { - n = n->left; - continue; - } - if(n->op == OINDEX && isfixedarray(n->left->type)) { - n = n->left; - continue; - } - break; - } - return n; -} - -/* - * Is it possible that the computation of n might be - * affected by writes in as up to but not including stop? - */ -static int -aliased(Node *n, NodeList *all, NodeList *stop) -{ - int memwrite, varwrite; - Node *a; - NodeList *l; - - if(n == N) - return 0; - - // Look for obvious aliasing: a variable being assigned - // during the all list and appearing in n. - // Also record whether there are any writes to main memory. - // Also record whether there are any writes to variables - // whose addresses have been taken. - memwrite = 0; - varwrite = 0; - for(l=all; l!=stop; l=l->next) { - a = outervalue(l->n->left); - if(a->op != ONAME) { - memwrite = 1; - continue; - } - switch(n->class) { - default: - varwrite = 1; - continue; - case PAUTO: - case PPARAM: - case PPARAMOUT: - if(n->addrtaken) { - varwrite = 1; - continue; - } - if(vmatch2(a, n)) { - // Direct hit. - return 1; - } - } - } - - // The variables being written do not appear in n. - // However, n might refer to computed addresses - // that are being written. - - // If no computed addresses are affected by the writes, no aliasing. - if(!memwrite && !varwrite) - return 0; - - // If n does not refer to computed addresses - // (that is, if n only refers to variables whose addresses - // have not been taken), no aliasing. - if(varexpr(n)) - return 0; - - // Otherwise, both the writes and n refer to computed memory addresses. - // Assume that they might conflict. - return 1; -} - -/* - * does the evaluation of n only refer to variables - * whose addresses have not been taken? - * (and no other memory) - */ -static int -varexpr(Node *n) -{ - if(n == N) - return 1; - - switch(n->op) { - case OLITERAL: - return 1; - case ONAME: - switch(n->class) { - case PAUTO: - case PPARAM: - case PPARAMOUT: - if(!n->addrtaken) - return 1; - } - return 0; - - case OADD: - case OSUB: - case OOR: - case OXOR: - case OMUL: - case ODIV: - case OMOD: - case OLSH: - case ORSH: - case OAND: - case OANDNOT: - case OPLUS: - case OMINUS: - case OCOM: - case OPAREN: - case OANDAND: - case OOROR: - case ODOT: // but not ODOTPTR - case OCONV: - case OCONVNOP: - case OCONVIFACE: - case ODOTTYPE: - return varexpr(n->left) && varexpr(n->right); - } - - // Be conservative. - return 0; -} - -/* - * is the name l mentioned in r? - */ -static int -vmatch2(Node *l, Node *r) -{ - NodeList *ll; - - if(r == N) - return 0; - switch(r->op) { - case ONAME: - // match each right given left - return l == r; - case OLITERAL: - return 0; - } - if(vmatch2(l, r->left)) - return 1; - if(vmatch2(l, r->right)) - return 1; - for(ll=r->list; ll; ll=ll->next) - if(vmatch2(l, ll->n)) - return 1; - return 0; -} - -/* - * is any name mentioned in l also mentioned in r? - * called by sinit.c - */ -int -vmatch1(Node *l, Node *r) -{ - NodeList *ll; - - /* - * isolate all left sides - */ - if(l == N || r == N) - return 0; - switch(l->op) { - case ONAME: - switch(l->class) { - case PPARAM: - case PPARAMREF: - case PAUTO: - break; - default: - // assignment to non-stack variable - // must be delayed if right has function calls. - if(r->ullman >= UINF) - return 1; - break; - } - return vmatch2(l, r); - case OLITERAL: - return 0; - } - if(vmatch1(l->left, r)) - return 1; - if(vmatch1(l->right, r)) - return 1; - for(ll=l->list; ll; ll=ll->next) - if(vmatch1(ll->n, r)) - return 1; - return 0; -} - -/* - * walk through argin parameters. - * generate and return code to allocate - * copies of escaped parameters to the heap. - */ -static NodeList* -paramstoheap(Type **argin, int out) -{ - Type *t; - Iter savet; - Node *v, *as; - NodeList *nn; - - nn = nil; - for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { - v = t->nname; - if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result - v = N; - // For precise stacks, the garbage collector assumes results - // are always live, so zero them always. - if(out) { - // Defer might stop a panic and show the - // return values as they exist at the time of panic. - // Make sure to zero them on entry to the function. - nn = list(nn, nod(OAS, nodarg(t, 1), N)); - } - if(v == N || !(v->class & PHEAP)) - continue; - - // generate allocation & copying code - if(compiling_runtime) - yyerror("%N escapes to heap, not allowed in runtime.", v); - if(v->alloc == nil) - v->alloc = callnew(v->type); - nn = list(nn, nod(OAS, v->heapaddr, v->alloc)); - if((v->class & ~PHEAP) != PPARAMOUT) { - as = nod(OAS, v, v->stackparam); - v->stackparam->typecheck = 1; - typecheck(&as, Etop); - as = applywritebarrier(as, &nn); - nn = list(nn, as); - } - } - return nn; -} - -/* - * walk through argout parameters copying back to stack - */ -static NodeList* -returnsfromheap(Type **argin) -{ - Type *t; - Iter savet; - Node *v; - NodeList *nn; - - nn = nil; - for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) { - v = t->nname; - if(v == N || v->class != (PHEAP|PPARAMOUT)) - continue; - nn = list(nn, nod(OAS, v->stackparam, v)); - } - return nn; -} - -/* - * take care of migrating any function in/out args - * between the stack and the heap. adds code to - * curfn's before and after lists. - */ -static void -heapmoves(void) -{ - NodeList *nn; - int32 lno; - - lno = lineno; - lineno = curfn->lineno; - nn = paramstoheap(getthis(curfn->type), 0); - nn = concat(nn, paramstoheap(getinarg(curfn->type), 0)); - nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1)); - curfn->enter = concat(curfn->enter, nn); - lineno = curfn->endlineno; - curfn->exit = returnsfromheap(getoutarg(curfn->type)); - lineno = lno; -} - -static Node* -vmkcall(Node *fn, Type *t, NodeList **init, va_list va) -{ - int i, n; - Node *r; - NodeList *args; - - if(fn->type == T || fn->type->etype != TFUNC) - fatal("mkcall %N %T", fn, fn->type); - - args = nil; - n = fn->type->intuple; - for(i=0; ilist = args; - if(fn->type->outtuple > 0) - typecheck(&r, Erv | Efnstruct); - else - typecheck(&r, Etop); - walkexpr(&r, init); - r->type = t; - return r; -} - -Node* -mkcall(char *name, Type *t, NodeList **init, ...) -{ - Node *r; - va_list va; - - va_start(va, init); - r = vmkcall(syslook(name, 0), t, init, va); - va_end(va); - return r; -} - -Node* -mkcall1(Node *fn, Type *t, NodeList **init, ...) -{ - Node *r; - va_list va; - - va_start(va, init); - r = vmkcall(fn, t, init, va); - va_end(va); - return r; -} - -Node* -conv(Node *n, Type *t) -{ - if(eqtype(n->type, t)) - return n; - n = nod(OCONV, n, N); - n->type = t; - typecheck(&n, Erv); - return n; -} - -Node* -chanfn(char *name, int n, Type *t) -{ - Node *fn; - int i; - - if(t->etype != TCHAN) - fatal("chanfn %T", t); - fn = syslook(name, 1); - for(i=0; itype); - return fn; -} - -static Node* -mapfn(char *name, Type *t) -{ - Node *fn; - - if(t->etype != TMAP) - fatal("mapfn %T", t); - fn = syslook(name, 1); - argtype(fn, t->down); - argtype(fn, t->type); - argtype(fn, t->down); - argtype(fn, t->type); - return fn; -} - -static Node* -mapfndel(char *name, Type *t) -{ - Node *fn; - - if(t->etype != TMAP) - fatal("mapfn %T", t); - fn = syslook(name, 1); - argtype(fn, t->down); - argtype(fn, t->type); - argtype(fn, t->down); - return fn; -} - -static Node* -writebarrierfn(char *name, Type *l, Type *r) -{ - Node *fn; - - fn = syslook(name, 1); - argtype(fn, l); - argtype(fn, r); - return fn; -} - -static Node* -addstr(Node *n, NodeList **init) -{ - Node *r, *cat, *slice, *buf; - NodeList *args, *l; - int c; - vlong sz; - Type *t; - - // orderexpr rewrote OADDSTR to have a list of strings. - c = count(n->list); - if(c < 2) - yyerror("addstr count %d too small", c); - - buf = nodnil(); - if(n->esc == EscNone) { - sz = 0; - for(l=n->list; l != nil; l=l->next) { - if(n->op == OLITERAL) - sz += n->val.u.sval->len; - } - // Don't allocate the buffer if the result won't fit. - if(sz < tmpstringbufsize) { - // Create temporary buffer for result string on stack. - t = aindex(nodintconst(tmpstringbufsize), types[TUINT8]); - buf = nod(OADDR, temp(t), N); - } - } - - // build list of string arguments - args = list1(buf); - for(l=n->list; l != nil; l=l->next) - args = list(args, conv(l->n, types[TSTRING])); - - if(c <= 5) { - // small numbers of strings use direct runtime helpers. - // note: orderexpr knows this cutoff too. - snprint(namebuf, sizeof(namebuf), "concatstring%d", c); - } else { - // large numbers of strings are passed to the runtime as a slice. - strcpy(namebuf, "concatstrings"); - t = typ(TARRAY); - t->type = types[TSTRING]; - t->bound = -1; - slice = nod(OCOMPLIT, N, typenod(t)); - slice->alloc = n->alloc; - slice->list = args->next; // skip buf arg - args = list1(buf); - args = list(args, slice); - slice->esc = EscNone; - } - cat = syslook(namebuf, 1); - r = nod(OCALL, cat, N); - r->list = args; - typecheck(&r, Erv); - walkexpr(&r, init); - r->type = n->type; - - return r; -} - -// expand append(l1, l2...) to -// init { -// s := l1 -// if n := len(l1) + len(l2) - cap(s); n > 0 { -// s = growslice(s, n) -// } -// s = s[:len(l1)+len(l2)] -// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) -// } -// s -// -// l2 is allowed to be a string. -static Node* -appendslice(Node *n, NodeList **init) -{ - NodeList *l; - Node *l1, *l2, *nt, *nif, *fn; - Node *nptr1, *nptr2, *nwid; - Node *s; - - walkexprlistsafe(n->list, init); - - // walkexprlistsafe will leave OINDEX (s[n]) alone if both s - // and n are name or literal, but those may index the slice we're - // modifying here. Fix explicitly. - for(l=n->list; l; l=l->next) - l->n = cheapexpr(l->n, init); - - l1 = n->list->n; - l2 = n->list->next->n; - - s = temp(l1->type); // var s []T - l = nil; - l = list(l, nod(OAS, s, l1)); // s = l1 - - nt = temp(types[TINT]); - nif = nod(OIF, N, N); - // n := len(s) + len(l2) - cap(s) - nif->ninit = list1(nod(OAS, nt, - nod(OSUB, nod(OADD, nod(OLEN, s, N), nod(OLEN, l2, N)), nod(OCAP, s, N)))); - nif->ntest = nod(OGT, nt, nodintconst(0)); - // instantiate growslice(Type*, []any, int64) []any - fn = syslook("growslice", 1); - argtype(fn, s->type->type); - argtype(fn, s->type->type); - - // s = growslice(T, s, n) - nif->nbody = list1(nod(OAS, s, mkcall1(fn, s->type, &nif->ninit, - typename(s->type), - s, - conv(nt, types[TINT64])))); - - l = list(l, nif); - - if(haspointers(l1->type->type)) { - // copy(s[len(l1):len(l1)+len(l2)], l2) - nptr1 = nod(OSLICE, s, nod(OKEY, - nod(OLEN, l1, N), - nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N)))); - nptr1->etype = 1; - nptr2 = l2; - fn = syslook("typedslicecopy", 1); - argtype(fn, l1->type); - argtype(fn, l2->type); - nt = mkcall1(fn, types[TINT], &l, - typename(l1->type->type), - nptr1, nptr2); - l = list(l, nt); - } else if(flag_race) { - // rely on runtime to instrument copy. - // copy(s[len(l1):len(l1)+len(l2)], l2) - nptr1 = nod(OSLICE, s, nod(OKEY, - nod(OLEN, l1, N), - nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N)))); - nptr1->etype = 1; - nptr2 = l2; - if(l2->type->etype == TSTRING) - fn = syslook("slicestringcopy", 1); - else - fn = syslook("slicecopy", 1); - argtype(fn, l1->type); - argtype(fn, l2->type); - nt = mkcall1(fn, types[TINT], &l, - nptr1, nptr2, - nodintconst(s->type->type->width)); - l = list(l, nt); - } else { - // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) - nptr1 = nod(OINDEX, s, nod(OLEN, l1, N)); - nptr1->bounded = 1; - nptr1 = nod(OADDR, nptr1, N); - - nptr2 = nod(OSPTR, l2, N); - - fn = syslook("memmove", 1); - argtype(fn, s->type->type); // 1 old []any - argtype(fn, s->type->type); // 2 ret []any - - nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l); - nwid = nod(OMUL, nwid, nodintconst(s->type->type->width)); - nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid); - l = list(l, nt); - } - - // s = s[:len(l1)+len(l2)] - nt = nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N)); - nt = nod(OSLICE, s, nod(OKEY, N, nt)); - nt->etype = 1; - l = list(l, nod(OAS, s, nt)); - - typechecklist(l, Etop); - walkstmtlist(l); - *init = concat(*init, l); - return s; -} - -// expand append(src, a [, b]* ) to -// -// init { -// s := src -// const argc = len(args) - 1 -// if cap(s) - len(s) < argc { -// s = growslice(s, argc) -// } -// n := len(s) -// s = s[:n+argc] -// s[n] = a -// s[n+1] = b -// ... -// } -// s -static Node* -append(Node *n, NodeList **init) -{ - NodeList *l, *a; - Node *nsrc, *ns, *nn, *na, *nx, *fn; - int argc; - - walkexprlistsafe(n->list, init); - - // walkexprlistsafe will leave OINDEX (s[n]) alone if both s - // and n are name or literal, but those may index the slice we're - // modifying here. Fix explicitly. - for(l=n->list; l; l=l->next) - l->n = cheapexpr(l->n, init); - - nsrc = n->list->n; - - // Resolve slice type of multi-valued return. - if(istype(nsrc->type, TSTRUCT)) - nsrc->type = nsrc->type->type->type; - argc = count(n->list) - 1; - if (argc < 1) { - return nsrc; - } - - l = nil; - - ns = temp(nsrc->type); - l = list(l, nod(OAS, ns, nsrc)); // s = src - - na = nodintconst(argc); // const argc - nx = nod(OIF, N, N); // if cap(s) - len(s) < argc - nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na); - - fn = syslook("growslice", 1); // growslice(, old []T, n int64) (ret []T) - argtype(fn, ns->type->type); // 1 old []any - argtype(fn, ns->type->type); // 2 ret []any - - nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit, - typename(ns->type), - ns, - conv(na, types[TINT64])))); - l = list(l, nx); - - nn = temp(types[TINT]); - l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s) - - nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc] - nx->etype = 1; - l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc] - - for (a = n->list->next; a != nil; a = a->next) { - nx = nod(OINDEX, ns, nn); // s[n] ... - nx->bounded = 1; - l = list(l, nod(OAS, nx, a->n)); // s[n] = arg - if (a->next != nil) - l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1 - } - - typechecklist(l, Etop); - walkstmtlist(l); - *init = concat(*init, l); - return ns; -} - -// Lower copy(a, b) to a memmove call or a runtime call. -// -// init { -// n := len(a) -// if n > len(b) { n = len(b) } -// memmove(a.ptr, b.ptr, n*sizeof(elem(a))) -// } -// n; -// -// Also works if b is a string. -// -static Node* -copyany(Node *n, NodeList **init, int runtimecall) -{ - Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn; - NodeList *l; - - if(haspointers(n->left->type->type)) { - fn = writebarrierfn("typedslicecopy", n->left->type, n->right->type); - return mkcall1(fn, n->type, init, typename(n->left->type->type), n->left, n->right); - } - - if(runtimecall) { - if(n->right->type->etype == TSTRING) - fn = syslook("slicestringcopy", 1); - else - fn = syslook("slicecopy", 1); - argtype(fn, n->left->type); - argtype(fn, n->right->type); - return mkcall1(fn, n->type, init, - n->left, n->right, - nodintconst(n->left->type->type->width)); - } - walkexpr(&n->left, init); - walkexpr(&n->right, init); - nl = temp(n->left->type); - nr = temp(n->right->type); - l = nil; - l = list(l, nod(OAS, nl, n->left)); - l = list(l, nod(OAS, nr, n->right)); - - nfrm = nod(OSPTR, nr, N); - nto = nod(OSPTR, nl, N); - - nlen = temp(types[TINT]); - // n = len(to) - l = list(l, nod(OAS, nlen, nod(OLEN, nl, N))); - // if n > len(frm) { n = len(frm) } - nif = nod(OIF, N, N); - nif->ntest = nod(OGT, nlen, nod(OLEN, nr, N)); - nif->nbody = list(nif->nbody, - nod(OAS, nlen, nod(OLEN, nr, N))); - l = list(l, nif); - - // Call memmove. - fn = syslook("memmove", 1); - argtype(fn, nl->type->type); - argtype(fn, nl->type->type); - nwid = temp(types[TUINTPTR]); - l = list(l, nod(OAS, nwid, conv(nlen, types[TUINTPTR]))); - nwid = nod(OMUL, nwid, nodintconst(nl->type->type->width)); - l = list(l, mkcall1(fn, T, init, nto, nfrm, nwid)); - - typechecklist(l, Etop); - walkstmtlist(l); - *init = concat(*init, l); - return nlen; -} - -// Generate frontend part for OSLICE[3][ARR|STR] -// -static Node* -sliceany(Node* n, NodeList **init) -{ - int bounded, slice3; - Node *src, *lb, *hb, *cb, *bound, *chk, *chk0, *chk1, *chk2; - int64 lbv, hbv, cbv, bv, w; - Type *bt; - -// print("before sliceany: %+N\n", n); - - src = n->left; - lb = n->right->left; - slice3 = n->op == OSLICE3 || n->op == OSLICE3ARR; - if(slice3) { - hb = n->right->right->left; - cb = n->right->right->right; - } else { - hb = n->right->right; - cb = N; - } - - bounded = n->etype; - - if(n->op == OSLICESTR) - bound = nod(OLEN, src, N); - else - bound = nod(OCAP, src, N); - - typecheck(&bound, Erv); - walkexpr(&bound, init); // if src is an array, bound will be a const now. - - // static checks if possible - bv = 1LL<<50; - if(isconst(bound, CTINT)) { - if(!smallintconst(bound)) - yyerror("array len too large"); - else - bv = mpgetfix(bound->val.u.xval); - } - - if(isconst(cb, CTINT)) { - cbv = mpgetfix(cb->val.u.xval); - if(cbv < 0 || cbv > bv) - yyerror("slice index out of bounds"); - } - if(isconst(hb, CTINT)) { - hbv = mpgetfix(hb->val.u.xval); - if(hbv < 0 || hbv > bv) - yyerror("slice index out of bounds"); - } - if(isconst(lb, CTINT)) { - lbv = mpgetfix(lb->val.u.xval); - if(lbv < 0 || lbv > bv) { - yyerror("slice index out of bounds"); - lbv = -1; - } - if(lbv == 0) - lb = N; - } - - // Checking src[lb:hb:cb] or src[lb:hb]. - // if chk0 || chk1 || chk2 { panicslice() } - chk = N; - chk0 = N; // cap(src) < cb - chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb] - chk2 = N; // hb < lb - - // All comparisons are unsigned to avoid testing < 0. - bt = types[simtype[TUINT]]; - if(cb != N && cb->type->width > 4) - bt = types[TUINT64]; - if(hb != N && hb->type->width > 4) - bt = types[TUINT64]; - if(lb != N && lb->type->width > 4) - bt = types[TUINT64]; - - bound = cheapexpr(conv(bound, bt), init); - - if(cb != N) { - cb = cheapexpr(conv(cb, bt), init); - if(!bounded) - chk0 = nod(OLT, bound, cb); - } else if(slice3) { - // When we figure out what this means, implement it. - fatal("slice3 with cb == N"); // rejected by parser - } - - if(hb != N) { - hb = cheapexpr(conv(hb, bt), init); - if(!bounded) { - if(cb != N) - chk1 = nod(OLT, cb, hb); - else - chk1 = nod(OLT, bound, hb); - } - } else if(slice3) { - // When we figure out what this means, implement it. - fatal("slice3 with hb == N"); // rejected by parser - } else if(n->op == OSLICEARR) { - hb = bound; - } else { - hb = nod(OLEN, src, N); - typecheck(&hb, Erv); - walkexpr(&hb, init); - hb = cheapexpr(conv(hb, bt), init); - } - - if(lb != N) { - lb = cheapexpr(conv(lb, bt), init); - if(!bounded) - chk2 = nod(OLT, hb, lb); - } - - if(chk0 != N || chk1 != N || chk2 != N) { - chk = nod(OIF, N, N); - chk->nbody = list1(mkcall("panicslice", T, init)); - chk->likely = -1; - if(chk0 != N) - chk->ntest = chk0; - if(chk1 != N) { - if(chk->ntest == N) - chk->ntest = chk1; - else - chk->ntest = nod(OOROR, chk->ntest, chk1); - } - if(chk2 != N) { - if(chk->ntest == N) - chk->ntest = chk2; - else - chk->ntest = nod(OOROR, chk->ntest, chk2); - } - typecheck(&chk, Etop); - walkstmt(&chk); - *init = concat(*init, chk->ninit); - chk->ninit = nil; - *init = list(*init, chk); - } - - // prepare new cap, len and offs for backend cgen_slice - // cap = bound [ - lo ] - n->right = N; - n->list = nil; - if(!slice3) - cb = bound; - if(lb == N) - bound = conv(cb, types[simtype[TUINT]]); - else - bound = nod(OSUB, conv(cb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]])); - typecheck(&bound, Erv); - walkexpr(&bound, init); - n->list = list(n->list, bound); - - // len = hi [ - lo] - if(lb == N) - hb = conv(hb, types[simtype[TUINT]]); - else - hb = nod(OSUB, conv(hb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]])); - typecheck(&hb, Erv); - walkexpr(&hb, init); - n->list = list(n->list, hb); - - // offs = [width *] lo, but omit if zero - if(lb != N) { - if(n->op == OSLICESTR) - w = 1; - else - w = n->type->type->width; - lb = conv(lb, types[TUINTPTR]); - if(w > 1) - lb = nod(OMUL, nodintconst(w), lb); - typecheck(&lb, Erv); - walkexpr(&lb, init); - n->list = list(n->list, lb); - } - -// print("after sliceany: %+N\n", n); - - return n; -} - -static Node* -eqfor(Type *t, int *needsize) -{ - int a; - Node *n; - Node *ntype; - Sym *sym; - - // Should only arrive here with large memory or - // a struct/array containing a non-memory field/element. - // Small memory is handled inline, and single non-memory - // is handled during type check (OCMPSTR etc). - a = algtype1(t, nil); - if(a != AMEM && a != -1) - fatal("eqfor %T", t); - - if(a == AMEM) { - n = syslook("memequal", 1); - argtype(n, t); - argtype(n, t); - *needsize = 1; - return n; - } - - sym = typesymprefix(".eq", t); - n = newname(sym); - n->class = PFUNC; - ntype = nod(OTFUNC, N, N); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); - ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t)))); - ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL]))); - typecheck(&ntype, Etype); - n->type = ntype->type; - *needsize = 0; - return n; -} - -static int -countfield(Type *t) -{ - Type *t1; - int n; - - n = 0; - for(t1=t->type; t1!=T; t1=t1->down) - n++; - return n; -} - -static void -walkcompare(Node **np, NodeList **init) -{ - Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr; - Node *x, *ok; - int andor, i, needsize; - Type *t, *t1; - - n = *np; - - // Given interface value l and concrete value r, rewrite - // l == r - // to - // x, ok := l.(type(r)); ok && x == r - // Handle != similarly. - // This avoids the allocation that would be required - // to convert r to l for comparison. - l = N; - r = N; - if(isinter(n->left->type) && !isinter(n->right->type)) { - l = n->left; - r = n->right; - } else if(!isinter(n->left->type) && isinter(n->right->type)) { - l = n->right; - r = n->left; - } - if(l != N) { - x = temp(r->type); - ok = temp(types[TBOOL]); - - // l.(type(r)) - a = nod(ODOTTYPE, l, N); - a->type = r->type; - - // x, ok := l.(type(r)) - expr = nod(OAS2, N, N); - expr->list = list1(x); - expr->list = list(expr->list, ok); - expr->rlist = list1(a); - typecheck(&expr, Etop); - walkexpr(&expr, init); - - if(n->op == OEQ) - r = nod(OANDAND, ok, nod(OEQ, x, r)); - else - r = nod(OOROR, nod(ONOT, ok, N), nod(ONE, x, r)); - *init = list(*init, expr); - goto ret; - } - - // Must be comparison of array or struct. - // Otherwise back end handles it. - t = n->left->type; - switch(t->etype) { - default: - return; - case TARRAY: - if(isslice(t)) - return; - break; - case TSTRUCT: - break; - } - - cmpl = n->left; - while(cmpl != N && cmpl->op == OCONVNOP) - cmpl = cmpl->left; - cmpr = n->right; - while(cmpr != N && cmpr->op == OCONVNOP) - cmpr = cmpr->left; - - if(!islvalue(cmpl) || !islvalue(cmpr)) { - fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr); - } - - l = temp(ptrto(t)); - a = nod(OAS, l, nod(OADDR, cmpl, N)); - a->right->etype = 1; // addr does not escape - typecheck(&a, Etop); - *init = list(*init, a); - - r = temp(ptrto(t)); - a = nod(OAS, r, nod(OADDR, cmpr, N)); - a->right->etype = 1; // addr does not escape - typecheck(&a, Etop); - *init = list(*init, a); - - expr = N; - andor = OANDAND; - if(n->op == ONE) - andor = OOROR; - - if(t->etype == TARRAY && - t->bound <= 4 && - issimple[t->type->etype]) { - // Four or fewer elements of a basic type. - // Unroll comparisons. - for(i=0; ibound; i++) { - li = nod(OINDEX, l, nodintconst(i)); - ri = nod(OINDEX, r, nodintconst(i)); - a = nod(n->op, li, ri); - if(expr == N) - expr = a; - else - expr = nod(andor, expr, a); - } - if(expr == N) - expr = nodbool(n->op == OEQ); - r = expr; - goto ret; - } - - if(t->etype == TSTRUCT && countfield(t) <= 4) { - // Struct of four or fewer fields. - // Inline comparisons. - for(t1=t->type; t1; t1=t1->down) { - if(isblanksym(t1->sym)) - continue; - li = nod(OXDOT, l, newname(t1->sym)); - ri = nod(OXDOT, r, newname(t1->sym)); - a = nod(n->op, li, ri); - if(expr == N) - expr = a; - else - expr = nod(andor, expr, a); - } - if(expr == N) - expr = nodbool(n->op == OEQ); - r = expr; - goto ret; - } - - // Chose not to inline. Call equality function directly. - call = nod(OCALL, eqfor(t, &needsize), N); - call->list = list(call->list, l); - call->list = list(call->list, r); - if(needsize) - call->list = list(call->list, nodintconst(t->width)); - r = call; - if(n->op != OEQ) - r = nod(ONOT, r, N); - goto ret; - -ret: - typecheck(&r, Erv); - walkexpr(&r, init); - if(r->type != n->type) { - r = nod(OCONVNOP, r, N); - r->type = n->type; - r->typecheck = 1; - } - *np = r; - return; -} - -static int -samecheap(Node *a, Node *b) -{ - Node *ar, *br; - while(a != N && b != N && a->op == b->op) { - switch(a->op) { - default: - return 0; - case ONAME: - return a == b; - case ODOT: - case ODOTPTR: - ar = a->right; - br = b->right; - if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym) - return 0; - break; - case OINDEX: - ar = a->right; - br = b->right; - if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0) - return 0; - break; - } - a = a->left; - b = b->left; - } - return 0; -} - -static void -walkrotate(Node **np) -{ - int w, sl, sr, s; - Node *l, *r; - Node *n; - - if(thearch.thechar == '9') - return; - - n = *np; - - // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value. - l = n->left; - r = n->right; - if((n->op != OOR && n->op != OXOR) || - (l->op != OLSH && l->op != ORSH) || - (r->op != OLSH && r->op != ORSH) || - n->type == T || issigned[n->type->etype] || - l->op == r->op) { - return; - } - - // Want same, side effect-free expression on lhs of both shifts. - if(!samecheap(l->left, r->left)) - return; - - // Constants adding to width? - w = l->type->width * 8; - if(smallintconst(l->right) && smallintconst(r->right)) { - if((sl=mpgetfix(l->right->val.u.xval)) >= 0 && (sr=mpgetfix(r->right->val.u.xval)) >= 0 && sl+sr == w) - goto yes; - return; - } - - // TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31). - return; - -yes: - // Rewrite left shift half to left rotate. - if(l->op == OLSH) - n = l; - else - n = r; - n->op = OLROT; - - // Remove rotate 0 and rotate w. - s = mpgetfix(n->right->val.u.xval); - if(s == 0 || s == w) - n = n->left; - - *np = n; - return; -} - -/* - * walkmul rewrites integer multiplication by powers of two as shifts. - */ -static void -walkmul(Node **np, NodeList **init) -{ - Node *n, *nl, *nr; - int pow, neg, w; - - n = *np; - if(!isint[n->type->etype]) - return; - - if(n->right->op == OLITERAL) { - nl = n->left; - nr = n->right; - } else if(n->left->op == OLITERAL) { - nl = n->right; - nr = n->left; - } else - return; - - neg = 0; - - // x*0 is 0 (and side effects of x). - if(mpgetfix(nr->val.u.xval) == 0) { - cheapexpr(nl, init); - nodconst(n, n->type, 0); - goto ret; - } - - // nr is a constant. - pow = powtwo(nr); - if(pow < 0) - return; - if(pow >= 1000) { - // negative power of 2, like -16 - neg = 1; - pow -= 1000; - } - - w = nl->type->width*8; - if(pow+1 >= w)// too big, shouldn't happen - return; - - nl = cheapexpr(nl, init); - - if(pow == 0) { - // x*1 is x - n = nl; - goto ret; - } - - n = nod(OLSH, nl, nodintconst(pow)); - -ret: - if(neg) - n = nod(OMINUS, n, N); - - typecheck(&n, Erv); - walkexpr(&n, init); - *np = n; -} - -/* - * walkdiv rewrites division by a constant as less expensive - * operations. - */ -static void -walkdiv(Node **np, NodeList **init) -{ - Node *n, *nl, *nr, *nc; - Node *n1, *n2, *n3, *n4; - int pow; // if >= 0, nr is 1<right->op != OLITERAL) - return; - // nr is a constant. - nl = cheapexpr(n->left, init); - nr = n->right; - - // special cases of mod/div - // by a constant - w = nl->type->width*8; - s = 0; - pow = powtwo(nr); - if(pow >= 1000) { - // negative power of 2 - s = 1; - pow -= 1000; - } - - if(pow+1 >= w) { - // divisor too large. - return; - } - if(pow < 0) { - goto divbymul; - } - - switch(pow) { - case 0: - if(n->op == OMOD) { - // nl % 1 is zero. - nodconst(n, n->type, 0); - } else if(s) { - // divide by -1 - n->op = OMINUS; - n->right = N; - } else { - // divide by 1 - n = nl; - } - break; - default: - if(issigned[n->type->etype]) { - if(n->op == OMOD) { - // signed modulo 2^pow is like ANDing - // with the last pow bits, but if nl < 0, - // nl & (2^pow-1) is (nl+1)%2^pow - 1. - nc = nod(OXXX, N, N); - nodconst(nc, types[simtype[TUINT]], w-1); - n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0. - if(pow == 1) { - typecheck(&n1, Erv); - n1 = cheapexpr(n1, init); - // n = (nl+ε)&1 -ε where ε=1 iff nl<0. - n2 = nod(OSUB, nl, n1); - nc = nod(OXXX, N, N); - nodconst(nc, nl->type, 1); - n3 = nod(OAND, n2, nc); - n = nod(OADD, n3, n1); - } else { - // n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0. - nc = nod(OXXX, N, N); - nodconst(nc, nl->type, (1LL<= 0, nl >> n == nl / nr - // if nl < 0, we want to add 2^n-1 first. - nc = nod(OXXX, N, N); - nodconst(nc, types[simtype[TUINT]], w-1); - n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0. - if(pow == 1) { - // nl+1 is nl-(-1) - n->left = nod(OSUB, nl, n1); - } else { - // Do a logical right right on -1 to keep pow bits. - nc = nod(OXXX, N, N); - nodconst(nc, types[simtype[TUINT]], w-pow); - n2 = nod(ORSH, conv(n1, tounsigned(nl->type)), nc); - n->left = nod(OADD, nl, conv(n2, nl->type)); - } - // n = (nl + 2^pow-1) >> pow - n->op = ORSH; - nc = nod(OXXX, N, N); - nodconst(nc, types[simtype[TUINT]], pow); - n->right = nc; - n->typecheck = 0; - } - if(s) - n = nod(OMINUS, n, N); - break; - } - nc = nod(OXXX, N, N); - if(n->op == OMOD) { - // n = nl & (nr-1) - n->op = OAND; - nodconst(nc, nl->type, mpgetfix(nr->val.u.xval)-1); - } else { - // n = nl >> pow - n->op = ORSH; - nodconst(nc, types[simtype[TUINT]], pow); - } - n->typecheck = 0; - n->right = nc; - break; - } - goto ret; - -divbymul: - // try to do division by multiply by (2^w)/d - // see hacker's delight chapter 10 - // TODO: support 64-bit magic multiply here. - m.w = w; - if(issigned[nl->type->etype]) { - m.sd = mpgetfix(nr->val.u.xval); - smagic(&m); - } else { - m.ud = mpgetfix(nr->val.u.xval); - umagic(&m); - } - if(m.bad) - return; - - // We have a quick division method so use it - // for modulo too. - if(n->op == OMOD) - goto longmod; - - switch(simtype[nl->type->etype]) { - default: - return; - - case TUINT8: - case TUINT16: - case TUINT32: - // n1 = nl * magic >> w (HMUL) - nc = nod(OXXX, N, N); - nodconst(nc, nl->type, m.um); - n1 = nod(OMUL, nl, nc); - typecheck(&n1, Erv); - n1->op = OHMUL; - if(m.ua) { - // Select a Go type with (at least) twice the width. - switch(simtype[nl->type->etype]) { - default: - return; - case TUINT8: - case TUINT16: - twide = types[TUINT32]; - break; - case TUINT32: - twide = types[TUINT64]; - break; - case TINT8: - case TINT16: - twide = types[TINT32]; - break; - case TINT32: - twide = types[TINT64]; - break; - } - - // add numerator (might overflow). - // n2 = (n1 + nl) - n2 = nod(OADD, conv(n1, twide), conv(nl, twide)); - - // shift by m.s - nc = nod(OXXX, N, N); - nodconst(nc, types[TUINT], m.s); - n = conv(nod(ORSH, n2, nc), nl->type); - } else { - // n = n1 >> m.s - nc = nod(OXXX, N, N); - nodconst(nc, types[TUINT], m.s); - n = nod(ORSH, n1, nc); - } - break; - - case TINT8: - case TINT16: - case TINT32: - // n1 = nl * magic >> w - nc = nod(OXXX, N, N); - nodconst(nc, nl->type, m.sm); - n1 = nod(OMUL, nl, nc); - typecheck(&n1, Erv); - n1->op = OHMUL; - if(m.sm < 0) { - // add the numerator. - n1 = nod(OADD, n1, nl); - } - // shift by m.s - nc = nod(OXXX, N, N); - nodconst(nc, types[TUINT], m.s); - n2 = conv(nod(ORSH, n1, nc), nl->type); - // add 1 iff n1 is negative. - nc = nod(OXXX, N, N); - nodconst(nc, types[TUINT], w-1); - n3 = nod(ORSH, nl, nc); // n4 = -1 iff n1 is negative. - n = nod(OSUB, n2, n3); - // apply sign. - if(m.sd < 0) - n = nod(OMINUS, n, N); - break; - } - goto ret; - -longmod: - // rewrite as A%B = A - (A/B*B). - n1 = nod(ODIV, nl, nr); - n2 = nod(OMUL, n1, nr); - n = nod(OSUB, nl, n2); - goto ret; - -ret: - typecheck(&n, Erv); - walkexpr(&n, init); - *np = n; -} - -// return 1 if integer n must be in range [0, max), 0 otherwise -static int -bounded(Node *n, int64 max) -{ - int64 v; - int32 bits; - int sign; - - if(n->type == T || !isint[n->type->etype]) - return 0; - - sign = issigned[n->type->etype]; - bits = 8*n->type->width; - - if(smallintconst(n)) { - v = mpgetfix(n->val.u.xval); - return 0 <= v && v < max; - } - - switch(n->op) { - case OAND: - v = -1; - if(smallintconst(n->left)) { - v = mpgetfix(n->left->val.u.xval); - } else if(smallintconst(n->right)) { - v = mpgetfix(n->right->val.u.xval); - } - if(0 <= v && v < max) - return 1; - break; - - case OMOD: - if(!sign && smallintconst(n->right)) { - v = mpgetfix(n->right->val.u.xval); - if(0 <= v && v <= max) - return 1; - } - break; - - case ODIV: - if(!sign && smallintconst(n->right)) { - v = mpgetfix(n->right->val.u.xval); - while(bits > 0 && v >= 2) { - bits--; - v >>= 1; - } - } - break; - - case ORSH: - if(!sign && smallintconst(n->right)) { - v = mpgetfix(n->right->val.u.xval); - if(v > bits) - return 1; - bits -= v; - } - break; - } - - if(!sign && bits <= 62 && (1LL<op) { - default: - fatal("usefield %O", n->op); - case ODOT: - case ODOTPTR: - break; - } - - field = n->paramfld; - if(field == T) - fatal("usefield %T %S without paramfld", n->left->type, n->right->sym); - if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil) - return; - - // dedup on list - if(field->lastfn == curfn) - return; - field->lastfn = curfn; - field->outer = n->left->type; - if(isptr[field->outer->etype]) - field->outer = field->outer->type; - if(field->outer->sym == S) - yyerror("tracked field must be in named struct type"); - if(!exportname(field->sym->name)) - yyerror("tracked field must be exported (upper case)"); - - l = typ(0); - l->type = field; - l->down = curfn->paramfld; - curfn->paramfld = l; -} - -static int -candiscardlist(NodeList *l) -{ - for(; l; l=l->next) - if(!candiscard(l->n)) - return 0; - return 1; -} - -int -candiscard(Node *n) -{ - if(n == N) - return 1; - - switch(n->op) { - default: - return 0; - - case ONAME: - case ONONAME: - case OTYPE: - case OPACK: - case OLITERAL: - case OADD: - case OSUB: - case OOR: - case OXOR: - case OADDSTR: - case OADDR: - case OANDAND: - case OARRAYBYTESTR: - case OARRAYRUNESTR: - case OSTRARRAYBYTE: - case OSTRARRAYRUNE: - case OCAP: - case OCMPIFACE: - case OCMPSTR: - case OCOMPLIT: - case OMAPLIT: - case OSTRUCTLIT: - case OARRAYLIT: - case OPTRLIT: - case OCONV: - case OCONVIFACE: - case OCONVNOP: - case ODOT: - case OEQ: - case ONE: - case OLT: - case OLE: - case OGT: - case OGE: - case OKEY: - case OLEN: - case OMUL: - case OLSH: - case ORSH: - case OAND: - case OANDNOT: - case ONEW: - case ONOT: - case OCOM: - case OPLUS: - case OMINUS: - case OOROR: - case OPAREN: - case ORUNESTR: - case OREAL: - case OIMAG: - case OCOMPLEX: - // Discardable as long as the subpieces are. - break; - - case ODIV: - case OMOD: - // Discardable as long as we know it's not division by zero. - if(isconst(n->right, CTINT) && mpcmpfixc(n->right->val.u.xval, 0) != 0) - break; - if(isconst(n->right, CTFLT) && mpcmpfltc(n->right->val.u.fval, 0) != 0) - break; - return 0; - - case OMAKECHAN: - case OMAKEMAP: - // Discardable as long as we know it won't fail because of a bad size. - if(isconst(n->left, CTINT) && mpcmpfixc(n->left->val.u.xval, 0) == 0) - break; - return 0; - - case OMAKESLICE: - // Difficult to tell what sizes are okay. - return 0; - } - - if(!candiscard(n->left) || - !candiscard(n->right) || - !candiscard(n->ntest) || - !candiscard(n->nincr) || - !candiscardlist(n->ninit) || - !candiscardlist(n->nbody) || - !candiscardlist(n->nelse) || - !candiscardlist(n->list) || - !candiscardlist(n->rlist)) { - return 0; - } - - return 1; -} - -// rewrite -// print(x, y, z) -// into -// func(a1, a2, a3) { -// print(a1, a2, a3) -// }(x, y, z) -// and same for println. -static void -walkprintfunc(Node **np, NodeList **init) -{ - Node *n; - Node *a, *fn, *t, *oldfn; - NodeList *l, *printargs; - int num; - char buf[100]; - static int prgen; - - n = *np; - - if(n->ninit != nil) { - walkstmtlist(n->ninit); - *init = concat(*init, n->ninit); - n->ninit = nil; - } - - t = nod(OTFUNC, N, N); - num = 0; - printargs = nil; - for(l=n->list; l != nil; l=l->next) { - snprint(buf, sizeof buf, "a%d", num++); - a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type)); - t->list = list(t->list, a); - printargs = list(printargs, a->left); - } - - fn = nod(ODCLFUNC, N, N); - snprint(buf, sizeof buf, "print·%d", ++prgen); - fn->nname = newname(lookup(buf)); - fn->nname->defn = fn; - fn->nname->ntype = t; - declare(fn->nname, PFUNC); - - oldfn = curfn; - curfn = nil; - funchdr(fn); - - a = nod(n->op, N, N); - a->list = printargs; - typecheck(&a, Etop); - walkstmt(&a); - - fn->nbody = list1(a); - - funcbody(fn); - - typecheck(&fn, Etop); - typechecklist(fn->nbody, Etop); - xtop = list(xtop, fn); - curfn = oldfn; - - a = nod(OCALL, N, N); - a->left = fn->nname; - a->list = n->list; - typecheck(&a, Etop); - walkexpr(&a, init); - *np = a; -} diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c deleted file mode 100644 index d45623a3e6..0000000000 --- a/src/cmd/gc/y.tab.c +++ /dev/null @@ -1,5134 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton implementation for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.3" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LLITERAL = 258, - LASOP = 259, - LCOLAS = 260, - LBREAK = 261, - LCASE = 262, - LCHAN = 263, - LCONST = 264, - LCONTINUE = 265, - LDDD = 266, - LDEFAULT = 267, - LDEFER = 268, - LELSE = 269, - LFALL = 270, - LFOR = 271, - LFUNC = 272, - LGO = 273, - LGOTO = 274, - LIF = 275, - LIMPORT = 276, - LINTERFACE = 277, - LMAP = 278, - LNAME = 279, - LPACKAGE = 280, - LRANGE = 281, - LRETURN = 282, - LSELECT = 283, - LSTRUCT = 284, - LSWITCH = 285, - LTYPE = 286, - LVAR = 287, - LANDAND = 288, - LANDNOT = 289, - LBODY = 290, - LCOMM = 291, - LDEC = 292, - LEQ = 293, - LGE = 294, - LGT = 295, - LIGNORE = 296, - LINC = 297, - LLE = 298, - LLSH = 299, - LLT = 300, - LNE = 301, - LOROR = 302, - LRSH = 303, - NotPackage = 304, - NotParen = 305, - PreferToRightParen = 306 - }; -#endif -/* Tokens. */ -#define LLITERAL 258 -#define LASOP 259 -#define LCOLAS 260 -#define LBREAK 261 -#define LCASE 262 -#define LCHAN 263 -#define LCONST 264 -#define LCONTINUE 265 -#define LDDD 266 -#define LDEFAULT 267 -#define LDEFER 268 -#define LELSE 269 -#define LFALL 270 -#define LFOR 271 -#define LFUNC 272 -#define LGO 273 -#define LGOTO 274 -#define LIF 275 -#define LIMPORT 276 -#define LINTERFACE 277 -#define LMAP 278 -#define LNAME 279 -#define LPACKAGE 280 -#define LRANGE 281 -#define LRETURN 282 -#define LSELECT 283 -#define LSTRUCT 284 -#define LSWITCH 285 -#define LTYPE 286 -#define LVAR 287 -#define LANDAND 288 -#define LANDNOT 289 -#define LBODY 290 -#define LCOMM 291 -#define LDEC 292 -#define LEQ 293 -#define LGE 294 -#define LGT 295 -#define LIGNORE 296 -#define LINC 297 -#define LLE 298 -#define LLSH 299 -#define LLT 300 -#define LNE 301 -#define LOROR 302 -#define LRSH 303 -#define NotPackage 304 -#define NotParen 305 -#define PreferToRightParen 306 - - - - -/* Copy the first part of user declarations. */ -#line 20 "go.y" - -#include -#include /* if we don't, bison will, and go.h re-#defines getc */ -#include -#include "go.h" - -static void fixlbrace(int); - - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 0 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 1 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 28 "go.y" -{ - Node* node; - NodeList* list; - Type* type; - Sym* sym; - struct Val val; - int i; -} -/* Line 193 of yacc.c. */ -#line 216 "y.tab.c" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - - - -/* Copy the second part of user declarations. */ - - -/* Line 216 of yacc.c. */ -#line 229 "y.tab.c" - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int i) -#else -static int -YYID (i) - int i; -#endif -{ - return i; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined _STDLIB_H \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef _STDLIB_H -# define _STDLIB_H 1 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss; - YYSTYPE yyvs; - }; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -/* Copy COUNT objects from FROM to TO. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(To, From, Count) \ - __builtin_memcpy (To, From, (Count) * sizeof (*(From))) -# else -# define YYCOPY(To, From, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (To)[yyi] = (From)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack, Stack, yysize); \ - Stack = &yyptr->Stack; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 4 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 2201 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 76 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 142 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 352 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 669 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 306 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 69, 2, 2, 64, 55, 56, 2, - 59, 60, 53, 49, 75, 50, 63, 54, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 66, 62, - 2, 65, 2, 73, 74, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 71, 2, 72, 52, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 67, 51, 68, 70, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 57, 58, 61 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 8, 9, 13, 14, 18, 19, 23, - 26, 32, 36, 40, 43, 45, 49, 51, 54, 57, - 62, 63, 65, 66, 71, 72, 74, 76, 78, 80, - 83, 89, 93, 96, 102, 110, 114, 117, 123, 127, - 129, 132, 137, 141, 146, 150, 152, 155, 157, 159, - 162, 164, 168, 172, 176, 179, 182, 186, 192, 198, - 201, 202, 207, 208, 212, 213, 216, 217, 222, 227, - 232, 235, 241, 243, 245, 248, 249, 253, 255, 259, - 260, 261, 262, 271, 272, 278, 279, 282, 283, 286, - 287, 288, 296, 297, 303, 305, 309, 313, 317, 321, - 325, 329, 333, 337, 341, 345, 349, 353, 357, 361, - 365, 369, 373, 377, 381, 385, 387, 390, 393, 396, - 399, 402, 405, 408, 411, 415, 421, 428, 430, 432, - 436, 442, 448, 453, 460, 469, 471, 477, 483, 489, - 497, 499, 500, 504, 506, 511, 513, 518, 520, 524, - 526, 528, 530, 532, 534, 536, 538, 539, 541, 543, - 545, 547, 552, 557, 559, 561, 563, 566, 568, 570, - 572, 574, 576, 580, 582, 584, 586, 589, 591, 593, - 595, 597, 601, 603, 605, 607, 609, 611, 613, 615, - 617, 619, 623, 628, 633, 636, 640, 646, 648, 650, - 653, 657, 663, 667, 673, 677, 681, 687, 696, 702, - 711, 717, 718, 722, 723, 725, 729, 731, 736, 739, - 740, 744, 746, 750, 752, 756, 758, 762, 764, 768, - 770, 774, 778, 781, 786, 790, 796, 802, 804, 808, - 810, 813, 815, 819, 824, 826, 829, 832, 834, 836, - 840, 841, 844, 845, 847, 849, 851, 853, 855, 857, - 859, 861, 863, 864, 869, 871, 874, 877, 880, 883, - 886, 889, 891, 895, 897, 901, 903, 907, 909, 913, - 915, 919, 921, 923, 927, 931, 932, 935, 936, 938, - 939, 941, 942, 944, 945, 947, 948, 950, 951, 953, - 954, 956, 957, 959, 960, 962, 967, 972, 978, 985, - 990, 995, 997, 999, 1001, 1003, 1005, 1007, 1009, 1011, - 1013, 1017, 1022, 1028, 1033, 1038, 1041, 1044, 1049, 1053, - 1057, 1063, 1067, 1072, 1076, 1082, 1084, 1085, 1087, 1091, - 1093, 1095, 1098, 1100, 1102, 1108, 1109, 1112, 1114, 1118, - 1120, 1124, 1126 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int16 yyrhs[] = -{ - 77, 0, -1, 79, 78, 81, 166, -1, -1, 25, - 141, 62, -1, -1, 80, 86, 88, -1, -1, 81, - 82, 62, -1, 21, 83, -1, 21, 59, 84, 190, - 60, -1, 21, 59, 60, -1, 85, 86, 88, -1, - 85, 88, -1, 83, -1, 84, 62, 83, -1, 3, - -1, 141, 3, -1, 63, 3, -1, 25, 24, 87, - 62, -1, -1, 24, -1, -1, 89, 214, 64, 64, - -1, -1, 91, -1, 158, -1, 181, -1, 1, -1, - 32, 93, -1, 32, 59, 167, 190, 60, -1, 32, - 59, 60, -1, 92, 94, -1, 92, 59, 94, 190, - 60, -1, 92, 59, 94, 62, 168, 190, 60, -1, - 92, 59, 60, -1, 31, 97, -1, 31, 59, 169, - 190, 60, -1, 31, 59, 60, -1, 9, -1, 185, - 146, -1, 185, 146, 65, 186, -1, 185, 65, 186, - -1, 185, 146, 65, 186, -1, 185, 65, 186, -1, - 94, -1, 185, 146, -1, 185, -1, 141, -1, 96, - 146, -1, 126, -1, 126, 4, 126, -1, 186, 65, - 186, -1, 186, 5, 186, -1, 126, 42, -1, 126, - 37, -1, 7, 187, 66, -1, 7, 187, 65, 126, - 66, -1, 7, 187, 5, 126, 66, -1, 12, 66, - -1, -1, 67, 101, 183, 68, -1, -1, 99, 103, - 183, -1, -1, 104, 102, -1, -1, 35, 106, 183, - 68, -1, 186, 65, 26, 126, -1, 186, 5, 26, - 126, -1, 26, 126, -1, 194, 62, 194, 62, 194, - -1, 194, -1, 107, -1, 108, 105, -1, -1, 16, - 111, 109, -1, 194, -1, 194, 62, 194, -1, -1, - -1, -1, 20, 114, 112, 115, 105, 116, 119, 120, - -1, -1, 14, 20, 118, 112, 105, -1, -1, 119, - 117, -1, -1, 14, 100, -1, -1, -1, 30, 122, - 112, 123, 35, 104, 68, -1, -1, 28, 125, 35, - 104, 68, -1, 127, -1, 126, 47, 126, -1, 126, - 33, 126, -1, 126, 38, 126, -1, 126, 46, 126, - -1, 126, 45, 126, -1, 126, 43, 126, -1, 126, - 39, 126, -1, 126, 40, 126, -1, 126, 49, 126, - -1, 126, 50, 126, -1, 126, 51, 126, -1, 126, - 52, 126, -1, 126, 53, 126, -1, 126, 54, 126, - -1, 126, 55, 126, -1, 126, 56, 126, -1, 126, - 34, 126, -1, 126, 44, 126, -1, 126, 48, 126, - -1, 126, 36, 126, -1, 134, -1, 53, 127, -1, - 56, 127, -1, 49, 127, -1, 50, 127, -1, 69, - 127, -1, 70, 127, -1, 52, 127, -1, 36, 127, - -1, 134, 59, 60, -1, 134, 59, 187, 191, 60, - -1, 134, 59, 187, 11, 191, 60, -1, 3, -1, - 143, -1, 134, 63, 141, -1, 134, 63, 59, 135, - 60, -1, 134, 63, 59, 31, 60, -1, 134, 71, - 126, 72, -1, 134, 71, 192, 66, 192, 72, -1, - 134, 71, 192, 66, 192, 66, 192, 72, -1, 128, - -1, 149, 59, 126, 191, 60, -1, 150, 137, 130, - 189, 68, -1, 129, 67, 130, 189, 68, -1, 59, - 135, 60, 67, 130, 189, 68, -1, 165, -1, -1, - 126, 66, 133, -1, 126, -1, 67, 130, 189, 68, - -1, 126, -1, 67, 130, 189, 68, -1, 129, -1, - 59, 135, 60, -1, 126, -1, 147, -1, 146, -1, - 35, -1, 67, -1, 141, -1, 141, -1, -1, 138, - -1, 24, -1, 142, -1, 73, -1, 74, 3, 63, - 24, -1, 74, 3, 63, 73, -1, 141, -1, 138, - -1, 11, -1, 11, 146, -1, 155, -1, 161, -1, - 153, -1, 154, -1, 152, -1, 59, 146, 60, -1, - 155, -1, 161, -1, 153, -1, 53, 147, -1, 161, - -1, 153, -1, 154, -1, 152, -1, 59, 146, 60, - -1, 161, -1, 153, -1, 153, -1, 155, -1, 161, - -1, 153, -1, 154, -1, 152, -1, 143, -1, 143, - 63, 141, -1, 71, 192, 72, 146, -1, 71, 11, - 72, 146, -1, 8, 148, -1, 8, 36, 146, -1, - 23, 71, 146, 72, 146, -1, 156, -1, 157, -1, - 53, 146, -1, 36, 8, 146, -1, 29, 137, 170, - 190, 68, -1, 29, 137, 68, -1, 22, 137, 171, - 190, 68, -1, 22, 137, 68, -1, 17, 159, 162, - -1, 141, 59, 179, 60, 163, -1, 59, 179, 60, - 141, 59, 179, 60, 163, -1, 200, 59, 195, 60, - 210, -1, 59, 215, 60, 141, 59, 195, 60, 210, - -1, 17, 59, 179, 60, 163, -1, -1, 67, 183, - 68, -1, -1, 151, -1, 59, 179, 60, -1, 161, - -1, 164, 137, 183, 68, -1, 164, 1, -1, -1, - 166, 90, 62, -1, 93, -1, 167, 62, 93, -1, - 95, -1, 168, 62, 95, -1, 97, -1, 169, 62, - 97, -1, 172, -1, 170, 62, 172, -1, 175, -1, - 171, 62, 175, -1, 184, 146, 198, -1, 174, 198, - -1, 59, 174, 60, 198, -1, 53, 174, 198, -1, - 59, 53, 174, 60, 198, -1, 53, 59, 174, 60, - 198, -1, 24, -1, 24, 63, 141, -1, 173, -1, - 138, 176, -1, 173, -1, 59, 173, 60, -1, 59, - 179, 60, 163, -1, 136, -1, 141, 136, -1, 141, - 145, -1, 145, -1, 177, -1, 178, 75, 177, -1, - -1, 178, 191, -1, -1, 100, -1, 91, -1, 181, - -1, 1, -1, 98, -1, 110, -1, 121, -1, 124, - -1, 113, -1, -1, 144, 66, 182, 180, -1, 15, - -1, 6, 140, -1, 10, 140, -1, 18, 128, -1, - 13, 128, -1, 19, 138, -1, 27, 193, -1, 180, - -1, 183, 62, 180, -1, 138, -1, 184, 75, 138, - -1, 139, -1, 185, 75, 139, -1, 126, -1, 186, - 75, 126, -1, 135, -1, 187, 75, 135, -1, 131, - -1, 132, -1, 188, 75, 131, -1, 188, 75, 132, - -1, -1, 188, 191, -1, -1, 62, -1, -1, 75, - -1, -1, 126, -1, -1, 186, -1, -1, 98, -1, - -1, 215, -1, -1, 216, -1, -1, 217, -1, -1, - 3, -1, 21, 24, 3, 62, -1, 32, 200, 202, - 62, -1, 9, 200, 65, 213, 62, -1, 9, 200, - 202, 65, 213, 62, -1, 31, 201, 202, 62, -1, - 17, 160, 162, 62, -1, 142, -1, 200, -1, 204, - -1, 205, -1, 206, -1, 204, -1, 206, -1, 142, - -1, 24, -1, 71, 72, 202, -1, 71, 3, 72, - 202, -1, 23, 71, 202, 72, 202, -1, 29, 67, - 196, 68, -1, 22, 67, 197, 68, -1, 53, 202, - -1, 8, 203, -1, 8, 59, 205, 60, -1, 8, - 36, 202, -1, 36, 8, 202, -1, 17, 59, 195, - 60, 210, -1, 141, 202, 198, -1, 141, 11, 202, - 198, -1, 141, 202, 198, -1, 141, 59, 195, 60, - 210, -1, 202, -1, -1, 211, -1, 59, 195, 60, - -1, 202, -1, 3, -1, 50, 3, -1, 141, -1, - 212, -1, 59, 212, 49, 212, 60, -1, -1, 214, - 199, -1, 207, -1, 215, 75, 207, -1, 208, -1, - 216, 62, 208, -1, 209, -1, 217, 62, 209, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 124, 124, 133, 139, 150, 150, 165, 166, 169, - 170, 171, 174, 211, 222, 223, 226, 233, 240, 249, - 263, 264, 271, 271, 284, 288, 289, 293, 298, 304, - 308, 312, 316, 322, 328, 334, 339, 343, 347, 353, - 359, 363, 367, 373, 377, 383, 384, 388, 394, 403, - 409, 427, 432, 444, 460, 466, 474, 494, 512, 521, - 540, 539, 554, 553, 585, 588, 595, 594, 605, 611, - 618, 625, 636, 642, 645, 653, 652, 663, 669, 681, - 685, 690, 680, 711, 710, 723, 726, 732, 735, 747, - 751, 746, 769, 768, 784, 785, 789, 793, 797, 801, - 805, 809, 813, 817, 821, 825, 829, 833, 837, 841, - 845, 849, 853, 857, 862, 868, 869, 873, 884, 888, - 892, 896, 901, 905, 915, 919, 924, 932, 936, 937, - 948, 952, 956, 960, 964, 972, 973, 979, 986, 992, - 999, 1002, 1009, 1015, 1032, 1039, 1040, 1047, 1048, 1067, - 1068, 1071, 1074, 1078, 1089, 1098, 1104, 1107, 1110, 1117, - 1118, 1124, 1137, 1152, 1160, 1172, 1177, 1183, 1184, 1185, - 1186, 1187, 1188, 1194, 1195, 1196, 1197, 1203, 1204, 1205, - 1206, 1207, 1213, 1214, 1217, 1220, 1221, 1222, 1223, 1224, - 1227, 1228, 1241, 1245, 1250, 1255, 1260, 1264, 1265, 1268, - 1274, 1281, 1287, 1294, 1300, 1311, 1327, 1356, 1394, 1419, - 1437, 1446, 1449, 1457, 1461, 1465, 1472, 1478, 1483, 1495, - 1498, 1510, 1511, 1517, 1518, 1524, 1528, 1534, 1535, 1541, - 1545, 1551, 1574, 1579, 1585, 1591, 1598, 1607, 1616, 1631, - 1637, 1642, 1646, 1653, 1666, 1667, 1673, 1679, 1682, 1686, - 1692, 1695, 1704, 1707, 1708, 1712, 1713, 1719, 1720, 1721, - 1722, 1723, 1725, 1724, 1739, 1745, 1749, 1753, 1757, 1761, - 1766, 1785, 1791, 1799, 1803, 1809, 1813, 1819, 1823, 1829, - 1833, 1842, 1846, 1850, 1854, 1860, 1863, 1871, 1872, 1874, - 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, 1899, 1902, - 1905, 1908, 1911, 1914, 1917, 1923, 1927, 1931, 1935, 1939, - 1943, 1963, 1970, 1981, 1982, 1983, 1986, 1987, 1990, 1994, - 2004, 2008, 2012, 2016, 2020, 2024, 2028, 2034, 2040, 2048, - 2056, 2062, 2069, 2085, 2107, 2111, 2117, 2120, 2123, 2127, - 2137, 2141, 2160, 2168, 2169, 2181, 2182, 2185, 2189, 2195, - 2199, 2205, 2209 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -const char *yytname[] = -{ - "$end", "error", "$undefined", "LLITERAL", "LASOP", "LCOLAS", "LBREAK", - "LCASE", "LCHAN", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER", - "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT", - "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN", - "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT", - "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE", - "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'", - "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'", - "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'", - "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file", - "package", "loadsys", "@1", "imports", "import", "import_stmt", - "import_stmt_list", "import_here", "import_package", "import_safety", - "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl", - "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case", - "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body", - "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6", - "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list", - "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr", - "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval", - "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type", - "name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym", - "hidden_importsym", "name", "labelname", "dotdotdot", "ntype", - "non_expr_type", "non_recvchantype", "convtype", "comptype", - "fnret_type", "dotname", "othertype", "ptrtype", "recvchantype", - "structtype", "interfacetype", "xfndcl", "fndcl", "hidden_fndcl", - "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral", "xdcl_list", - "vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list", - "interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl", - "indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt", - "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list", - "expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list", - "osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt", - "ohidden_funarg_list", "ohidden_structdcl_list", - "ohidden_interfacedcl_list", "oliteral", "hidden_import", - "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type", - "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan", - "hidden_type_func", "hidden_funarg", "hidden_structdcl", - "hidden_interfacedcl", "ohidden_funres", "hidden_funres", - "hidden_literal", "hidden_constant", "hidden_import_list", - "hidden_funarg_list", "hidden_structdcl_list", - "hidden_interfacedcl_list", 0 -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 43, - 45, 124, 94, 42, 47, 37, 38, 304, 305, 40, - 41, 306, 59, 46, 36, 61, 58, 123, 125, 33, - 126, 91, 93, 63, 64, 44 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 76, 77, 78, 78, 80, 79, 81, 81, 82, - 82, 82, 83, 83, 84, 84, 85, 85, 85, 86, - 87, 87, 89, 88, 90, 90, 90, 90, 90, 91, - 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, - 93, 93, 93, 94, 94, 95, 95, 95, 96, 97, - 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, - 101, 100, 103, 102, 104, 104, 106, 105, 107, 107, - 107, 108, 108, 108, 109, 111, 110, 112, 112, 114, - 115, 116, 113, 118, 117, 119, 119, 120, 120, 122, - 123, 121, 125, 124, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 128, 128, 128, 129, 129, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, - 129, 130, 131, 132, 132, 133, 133, 134, 134, 135, - 135, 136, 137, 137, 138, 139, 140, 140, 141, 141, - 141, 142, 142, 143, 144, 145, 145, 146, 146, 146, - 146, 146, 146, 147, 147, 147, 147, 148, 148, 148, - 148, 148, 149, 149, 150, 151, 151, 151, 151, 151, - 152, 152, 153, 153, 153, 153, 153, 153, 153, 154, - 155, 156, 156, 157, 157, 158, 159, 159, 160, 160, - 161, 162, 162, 163, 163, 163, 164, 165, 165, 166, - 166, 167, 167, 168, 168, 169, 169, 170, 170, 171, - 171, 172, 172, 172, 172, 172, 172, 173, 173, 174, - 175, 175, 175, 176, 177, 177, 177, 177, 178, 178, - 179, 179, 180, 180, 180, 180, 180, 181, 181, 181, - 181, 181, 182, 181, 181, 181, 181, 181, 181, 181, - 181, 183, 183, 184, 184, 185, 185, 186, 186, 187, - 187, 188, 188, 188, 188, 189, 189, 190, 190, 191, - 191, 192, 192, 193, 193, 194, 194, 195, 195, 196, - 196, 197, 197, 198, 198, 199, 199, 199, 199, 199, - 199, 200, 201, 202, 202, 202, 203, 203, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 204, 205, - 206, 207, 207, 208, 209, 209, 210, 210, 211, 211, - 212, 212, 212, 213, 213, 214, 214, 215, 215, 216, - 216, 217, 217 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 4, 0, 3, 0, 3, 0, 3, 2, - 5, 3, 3, 2, 1, 3, 1, 2, 2, 4, - 0, 1, 0, 4, 0, 1, 1, 1, 1, 2, - 5, 3, 2, 5, 7, 3, 2, 5, 3, 1, - 2, 4, 3, 4, 3, 1, 2, 1, 1, 2, - 1, 3, 3, 3, 2, 2, 3, 5, 5, 2, - 0, 4, 0, 3, 0, 2, 0, 4, 4, 4, - 2, 5, 1, 1, 2, 0, 3, 1, 3, 0, - 0, 0, 8, 0, 5, 0, 2, 0, 2, 0, - 0, 7, 0, 5, 1, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 1, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 5, 6, 1, 1, 3, - 5, 5, 4, 6, 8, 1, 5, 5, 5, 7, - 1, 0, 3, 1, 4, 1, 4, 1, 3, 1, - 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, - 1, 4, 4, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 3, 1, 1, 1, 2, 1, 1, 1, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 4, 4, 2, 3, 5, 1, 1, 2, - 3, 5, 3, 5, 3, 3, 5, 8, 5, 8, - 5, 0, 3, 0, 1, 3, 1, 4, 2, 0, - 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 3, 2, 4, 3, 5, 5, 1, 3, 1, - 2, 1, 3, 4, 1, 2, 2, 1, 1, 3, - 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 4, 1, 2, 2, 2, 2, 2, - 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, - 3, 1, 1, 3, 3, 0, 2, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 0, 1, 4, 4, 5, 6, 4, - 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 3, 4, 5, 4, 4, 2, 2, 4, 3, 3, - 5, 3, 4, 3, 5, 1, 0, 1, 3, 1, - 1, 2, 1, 1, 5, 0, 2, 1, 3, 1, - 3, 1, 3 -}; - -/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state - STATE-NUM when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint16 yydefact[] = -{ - 5, 0, 3, 0, 1, 0, 7, 0, 22, 158, - 160, 0, 0, 159, 219, 20, 6, 345, 0, 4, - 0, 0, 0, 21, 0, 0, 0, 16, 0, 0, - 9, 22, 0, 8, 28, 127, 156, 0, 39, 156, - 0, 264, 75, 0, 0, 0, 79, 0, 0, 293, - 92, 0, 89, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 291, 0, 25, 0, 257, 258, - 261, 259, 260, 50, 94, 135, 147, 115, 164, 163, - 128, 0, 0, 0, 184, 197, 198, 26, 216, 0, - 140, 27, 0, 19, 0, 0, 0, 0, 0, 0, - 346, 161, 162, 11, 14, 287, 18, 22, 13, 17, - 157, 265, 154, 0, 0, 0, 0, 163, 190, 194, - 180, 178, 179, 177, 266, 135, 0, 295, 250, 0, - 211, 135, 269, 295, 152, 153, 0, 0, 277, 294, - 270, 0, 0, 295, 0, 0, 36, 48, 0, 29, - 275, 155, 0, 123, 118, 119, 122, 116, 117, 0, - 0, 149, 0, 150, 175, 173, 174, 120, 121, 0, - 292, 0, 220, 0, 32, 0, 0, 0, 0, 0, - 55, 0, 0, 0, 54, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 141, - 0, 0, 291, 262, 0, 141, 218, 0, 0, 0, - 0, 311, 0, 0, 211, 0, 0, 312, 0, 0, - 23, 288, 0, 12, 250, 0, 0, 195, 171, 169, - 170, 167, 168, 199, 0, 0, 0, 296, 73, 0, - 76, 0, 72, 165, 244, 163, 247, 151, 248, 289, - 0, 250, 0, 205, 80, 77, 158, 0, 204, 0, - 287, 241, 229, 0, 64, 0, 0, 202, 273, 287, - 227, 239, 303, 0, 90, 38, 225, 287, 49, 31, - 221, 287, 0, 0, 40, 0, 176, 148, 0, 0, - 35, 287, 0, 0, 51, 96, 111, 114, 97, 101, - 102, 100, 112, 99, 98, 95, 113, 103, 104, 105, - 106, 107, 108, 109, 110, 285, 124, 279, 289, 0, - 129, 292, 0, 0, 289, 285, 256, 60, 254, 253, - 271, 255, 0, 53, 52, 278, 0, 0, 0, 0, - 319, 0, 0, 0, 0, 0, 318, 0, 313, 314, - 315, 0, 347, 0, 0, 297, 0, 0, 0, 15, - 10, 0, 0, 0, 181, 191, 70, 66, 74, 0, - 0, 295, 166, 245, 246, 290, 251, 213, 0, 0, - 0, 295, 0, 237, 0, 250, 240, 288, 0, 0, - 0, 0, 303, 0, 0, 288, 0, 304, 232, 0, - 303, 0, 288, 0, 288, 0, 42, 276, 0, 0, - 0, 200, 171, 169, 170, 168, 141, 193, 192, 288, - 0, 44, 0, 141, 143, 281, 282, 289, 0, 289, - 290, 0, 0, 0, 132, 291, 263, 290, 0, 0, - 0, 0, 217, 0, 0, 326, 316, 317, 297, 301, - 0, 299, 0, 325, 340, 0, 0, 342, 343, 0, - 0, 0, 0, 0, 303, 0, 0, 310, 0, 298, - 305, 309, 306, 213, 172, 0, 0, 0, 0, 249, - 250, 163, 214, 189, 187, 188, 185, 186, 210, 213, - 212, 81, 78, 238, 242, 0, 230, 203, 196, 0, - 0, 93, 62, 65, 0, 234, 0, 303, 228, 201, - 274, 231, 64, 226, 37, 222, 30, 41, 0, 285, - 45, 223, 287, 47, 33, 43, 285, 0, 290, 286, - 138, 0, 280, 125, 131, 130, 0, 136, 137, 0, - 272, 328, 0, 0, 319, 0, 318, 0, 335, 351, - 302, 0, 0, 0, 349, 300, 329, 341, 0, 307, - 0, 320, 0, 303, 331, 0, 348, 336, 0, 69, - 68, 295, 0, 250, 206, 85, 213, 0, 59, 0, - 303, 303, 233, 0, 172, 0, 288, 0, 46, 0, - 141, 145, 142, 283, 284, 126, 291, 133, 61, 327, - 336, 297, 324, 0, 0, 303, 323, 0, 0, 321, - 308, 332, 297, 297, 339, 208, 337, 67, 71, 215, - 0, 87, 243, 0, 0, 56, 0, 63, 236, 235, - 91, 139, 224, 34, 144, 285, 0, 330, 0, 352, - 322, 333, 350, 0, 0, 0, 213, 0, 86, 82, - 0, 0, 0, 134, 336, 344, 336, 338, 207, 83, - 88, 58, 57, 146, 334, 209, 295, 0, 84 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 1, 6, 2, 3, 14, 21, 30, 105, 31, - 8, 24, 16, 17, 65, 328, 67, 149, 520, 521, - 145, 146, 68, 502, 329, 440, 503, 579, 390, 368, - 475, 238, 239, 240, 69, 127, 254, 70, 133, 380, - 575, 648, 666, 621, 649, 71, 143, 401, 72, 141, - 73, 74, 75, 76, 315, 425, 426, 592, 77, 317, - 244, 136, 78, 150, 111, 117, 13, 80, 81, 246, - 247, 163, 119, 82, 83, 482, 228, 84, 230, 231, - 85, 86, 87, 130, 214, 88, 253, 488, 89, 90, - 22, 281, 522, 277, 269, 260, 270, 271, 272, 262, - 386, 248, 249, 250, 330, 331, 323, 332, 273, 152, - 92, 318, 427, 428, 222, 376, 171, 140, 255, 468, - 553, 547, 398, 100, 212, 218, 614, 445, 348, 349, - 350, 352, 554, 549, 615, 616, 458, 459, 25, 469, - 555, 550 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -473 -static const yytype_int16 yypact[] = -{ - -473, 65, 22, 49, -473, 261, -473, 64, -473, -473, - -473, 95, 52, -473, 143, 145, -473, -473, 104, -473, - 68, 128, 1049, -473, 142, 305, 16, -473, 56, 204, - -473, 49, 220, -473, -473, -473, 261, 974, -473, 261, - 562, -473, -473, 288, 562, 261, -473, 14, 147, 1615, - -473, 14, -473, 395, 401, 1615, 1615, 1615, 1615, 1615, - 1615, 1658, 1615, 1615, 737, 168, -473, 414, -473, -473, - -473, -473, -473, 649, -473, -473, 165, 122, -473, 169, - -473, 177, 218, 14, 219, -473, -473, -473, 235, 89, - -473, -473, 34, -473, 206, 124, 286, 206, 206, 260, - -473, -473, -473, -473, -473, 265, -473, -473, -473, -473, - -473, -473, -473, 270, 1803, 1803, 1803, -473, 269, -473, - -473, -473, -473, -473, -473, 39, 122, 882, 1777, 283, - 277, 230, -473, 1615, -473, -473, 292, 1803, 2097, 280, - -473, 332, 315, 1615, 215, 1803, -473, -473, 244, -473, - -473, -473, 949, -473, -473, -473, -473, -473, -473, 1701, - 1658, 2097, 298, -473, 9, -473, 59, -473, -473, 303, - 2097, 319, -473, 330, -473, 1744, 1615, 1615, 1615, 1615, - -473, 1615, 1615, 1615, -473, 1615, 1615, 1615, 1615, 1615, - 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, 1615, -473, - 1297, 455, 1615, -473, 1615, -473, -473, 1225, 1615, 1615, - 1615, -473, 594, 261, 277, 328, 403, -473, 1308, 1308, - -473, 152, 352, -473, 1777, 405, 1803, -473, -473, -473, - -473, -473, -473, -473, 354, 261, 1615, -473, -473, 382, - -473, 47, 360, 1803, -473, 1777, -473, -473, -473, 351, - 367, 1777, 1225, -473, -473, 366, 84, 407, -473, 374, - 373, -473, -473, 372, -473, 138, 42, -473, -473, 377, - -473, -473, 442, 1769, -473, -473, -473, 384, -473, -473, - -473, 389, 1615, 261, 391, 1830, -473, 394, 1803, 1803, - -473, 409, 1615, 411, 2097, 1935, -473, 2121, 1080, 1080, - 1080, 1080, -473, 1080, 1080, 2145, -473, 503, 503, 503, - 503, -473, -473, -473, -473, 1352, -473, -473, 27, 1407, - -473, 1995, 412, 1147, 1962, 1352, -473, -473, -473, -473, - -473, -473, 7, 280, 280, 2097, 698, 418, 415, 413, - -473, 416, 477, 1308, 188, 31, -473, 425, -473, -473, - -473, 1897, -473, 221, 433, 261, 434, 436, 439, -473, - -473, 432, 1803, 452, -473, -473, 2097, -473, -473, 1462, - 1517, 1615, -473, -473, -473, 1777, -473, 1856, 453, 91, - 382, 1615, 261, 454, 456, 1777, -473, 475, 451, 1803, - 133, 407, 442, 407, 460, 326, 462, -473, -473, 261, - 442, 467, 261, 478, 261, 486, 280, -473, 1615, 1864, - 1803, -473, 26, 248, 264, 430, -473, -473, -473, 261, - 492, 280, 1615, -473, 2025, -473, -473, 485, 493, 487, - 1658, 504, 506, 508, -473, 1615, -473, -473, 512, 505, - 1225, 1147, -473, 1308, 517, -473, -473, -473, 261, 1889, - 1308, 261, 1308, -473, -473, 571, 155, -473, -473, 514, - 509, 1308, 188, 1308, 442, 261, 261, -473, 518, 507, - -473, -473, -473, 1856, -473, 1225, 1615, 1615, 521, -473, - 1777, 528, -473, -473, -473, -473, -473, -473, -473, 1856, - -473, -473, -473, -473, -473, 520, -473, -473, -473, 1658, - 522, -473, -473, -473, 530, -473, 532, 442, -473, -473, - -473, -473, -473, -473, -473, -473, -473, 280, 535, 1352, - -473, -473, 536, 1744, -473, 280, 1352, 1560, 1352, -473, - -473, 539, -473, -473, -473, -473, 247, -473, -473, 308, - -473, -473, 541, 543, 545, 546, 547, 544, -473, -473, - 551, 548, 1308, 554, -473, 557, -473, -473, 576, -473, - 1308, -473, 564, 442, -473, 568, -473, 1923, 318, 2097, - 2097, 1615, 569, 1777, -473, -473, 1856, 156, -473, 1147, - 442, 442, -473, 243, 483, 563, 261, 577, 411, 570, - -473, 2097, -473, -473, -473, -473, 1615, -473, -473, -473, - 1923, 261, -473, 1889, 1308, 442, -473, 261, 155, -473, - -473, -473, 261, 261, -473, -473, -473, -473, -473, -473, - 579, 627, -473, 1615, 1615, -473, 1658, 580, -473, -473, - -473, -473, -473, -473, -473, 1352, 572, -473, 583, -473, - -473, -473, -473, 585, 586, 590, 1856, 77, -473, -473, - 2049, 2073, 584, -473, 1923, -473, 1923, -473, -473, -473, - -473, -473, -473, -473, -473, -473, 1615, 382, -473 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -473, -473, -473, -473, -473, -473, -473, -12, -473, -473, - 624, -473, -1, -473, -473, 635, -473, -137, -48, 74, - -473, -130, -112, -473, 11, -473, -473, -473, 149, -372, - -473, -473, -473, -473, -473, -473, -140, -473, -473, -473, - -473, -473, -473, -473, -473, -473, -473, -473, -473, -473, - 662, 448, 257, -473, -196, 135, 139, -473, 262, -59, - 424, -16, -3, 387, 632, 427, 313, 20, -473, 428, - -89, 524, -473, -473, -473, -473, -36, -37, -31, -49, - -473, -473, -473, -473, -473, -32, 458, -472, -473, -473, - -473, -473, -473, -473, -473, -473, 279, -108, -211, 290, - -473, 306, -473, -214, -291, 658, -473, -230, -473, -63, - -6, 191, -473, -302, -219, -254, -195, -473, -107, -435, - -473, -473, -347, -473, 323, -473, 72, -473, 371, 268, - 380, 242, 102, 110, -468, -473, -438, 255, -473, 515, - -473, -473 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If zero, do what YYDEFACT says. - If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -278 -static const yytype_int16 yytable[] = -{ - 121, 120, 162, 274, 175, 123, 122, 322, 491, 325, - 361, 280, 165, 543, 276, 237, 104, 574, 558, 174, - 242, 237, 379, 439, 164, 227, 233, 234, 261, 166, - 108, 237, 436, 110, 460, 142, 110, 378, 429, 208, - 101, 388, 132, 139, -184, 505, -268, 5, 263, 134, - 396, -268, 369, 511, 392, 394, 278, 118, 403, 27, - -216, -180, 405, 284, 431, 4, 383, 205, -183, 441, - 438, 27, 420, 207, 7, 442, -184, 229, 229, 229, - 9, 135, 232, 232, 232, -180, 293, -237, 15, 102, - 206, 229, 9, -180, -216, 393, 232, 659, 18, 209, - 229, -268, 430, 461, 622, 232, 223, -268, 229, 210, - 175, 165, 370, 232, 19, 229, 103, 564, -182, 29, - 232, 241, 210, 164, 134, 291, -216, 28, 166, 10, - 11, 29, 637, 259, 118, 118, 118, 363, 229, 268, - 499, 10, 11, 232, 327, 500, -237, 382, 118, 384, - 540, 165, -237, 441, 372, 27, 135, 118, 454, 490, - 582, 623, 383, 164, 20, 118, 638, 26, 166, 23, - 643, 495, 118, 529, 658, 531, 9, 644, 645, 9, - 504, 200, 506, 213, 400, 201, 664, 229, 665, 229, - 33, 454, 232, 202, 232, 118, 411, 391, 11, 417, - 418, 501, 333, 334, 93, 455, 229, 106, 229, 359, - 539, 232, 9, 232, 229, 29, 611, 585, 137, 232, - 519, 624, 625, 109, 589, 10, 11, 526, 10, 11, - 172, 626, 199, 628, 629, -154, 229, -267, 455, 9, - 536, 232, -267, 203, 118, 568, 118, 456, 413, 412, - 499, 229, 229, 415, 414, 500, 232, 232, 641, 237, - 433, 10, 11, 118, 478, 118, 572, 515, 9, 237, - 165, 118, 513, 411, 492, 275, 406, 204, -183, 261, - 11, 465, 164, -178, 347, 9, 421, 166, 10, 11, - 357, 358, -267, 118, -182, 668, 466, 125, -267, -179, - 498, 131, 126, 587, 279, 118, 126, -178, 118, 118, - 216, 630, 9, 596, 94, -178, 256, 10, 11, 597, - 227, 518, 95, -179, 220, 229, 96, 221, 486, 224, - 232, -179, 235, 652, 10, 11, 97, 98, 229, 256, - 484, 483, 251, 232, 252, 487, 485, 128, 229, 627, - 256, 257, 229, 232, 9, 210, 523, 232, 287, 620, - 258, 10, 11, 333, 334, 10, 11, 264, 265, 99, - 441, 532, 229, 229, 266, 288, 598, 232, 232, 265, - 441, 165, 118, 267, 259, 266, 617, 355, 10, 11, - 290, 289, 268, 164, 635, 118, 510, 118, 166, 10, - 11, 636, 517, 10, 11, 118, 356, 211, 211, 118, - 211, 211, 360, 362, 364, 453, 525, 367, 215, 9, - 217, 219, 371, 464, 486, 9, 375, 377, 381, 118, - 118, 383, 12, 385, 588, 387, 484, 483, 9, 395, - 486, 487, 485, 229, 389, 397, 402, 32, 232, 79, - 165, 404, 484, 483, 144, 32, 408, 487, 485, 237, - 148, 416, 164, 112, 618, -177, 112, 166, 10, 11, - 129, 419, 112, 173, 10, 11, 422, 448, 435, 9, - 147, 151, 449, 451, 450, 452, 229, 10, 11, -177, - 462, 232, 473, 118, 151, 467, 470, -177, 471, 256, - 118, 472, 512, 153, 154, 155, 156, 157, 158, 118, - 167, 168, 474, 489, 319, 541, 494, 382, -181, 497, - 507, 548, 551, 523, 556, 346, 667, 486, 10, 11, - 509, 346, 346, 561, 257, 563, 229, 178, 514, 484, - 483, 232, -181, 118, 487, 485, 516, 186, 10, 11, - -181, 190, 524, 342, 237, 245, 195, 196, 197, 198, - 528, 530, 437, 112, 533, 35, 534, 532, 535, 112, - 37, 147, 537, 538, 557, 151, 559, 165, 567, 113, - 576, 560, 466, 571, 47, 48, 9, 573, 578, 164, - 580, 51, 581, 118, 166, 584, 118, 486, 586, 595, - 151, 599, 336, 600, -158, 601, -159, 153, 157, 484, - 483, 337, 602, 603, 487, 485, 338, 339, 340, 607, - 604, 61, 606, 341, 605, 608, 610, 612, 320, 619, - 342, 631, 609, 64, 79, 10, 11, 633, 634, 646, - 351, 647, 441, 654, 653, 655, 656, 343, 32, 346, - 657, 245, 663, 176, -277, 107, 346, 66, 660, 344, - 632, 583, 365, 593, 346, 345, 118, 594, 11, 373, - 407, 124, 354, 374, 508, 548, 640, 496, 245, 79, - 91, 479, 177, 178, 286, 179, 180, 181, 182, 183, - 577, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 336, 446, 566, 642, - 151, 138, 542, 639, -277, 337, 447, 562, 0, 0, - 338, 339, 340, 161, -277, 0, 170, 341, 353, 0, - 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, - 35, 0, 0, 0, 0, 37, 0, 0, 169, 0, - 79, 343, 0, 0, 113, 0, 346, 444, 0, 47, - 48, 9, 546, 346, 0, 346, 51, 0, 0, 345, - 0, 457, 11, 55, 346, 0, 346, 0, 0, 0, - 0, 0, 351, 0, 0, 0, 56, 57, 0, 58, - 59, 0, 0, 60, 0, 0, 61, 0, 0, 0, - 0, 0, 245, 0, 481, 0, 62, 63, 64, 493, - 10, 11, 245, 0, 112, 0, 0, 0, 0, 0, - 0, 0, 112, 0, 0, 0, 112, 0, 0, 147, - 0, 151, 0, 0, 0, 0, 0, 0, 294, 295, - 296, 297, 0, 298, 299, 300, 151, 301, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 0, 161, 0, 321, 346, 324, 79, 79, 0, - 138, 138, 335, 346, 0, 351, 545, 0, 552, 0, - 346, 0, 0, 457, 0, 35, 0, 0, 0, 457, - 37, 0, 565, 351, 0, 0, 0, 0, 366, 113, - 0, 0, 79, 0, 47, 48, 9, 245, 236, 0, - 0, 51, 0, 346, 0, 0, 546, 346, 55, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, - 0, 61, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 62, 63, 64, 138, 10, 11, 37, 0, 0, - 0, 0, 0, 0, 0, 0, 113, 346, 0, 346, - 0, 47, 48, 9, 0, 0, 0, 424, 51, 0, - 0, 161, 37, 0, 0, 225, 0, 424, 0, 0, - 0, 113, 0, 0, 0, 0, 47, 48, 9, 0, - 245, 0, 115, 51, 0, 0, 79, 0, 226, 0, - 114, 0, 0, 151, 282, 0, 0, 0, 0, 0, - 64, 0, 10, 11, 283, 0, 0, 115, 351, 0, - 545, 138, 138, 116, 552, 457, 0, 0, 0, 351, - 351, 0, 0, 0, 0, 64, 0, 10, 11, -2, - 34, 0, 35, 0, 0, 36, 0, 37, 38, 39, - 0, 0, 40, 0, 41, 42, 43, 44, 45, 46, - 138, 47, 48, 9, 0, 0, 49, 50, 51, 52, - 53, 54, 0, 0, 138, 55, 0, 0, 0, 0, - 0, 0, 161, 0, 0, 0, 0, 170, 56, 57, - 0, 58, 59, 0, 0, 60, 0, 0, 61, 0, - 0, -24, 0, 0, 178, 0, 0, 0, 62, 63, - 64, 0, 10, 11, 186, 0, 0, 0, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 0, 569, 570, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 0, - 35, 0, 0, 36, -252, 37, 38, 39, 0, -252, - 40, 161, 41, 42, 113, 44, 45, 46, 0, 47, - 48, 9, 0, 0, 49, 50, 51, 52, 53, 54, - 0, 424, 0, 55, 0, 0, 0, 0, 424, 591, - 424, 0, 0, 0, 0, 0, 56, 57, 0, 58, - 59, 0, 0, 60, 0, 0, 61, 0, 0, -252, - 0, 0, 0, 0, 327, -252, 62, 63, 64, 0, - 10, 11, 0, 0, 0, 0, 326, 0, 35, 0, - 0, 36, 0, 37, 38, 39, 0, 0, 40, 0, - 41, 42, 113, 44, 45, 46, 0, 47, 48, 9, - 0, 0, 49, 50, 51, 52, 53, 54, 170, 0, - 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 56, 57, 0, 58, 59, 0, - 0, 60, 0, 0, 61, 650, 651, -252, 161, 0, - 0, 0, 327, -252, 62, 63, 64, 424, 10, 11, - 35, 0, 0, 0, 0, 37, 0, 0, 0, 0, - 0, 0, 0, 0, 113, 0, 336, 0, 0, 47, - 48, 9, 0, 0, 0, 337, 51, 0, 0, 0, - 338, 339, 340, 159, 0, 0, 0, 341, 0, 0, - 0, 0, 0, 0, 342, 0, 56, 57, 0, 58, - 160, 0, 0, 60, 0, 35, 61, 316, 0, 0, - 37, 343, 0, 0, 0, 0, 62, 63, 64, 113, - 10, 11, 0, 0, 47, 48, 9, 0, 0, 345, - 0, 51, 11, 0, 0, 0, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, - 35, 61, 0, 0, 0, 37, 0, 0, 0, 423, - 0, 62, 63, 64, 113, 10, 11, 0, 0, 47, - 48, 9, 0, 0, 0, 0, 51, 0, 432, 0, - 0, 0, 0, 159, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 56, 57, 0, 58, - 160, 0, 0, 60, 0, 35, 61, 0, 0, 0, - 37, 0, 0, 0, 0, 0, 62, 63, 64, 113, - 10, 11, 0, 0, 47, 48, 9, 0, 476, 0, - 0, 51, 0, 0, 0, 0, 0, 0, 55, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 56, 57, 0, 58, 59, 0, 0, 60, 0, - 35, 61, 0, 0, 0, 37, 0, 0, 0, 0, - 0, 62, 63, 64, 113, 10, 11, 0, 0, 47, - 48, 9, 0, 477, 0, 0, 51, 0, 0, 0, - 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 35, 0, 0, 56, 57, 37, 58, - 59, 0, 0, 60, 0, 0, 61, 113, 0, 0, - 0, 0, 47, 48, 9, 0, 62, 63, 64, 51, - 10, 11, 0, 0, 0, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, - 57, 0, 58, 59, 0, 0, 60, 0, 35, 61, - 0, 0, 0, 37, 0, 0, 0, 590, 0, 62, - 63, 64, 113, 10, 11, 0, 0, 47, 48, 9, - 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, - 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 35, 0, 0, 56, 57, 37, 58, 59, 0, - 0, 60, 0, 0, 61, 113, 0, 0, 0, 0, - 47, 48, 9, 0, 62, 63, 64, 51, 10, 11, - 0, 0, 0, 0, 159, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 35, 0, 0, 56, 57, 285, - 58, 160, 0, 0, 60, 0, 0, 61, 113, 0, - 0, 0, 0, 47, 48, 9, 0, 62, 63, 64, - 51, 10, 11, 0, 0, 0, 0, 55, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 56, 57, 37, 58, 59, 0, 0, 60, 0, 0, - 61, 113, 0, 0, 0, 0, 47, 48, 9, 0, - 62, 63, 64, 51, 10, 11, 0, 37, 0, 0, - 225, 0, 0, 0, 0, 37, 113, 0, 243, 0, - 0, 47, 48, 9, 113, 0, 0, 115, 51, 47, - 48, 9, 0, 226, 0, 225, 51, 0, 0, 292, - 0, 37, 0, 225, 0, 64, 0, 10, 11, 283, - 113, 0, 115, 0, 0, 47, 48, 9, 226, 0, - 115, 0, 51, 0, 0, 0, 226, 0, 37, 225, - 64, 0, 10, 11, 399, 0, 0, 113, 64, 0, - 10, 11, 47, 48, 9, 0, 115, 0, 0, 51, - 0, 0, 226, 0, 37, 0, 409, 0, 0, 0, - 0, 0, 285, 113, 64, 0, 10, 11, 47, 48, - 9, 113, 0, 115, 0, 51, 47, 48, 9, 410, - 0, 0, 225, 51, 0, 0, 0, 336, 0, 0, - 225, 64, 0, 10, 11, 336, 337, 0, 463, 115, - 0, 338, 339, 544, 337, 480, 0, 115, 341, 338, - 339, 340, 0, 226, 0, 342, 341, 64, 0, 10, - 11, 336, 0, 342, 0, 64, 0, 10, 11, 0, - 337, 0, 343, 0, 0, 338, 339, 340, 0, 0, - 343, 0, 341, 0, 0, 0, 0, 0, 0, 342, - 345, 0, 10, 11, 0, 0, 0, 0, 345, 178, - 0, 11, 0, 181, 182, 183, 343, 0, 185, 186, - 187, 188, 613, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 0, 0, 345, 177, 178, 11, 179, 0, - 181, 182, 183, 0, 0, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 177, 178, - 0, 179, 0, 181, 182, 183, 0, 437, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 0, 0, 0, 0, 0, 0, 177, 178, - 0, 179, 0, 181, 182, 183, 0, 434, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 177, 178, 0, 179, 0, 181, 182, 183, - 0, 527, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 177, 178, 0, 179, - 0, 181, 182, 183, 0, 661, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 177, 178, 0, 179, 0, 181, 182, 183, 0, 662, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 177, 178, 0, 0, 0, 181, - 182, 183, 0, 0, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 177, 178, - 0, 0, 0, 181, 182, 183, 0, 0, 185, 186, - 187, 188, 0, 190, 191, 192, 193, 194, 195, 196, - 197, 198 -}; - -static const yytype_int16 yycheck[] = -{ - 37, 37, 61, 143, 67, 37, 37, 202, 380, 205, - 224, 148, 61, 448, 144, 127, 28, 489, 456, 67, - 127, 133, 252, 325, 61, 114, 115, 116, 136, 61, - 31, 143, 323, 36, 3, 51, 39, 251, 11, 5, - 24, 260, 45, 49, 35, 392, 7, 25, 137, 35, - 269, 12, 5, 400, 265, 266, 145, 37, 277, 3, - 1, 35, 281, 152, 318, 0, 24, 83, 59, 62, - 324, 3, 291, 89, 25, 68, 67, 114, 115, 116, - 24, 67, 114, 115, 116, 59, 175, 3, 24, 73, - 1, 128, 24, 67, 35, 53, 128, 20, 3, 65, - 137, 62, 75, 72, 576, 137, 107, 68, 145, 75, - 173, 160, 65, 145, 62, 152, 60, 464, 59, 63, - 152, 127, 75, 160, 35, 173, 67, 59, 160, 73, - 74, 63, 600, 136, 114, 115, 116, 226, 175, 142, - 7, 73, 74, 175, 67, 12, 62, 63, 128, 257, - 441, 200, 68, 62, 243, 3, 67, 137, 3, 68, - 507, 5, 24, 200, 21, 145, 601, 63, 200, 24, - 608, 385, 152, 427, 646, 429, 24, 612, 613, 24, - 391, 59, 393, 59, 273, 63, 654, 224, 656, 226, - 62, 3, 224, 71, 226, 175, 285, 59, 74, 288, - 289, 68, 208, 209, 62, 50, 243, 3, 245, 221, - 440, 243, 24, 245, 251, 63, 563, 519, 71, 251, - 416, 65, 66, 3, 526, 73, 74, 423, 73, 74, - 62, 75, 67, 580, 581, 66, 273, 7, 50, 24, - 435, 273, 12, 66, 224, 475, 226, 59, 285, 285, - 7, 288, 289, 285, 285, 12, 288, 289, 605, 371, - 319, 73, 74, 243, 371, 245, 480, 404, 24, 381, - 319, 251, 402, 362, 381, 60, 282, 59, 59, 387, - 74, 60, 319, 35, 212, 24, 292, 319, 73, 74, - 218, 219, 62, 273, 59, 667, 75, 40, 68, 35, - 389, 44, 40, 522, 60, 285, 44, 59, 288, 289, - 24, 68, 24, 66, 9, 67, 24, 73, 74, 72, - 409, 410, 17, 59, 64, 362, 21, 62, 377, 59, - 362, 67, 63, 635, 73, 74, 31, 32, 375, 24, - 377, 377, 59, 375, 67, 377, 377, 59, 385, 579, - 24, 59, 389, 385, 24, 75, 419, 389, 60, 573, - 68, 73, 74, 369, 370, 73, 74, 35, 53, 64, - 62, 430, 409, 410, 59, 72, 68, 409, 410, 53, - 62, 430, 362, 68, 387, 59, 68, 59, 73, 74, - 60, 72, 395, 430, 590, 375, 399, 377, 430, 73, - 74, 596, 408, 73, 74, 385, 3, 94, 95, 389, - 97, 98, 60, 8, 60, 343, 422, 35, 95, 24, - 97, 98, 62, 351, 473, 24, 75, 60, 62, 409, - 410, 24, 5, 59, 523, 62, 473, 473, 24, 62, - 489, 473, 473, 480, 72, 3, 62, 20, 480, 22, - 499, 62, 489, 489, 59, 28, 65, 489, 489, 571, - 59, 67, 499, 36, 571, 35, 39, 499, 73, 74, - 43, 62, 45, 59, 73, 74, 65, 59, 66, 24, - 53, 54, 67, 67, 71, 8, 523, 73, 74, 59, - 65, 523, 60, 473, 67, 62, 62, 67, 62, 24, - 480, 62, 35, 55, 56, 57, 58, 59, 60, 489, - 62, 63, 60, 60, 59, 443, 60, 63, 35, 68, - 60, 449, 450, 586, 452, 212, 666, 576, 73, 74, - 68, 218, 219, 461, 59, 463, 573, 34, 60, 576, - 576, 573, 59, 523, 576, 576, 60, 44, 73, 74, - 67, 48, 60, 36, 666, 128, 53, 54, 55, 56, - 75, 68, 75, 136, 60, 3, 60, 626, 60, 142, - 8, 144, 60, 68, 3, 148, 62, 626, 60, 17, - 60, 72, 75, 62, 22, 23, 24, 59, 66, 626, - 60, 29, 60, 573, 626, 60, 576, 646, 62, 60, - 173, 60, 8, 60, 59, 59, 59, 159, 160, 646, - 646, 17, 68, 62, 646, 646, 22, 23, 24, 62, - 72, 59, 68, 29, 552, 49, 62, 59, 201, 60, - 36, 68, 560, 71, 207, 73, 74, 60, 68, 60, - 213, 14, 62, 60, 72, 60, 60, 53, 221, 336, - 60, 224, 68, 4, 5, 31, 343, 22, 647, 65, - 586, 512, 235, 528, 351, 71, 646, 528, 74, 245, - 283, 39, 214, 245, 395, 603, 604, 387, 251, 252, - 22, 375, 33, 34, 160, 36, 37, 38, 39, 40, - 499, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 8, 336, 466, 607, - 283, 49, 444, 603, 65, 17, 336, 462, -1, -1, - 22, 23, 24, 61, 75, -1, 64, 29, 213, -1, - -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, - 3, -1, -1, -1, -1, 8, -1, -1, 11, -1, - 323, 53, -1, -1, 17, -1, 443, 59, -1, 22, - 23, 24, 449, 450, -1, 452, 29, -1, -1, 71, - -1, 344, 74, 36, 461, -1, 463, -1, -1, -1, - -1, -1, 355, -1, -1, -1, 49, 50, -1, 52, - 53, -1, -1, 56, -1, -1, 59, -1, -1, -1, - -1, -1, 375, -1, 377, -1, 69, 70, 71, 382, - 73, 74, 385, -1, 387, -1, -1, -1, -1, -1, - -1, -1, 395, -1, -1, -1, 399, -1, -1, 402, - -1, 404, -1, -1, -1, -1, -1, -1, 176, 177, - 178, 179, -1, 181, 182, 183, 419, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, -1, 200, -1, 202, 552, 204, 440, 441, -1, - 208, 209, 210, 560, -1, 448, 449, -1, 451, -1, - 567, -1, -1, 456, -1, 3, -1, -1, -1, 462, - 8, -1, 465, 466, -1, -1, -1, -1, 236, 17, - -1, -1, 475, -1, 22, 23, 24, 480, 26, -1, - -1, 29, -1, 600, -1, -1, 603, 604, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, - -1, 59, -1, -1, 282, -1, -1, -1, -1, -1, - -1, 69, 70, 71, 292, 73, 74, 8, -1, -1, - -1, -1, -1, -1, -1, -1, 17, 654, -1, 656, - -1, 22, 23, 24, -1, -1, -1, 315, 29, -1, - -1, 319, 8, -1, -1, 36, -1, 325, -1, -1, - -1, 17, -1, -1, -1, -1, 22, 23, 24, -1, - 573, -1, 53, 29, -1, -1, 579, -1, 59, -1, - 36, -1, -1, 586, 65, -1, -1, -1, -1, -1, - 71, -1, 73, 74, 75, -1, -1, 53, 601, -1, - 603, 369, 370, 59, 607, 608, -1, -1, -1, 612, - 613, -1, -1, -1, -1, 71, -1, 73, 74, 0, - 1, -1, 3, -1, -1, 6, -1, 8, 9, 10, - -1, -1, 13, -1, 15, 16, 17, 18, 19, 20, - 408, 22, 23, 24, -1, -1, 27, 28, 29, 30, - 31, 32, -1, -1, 422, 36, -1, -1, -1, -1, - -1, -1, 430, -1, -1, -1, -1, 435, 49, 50, - -1, 52, 53, -1, -1, 56, -1, -1, 59, -1, - -1, 62, -1, -1, 34, -1, -1, -1, 69, 70, - 71, -1, 73, 74, 44, -1, -1, -1, 48, 49, - 50, 51, 52, 53, 54, 55, 56, -1, 476, 477, - -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, - 3, -1, -1, 6, 7, 8, 9, 10, -1, 12, - 13, 499, 15, 16, 17, 18, 19, 20, -1, 22, - 23, 24, -1, -1, 27, 28, 29, 30, 31, 32, - -1, 519, -1, 36, -1, -1, -1, -1, 526, 527, - 528, -1, -1, -1, -1, -1, 49, 50, -1, 52, - 53, -1, -1, 56, -1, -1, 59, -1, -1, 62, - -1, -1, -1, -1, 67, 68, 69, 70, 71, -1, - 73, 74, -1, -1, -1, -1, 1, -1, 3, -1, - -1, 6, -1, 8, 9, 10, -1, -1, 13, -1, - 15, 16, 17, 18, 19, 20, -1, 22, 23, 24, - -1, -1, 27, 28, 29, 30, 31, 32, 596, -1, - -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 49, 50, -1, 52, 53, -1, - -1, 56, -1, -1, 59, 623, 624, 62, 626, -1, - -1, -1, 67, 68, 69, 70, 71, 635, 73, 74, - 3, -1, -1, -1, -1, 8, -1, -1, -1, -1, - -1, -1, -1, -1, 17, -1, 8, -1, -1, 22, - 23, 24, -1, -1, -1, 17, 29, -1, -1, -1, - 22, 23, 24, 36, -1, -1, -1, 29, -1, -1, - -1, -1, -1, -1, 36, -1, 49, 50, -1, 52, - 53, -1, -1, 56, -1, 3, 59, 60, -1, -1, - 8, 53, -1, -1, -1, -1, 69, 70, 71, 17, - 73, 74, -1, -1, 22, 23, 24, -1, -1, 71, - -1, 29, 74, -1, -1, -1, -1, -1, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, - 3, 59, -1, -1, -1, 8, -1, -1, -1, 67, - -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, - 23, 24, -1, -1, -1, -1, 29, -1, 31, -1, - -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 49, 50, -1, 52, - 53, -1, -1, 56, -1, 3, 59, -1, -1, -1, - 8, -1, -1, -1, -1, -1, 69, 70, 71, 17, - 73, 74, -1, -1, 22, 23, 24, -1, 26, -1, - -1, 29, -1, -1, -1, -1, -1, -1, 36, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 49, 50, -1, 52, 53, -1, -1, 56, -1, - 3, 59, -1, -1, -1, 8, -1, -1, -1, -1, - -1, 69, 70, 71, 17, 73, 74, -1, -1, 22, - 23, 24, -1, 26, -1, -1, 29, -1, -1, -1, - -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 3, -1, -1, 49, 50, 8, 52, - 53, -1, -1, 56, -1, -1, 59, 17, -1, -1, - -1, -1, 22, 23, 24, -1, 69, 70, 71, 29, - 73, 74, -1, -1, -1, -1, 36, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 49, - 50, -1, 52, 53, -1, -1, 56, -1, 3, 59, - -1, -1, -1, 8, -1, -1, -1, 67, -1, 69, - 70, 71, 17, 73, 74, -1, -1, 22, 23, 24, - -1, -1, -1, -1, 29, -1, -1, -1, -1, -1, - -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 3, -1, -1, 49, 50, 8, 52, 53, -1, - -1, 56, -1, -1, 59, 17, -1, -1, -1, -1, - 22, 23, 24, -1, 69, 70, 71, 29, 73, 74, - -1, -1, -1, -1, 36, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 3, -1, -1, 49, 50, 8, - 52, 53, -1, -1, 56, -1, -1, 59, 17, -1, - -1, -1, -1, 22, 23, 24, -1, 69, 70, 71, - 29, 73, 74, -1, -1, -1, -1, 36, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 49, 50, 8, 52, 53, -1, -1, 56, -1, -1, - 59, 17, -1, -1, -1, -1, 22, 23, 24, -1, - 69, 70, 71, 29, 73, 74, -1, 8, -1, -1, - 36, -1, -1, -1, -1, 8, 17, -1, 11, -1, - -1, 22, 23, 24, 17, -1, -1, 53, 29, 22, - 23, 24, -1, 59, -1, 36, 29, -1, -1, 65, - -1, 8, -1, 36, -1, 71, -1, 73, 74, 75, - 17, -1, 53, -1, -1, 22, 23, 24, 59, -1, - 53, -1, 29, -1, -1, -1, 59, -1, 8, 36, - 71, -1, 73, 74, 75, -1, -1, 17, 71, -1, - 73, 74, 22, 23, 24, -1, 53, -1, -1, 29, - -1, -1, 59, -1, 8, -1, 36, -1, -1, -1, - -1, -1, 8, 17, 71, -1, 73, 74, 22, 23, - 24, 17, -1, 53, -1, 29, 22, 23, 24, 59, - -1, -1, 36, 29, -1, -1, -1, 8, -1, -1, - 36, 71, -1, 73, 74, 8, 17, -1, 11, 53, - -1, 22, 23, 24, 17, 59, -1, 53, 29, 22, - 23, 24, -1, 59, -1, 36, 29, 71, -1, 73, - 74, 8, -1, 36, -1, 71, -1, 73, 74, -1, - 17, -1, 53, -1, -1, 22, 23, 24, -1, -1, - 53, -1, 29, -1, -1, -1, -1, -1, -1, 36, - 71, -1, 73, 74, -1, -1, -1, -1, 71, 34, - -1, 74, -1, 38, 39, 40, 53, -1, 43, 44, - 45, 46, 59, 48, 49, 50, 51, 52, 53, 54, - 55, 56, -1, -1, 71, 33, 34, 74, 36, -1, - 38, 39, 40, -1, -1, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 33, 34, - -1, 36, -1, 38, 39, 40, -1, 75, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, -1, -1, -1, -1, -1, -1, 33, 34, - -1, 36, -1, 38, 39, 40, -1, 72, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 33, 34, -1, 36, -1, 38, 39, 40, - -1, 66, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 33, 34, -1, 36, - -1, 38, 39, 40, -1, 66, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 33, 34, -1, 36, -1, 38, 39, 40, -1, 66, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 33, 34, -1, -1, -1, 38, - 39, 40, -1, -1, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 33, 34, - -1, -1, -1, 38, 39, 40, -1, -1, 43, 44, - 45, 46, -1, 48, 49, 50, 51, 52, 53, 54, - 55, 56 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 77, 79, 80, 0, 25, 78, 25, 86, 24, - 73, 74, 141, 142, 81, 24, 88, 89, 3, 62, - 21, 82, 166, 24, 87, 214, 63, 3, 59, 63, - 83, 85, 141, 62, 1, 3, 6, 8, 9, 10, - 13, 15, 16, 17, 18, 19, 20, 22, 23, 27, - 28, 29, 30, 31, 32, 36, 49, 50, 52, 53, - 56, 59, 69, 70, 71, 90, 91, 92, 98, 110, - 113, 121, 124, 126, 127, 128, 129, 134, 138, 141, - 143, 144, 149, 150, 153, 156, 157, 158, 161, 164, - 165, 181, 186, 62, 9, 17, 21, 31, 32, 64, - 199, 24, 73, 60, 83, 84, 3, 86, 88, 3, - 138, 140, 141, 17, 36, 53, 59, 141, 143, 148, - 152, 153, 154, 161, 140, 128, 134, 111, 59, 141, - 159, 128, 138, 114, 35, 67, 137, 71, 126, 186, - 193, 125, 137, 122, 59, 96, 97, 141, 59, 93, - 139, 141, 185, 127, 127, 127, 127, 127, 127, 36, - 53, 126, 135, 147, 153, 155, 161, 127, 127, 11, - 126, 192, 62, 59, 94, 185, 4, 33, 34, 36, - 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 67, - 59, 63, 71, 66, 59, 137, 1, 137, 5, 65, - 75, 142, 200, 59, 160, 200, 24, 200, 201, 200, - 64, 62, 190, 88, 59, 36, 59, 146, 152, 153, - 154, 155, 161, 146, 146, 63, 26, 98, 107, 108, - 109, 186, 194, 11, 136, 141, 145, 146, 177, 178, - 179, 59, 67, 162, 112, 194, 24, 59, 68, 138, - 171, 173, 175, 146, 35, 53, 59, 68, 138, 170, - 172, 173, 174, 184, 112, 60, 97, 169, 146, 60, - 93, 167, 65, 75, 146, 8, 147, 60, 72, 72, - 60, 94, 65, 146, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, - 126, 126, 126, 126, 126, 130, 60, 135, 187, 59, - 141, 126, 192, 182, 126, 130, 1, 67, 91, 100, - 180, 181, 183, 186, 186, 126, 8, 17, 22, 23, - 24, 29, 36, 53, 65, 71, 142, 202, 204, 205, - 206, 141, 207, 215, 162, 59, 3, 202, 202, 83, - 60, 179, 8, 146, 60, 141, 126, 35, 105, 5, - 65, 62, 146, 136, 145, 75, 191, 60, 179, 183, - 115, 62, 63, 24, 173, 59, 176, 62, 190, 72, - 104, 59, 174, 53, 174, 62, 190, 3, 198, 75, - 146, 123, 62, 190, 62, 190, 186, 139, 65, 36, - 59, 146, 152, 153, 154, 161, 67, 146, 146, 62, - 190, 186, 65, 67, 126, 131, 132, 188, 189, 11, - 75, 191, 31, 135, 72, 66, 180, 75, 191, 189, - 101, 62, 68, 36, 59, 203, 204, 206, 59, 67, - 71, 67, 8, 202, 3, 50, 59, 141, 212, 213, - 3, 72, 65, 11, 202, 60, 75, 62, 195, 215, - 62, 62, 62, 60, 60, 106, 26, 26, 194, 177, - 59, 141, 151, 152, 153, 154, 155, 161, 163, 60, - 68, 105, 194, 141, 60, 179, 175, 68, 146, 7, - 12, 68, 99, 102, 174, 198, 174, 60, 172, 68, - 138, 198, 35, 97, 60, 93, 60, 186, 146, 130, - 94, 95, 168, 185, 60, 186, 130, 66, 75, 191, - 68, 191, 135, 60, 60, 60, 192, 60, 68, 183, - 180, 202, 205, 195, 24, 141, 142, 197, 202, 209, - 217, 202, 141, 196, 208, 216, 202, 3, 212, 62, - 72, 202, 213, 202, 198, 141, 207, 60, 183, 126, - 126, 62, 179, 59, 163, 116, 60, 187, 66, 103, - 60, 60, 198, 104, 60, 189, 62, 190, 146, 189, - 67, 126, 133, 131, 132, 60, 66, 72, 68, 60, - 60, 59, 68, 62, 72, 202, 68, 62, 49, 202, - 62, 198, 59, 59, 202, 210, 211, 68, 194, 60, - 179, 119, 163, 5, 65, 66, 75, 183, 198, 198, - 68, 68, 95, 60, 68, 130, 192, 210, 195, 209, - 202, 198, 208, 212, 195, 195, 60, 14, 117, 120, - 126, 126, 189, 72, 60, 60, 60, 60, 163, 20, - 100, 66, 66, 68, 210, 210, 118, 112, 105 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. */ - -#define YYFAIL goto yyerrlab - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY && yylen == 1) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - yytoken = YYTRANSLATE (yychar); \ - YYPOPSTACK (1); \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* YY_LOCATION_PRINT -- Print the location on the stream. - This macro was not mandated originally: define only if we know - we won't break user code: when these are the locations we know. */ - -#ifndef YY_LOCATION_PRINT -# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL -# define YY_LOCATION_PRINT(File, Loc) \ - fprintf (File, "%d.%d-%d.%d", \ - (Loc).first_line, (Loc).first_column, \ - (Loc).last_line, (Loc).last_column) -# else -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) -#else -static void -yy_stack_print (bottom, top) - yytype_int16 *bottom; - yytype_int16 *top; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; bottom <= top; ++bottom) - YYFPRINTF (stderr, " %d", *bottom); - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - fprintf (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - fprintf (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into YYRESULT an error message about the unexpected token - YYCHAR while in state YYSTATE. Return the number of bytes copied, - including the terminating null byte. If YYRESULT is null, do not - copy anything; just return the number of bytes that would be - copied. As a special case, return 0 if an ordinary "syntax error" - message will do. Return YYSIZE_MAXIMUM if overflow occurs during - size calculation. */ -static YYSIZE_T -yysyntax_error (char *yyresult, int yystate, int yychar) -{ - int yyn = yypact[yystate]; - - if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) - return 0; - else - { - int yytype = YYTRANSLATE (yychar); - YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - int yysize_overflow = 0; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - int yyx; - -# if 0 - /* This is so xgettext sees the translatable formats that are - constructed on the fly. */ - YY_("syntax error, unexpected %s"); - YY_("syntax error, unexpected %s, expecting %s"); - YY_("syntax error, unexpected %s, expecting %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s"); - YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); -# endif - char *yyfmt; - char const *yyf; - static char const yyunexpected[] = "syntax error, unexpected %s"; - static char const yyexpecting[] = ", expecting %s"; - static char const yyor[] = " or %s"; - char yyformat[sizeof yyunexpected - + sizeof yyexpecting - 1 - + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) - * (sizeof yyor - 1))]; - char const *yyprefix = yyexpecting; - - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yycount = 1; - - yyarg[0] = yytname[yytype]; - yyfmt = yystpcpy (yyformat, yyunexpected); - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - yyformat[sizeof yyunexpected - 1] = '\0'; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (0, yytname[yyx]); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - yyfmt = yystpcpy (yyfmt, yyprefix); - yyprefix = yyor; - } - - yyf = YY_(yyformat); - yysize1 = yysize + yystrlen (yyf); - yysize_overflow |= (yysize1 < yysize); - yysize = yysize1; - - if (yysize_overflow) - return YYSIZE_MAXIMUM; - - if (yyresult) - { - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - char *yyp = yyresult; - int yyi = 0; - while ((*yyp = *yyf) != '\0') - { - if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyf += 2; - } - else - { - yyp++; - yyf++; - } - } - } - return yysize; - } -} -#endif /* YYERROR_VERBOSE */ - - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ - -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - - -/* The look-ahead symbol. */ -int yychar, yystate; - -/* The semantic value of the look-ahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - - int yyn; - int yyresult; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - /* Look-ahead token as an internal (translated) token number. */ - int yytoken = 0; -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - - /* Three stacks and their tools: - `yyss': related to states, - `yyvs': related to semantic values, - `yyls': related to locations. - - Refer to the stacks thru separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss = yyssa; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs = yyvsa; - YYSTYPE *yyvsp; - - - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - YYSIZE_T yystacksize = YYINITDEPTH; - - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss); - YYSTACK_RELOCATE (yyvs); - -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - look-ahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to look-ahead token. */ - yyn = yypact[yystate]; - if (yyn == YYPACT_NINF) - goto yydefault; - - /* Not known => get a look-ahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yyn == 0 || yyn == YYTABLE_NINF) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - if (yyn == YYFINAL) - YYACCEPT; - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the look-ahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token unless it is eof. */ - if (yychar != YYEOF) - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 2: -#line 128 "go.y" - { - xtop = concat(xtop, (yyvsp[(4) - (4)].list)); - } - break; - - case 3: -#line 134 "go.y" - { - prevlineno = lineno; - yyerror("package statement must be first"); - errorexit(); - } - break; - - case 4: -#line 140 "go.y" - { - mkpackage((yyvsp[(2) - (3)].sym)->name); - } - break; - - case 5: -#line 150 "go.y" - { - importpkg = runtimepkg; - - if(debug['A']) - cannedimports("runtime.builtin", "package runtime\n\n$$\n\n"); - else - cannedimports("runtime.builtin", runtimeimport); - curio.importsafe = 1; - } - break; - - case 6: -#line 161 "go.y" - { - importpkg = nil; - } - break; - - case 12: -#line 175 "go.y" - { - Pkg *ipkg; - Sym *my; - Node *pack; - - ipkg = importpkg; - my = importmyname; - importpkg = nil; - importmyname = S; - - if(my == nil) - my = lookup(ipkg->name); - - pack = nod(OPACK, N, N); - pack->sym = my; - pack->pkg = ipkg; - pack->lineno = (yyvsp[(1) - (3)].i); - - if(my->name[0] == '.') { - importdot(ipkg, pack); - break; - } - if(strcmp(my->name, "init") == 0) { - yyerror("cannot import package as init - init must be a func"); - break; - } - if(my->name[0] == '_' && my->name[1] == '\0') - break; - if(my->def) { - lineno = (yyvsp[(1) - (3)].i); - redeclare(my, "as imported package name"); - } - my->def = pack; - my->lastlineno = (yyvsp[(1) - (3)].i); - my->block = 1; // at top level - } - break; - - case 13: -#line 212 "go.y" - { - // When an invalid import path is passed to importfile, - // it calls yyerror and then sets up a fake import with - // no package statement. This allows us to test more - // than one invalid import statement in a single file. - if(nerrors == 0) - fatal("phase error in import"); - } - break; - - case 16: -#line 227 "go.y" - { - // import with original name - (yyval.i) = parserline(); - importmyname = S; - importfile(&(yyvsp[(1) - (1)].val), (yyval.i)); - } - break; - - case 17: -#line 234 "go.y" - { - // import with given name - (yyval.i) = parserline(); - importmyname = (yyvsp[(1) - (2)].sym); - importfile(&(yyvsp[(2) - (2)].val), (yyval.i)); - } - break; - - case 18: -#line 241 "go.y" - { - // import into my name space - (yyval.i) = parserline(); - importmyname = lookup("."); - importfile(&(yyvsp[(2) - (2)].val), (yyval.i)); - } - break; - - case 19: -#line 250 "go.y" - { - if(importpkg->name == nil) { - importpkg->name = (yyvsp[(2) - (4)].sym)->name; - pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++; - } else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0) - yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path); - importpkg->direct = 1; - importpkg->safe = curio.importsafe; - - if(safemode && !curio.importsafe) - yyerror("cannot import unsafe package \"%Z\"", importpkg->path); - } - break; - - case 21: -#line 265 "go.y" - { - if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0) - curio.importsafe = 1; - } - break; - - case 22: -#line 271 "go.y" - { - defercheckwidth(); - } - break; - - case 23: -#line 275 "go.y" - { - resumecheckwidth(); - unimportfile(); - } - break; - - case 24: -#line 284 "go.y" - { - yyerror("empty top-level declaration"); - (yyval.list) = nil; - } - break; - - case 26: -#line 290 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 27: -#line 294 "go.y" - { - yyerror("non-declaration statement outside function body"); - (yyval.list) = nil; - } - break; - - case 28: -#line 299 "go.y" - { - (yyval.list) = nil; - } - break; - - case 29: -#line 305 "go.y" - { - (yyval.list) = (yyvsp[(2) - (2)].list); - } - break; - - case 30: -#line 309 "go.y" - { - (yyval.list) = (yyvsp[(3) - (5)].list); - } - break; - - case 31: -#line 313 "go.y" - { - (yyval.list) = nil; - } - break; - - case 32: -#line 317 "go.y" - { - (yyval.list) = (yyvsp[(2) - (2)].list); - iota = -100000; - lastconst = nil; - } - break; - - case 33: -#line 323 "go.y" - { - (yyval.list) = (yyvsp[(3) - (5)].list); - iota = -100000; - lastconst = nil; - } - break; - - case 34: -#line 329 "go.y" - { - (yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list)); - iota = -100000; - lastconst = nil; - } - break; - - case 35: -#line 335 "go.y" - { - (yyval.list) = nil; - iota = -100000; - } - break; - - case 36: -#line 340 "go.y" - { - (yyval.list) = list1((yyvsp[(2) - (2)].node)); - } - break; - - case 37: -#line 344 "go.y" - { - (yyval.list) = (yyvsp[(3) - (5)].list); - } - break; - - case 38: -#line 348 "go.y" - { - (yyval.list) = nil; - } - break; - - case 39: -#line 354 "go.y" - { - iota = 0; - } - break; - - case 40: -#line 360 "go.y" - { - (yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); - } - break; - - case 41: -#line 364 "go.y" - { - (yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); - } - break; - - case 42: -#line 368 "go.y" - { - (yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list)); - } - break; - - case 43: -#line 374 "go.y" - { - (yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list)); - } - break; - - case 44: -#line 378 "go.y" - { - (yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list)); - } - break; - - case 46: -#line 385 "go.y" - { - (yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil); - } - break; - - case 47: -#line 389 "go.y" - { - (yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil); - } - break; - - case 48: -#line 395 "go.y" - { - // different from dclname because the name - // becomes visible right here, not at the end - // of the declaration. - (yyval.node) = typedcl0((yyvsp[(1) - (1)].sym)); - } - break; - - case 49: -#line 404 "go.y" - { - (yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1); - } - break; - - case 50: -#line 410 "go.y" - { - (yyval.node) = (yyvsp[(1) - (1)].node); - - // These nodes do not carry line numbers. - // Since a bare name used as an expression is an error, - // introduce a wrapper node to give the correct line. - switch((yyval.node)->op) { - case ONAME: - case ONONAME: - case OTYPE: - case OPACK: - case OLITERAL: - (yyval.node) = nod(OPAREN, (yyval.node), N); - (yyval.node)->implicit = 1; - break; - } - } - break; - - case 51: -#line 428 "go.y" - { - (yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - (yyval.node)->etype = (yyvsp[(2) - (3)].i); // rathole to pass opcode - } - break; - - case 52: -#line 433 "go.y" - { - if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) { - // simple - (yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n); - break; - } - // multiple - (yyval.node) = nod(OAS2, N, N); - (yyval.node)->list = (yyvsp[(1) - (3)].list); - (yyval.node)->rlist = (yyvsp[(3) - (3)].list); - } - break; - - case 53: -#line 445 "go.y" - { - if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) { - (yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right); - if((yyvsp[(3) - (3)].list)->next != nil) - yyerror("expr.(type) must be alone in list"); - if((yyvsp[(1) - (3)].list)->next != nil) - yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1); - else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n)) - yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n); - else - (yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym); // it's a colas, so must not re-use an oldname. - break; - } - (yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list), (yyvsp[(2) - (3)].i)); - } - break; - - case 54: -#line 461 "go.y" - { - (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); - (yyval.node)->implicit = 1; - (yyval.node)->etype = OADD; - } - break; - - case 55: -#line 467 "go.y" - { - (yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1)); - (yyval.node)->implicit = 1; - (yyval.node)->etype = OSUB; - } - break; - - case 56: -#line 475 "go.y" - { - Node *n, *nn; - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - (yyval.node) = nod(OXCASE, N, N); - (yyval.node)->list = (yyvsp[(2) - (3)].list); - if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { - // type switch - declare variable - nn = newname(n->sym); - declare(nn, dclcontext); - (yyval.node)->nname = nn; - - // keep track of the instances for reporting unused - nn->defn = typesw->right; - } - } - break; - - case 57: -#line 495 "go.y" - { - Node *n; - - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - (yyval.node) = nod(OXCASE, N, N); - if((yyvsp[(2) - (5)].list)->next == nil) - n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node)); - else { - n = nod(OAS2, N, N); - n->list = (yyvsp[(2) - (5)].list); - n->rlist = list1((yyvsp[(4) - (5)].node)); - } - (yyval.node)->list = list1(n); - } - break; - - case 58: -#line 513 "go.y" - { - // will be converted to OCASE - // right will point to next case - // done in casebody() - markdcl(); - (yyval.node) = nod(OXCASE, N, N); - (yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node)), (yyvsp[(3) - (5)].i))); - } - break; - - case 59: -#line 522 "go.y" - { - Node *n, *nn; - - markdcl(); - (yyval.node) = nod(OXCASE, N, N); - if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) { - // type switch - declare variable - nn = newname(n->sym); - declare(nn, dclcontext); - (yyval.node)->nname = nn; - - // keep track of the instances for reporting unused - nn->defn = typesw->right; - } - } - break; - - case 60: -#line 540 "go.y" - { - markdcl(); - } - break; - - case 61: -#line 544 "go.y" - { - if((yyvsp[(3) - (4)].list) == nil) - (yyval.node) = nod(OEMPTY, N, N); - else - (yyval.node) = liststmt((yyvsp[(3) - (4)].list)); - popdcl(); - } - break; - - case 62: -#line 554 "go.y" - { - // If the last token read by the lexer was consumed - // as part of the case, clear it (parser has cleared yychar). - // If the last token read by the lexer was the lookahead - // leave it alone (parser has it cached in yychar). - // This is so that the stmt_list action doesn't look at - // the case tokens if the stmt_list is empty. - yylast = yychar; - (yyvsp[(1) - (1)].node)->xoffset = block; - } - break; - - case 63: -#line 565 "go.y" - { - int last; - - // This is the only place in the language where a statement - // list is not allowed to drop the final semicolon, because - // it's the only place where a statement list is not followed - // by a closing brace. Handle the error for pedantry. - - // Find the final token of the statement list. - // yylast is lookahead; yyprev is last of stmt_list - last = yyprev; - - if(last > 0 && last != ';' && yychar != '}') - yyerror("missing statement after label"); - (yyval.node) = (yyvsp[(1) - (3)].node); - (yyval.node)->nbody = (yyvsp[(3) - (3)].list); - popdcl(); - } - break; - - case 64: -#line 585 "go.y" - { - (yyval.list) = nil; - } - break; - - case 65: -#line 589 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node)); - } - break; - - case 66: -#line 595 "go.y" - { - markdcl(); - } - break; - - case 67: -#line 599 "go.y" - { - (yyval.list) = (yyvsp[(3) - (4)].list); - popdcl(); - } - break; - - case 68: -#line 606 "go.y" - { - (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); - (yyval.node)->list = (yyvsp[(1) - (4)].list); - (yyval.node)->etype = 0; // := flag - } - break; - - case 69: -#line 612 "go.y" - { - (yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node)); - (yyval.node)->list = (yyvsp[(1) - (4)].list); - (yyval.node)->colas = 1; - colasdefn((yyvsp[(1) - (4)].list), (yyval.node)); - } - break; - - case 70: -#line 619 "go.y" - { - (yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node)); - (yyval.node)->etype = 0; // := flag - } - break; - - case 71: -#line 626 "go.y" - { - // init ; test ; incr - if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0) - yyerror("cannot declare in the for-increment"); - (yyval.node) = nod(OFOR, N, N); - if((yyvsp[(1) - (5)].node) != N) - (yyval.node)->ninit = list1((yyvsp[(1) - (5)].node)); - (yyval.node)->ntest = (yyvsp[(3) - (5)].node); - (yyval.node)->nincr = (yyvsp[(5) - (5)].node); - } - break; - - case 72: -#line 637 "go.y" - { - // normal test - (yyval.node) = nod(OFOR, N, N); - (yyval.node)->ntest = (yyvsp[(1) - (1)].node); - } - break; - - case 74: -#line 646 "go.y" - { - (yyval.node) = (yyvsp[(1) - (2)].node); - (yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list)); - } - break; - - case 75: -#line 653 "go.y" - { - markdcl(); - } - break; - - case 76: -#line 657 "go.y" - { - (yyval.node) = (yyvsp[(3) - (3)].node); - popdcl(); - } - break; - - case 77: -#line 664 "go.y" - { - // test - (yyval.node) = nod(OIF, N, N); - (yyval.node)->ntest = (yyvsp[(1) - (1)].node); - } - break; - - case 78: -#line 670 "go.y" - { - // init ; test - (yyval.node) = nod(OIF, N, N); - if((yyvsp[(1) - (3)].node) != N) - (yyval.node)->ninit = list1((yyvsp[(1) - (3)].node)); - (yyval.node)->ntest = (yyvsp[(3) - (3)].node); - } - break; - - case 79: -#line 681 "go.y" - { - markdcl(); - } - break; - - case 80: -#line 685 "go.y" - { - if((yyvsp[(3) - (3)].node)->ntest == N) - yyerror("missing condition in if statement"); - } - break; - - case 81: -#line 690 "go.y" - { - (yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); - } - break; - - case 82: -#line 694 "go.y" - { - Node *n; - NodeList *nn; - - (yyval.node) = (yyvsp[(3) - (8)].node); - n = (yyvsp[(3) - (8)].node); - popdcl(); - for(nn = concat((yyvsp[(7) - (8)].list), (yyvsp[(8) - (8)].list)); nn; nn = nn->next) { - if(nn->n->op == OIF) - popdcl(); - n->nelse = list1(nn->n); - n = nn->n; - } - } - break; - - case 83: -#line 711 "go.y" - { - markdcl(); - } - break; - - case 84: -#line 715 "go.y" - { - if((yyvsp[(4) - (5)].node)->ntest == N) - yyerror("missing condition in if statement"); - (yyvsp[(4) - (5)].node)->nbody = (yyvsp[(5) - (5)].list); - (yyval.list) = list1((yyvsp[(4) - (5)].node)); - } - break; - - case 85: -#line 723 "go.y" - { - (yyval.list) = nil; - } - break; - - case 86: -#line 727 "go.y" - { - (yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list)); - } - break; - - case 87: -#line 732 "go.y" - { - (yyval.list) = nil; - } - break; - - case 88: -#line 736 "go.y" - { - NodeList *node; - - node = mal(sizeof *node); - node->n = (yyvsp[(2) - (2)].node); - node->end = node; - (yyval.list) = node; - } - break; - - case 89: -#line 747 "go.y" - { - markdcl(); - } - break; - - case 90: -#line 751 "go.y" - { - Node *n; - n = (yyvsp[(3) - (3)].node)->ntest; - if(n != N && n->op != OTYPESW) - n = N; - typesw = nod(OXXX, typesw, n); - } - break; - - case 91: -#line 759 "go.y" - { - (yyval.node) = (yyvsp[(3) - (7)].node); - (yyval.node)->op = OSWITCH; - (yyval.node)->list = (yyvsp[(6) - (7)].list); - typesw = typesw->left; - popdcl(); - } - break; - - case 92: -#line 769 "go.y" - { - typesw = nod(OXXX, typesw, N); - } - break; - - case 93: -#line 773 "go.y" - { - (yyval.node) = nod(OSELECT, N, N); - (yyval.node)->lineno = typesw->lineno; - (yyval.node)->list = (yyvsp[(4) - (5)].list); - typesw = typesw->left; - } - break; - - case 95: -#line 786 "go.y" - { - (yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 96: -#line 790 "go.y" - { - (yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 97: -#line 794 "go.y" - { - (yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 98: -#line 798 "go.y" - { - (yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 99: -#line 802 "go.y" - { - (yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 100: -#line 806 "go.y" - { - (yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 101: -#line 810 "go.y" - { - (yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 102: -#line 814 "go.y" - { - (yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 103: -#line 818 "go.y" - { - (yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 104: -#line 822 "go.y" - { - (yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 105: -#line 826 "go.y" - { - (yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 106: -#line 830 "go.y" - { - (yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 107: -#line 834 "go.y" - { - (yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 108: -#line 838 "go.y" - { - (yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 109: -#line 842 "go.y" - { - (yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 110: -#line 846 "go.y" - { - (yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 111: -#line 850 "go.y" - { - (yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 112: -#line 854 "go.y" - { - (yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 113: -#line 858 "go.y" - { - (yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 114: -#line 863 "go.y" - { - (yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 116: -#line 870 "go.y" - { - (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); - } - break; - - case 117: -#line 874 "go.y" - { - if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) { - // Special case for &T{...}: turn into (*T){...}. - (yyval.node) = (yyvsp[(2) - (2)].node); - (yyval.node)->right = nod(OIND, (yyval.node)->right, N); - (yyval.node)->right->implicit = 1; - } else { - (yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N); - } - } - break; - - case 118: -#line 885 "go.y" - { - (yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N); - } - break; - - case 119: -#line 889 "go.y" - { - (yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N); - } - break; - - case 120: -#line 893 "go.y" - { - (yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N); - } - break; - - case 121: -#line 897 "go.y" - { - yyerror("the bitwise complement operator is ^"); - (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); - } - break; - - case 122: -#line 902 "go.y" - { - (yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N); - } - break; - - case 123: -#line 906 "go.y" - { - (yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N); - } - break; - - case 124: -#line 916 "go.y" - { - (yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N); - } - break; - - case 125: -#line 920 "go.y" - { - (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); - (yyval.node)->list = (yyvsp[(3) - (5)].list); - } - break; - - case 126: -#line 925 "go.y" - { - (yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N); - (yyval.node)->list = (yyvsp[(3) - (6)].list); - (yyval.node)->isddd = 1; - } - break; - - case 127: -#line 933 "go.y" - { - (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); - } - break; - - case 129: -#line 938 "go.y" - { - if((yyvsp[(1) - (3)].node)->op == OPACK) { - Sym *s; - s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg); - (yyvsp[(1) - (3)].node)->used = 1; - (yyval.node) = oldname(s); - break; - } - (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym))); - } - break; - - case 130: -#line 949 "go.y" - { - (yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node)); - } - break; - - case 131: -#line 953 "go.y" - { - (yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node)); - } - break; - - case 132: -#line 957 "go.y" - { - (yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)); - } - break; - - case 133: -#line 961 "go.y" - { - (yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node))); - } - break; - - case 134: -#line 965 "go.y" - { - if((yyvsp[(5) - (8)].node) == N) - yyerror("middle index required in 3-index slice"); - if((yyvsp[(7) - (8)].node) == N) - yyerror("final index required in 3-index slice"); - (yyval.node) = nod(OSLICE3, (yyvsp[(1) - (8)].node), nod(OKEY, (yyvsp[(3) - (8)].node), nod(OKEY, (yyvsp[(5) - (8)].node), (yyvsp[(7) - (8)].node)))); - } - break; - - case 136: -#line 974 "go.y" - { - // conversion - (yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N); - (yyval.node)->list = list1((yyvsp[(3) - (5)].node)); - } - break; - - case 137: -#line 980 "go.y" - { - (yyval.node) = (yyvsp[(3) - (5)].node); - (yyval.node)->right = (yyvsp[(1) - (5)].node); - (yyval.node)->list = (yyvsp[(4) - (5)].list); - fixlbrace((yyvsp[(2) - (5)].i)); - } - break; - - case 138: -#line 987 "go.y" - { - (yyval.node) = (yyvsp[(3) - (5)].node); - (yyval.node)->right = (yyvsp[(1) - (5)].node); - (yyval.node)->list = (yyvsp[(4) - (5)].list); - } - break; - - case 139: -#line 993 "go.y" - { - yyerror("cannot parenthesize type in composite literal"); - (yyval.node) = (yyvsp[(5) - (7)].node); - (yyval.node)->right = (yyvsp[(2) - (7)].node); - (yyval.node)->list = (yyvsp[(6) - (7)].list); - } - break; - - case 141: -#line 1002 "go.y" - { - // composite expression. - // make node early so we get the right line number. - (yyval.node) = nod(OCOMPLIT, N, N); - } - break; - - case 142: -#line 1010 "go.y" - { - (yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node)); - } - break; - - case 143: -#line 1016 "go.y" - { - // These nodes do not carry line numbers. - // Since a composite literal commonly spans several lines, - // the line number on errors may be misleading. - // Introduce a wrapper node to give the correct line. - (yyval.node) = (yyvsp[(1) - (1)].node); - switch((yyval.node)->op) { - case ONAME: - case ONONAME: - case OTYPE: - case OPACK: - case OLITERAL: - (yyval.node) = nod(OPAREN, (yyval.node), N); - (yyval.node)->implicit = 1; - } - } - break; - - case 144: -#line 1033 "go.y" - { - (yyval.node) = (yyvsp[(2) - (4)].node); - (yyval.node)->list = (yyvsp[(3) - (4)].list); - } - break; - - case 146: -#line 1041 "go.y" - { - (yyval.node) = (yyvsp[(2) - (4)].node); - (yyval.node)->list = (yyvsp[(3) - (4)].list); - } - break; - - case 148: -#line 1049 "go.y" - { - (yyval.node) = (yyvsp[(2) - (3)].node); - - // Need to know on lhs of := whether there are ( ). - // Don't bother with the OPAREN in other cases: - // it's just a waste of memory and time. - switch((yyval.node)->op) { - case ONAME: - case ONONAME: - case OPACK: - case OTYPE: - case OLITERAL: - case OTYPESW: - (yyval.node) = nod(OPAREN, (yyval.node), N); - } - } - break; - - case 152: -#line 1075 "go.y" - { - (yyval.i) = LBODY; - } - break; - - case 153: -#line 1079 "go.y" - { - (yyval.i) = '{'; - } - break; - - case 154: -#line 1090 "go.y" - { - if((yyvsp[(1) - (1)].sym) == S) - (yyval.node) = N; - else - (yyval.node) = newname((yyvsp[(1) - (1)].sym)); - } - break; - - case 155: -#line 1099 "go.y" - { - (yyval.node) = dclname((yyvsp[(1) - (1)].sym)); - } - break; - - case 156: -#line 1104 "go.y" - { - (yyval.node) = N; - } - break; - - case 158: -#line 1111 "go.y" - { - (yyval.sym) = (yyvsp[(1) - (1)].sym); - // during imports, unqualified non-exported identifiers are from builtinpkg - if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name)) - (yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); - } - break; - - case 160: -#line 1119 "go.y" - { - (yyval.sym) = S; - } - break; - - case 161: -#line 1125 "go.y" - { - Pkg *p; - - if((yyvsp[(2) - (4)].val).u.sval->len == 0) - p = importpkg; - else { - if(isbadimport((yyvsp[(2) - (4)].val).u.sval)) - errorexit(); - p = mkpkg((yyvsp[(2) - (4)].val).u.sval); - } - (yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, p); - } - break; - - case 162: -#line 1138 "go.y" - { - Pkg *p; - - if((yyvsp[(2) - (4)].val).u.sval->len == 0) - p = importpkg; - else { - if(isbadimport((yyvsp[(2) - (4)].val).u.sval)) - errorexit(); - p = mkpkg((yyvsp[(2) - (4)].val).u.sval); - } - (yyval.sym) = pkglookup("?", p); - } - break; - - case 163: -#line 1153 "go.y" - { - (yyval.node) = oldname((yyvsp[(1) - (1)].sym)); - if((yyval.node)->pack != N) - (yyval.node)->pack->used = 1; - } - break; - - case 165: -#line 1173 "go.y" - { - yyerror("final argument in variadic function missing type"); - (yyval.node) = nod(ODDD, typenod(typ(TINTER)), N); - } - break; - - case 166: -#line 1178 "go.y" - { - (yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N); - } - break; - - case 172: -#line 1189 "go.y" - { - (yyval.node) = (yyvsp[(2) - (3)].node); - } - break; - - case 176: -#line 1198 "go.y" - { - (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); - } - break; - - case 181: -#line 1208 "go.y" - { - (yyval.node) = (yyvsp[(2) - (3)].node); - } - break; - - case 191: -#line 1229 "go.y" - { - if((yyvsp[(1) - (3)].node)->op == OPACK) { - Sym *s; - s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg); - (yyvsp[(1) - (3)].node)->used = 1; - (yyval.node) = oldname(s); - break; - } - (yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym))); - } - break; - - case 192: -#line 1242 "go.y" - { - (yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node)); - } - break; - - case 193: -#line 1246 "go.y" - { - // array literal of nelem - (yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node)); - } - break; - - case 194: -#line 1251 "go.y" - { - (yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N); - (yyval.node)->etype = Cboth; - } - break; - - case 195: -#line 1256 "go.y" - { - (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); - (yyval.node)->etype = Csend; - } - break; - - case 196: -#line 1261 "go.y" - { - (yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)); - } - break; - - case 199: -#line 1269 "go.y" - { - (yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N); - } - break; - - case 200: -#line 1275 "go.y" - { - (yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N); - (yyval.node)->etype = Crecv; - } - break; - - case 201: -#line 1282 "go.y" - { - (yyval.node) = nod(OTSTRUCT, N, N); - (yyval.node)->list = (yyvsp[(3) - (5)].list); - fixlbrace((yyvsp[(2) - (5)].i)); - } - break; - - case 202: -#line 1288 "go.y" - { - (yyval.node) = nod(OTSTRUCT, N, N); - fixlbrace((yyvsp[(2) - (3)].i)); - } - break; - - case 203: -#line 1295 "go.y" - { - (yyval.node) = nod(OTINTER, N, N); - (yyval.node)->list = (yyvsp[(3) - (5)].list); - fixlbrace((yyvsp[(2) - (5)].i)); - } - break; - - case 204: -#line 1301 "go.y" - { - (yyval.node) = nod(OTINTER, N, N); - fixlbrace((yyvsp[(2) - (3)].i)); - } - break; - - case 205: -#line 1312 "go.y" - { - (yyval.node) = (yyvsp[(2) - (3)].node); - if((yyval.node) == N) - break; - if(noescape && (yyvsp[(3) - (3)].list) != nil) - yyerror("can only use //go:noescape with external func implementations"); - (yyval.node)->nbody = (yyvsp[(3) - (3)].list); - (yyval.node)->endlineno = lineno; - (yyval.node)->noescape = noescape; - (yyval.node)->nosplit = nosplit; - (yyval.node)->nowritebarrier = nowritebarrier; - funcbody((yyval.node)); - } - break; - - case 206: -#line 1328 "go.y" - { - Node *t; - - (yyval.node) = N; - (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); - - if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) { - (yyvsp[(1) - (5)].sym) = renameinit(); - if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil) - yyerror("func init must have no arguments and no return values"); - } - if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) { - if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil) - yyerror("func main must have no arguments and no return values"); - } - - t = nod(OTFUNC, N, N); - t->list = (yyvsp[(3) - (5)].list); - t->rlist = (yyvsp[(5) - (5)].list); - - (yyval.node) = nod(ODCLFUNC, N, N); - (yyval.node)->nname = newname((yyvsp[(1) - (5)].sym)); - (yyval.node)->nname->defn = (yyval.node); - (yyval.node)->nname->ntype = t; // TODO: check if nname already has an ntype - declare((yyval.node)->nname, PFUNC); - - funchdr((yyval.node)); - } - break; - - case 207: -#line 1357 "go.y" - { - Node *rcvr, *t; - - (yyval.node) = N; - (yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0); - (yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1); - - if((yyvsp[(2) - (8)].list) == nil) { - yyerror("method has no receiver"); - break; - } - if((yyvsp[(2) - (8)].list)->next != nil) { - yyerror("method has multiple receivers"); - break; - } - rcvr = (yyvsp[(2) - (8)].list)->n; - if(rcvr->op != ODCLFIELD) { - yyerror("bad receiver in method"); - break; - } - - t = nod(OTFUNC, rcvr, N); - t->list = (yyvsp[(6) - (8)].list); - t->rlist = (yyvsp[(8) - (8)].list); - - (yyval.node) = nod(ODCLFUNC, N, N); - (yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym)); - (yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right); - (yyval.node)->nname->defn = (yyval.node); - (yyval.node)->nname->ntype = t; - (yyval.node)->nname->nointerface = nointerface; - declare((yyval.node)->nname, PFUNC); - - funchdr((yyval.node)); - } - break; - - case 208: -#line 1395 "go.y" - { - Sym *s; - Type *t; - - (yyval.node) = N; - - s = (yyvsp[(1) - (5)].sym); - t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); - - importsym(s, ONAME); - if(s->def != N && s->def->op == ONAME) { - if(eqtype(t, s->def->type)) { - dclcontext = PDISCARD; // since we skip funchdr below - break; - } - yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t); - } - - (yyval.node) = newname(s); - (yyval.node)->type = t; - declare((yyval.node), PFUNC); - - funchdr((yyval.node)); - } - break; - - case 209: -#line 1420 "go.y" - { - (yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); - (yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list)); - - checkwidth((yyval.node)->type); - addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0, nointerface); - nointerface = 0; - funchdr((yyval.node)); - - // inl.c's inlnode in on a dotmeth node expects to find the inlineable body as - // (dotmeth's type)->nname->inl, and dotmeth's type has been pulled - // out by typecheck's lookdot as this $$->ttype. So by providing - // this back link here we avoid special casing there. - (yyval.node)->type->nname = (yyval.node); - } - break; - - case 210: -#line 1438 "go.y" - { - (yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1); - (yyval.node) = nod(OTFUNC, N, N); - (yyval.node)->list = (yyvsp[(3) - (5)].list); - (yyval.node)->rlist = (yyvsp[(5) - (5)].list); - } - break; - - case 211: -#line 1446 "go.y" - { - (yyval.list) = nil; - } - break; - - case 212: -#line 1450 "go.y" - { - (yyval.list) = (yyvsp[(2) - (3)].list); - if((yyval.list) == nil) - (yyval.list) = list1(nod(OEMPTY, N, N)); - } - break; - - case 213: -#line 1458 "go.y" - { - (yyval.list) = nil; - } - break; - - case 214: -#line 1462 "go.y" - { - (yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node))); - } - break; - - case 215: -#line 1466 "go.y" - { - (yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0); - (yyval.list) = (yyvsp[(2) - (3)].list); - } - break; - - case 216: -#line 1473 "go.y" - { - closurehdr((yyvsp[(1) - (1)].node)); - } - break; - - case 217: -#line 1479 "go.y" - { - (yyval.node) = closurebody((yyvsp[(3) - (4)].list)); - fixlbrace((yyvsp[(2) - (4)].i)); - } - break; - - case 218: -#line 1484 "go.y" - { - (yyval.node) = closurebody(nil); - } - break; - - case 219: -#line 1495 "go.y" - { - (yyval.list) = nil; - } - break; - - case 220: -#line 1499 "go.y" - { - (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list)); - if(nsyntaxerrors == 0) - testdclstack(); - nointerface = 0; - noescape = 0; - nosplit = 0; - nowritebarrier = 0; - } - break; - - case 222: -#line 1512 "go.y" - { - (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); - } - break; - - case 224: -#line 1519 "go.y" - { - (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); - } - break; - - case 225: -#line 1525 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 226: -#line 1529 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 228: -#line 1536 "go.y" - { - (yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list)); - } - break; - - case 229: -#line 1542 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 230: -#line 1546 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 231: -#line 1552 "go.y" - { - NodeList *l; - - Node *n; - l = (yyvsp[(1) - (3)].list); - if(l == nil) { - // ? symbol, during import (list1(N) == nil) - n = (yyvsp[(2) - (3)].node); - if(n->op == OIND) - n = n->left; - n = embedded(n->sym, importpkg); - n->right = (yyvsp[(2) - (3)].node); - n->val = (yyvsp[(3) - (3)].val); - (yyval.list) = list1(n); - break; - } - - for(l=(yyvsp[(1) - (3)].list); l; l=l->next) { - l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node)); - l->n->val = (yyvsp[(3) - (3)].val); - } - } - break; - - case 232: -#line 1575 "go.y" - { - (yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val); - (yyval.list) = list1((yyvsp[(1) - (2)].node)); - } - break; - - case 233: -#line 1580 "go.y" - { - (yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val); - (yyval.list) = list1((yyvsp[(2) - (4)].node)); - yyerror("cannot parenthesize embedded type"); - } - break; - - case 234: -#line 1586 "go.y" - { - (yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N); - (yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val); - (yyval.list) = list1((yyvsp[(2) - (3)].node)); - } - break; - - case 235: -#line 1592 "go.y" - { - (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); - (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); - (yyval.list) = list1((yyvsp[(3) - (5)].node)); - yyerror("cannot parenthesize embedded type"); - } - break; - - case 236: -#line 1599 "go.y" - { - (yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N); - (yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val); - (yyval.list) = list1((yyvsp[(3) - (5)].node)); - yyerror("cannot parenthesize embedded type"); - } - break; - - case 237: -#line 1608 "go.y" - { - Node *n; - - (yyval.sym) = (yyvsp[(1) - (1)].sym); - n = oldname((yyvsp[(1) - (1)].sym)); - if(n->pack != N) - n->pack->used = 1; - } - break; - - case 238: -#line 1617 "go.y" - { - Pkg *pkg; - - if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) { - yyerror("%S is not a package", (yyvsp[(1) - (3)].sym)); - pkg = localpkg; - } else { - (yyvsp[(1) - (3)].sym)->def->used = 1; - pkg = (yyvsp[(1) - (3)].sym)->def->pkg; - } - (yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg); - } - break; - - case 239: -#line 1632 "go.y" - { - (yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg); - } - break; - - case 240: -#line 1638 "go.y" - { - (yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node)); - ifacedcl((yyval.node)); - } - break; - - case 241: -#line 1643 "go.y" - { - (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym))); - } - break; - - case 242: -#line 1647 "go.y" - { - (yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym))); - yyerror("cannot parenthesize embedded type"); - } - break; - - case 243: -#line 1654 "go.y" - { - // without func keyword - (yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1); - (yyval.node) = nod(OTFUNC, fakethis(), N); - (yyval.node)->list = (yyvsp[(2) - (4)].list); - (yyval.node)->rlist = (yyvsp[(4) - (4)].list); - } - break; - - case 245: -#line 1668 "go.y" - { - (yyval.node) = nod(ONONAME, N, N); - (yyval.node)->sym = (yyvsp[(1) - (2)].sym); - (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node)); - } - break; - - case 246: -#line 1674 "go.y" - { - (yyval.node) = nod(ONONAME, N, N); - (yyval.node)->sym = (yyvsp[(1) - (2)].sym); - (yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node)); - } - break; - - case 248: -#line 1683 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 249: -#line 1687 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 250: -#line 1692 "go.y" - { - (yyval.list) = nil; - } - break; - - case 251: -#line 1696 "go.y" - { - (yyval.list) = (yyvsp[(1) - (2)].list); - } - break; - - case 252: -#line 1704 "go.y" - { - (yyval.node) = N; - } - break; - - case 254: -#line 1709 "go.y" - { - (yyval.node) = liststmt((yyvsp[(1) - (1)].list)); - } - break; - - case 256: -#line 1714 "go.y" - { - (yyval.node) = N; - } - break; - - case 262: -#line 1725 "go.y" - { - (yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N); - (yyvsp[(1) - (2)].node)->sym = dclstack; // context, for goto restrictions - } - break; - - case 263: -#line 1730 "go.y" - { - NodeList *l; - - (yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node); - l = list1((yyvsp[(1) - (4)].node)); - if((yyvsp[(4) - (4)].node)) - l = list(l, (yyvsp[(4) - (4)].node)); - (yyval.node) = liststmt(l); - } - break; - - case 264: -#line 1740 "go.y" - { - // will be converted to OFALL - (yyval.node) = nod(OXFALL, N, N); - (yyval.node)->xoffset = block; - } - break; - - case 265: -#line 1746 "go.y" - { - (yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N); - } - break; - - case 266: -#line 1750 "go.y" - { - (yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N); - } - break; - - case 267: -#line 1754 "go.y" - { - (yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N); - } - break; - - case 268: -#line 1758 "go.y" - { - (yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N); - } - break; - - case 269: -#line 1762 "go.y" - { - (yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N); - (yyval.node)->sym = dclstack; // context, for goto restrictions - } - break; - - case 270: -#line 1767 "go.y" - { - (yyval.node) = nod(ORETURN, N, N); - (yyval.node)->list = (yyvsp[(2) - (2)].list); - if((yyval.node)->list == nil && curfn != N) { - NodeList *l; - - for(l=curfn->dcl; l; l=l->next) { - if(l->n->class == PPARAM) - continue; - if(l->n->class != PPARAMOUT) - break; - if(l->n->sym->def != l->n) - yyerror("%s is shadowed during return", l->n->sym->name); - } - } - } - break; - - case 271: -#line 1786 "go.y" - { - (yyval.list) = nil; - if((yyvsp[(1) - (1)].node) != N) - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 272: -#line 1792 "go.y" - { - (yyval.list) = (yyvsp[(1) - (3)].list); - if((yyvsp[(3) - (3)].node) != N) - (yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node)); - } - break; - - case 273: -#line 1800 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 274: -#line 1804 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 275: -#line 1810 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 276: -#line 1814 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 277: -#line 1820 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 278: -#line 1824 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 279: -#line 1830 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 280: -#line 1834 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 281: -#line 1843 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 282: -#line 1847 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 283: -#line 1851 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 284: -#line 1855 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 285: -#line 1860 "go.y" - { - (yyval.list) = nil; - } - break; - - case 286: -#line 1864 "go.y" - { - (yyval.list) = (yyvsp[(1) - (2)].list); - } - break; - - case 291: -#line 1878 "go.y" - { - (yyval.node) = N; - } - break; - - case 293: -#line 1884 "go.y" - { - (yyval.list) = nil; - } - break; - - case 295: -#line 1890 "go.y" - { - (yyval.node) = N; - } - break; - - case 297: -#line 1896 "go.y" - { - (yyval.list) = nil; - } - break; - - case 299: -#line 1902 "go.y" - { - (yyval.list) = nil; - } - break; - - case 301: -#line 1908 "go.y" - { - (yyval.list) = nil; - } - break; - - case 303: -#line 1914 "go.y" - { - (yyval.val).ctype = CTxxx; - } - break; - - case 305: -#line 1924 "go.y" - { - importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval); - } - break; - - case 306: -#line 1928 "go.y" - { - importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type)); - } - break; - - case 307: -#line 1932 "go.y" - { - importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node)); - } - break; - - case 308: -#line 1936 "go.y" - { - importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node)); - } - break; - - case 309: -#line 1940 "go.y" - { - importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type)); - } - break; - - case 310: -#line 1944 "go.y" - { - if((yyvsp[(2) - (4)].node) == N) { - dclcontext = PEXTERN; // since we skip the funcbody below - break; - } - - (yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list); - - funcbody((yyvsp[(2) - (4)].node)); - importlist = list(importlist, (yyvsp[(2) - (4)].node)); - - if(debug['E']) { - print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node)); - if(debug['m'] > 2 && (yyvsp[(2) - (4)].node)->inl) - print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl); - } - } - break; - - case 311: -#line 1964 "go.y" - { - (yyval.sym) = (yyvsp[(1) - (1)].sym); - structpkg = (yyval.sym)->pkg; - } - break; - - case 312: -#line 1971 "go.y" - { - (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); - importsym((yyvsp[(1) - (1)].sym), OTYPE); - } - break; - - case 318: -#line 1991 "go.y" - { - (yyval.type) = pkgtype((yyvsp[(1) - (1)].sym)); - } - break; - - case 319: -#line 1995 "go.y" - { - // predefined name like uint8 - (yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg); - if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) { - yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name); - (yyval.type) = T; - } else - (yyval.type) = (yyvsp[(1) - (1)].sym)->def->type; - } - break; - - case 320: -#line 2005 "go.y" - { - (yyval.type) = aindex(N, (yyvsp[(3) - (3)].type)); - } - break; - - case 321: -#line 2009 "go.y" - { - (yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type)); - } - break; - - case 322: -#line 2013 "go.y" - { - (yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type)); - } - break; - - case 323: -#line 2017 "go.y" - { - (yyval.type) = tostruct((yyvsp[(3) - (4)].list)); - } - break; - - case 324: -#line 2021 "go.y" - { - (yyval.type) = tointerface((yyvsp[(3) - (4)].list)); - } - break; - - case 325: -#line 2025 "go.y" - { - (yyval.type) = ptrto((yyvsp[(2) - (2)].type)); - } - break; - - case 326: -#line 2029 "go.y" - { - (yyval.type) = typ(TCHAN); - (yyval.type)->type = (yyvsp[(2) - (2)].type); - (yyval.type)->chan = Cboth; - } - break; - - case 327: -#line 2035 "go.y" - { - (yyval.type) = typ(TCHAN); - (yyval.type)->type = (yyvsp[(3) - (4)].type); - (yyval.type)->chan = Cboth; - } - break; - - case 328: -#line 2041 "go.y" - { - (yyval.type) = typ(TCHAN); - (yyval.type)->type = (yyvsp[(3) - (3)].type); - (yyval.type)->chan = Csend; - } - break; - - case 329: -#line 2049 "go.y" - { - (yyval.type) = typ(TCHAN); - (yyval.type)->type = (yyvsp[(3) - (3)].type); - (yyval.type)->chan = Crecv; - } - break; - - case 330: -#line 2057 "go.y" - { - (yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)); - } - break; - - case 331: -#line 2063 "go.y" - { - (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type))); - if((yyvsp[(1) - (3)].sym)) - (yyval.node)->left = newname((yyvsp[(1) - (3)].sym)); - (yyval.node)->val = (yyvsp[(3) - (3)].val); - } - break; - - case 332: -#line 2070 "go.y" - { - Type *t; - - t = typ(TARRAY); - t->bound = -1; - t->type = (yyvsp[(3) - (4)].type); - - (yyval.node) = nod(ODCLFIELD, N, typenod(t)); - if((yyvsp[(1) - (4)].sym)) - (yyval.node)->left = newname((yyvsp[(1) - (4)].sym)); - (yyval.node)->isddd = 1; - (yyval.node)->val = (yyvsp[(4) - (4)].val); - } - break; - - case 333: -#line 2086 "go.y" - { - Sym *s; - Pkg *p; - - if((yyvsp[(1) - (3)].sym) != S && strcmp((yyvsp[(1) - (3)].sym)->name, "?") != 0) { - (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type))); - (yyval.node)->val = (yyvsp[(3) - (3)].val); - } else { - s = (yyvsp[(2) - (3)].type)->sym; - if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype]) - s = (yyvsp[(2) - (3)].type)->type->sym; - p = importpkg; - if((yyvsp[(1) - (3)].sym) != S) - p = (yyvsp[(1) - (3)].sym)->pkg; - (yyval.node) = embedded(s, p); - (yyval.node)->right = typenod((yyvsp[(2) - (3)].type)); - (yyval.node)->val = (yyvsp[(3) - (3)].val); - } - } - break; - - case 334: -#line 2108 "go.y" - { - (yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list)))); - } - break; - - case 335: -#line 2112 "go.y" - { - (yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))); - } - break; - - case 336: -#line 2117 "go.y" - { - (yyval.list) = nil; - } - break; - - case 338: -#line 2124 "go.y" - { - (yyval.list) = (yyvsp[(2) - (3)].list); - } - break; - - case 339: -#line 2128 "go.y" - { - (yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)))); - } - break; - - case 340: -#line 2138 "go.y" - { - (yyval.node) = nodlit((yyvsp[(1) - (1)].val)); - } - break; - - case 341: -#line 2142 "go.y" - { - (yyval.node) = nodlit((yyvsp[(2) - (2)].val)); - switch((yyval.node)->val.ctype){ - case CTINT: - case CTRUNE: - mpnegfix((yyval.node)->val.u.xval); - break; - case CTFLT: - mpnegflt((yyval.node)->val.u.fval); - break; - case CTCPLX: - mpnegflt(&(yyval.node)->val.u.cval->real); - mpnegflt(&(yyval.node)->val.u.cval->imag); - break; - default: - yyerror("bad negated constant"); - } - } - break; - - case 342: -#line 2161 "go.y" - { - (yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg)); - if((yyval.node)->op != OLITERAL) - yyerror("bad constant %S", (yyval.node)->sym); - } - break; - - case 344: -#line 2170 "go.y" - { - if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) { - (yyval.node) = (yyvsp[(2) - (5)].node); - mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0); - break; - } - (yyvsp[(4) - (5)].node)->val.u.cval->real = (yyvsp[(4) - (5)].node)->val.u.cval->imag; - mpmovecflt(&(yyvsp[(4) - (5)].node)->val.u.cval->imag, 0.0); - (yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val); - } - break; - - case 347: -#line 2186 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 348: -#line 2190 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 349: -#line 2196 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 350: -#line 2200 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - case 351: -#line 2206 "go.y" - { - (yyval.list) = list1((yyvsp[(1) - (1)].node)); - } - break; - - case 352: -#line 2210 "go.y" - { - (yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node)); - } - break; - - -/* Line 1267 of yacc.c. */ -#line 4909 "y.tab.c" - default: break; - } - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else - { - YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); - if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) - { - YYSIZE_T yyalloc = 2 * yysize; - if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) - yyalloc = YYSTACK_ALLOC_MAXIMUM; - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yyalloc); - if (yymsg) - yymsg_alloc = yyalloc; - else - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - } - } - - if (0 < yysize && yysize <= yymsg_alloc) - { - (void) yysyntax_error (yymsg, yystate, yychar); - yyerror (yymsg); - } - else - { - yyerror (YY_("syntax error")); - if (yysize != 0) - goto yyexhaustedlab; - } - } -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse look-ahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse look-ahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (yyn != YYPACT_NINF) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - if (yyn == YYFINAL) - YYACCEPT; - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#ifndef yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEOF && yychar != YYEMPTY) - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - -#line 2214 "go.y" - - -static void -fixlbrace(int lbr) -{ - // If the opening brace was an LBODY, - // set up for another one now that we're done. - // See comment in lex.c about loophack. - if(lbr == LBODY) - loophack = 1; -} - - diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h deleted file mode 100644 index d01fbe1987..0000000000 --- a/src/cmd/gc/y.tab.h +++ /dev/null @@ -1,167 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.3. */ - -/* Skeleton interface for Bison's Yacc-like parsers in C - - Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - LLITERAL = 258, - LASOP = 259, - LCOLAS = 260, - LBREAK = 261, - LCASE = 262, - LCHAN = 263, - LCONST = 264, - LCONTINUE = 265, - LDDD = 266, - LDEFAULT = 267, - LDEFER = 268, - LELSE = 269, - LFALL = 270, - LFOR = 271, - LFUNC = 272, - LGO = 273, - LGOTO = 274, - LIF = 275, - LIMPORT = 276, - LINTERFACE = 277, - LMAP = 278, - LNAME = 279, - LPACKAGE = 280, - LRANGE = 281, - LRETURN = 282, - LSELECT = 283, - LSTRUCT = 284, - LSWITCH = 285, - LTYPE = 286, - LVAR = 287, - LANDAND = 288, - LANDNOT = 289, - LBODY = 290, - LCOMM = 291, - LDEC = 292, - LEQ = 293, - LGE = 294, - LGT = 295, - LIGNORE = 296, - LINC = 297, - LLE = 298, - LLSH = 299, - LLT = 300, - LNE = 301, - LOROR = 302, - LRSH = 303, - NotPackage = 304, - NotParen = 305, - PreferToRightParen = 306 - }; -#endif -/* Tokens. */ -#define LLITERAL 258 -#define LASOP 259 -#define LCOLAS 260 -#define LBREAK 261 -#define LCASE 262 -#define LCHAN 263 -#define LCONST 264 -#define LCONTINUE 265 -#define LDDD 266 -#define LDEFAULT 267 -#define LDEFER 268 -#define LELSE 269 -#define LFALL 270 -#define LFOR 271 -#define LFUNC 272 -#define LGO 273 -#define LGOTO 274 -#define LIF 275 -#define LIMPORT 276 -#define LINTERFACE 277 -#define LMAP 278 -#define LNAME 279 -#define LPACKAGE 280 -#define LRANGE 281 -#define LRETURN 282 -#define LSELECT 283 -#define LSTRUCT 284 -#define LSWITCH 285 -#define LTYPE 286 -#define LVAR 287 -#define LANDAND 288 -#define LANDNOT 289 -#define LBODY 290 -#define LCOMM 291 -#define LDEC 292 -#define LEQ 293 -#define LGE 294 -#define LGT 295 -#define LIGNORE 296 -#define LINC 297 -#define LLE 298 -#define LLSH 299 -#define LLT 300 -#define LNE 301 -#define LOROR 302 -#define LRSH 303 -#define NotPackage 304 -#define NotParen 305 -#define PreferToRightParen 306 - - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -#line 28 "go.y" -{ - Node* node; - NodeList* list; - Type* type; - Sym* sym; - struct Val val; - int i; -} -/* Line 1529 of yacc.c. */ -#line 160 "y.tab.h" - YYSTYPE; -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -# define YYSTYPE_IS_TRIVIAL 1 -#endif - -extern YYSTYPE yylval; - diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h deleted file mode 100644 index d0dd639ff3..0000000000 --- a/src/cmd/gc/yerr.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Example-based syntax error messages. -// See bisonerrors, Makefile, go.y. - -static struct { - int yystate; - int yychar; - char *msg; -} yymsg[] = { - // Each line of the form % token list - // is converted by bisonerrors into the yystate and yychar caused - // by that token list. - - {222, ',', - "unexpected comma during import block"}, - - {32, ';', - "missing import path; require quoted string"}, - - {380, ';', - "missing { after if clause"}, - - {401, ';', - "missing { after switch clause"}, - - {239, ';', - "missing { after for clause"}, - - {478, LBODY, - "missing { after for clause"}, - - {22, '{', - "unexpected semicolon or newline before {"}, - - {145, ';', - "unexpected semicolon or newline in type declaration"}, - - {37, '}', - "unexpected } in channel type"}, - - {37, ')', - "unexpected ) in channel type"}, - - {37, ',', - "unexpected comma in channel type"}, - - {441, LELSE, - "unexpected semicolon or newline before else"}, - - {259, ',', - "name list not allowed in interface type"}, - - {239, LVAR, - "var declaration not allowed in for initializer"}, - - {65, '{', - "unexpected { at end of statement"}, - - {379, '{', - "unexpected { at end of statement"}, - - {126, ';', - "argument to go/defer must be function call"}, - - {428, ';', - "need trailing comma before newline in composite literal"}, - - {439, ';', - "need trailing comma before newline in composite literal"}, - - {113, LNAME, - "nested func not allowed"}, - - {647, ';', - "else must be followed by if or statement block"} -}; diff --git a/src/cmd/new5a/a.y b/src/cmd/new5a/a.y deleted file mode 100644 index 39fab8fa26..0000000000 --- a/src/cmd/new5a/a.y +++ /dev/null @@ -1,795 +0,0 @@ -// Inferno utils/5a/a.y -// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -%{ -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/arm" -) -%} - -%union { - sym *asm.Sym - lval int32 - dval float64 - sval string - addr obj.Addr -} - -%left '|' -%left '^' -%left '&' -%left '<' '>' -%left '+' '-' -%left '*' '/' '%' -%token LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5 -%token LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA -%token LTYPEB LTYPEC LTYPED LTYPEE -%token LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK -%token LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD -%token LCONST LSP LSB LFP LPC -%token LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR -%token LCOND LS LAT LGLOBL -%token LFCONST -%token LSCONST -%token LNAME LLAB LVAR -%type con expr oexpr pointer offset sreg spreg creg -%type rcon cond reglist -%type gen rel reg regreg freg shift fcon frcon textsize -%type imm ximm name oreg ireg nireg ioreg imsr -%% -prog: -| prog - { - stmtline = asm.Lineno; - } - line - -line: - LNAME ':' - { - $1 = asm.LabelLookup($1); - if $1.Type == LLAB && $1.Value != int64(asm.PC) { - yyerror("redeclaration of %s", $1.Labelname) - } - $1.Type = LLAB; - $1.Value = int64(asm.PC) - } - line -| LNAME '=' expr ';' - { - $1.Type = LVAR; - $1.Value = int64($3); - } -| LVAR '=' expr ';' - { - if $1.Value != int64($3) { - yyerror("redeclaration of %s", $1.Name) - } - $1.Value = int64($3); - } -| ';' -| inst ';' -| error ';' - -inst: -/* - * ADD - */ - LTYPE1 cond imsr ',' spreg ',' reg - { - outcode($1, $2, &$3, $5, &$7); - } -| LTYPE1 cond imsr ',' spreg ',' - { - outcode($1, $2, &$3, $5, &nullgen); - } -| LTYPE1 cond imsr ',' reg - { - outcode($1, $2, &$3, 0, &$5); - } -/* - * MVN - */ -| LTYPE2 cond imsr ',' reg - { - outcode($1, $2, &$3, 0, &$5); - } -/* - * MOVW - */ -| LTYPE3 cond gen ',' gen - { - outcode($1, $2, &$3, 0, &$5); - } -/* - * B/BL - */ -| LTYPE4 cond comma rel - { - outcode($1, $2, &nullgen, 0, &$4); - } -| LTYPE4 cond comma nireg - { - outcode($1, $2, &nullgen, 0, &$4); - } -/* - * BX - */ -| LTYPEBX comma ireg - { - outcode($1, Always, &nullgen, 0, &$3); - } -/* - * BEQ - */ -| LTYPE5 comma rel - { - outcode($1, Always, &nullgen, 0, &$3); - } -/* - * SWI - */ -| LTYPE6 cond comma gen - { - outcode($1, $2, &nullgen, 0, &$4); - } -/* - * CMP - */ -| LTYPE7 cond imsr ',' spreg comma - { - outcode($1, $2, &$3, $5, &nullgen); - } -/* - * MOVM - */ -| LTYPE8 cond ioreg ',' '[' reglist ']' - { - var g obj.Addr - - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = int64($6); - outcode($1, $2, &$3, 0, &g); - } -| LTYPE8 cond '[' reglist ']' ',' ioreg - { - var g obj.Addr - - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = int64($4); - outcode($1, $2, &g, 0, &$7); - } -/* - * SWAP - */ -| LTYPE9 cond reg ',' ireg ',' reg - { - outcode($1, $2, &$5, int32($3.Reg), &$7); - } -| LTYPE9 cond reg ',' ireg comma - { - outcode($1, $2, &$5, int32($3.Reg), &$3); - } -| LTYPE9 cond comma ireg ',' reg - { - outcode($1, $2, &$4, int32($6.Reg), &$6); - } -/* - * RET - */ -| LTYPEA cond comma - { - outcode($1, $2, &nullgen, 0, &nullgen); - } -/* - * TEXT - */ -| LTYPEB name ',' '$' textsize - { - asm.Settext($2.Sym); - outcode($1, Always, &$2, 0, &$5); - } -| LTYPEB name ',' con ',' '$' textsize - { - asm.Settext($2.Sym); - outcode($1, Always, &$2, 0, &$7); - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST; - lastpc.From3.Offset = int64($4) - } - } -/* - * GLOBL - */ -| LGLOBL name ',' imm - { - asm.Settext($2.Sym) - outcode($1, Always, &$2, 0, &$4) - } -| LGLOBL name ',' con ',' imm - { - asm.Settext($2.Sym) - outcode($1, Always, &$2, 0, &$6) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = int64($4) - } - } - -/* - * DATA - */ -| LTYPEC name '/' con ',' ximm - { - outcode($1, Always, &$2, 0, &$6) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = int64($4) - } - } -/* - * CASE - */ -| LTYPED cond reg comma - { - outcode($1, $2, &$3, 0, &nullgen); - } -/* - * word - */ -| LTYPEH comma ximm - { - outcode($1, Always, &nullgen, 0, &$3); - } -/* - * floating-point coprocessor - */ -| LTYPEI cond freg ',' freg - { - outcode($1, $2, &$3, 0, &$5); - } -| LTYPEK cond frcon ',' freg - { - outcode($1, $2, &$3, 0, &$5); - } -| LTYPEK cond frcon ',' LFREG ',' freg - { - outcode($1, $2, &$3, $5, &$7); - } -| LTYPEL cond freg ',' freg comma - { - outcode($1, $2, &$3, int32($5.Reg), &nullgen); - } -/* - * MCR MRC - */ -| LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr - { - var g obj.Addr - - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = int64( - (0xe << 24) | /* opcode */ - ($1 << 20) | /* MCR/MRC */ - (($2^C_SCOND_XOR) << 28) | /* scond */ - (($3 & 15) << 8) | /* coprocessor number */ - (($5 & 7) << 21) | /* coprocessor operation */ - (($7 & 15) << 12) | /* arm register */ - (($9 & 15) << 16) | /* Crn */ - (($11 & 15) << 0) | /* Crm */ - (($12 & 7) << 5) | /* coprocessor information */ - (1<<4)); /* must be set */ - outcode(AMRC, Always, &nullgen, 0, &g); - } -/* - * MULL r1,r2,(hi,lo) - */ -| LTYPEM cond reg ',' reg ',' regreg - { - outcode($1, $2, &$3, int32($5.Reg), &$7); - } -/* - * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4 - * MULAW{T,B} r1,r2,r3,r4 - */ -| LTYPEN cond reg ',' reg ',' reg ',' spreg - { - $7.Type = obj.TYPE_REGREG2; - $7.Offset = int64($9); - outcode($1, $2, &$3, int32($5.Reg), &$7); - } -/* - * PLD - */ -| LTYPEPLD oreg - { - outcode($1, Always, &$2, 0, &nullgen); - } -/* - * PCDATA - */ -| LTYPEPC gen ',' gen - { - if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants") - } - outcode($1, Always, &$2, 0, &$4); - } -/* - * FUNCDATA - */ -| LTYPEF gen ',' gen - { - if $2.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if $4.Type != obj.NAME_EXTERN && $4.Type != obj.NAME_STATIC && $4.Type != obj.TYPE_MEM { - yyerror("value for FUNCDATA must be symbol reference") - } - outcode($1, Always, &$2, 0, &$4); - } -/* - * END - */ -| LTYPEE comma - { - outcode($1, Always, &nullgen, 0, &nullgen); - } - -textsize: - LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = int64($1) - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -int64($2) - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = int64($1) - $$.U.Argsize = int32($3); - } -| '-' LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -int64($2) - $$.U.Argsize = int32($4); - } - -cond: - { - $$ = Always; - } -| cond LCOND - { - $$ = ($1 & ^ C_SCOND) | $2; - } -| cond LS - { - $$ = $1 | $2; - } - -comma: -| ',' comma - -rel: - con '(' LPC ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_BRANCH; - $$.Offset = int64($1) + int64(asm.PC); - } -| LNAME offset - { - $1 = asm.LabelLookup($1); - $$ = nullgen; - if asm.Pass == 2 && $1.Type != LLAB { - yyerror("undefined label: %s", $1.Labelname) - } - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1.Value + int64($2); - } - -ximm: '$' con - { - $$ = nullgen; - $$.Type = obj.TYPE_CONST; - $$.Offset = int64($2); - } -| '$' oreg - { - $$ = $2; - $$.Type = obj.TYPE_ADDR; - } -| '$' LSCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_SCONST; - $$.U.Sval = $2 - } -| fcon - -fcon: - '$' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = $2; - } -| '$' '-' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = -$3; - } - -reglist: - spreg - { - $$ = 1 << uint($1&15); - } -| spreg '-' spreg - { - $$=0; - for i:=$1; i<=$3; i++ { - $$ |= 1<' '>' rcon - { - $$ = nullgen; - $$.Type = obj.TYPE_SHIFT; - $$.Offset = int64($1&15) | int64($4) | (1 << 5); - } -| spreg '-' '>' rcon - { - $$ = nullgen; - $$.Type = obj.TYPE_SHIFT; - $$.Offset = int64($1&15) | int64($4) | (2 << 5); - } -| spreg LAT '>' rcon - { - $$ = nullgen; - $$.Type = obj.TYPE_SHIFT; - $$.Offset = int64($1&15) | int64($4) | (3 << 5); - } - -rcon: - spreg - { - if $$ < REG_R0 || $$ > REG_R15 { - print("register value out of range\n") - } - $$ = (($1&15) << 8) | (1 << 4); - } -| con - { - if $$ < 0 || $$ >= 32 { - print("shift value out of range\n") - } - $$ = ($1&31) << 7; - } - -sreg: - LREG -| LPC - { - $$ = REGPC; - } -| LR '(' expr ')' - { - if $3 < 0 || $3 >= NREG { - print("register value out of range\n") - } - $$ = REG_R0 + $3; - } - -spreg: - sreg -| LSP - { - $$ = REGSP; - } - -creg: - LCREG -| LC '(' expr ')' - { - if $3 < 0 || $3 >= NREG { - print("register value out of range\n") - } - $$ = $3; // TODO(rsc): REG_C0+$3 - } - -frcon: - freg -| fcon - -freg: - LFREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } -| LF '(' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16(REG_F0 + $3); - } - -name: - con '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = int8($3); - $$.Sym = nil; - $$.Offset = int64($1); - } -| LNAME offset '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = int8($4); - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); - $$.Offset = int64($2); - } -| LNAME '<' '>' offset '(' LSB ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = obj.NAME_STATIC; - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); - $$.Offset = int64($4); - } - -offset: - { - $$ = 0; - } -| '+' con - { - $$ = $2; - } -| '-' con - { - $$ = -$2; - } - -pointer: - LSB -| LSP -| LFP - -con: - LCONST -| LVAR - { - $$ = int32($1.Value); - } -| '-' con - { - $$ = -$2; - } -| '+' con - { - $$ = $2; - } -| '~' con - { - $$ = ^$2; - } -| '(' expr ')' - { - $$ = $2; - } - -oexpr: - { - $$ = 0; - } -| ',' expr - { - $$ = $2; - } - -expr: - con -| expr '+' expr - { - $$ = $1 + $3; - } -| expr '-' expr - { - $$ = $1 - $3; - } -| expr '*' expr - { - $$ = $1 * $3; - } -| expr '/' expr - { - $$ = $1 / $3; - } -| expr '%' expr - { - $$ = $1 % $3; - } -| expr '<' '<' expr - { - $$ = $1 << uint($4); - } -| expr '>' '>' expr - { - $$ = $1 >> uint($4); - } -| expr '&' expr - { - $$ = $1 & $3; - } -| expr '^' expr - { - $$ = $1 ^ $3; - } -| expr '|' expr - { - $$ = $1 | $3; - } diff --git a/src/cmd/new5a/lex.go b/src/cmd/new5a/lex.go deleted file mode 100644 index 1afd827793..0000000000 --- a/src/cmd/new5a/lex.go +++ /dev/null @@ -1,371 +0,0 @@ -// Inferno utils/5a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -//go:generate go tool yacc a.y - -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/arm" -) - -var ( - yyerror = asm.Yyerror - nullgen obj.Addr - stmtline int32 -) - -const Always = arm.C_SCOND_NONE - -func main() { - cinit() - - asm.LSCONST = LSCONST - asm.LCONST = LCONST - asm.LFCONST = LFCONST - asm.LNAME = LNAME - asm.LVAR = LVAR - asm.LLAB = LLAB - - asm.Lexinit = lexinit - asm.Cclean = cclean - asm.Yyparse = yyparse - - asm.Thechar = '5' - asm.Thestring = "arm" - asm.Thelinkarch = &arm.Linkarm - - asm.Main() -} - -type yy struct{} - -func (yy) Lex(v *yySymType) int { - var av asm.Yylval - tok := asm.Yylex(&av) - v.sym = av.Sym - v.lval = int32(av.Lval) - v.sval = av.Sval - v.dval = av.Dval - return tok -} - -func (yy) Error(msg string) { - asm.Yyerror("%s", msg) -} - -func yyparse() { - yyParse(yy{}) -} - -var lexinit = []asm.Lextab{ - {"SP", LSP, obj.NAME_AUTO}, - {"SB", LSB, obj.NAME_EXTERN}, - {"FP", LFP, obj.NAME_PARAM}, - {"PC", LPC, obj.TYPE_BRANCH}, - - {"R", LR, 0}, - - {"R0", LREG, arm.REG_R0}, - {"R1", LREG, arm.REG_R1}, - {"R2", LREG, arm.REG_R2}, - {"R3", LREG, arm.REG_R3}, - {"R4", LREG, arm.REG_R4}, - {"R5", LREG, arm.REG_R5}, - {"R6", LREG, arm.REG_R6}, - {"R7", LREG, arm.REG_R7}, - {"R8", LREG, arm.REG_R8}, - {"R9", LREG, arm.REG_R9}, - {"g", LREG, arm.REG_R10}, // avoid unintentionally clobber g using R10 - {"R11", LREG, arm.REG_R11}, - {"R12", LREG, arm.REG_R12}, - {"R13", LREG, arm.REG_R13}, - {"R14", LREG, arm.REG_R14}, - {"R15", LREG, arm.REG_R15}, - {"F", LF, 0}, - {"F0", LFREG, arm.REG_F0}, - {"F1", LFREG, arm.REG_F1}, - {"F2", LFREG, arm.REG_F2}, - {"F3", LFREG, arm.REG_F3}, - {"F4", LFREG, arm.REG_F4}, - {"F5", LFREG, arm.REG_F5}, - {"F6", LFREG, arm.REG_F6}, - {"F7", LFREG, arm.REG_F7}, - {"F8", LFREG, arm.REG_F8}, - {"F9", LFREG, arm.REG_F9}, - {"F10", LFREG, arm.REG_F10}, - {"F11", LFREG, arm.REG_F11}, - {"F12", LFREG, arm.REG_F12}, - {"F13", LFREG, arm.REG_F13}, - {"F14", LFREG, arm.REG_F14}, - {"F15", LFREG, arm.REG_F15}, - {"C", LC, 0}, - {"C0", LCREG, 0}, - {"C1", LCREG, 1}, - {"C2", LCREG, 2}, - {"C3", LCREG, 3}, - {"C4", LCREG, 4}, - {"C5", LCREG, 5}, - {"C6", LCREG, 6}, - {"C7", LCREG, 7}, - {"C8", LCREG, 8}, - {"C9", LCREG, 9}, - {"C10", LCREG, 10}, - {"C11", LCREG, 11}, - {"C12", LCREG, 12}, - {"C13", LCREG, 13}, - {"C14", LCREG, 14}, - {"C15", LCREG, 15}, - {"CPSR", LPSR, arm.REG_CPSR}, - {"SPSR", LPSR, arm.REG_SPSR}, - {"FPSR", LFCR, arm.REG_FPSR}, - {"FPCR", LFCR, arm.REG_FPCR}, - {".EQ", LCOND, arm.C_SCOND_EQ}, - {".NE", LCOND, arm.C_SCOND_NE}, - {".CS", LCOND, arm.C_SCOND_HS}, - {".HS", LCOND, arm.C_SCOND_HS}, - {".CC", LCOND, arm.C_SCOND_LO}, - {".LO", LCOND, arm.C_SCOND_LO}, - {".MI", LCOND, arm.C_SCOND_MI}, - {".PL", LCOND, arm.C_SCOND_PL}, - {".VS", LCOND, arm.C_SCOND_VS}, - {".VC", LCOND, arm.C_SCOND_VC}, - {".HI", LCOND, arm.C_SCOND_HI}, - {".LS", LCOND, arm.C_SCOND_LS}, - {".GE", LCOND, arm.C_SCOND_GE}, - {".LT", LCOND, arm.C_SCOND_LT}, - {".GT", LCOND, arm.C_SCOND_GT}, - {".LE", LCOND, arm.C_SCOND_LE}, - {".AL", LCOND, arm.C_SCOND_NONE}, - {".U", LS, arm.C_UBIT}, - {".S", LS, arm.C_SBIT}, - {".W", LS, arm.C_WBIT}, - {".P", LS, arm.C_PBIT}, - {".PW", LS, arm.C_WBIT | arm.C_PBIT}, - {".WP", LS, arm.C_WBIT | arm.C_PBIT}, - {".F", LS, arm.C_FBIT}, - {".IBW", LS, arm.C_WBIT | arm.C_PBIT | arm.C_UBIT}, - {".IAW", LS, arm.C_WBIT | arm.C_UBIT}, - {".DBW", LS, arm.C_WBIT | arm.C_PBIT}, - {".DAW", LS, arm.C_WBIT}, - {".IB", LS, arm.C_PBIT | arm.C_UBIT}, - {".IA", LS, arm.C_UBIT}, - {".DB", LS, arm.C_PBIT}, - {".DA", LS, 0}, - {"@", LAT, 0}, - {"AND", LTYPE1, arm.AAND}, - {"EOR", LTYPE1, arm.AEOR}, - {"SUB", LTYPE1, arm.ASUB}, - {"RSB", LTYPE1, arm.ARSB}, - {"ADD", LTYPE1, arm.AADD}, - {"ADC", LTYPE1, arm.AADC}, - {"SBC", LTYPE1, arm.ASBC}, - {"RSC", LTYPE1, arm.ARSC}, - {"ORR", LTYPE1, arm.AORR}, - {"BIC", LTYPE1, arm.ABIC}, - {"SLL", LTYPE1, arm.ASLL}, - {"SRL", LTYPE1, arm.ASRL}, - {"SRA", LTYPE1, arm.ASRA}, - {"MUL", LTYPE1, arm.AMUL}, - {"MULA", LTYPEN, arm.AMULA}, - {"DIV", LTYPE1, arm.ADIV}, - {"MOD", LTYPE1, arm.AMOD}, - {"MULL", LTYPEM, arm.AMULL}, - {"MULAL", LTYPEM, arm.AMULAL}, - {"MULLU", LTYPEM, arm.AMULLU}, - {"MULALU", LTYPEM, arm.AMULALU}, - {"MVN", LTYPE2, arm.AMVN}, /* op2 ignored */ - {"MOVB", LTYPE3, arm.AMOVB}, - {"MOVBU", LTYPE3, arm.AMOVBU}, - {"MOVH", LTYPE3, arm.AMOVH}, - {"MOVHU", LTYPE3, arm.AMOVHU}, - {"MOVW", LTYPE3, arm.AMOVW}, - {"MOVD", LTYPE3, arm.AMOVD}, - {"MOVDF", LTYPE3, arm.AMOVDF}, - {"MOVDW", LTYPE3, arm.AMOVDW}, - {"MOVF", LTYPE3, arm.AMOVF}, - {"MOVFD", LTYPE3, arm.AMOVFD}, - {"MOVFW", LTYPE3, arm.AMOVFW}, - {"MOVWD", LTYPE3, arm.AMOVWD}, - {"MOVWF", LTYPE3, arm.AMOVWF}, - {"LDREX", LTYPE3, arm.ALDREX}, - {"LDREXD", LTYPE3, arm.ALDREXD}, - {"STREX", LTYPE9, arm.ASTREX}, - {"STREXD", LTYPE9, arm.ASTREXD}, - - /* - {"NEGF", LTYPEI, ANEGF}, - {"NEGD", LTYPEI, ANEGD}, - {"SQTF", LTYPEI, ASQTF}, - {"SQTD", LTYPEI, ASQTD}, - {"RNDF", LTYPEI, ARNDF}, - {"RNDD", LTYPEI, ARNDD}, - {"URDF", LTYPEI, AURDF}, - {"URDD", LTYPEI, AURDD}, - {"NRMF", LTYPEI, ANRMF}, - {"NRMD", LTYPEI, ANRMD}, - */ - {"ABSF", LTYPEI, arm.AABSF}, - {"ABSD", LTYPEI, arm.AABSD}, - {"SQRTF", LTYPEI, arm.ASQRTF}, - {"SQRTD", LTYPEI, arm.ASQRTD}, - {"CMPF", LTYPEL, arm.ACMPF}, - {"CMPD", LTYPEL, arm.ACMPD}, - {"ADDF", LTYPEK, arm.AADDF}, - {"ADDD", LTYPEK, arm.AADDD}, - {"SUBF", LTYPEK, arm.ASUBF}, - {"SUBD", LTYPEK, arm.ASUBD}, - {"MULF", LTYPEK, arm.AMULF}, - {"MULD", LTYPEK, arm.AMULD}, - {"DIVF", LTYPEK, arm.ADIVF}, - {"DIVD", LTYPEK, arm.ADIVD}, - {"B", LTYPE4, arm.AB}, - {"BL", LTYPE4, arm.ABL}, - {"BX", LTYPEBX, arm.ABX}, - {"BEQ", LTYPE5, arm.ABEQ}, - {"BNE", LTYPE5, arm.ABNE}, - {"BCS", LTYPE5, arm.ABCS}, - {"BHS", LTYPE5, arm.ABHS}, - {"BCC", LTYPE5, arm.ABCC}, - {"BLO", LTYPE5, arm.ABLO}, - {"BMI", LTYPE5, arm.ABMI}, - {"BPL", LTYPE5, arm.ABPL}, - {"BVS", LTYPE5, arm.ABVS}, - {"BVC", LTYPE5, arm.ABVC}, - {"BHI", LTYPE5, arm.ABHI}, - {"BLS", LTYPE5, arm.ABLS}, - {"BGE", LTYPE5, arm.ABGE}, - {"BLT", LTYPE5, arm.ABLT}, - {"BGT", LTYPE5, arm.ABGT}, - {"BLE", LTYPE5, arm.ABLE}, - {"BCASE", LTYPE5, arm.ABCASE}, - {"SWI", LTYPE6, arm.ASWI}, - {"CMP", LTYPE7, arm.ACMP}, - {"TST", LTYPE7, arm.ATST}, - {"TEQ", LTYPE7, arm.ATEQ}, - {"CMN", LTYPE7, arm.ACMN}, - {"MOVM", LTYPE8, arm.AMOVM}, - {"SWPBU", LTYPE9, arm.ASWPBU}, - {"SWPW", LTYPE9, arm.ASWPW}, - {"RET", LTYPEA, obj.ARET}, - {"RFE", LTYPEA, arm.ARFE}, - {"TEXT", LTYPEB, obj.ATEXT}, - {"GLOBL", LGLOBL, obj.AGLOBL}, - {"DATA", LTYPEC, obj.ADATA}, - {"CASE", LTYPED, arm.ACASE}, - {"END", LTYPEE, obj.AEND}, - {"WORD", LTYPEH, arm.AWORD}, - {"NOP", LTYPEI, obj.ANOP}, - {"MCR", LTYPEJ, 0}, - {"MRC", LTYPEJ, 1}, - {"PLD", LTYPEPLD, arm.APLD}, - {"UNDEF", LTYPEE, obj.AUNDEF}, - {"CLZ", LTYPE2, arm.ACLZ}, - {"MULWT", LTYPE1, arm.AMULWT}, - {"MULWB", LTYPE1, arm.AMULWB}, - {"MULAWT", LTYPEN, arm.AMULAWT}, - {"MULAWB", LTYPEN, arm.AMULAWB}, - {"USEFIELD", LTYPEN, obj.AUSEFIELD}, - {"PCDATA", LTYPEPC, obj.APCDATA}, - {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, -} - -func cinit() { -} - -func isreg(g *obj.Addr) bool { - return true -} - -func cclean() { - outcode(obj.AEND, Always, &nullgen, 0, &nullgen) -} - -var bcode = []int{ - arm.ABEQ, - arm.ABNE, - arm.ABCS, - arm.ABCC, - arm.ABMI, - arm.ABPL, - arm.ABVS, - arm.ABVC, - arm.ABHI, - arm.ABLS, - arm.ABGE, - arm.ABLT, - arm.ABGT, - arm.ABLE, - arm.AB, - obj.ANOP, -} - -var lastpc *obj.Prog - -func outcode(a, scond int32, g1 *obj.Addr, reg int32, g2 *obj.Addr) { - var p *obj.Prog - var pl *obj.Plist - - /* hack to make B.NE etc. work: turn it into the corresponding conditional */ - if a == arm.AB { - a = int32(bcode[(scond^arm.C_SCOND_XOR)&0xf]) - scond = (scond &^ 0xf) | Always - } - - if asm.Pass == 1 { - goto out - } - - p = new(obj.Prog) - *p = obj.Prog{} - p.Ctxt = asm.Ctxt - p.As = int16(a) - p.Lineno = stmtline - p.Scond = uint8(scond) - p.From = *g1 - p.Reg = int16(reg) - p.To = *g2 - p.Pc = int64(asm.PC) - - if lastpc == nil { - pl = obj.Linknewplist(asm.Ctxt) - pl.Firstpc = p - } else { - lastpc.Link = p - } - lastpc = p - -out: - if a != obj.AGLOBL && a != obj.ADATA { - asm.PC++ - } -} diff --git a/src/cmd/new5a/y.go b/src/cmd/new5a/y.go deleted file mode 100644 index 17ee80ee51..0000000000 --- a/src/cmd/new5a/y.go +++ /dev/null @@ -1,1362 +0,0 @@ -//line a.y:32 -package main - -import __yyfmt__ "fmt" - -//line a.y:32 -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/arm" -) - -//line a.y:41 -type yySymType struct { - yys int - sym *asm.Sym - lval int32 - dval float64 - sval string - addr obj.Addr -} - -const LTYPE1 = 57346 -const LTYPE2 = 57347 -const LTYPE3 = 57348 -const LTYPE4 = 57349 -const LTYPE5 = 57350 -const LTYPE6 = 57351 -const LTYPE7 = 57352 -const LTYPE8 = 57353 -const LTYPE9 = 57354 -const LTYPEA = 57355 -const LTYPEB = 57356 -const LTYPEC = 57357 -const LTYPED = 57358 -const LTYPEE = 57359 -const LTYPEG = 57360 -const LTYPEH = 57361 -const LTYPEI = 57362 -const LTYPEJ = 57363 -const LTYPEK = 57364 -const LTYPEL = 57365 -const LTYPEM = 57366 -const LTYPEN = 57367 -const LTYPEBX = 57368 -const LTYPEPLD = 57369 -const LCONST = 57370 -const LSP = 57371 -const LSB = 57372 -const LFP = 57373 -const LPC = 57374 -const LTYPEX = 57375 -const LTYPEPC = 57376 -const LTYPEF = 57377 -const LR = 57378 -const LREG = 57379 -const LF = 57380 -const LFREG = 57381 -const LC = 57382 -const LCREG = 57383 -const LPSR = 57384 -const LFCR = 57385 -const LCOND = 57386 -const LS = 57387 -const LAT = 57388 -const LGLOBL = 57389 -const LFCONST = 57390 -const LSCONST = 57391 -const LNAME = 57392 -const LLAB = 57393 -const LVAR = 57394 - -var yyToknames = []string{ - "'|'", - "'^'", - "'&'", - "'<'", - "'>'", - "'+'", - "'-'", - "'*'", - "'/'", - "'%'", - "LTYPE1", - "LTYPE2", - "LTYPE3", - "LTYPE4", - "LTYPE5", - "LTYPE6", - "LTYPE7", - "LTYPE8", - "LTYPE9", - "LTYPEA", - "LTYPEB", - "LTYPEC", - "LTYPED", - "LTYPEE", - "LTYPEG", - "LTYPEH", - "LTYPEI", - "LTYPEJ", - "LTYPEK", - "LTYPEL", - "LTYPEM", - "LTYPEN", - "LTYPEBX", - "LTYPEPLD", - "LCONST", - "LSP", - "LSB", - "LFP", - "LPC", - "LTYPEX", - "LTYPEPC", - "LTYPEF", - "LR", - "LREG", - "LF", - "LFREG", - "LC", - "LCREG", - "LPSR", - "LFCR", - "LCOND", - "LS", - "LAT", - "LGLOBL", - "LFCONST", - "LSCONST", - "LNAME", - "LLAB", - "LVAR", -} -var yyStatenames = []string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyMaxDepth = 200 - -//line yacctab:1 -var yyExca = []int{ - -1, 1, - 1, -1, - -2, 2, - -1, 196, - 68, 63, - -2, 53, -} - -const yyNprod = 134 -const yyPrivate = 57344 - -var yyTokenNames []string -var yyStates []string - -const yyLast = 708 - -var yyAct = []int{ - - 125, 328, 259, 73, 202, 79, 85, 106, 91, 195, - 3, 129, 84, 115, 75, 72, 338, 324, 278, 136, - 78, 77, 178, 177, 176, 174, 175, 169, 170, 171, - 172, 173, 301, 86, 86, 289, 52, 61, 62, 90, - 89, 86, 86, 86, 71, 103, 104, 284, 277, 86, - 58, 57, 276, 120, 275, 96, 99, 101, 263, 112, - 145, 105, 105, 224, 110, 334, 321, 302, 206, 105, - 140, 123, 141, 143, 146, 113, 249, 152, 151, 55, - 114, 58, 57, 197, 139, 92, 190, 165, 94, 341, - 148, 149, 95, 93, 44, 46, 164, 154, 150, 231, - 160, 128, 87, 56, 108, 64, 300, 311, 254, 167, - 55, 60, 45, 59, 152, 97, 253, 58, 57, 86, - 88, 255, 196, 340, 111, 184, 188, 189, 118, 191, - 333, 124, 126, 331, 56, 327, 325, 309, 39, 199, - 192, 108, 60, 308, 59, 211, 55, 58, 57, 92, - 45, 305, 94, 295, 86, 226, 95, 93, 292, 222, - 223, 288, 103, 104, 103, 104, 267, 86, 266, 262, - 56, 103, 104, 258, 38, 225, 55, 45, 60, 108, - 59, 245, 221, 45, 86, 233, 220, 144, 234, 235, - 236, 237, 238, 239, 252, 219, 242, 243, 244, 250, - 56, 246, 218, 247, 37, 248, 223, 200, 60, 216, - 59, 264, 100, 257, 215, 198, 194, 193, 183, 265, - 214, 182, 268, 269, 180, 271, 166, 153, 279, 279, - 279, 279, 137, 53, 53, 53, 127, 35, 36, 272, - 231, 273, 274, 317, 74, 83, 83, 281, 282, 283, - 217, 330, 329, 251, 196, 83, 293, 196, 323, 116, - 286, 287, 122, 291, 58, 57, 294, 90, 89, 314, - 133, 134, 135, 304, 303, 90, 270, 256, 261, 297, - 299, 147, 178, 177, 176, 174, 175, 169, 170, 171, - 172, 173, 138, 55, 92, 315, 312, 94, 162, 298, - 159, 95, 93, 316, 155, 156, 260, 157, 319, 310, - 58, 57, 318, 90, 89, 240, 313, 56, 241, 103, - 104, 181, 326, 80, 186, 60, 230, 59, 332, 229, - 322, 83, 335, 290, 92, 336, 228, 94, 296, 55, - 201, 95, 93, 207, 208, 209, 204, 203, 205, 285, - 212, 213, 306, 158, 337, 103, 104, 94, 131, 132, - 342, 95, 93, 56, 107, 107, 83, 227, 121, 102, - 8, 76, 107, 59, 7, 98, 133, 232, 130, 83, - 131, 132, 9, 10, 11, 12, 14, 15, 16, 17, - 18, 19, 20, 22, 23, 34, 83, 24, 25, 28, - 26, 27, 29, 30, 13, 31, 171, 172, 173, 58, - 57, 109, 32, 33, 2, 58, 57, 1, 119, 92, - 185, 142, 94, 320, 339, 21, 95, 93, 4, 0, - 5, 0, 0, 6, 103, 104, 0, 0, 55, 0, - 280, 280, 280, 280, 55, 92, 45, 0, 94, 0, - 58, 57, 95, 93, 90, 89, 0, 0, 81, 82, - 103, 104, 56, 0, 0, 0, 54, 0, 56, 0, - 60, 0, 59, 0, 0, 87, 76, 0, 59, 55, - 92, 0, 0, 94, 0, 0, 0, 95, 93, 90, - 89, 0, 0, 81, 82, 58, 163, 0, 58, 57, - 0, 54, 0, 56, 0, 122, 204, 203, 205, 251, - 87, 76, 0, 59, 178, 177, 176, 174, 175, 169, - 170, 171, 172, 173, 55, 58, 57, 55, 0, 0, - 0, 58, 57, 0, 58, 57, 0, 58, 57, 169, - 170, 171, 172, 173, 162, 161, 54, 0, 56, 187, - 0, 56, 0, 0, 55, 0, 76, 0, 59, 76, - 55, 59, 0, 55, 0, 0, 55, 0, 0, 0, - 0, 0, 204, 203, 205, 94, 117, 0, 56, 95, - 93, 210, 54, 0, 56, 54, 60, 56, 59, 0, - 56, 0, 76, 0, 59, 60, 0, 59, 76, 0, - 59, 178, 177, 176, 174, 175, 169, 170, 171, 172, - 173, 178, 177, 176, 174, 175, 169, 170, 171, 172, - 173, 178, 177, 176, 174, 175, 169, 170, 171, 172, - 173, 92, 0, 0, 94, 0, 0, 0, 95, 93, - 40, 0, 0, 0, 0, 0, 103, 104, 0, 0, - 0, 41, 42, 43, 0, 0, 47, 48, 49, 50, - 51, 0, 0, 307, 63, 0, 65, 66, 67, 68, - 69, 70, 179, 177, 176, 174, 175, 169, 170, 171, - 172, 173, 168, 178, 177, 176, 174, 175, 169, 170, - 171, 172, 173, 176, 174, 175, 169, 170, 171, 172, - 173, 174, 175, 169, 170, 171, 172, 173, -} -var yyPact = []int{ - - -1000, -1000, 368, -1000, 174, 140, -1000, 109, 73, -1000, - -1000, -1000, -1000, 84, 84, -1000, -1000, -1000, -1000, -1000, - 525, 525, 525, -1000, 84, -1000, -1000, -1000, -1000, -1000, - -1000, 522, 441, 441, 84, -1000, 400, 400, -1000, -1000, - 110, 110, 406, 117, 5, 84, 516, 117, 110, 301, - 380, 117, 170, 31, 371, -1000, -1000, 400, 400, 400, - 400, 166, 280, 592, 33, 265, -9, 265, 108, 592, - 592, -1000, 28, -1000, 8, -1000, 255, 161, -1000, -1000, - 27, -1000, -1000, 8, -1000, -1000, 297, 486, -1000, -1000, - 26, -1000, -1000, -1000, -1000, 17, 160, -1000, 368, 617, - -1000, 607, 158, -1000, -1000, -1000, -1000, -1000, 400, 155, - 152, 489, -1000, 295, -1000, -1000, 16, 349, 441, 151, - 150, 295, 13, 149, 5, -1000, -1000, 138, 307, -2, - 335, 400, 400, -1000, -1000, -1000, 510, 72, 400, 84, - -1000, 148, 143, -1000, -1000, 240, 136, 129, 120, 116, - 315, 533, -8, 441, 295, 360, 328, 321, 318, 8, - -1000, -1000, -1000, 41, 400, 400, 441, -1000, -1000, 400, - 400, 400, 400, 400, 308, 310, 400, 400, 400, -1000, - 295, -1000, 295, 441, -1000, -1000, 6, 371, -1000, -1000, - 211, -1000, -1000, 295, 49, 40, 111, 315, 5, 107, - 268, 103, -13, -1000, -1000, -1000, 307, 349, -1000, -1000, - -1000, -1000, 102, 100, -1000, 219, 227, 182, 219, 400, - 295, 295, -17, -19, -1000, -1000, -23, 255, 255, 255, - 255, -1000, -24, 278, -1000, 395, 395, -1000, -1000, -1000, - 400, 400, 694, 687, 668, 95, -1000, -1000, -1000, 467, - -2, -36, 84, 295, 92, 295, 295, 87, 295, -1000, - 289, 242, 37, -1000, -39, -3, 35, 33, -1000, -1000, - 85, 84, 597, 77, 71, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 530, 530, 295, -1000, - -1000, 39, 528, -1000, -1000, 46, -1000, -1000, 231, 285, - 268, -1000, 203, -1000, -1000, 219, -1000, 295, -4, 295, - -1000, -1000, -1000, -1000, -1000, 220, -1000, -54, -1000, 70, - -1000, 295, 69, -1000, -1000, 201, 67, 295, 64, -1000, - -5, 295, -1000, 201, 400, -55, 57, 18, -1000, -1000, - 400, -1000, 679, -} -var yyPgo = []int{ - - 0, 212, 19, 424, 4, 11, 8, 0, 1, 18, - 640, 9, 21, 13, 20, 423, 6, 323, 120, 421, - 2, 7, 5, 15, 12, 14, 420, 3, 369, 417, - 414, 10, 375, 374, 80, -} -var yyR1 = []int{ - - 0, 29, 30, 29, 32, 31, 31, 31, 31, 31, - 31, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 33, 33, 20, 20, 20, 20, - 10, 10, 10, 34, 34, 13, 13, 22, 22, 22, - 22, 18, 18, 11, 11, 11, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 26, 26, 25, 27, 27, - 24, 24, 24, 28, 28, 28, 21, 14, 15, 17, - 17, 17, 17, 9, 9, 6, 6, 6, 7, 7, - 8, 8, 19, 19, 16, 16, 23, 23, 23, 5, - 5, 5, 4, 4, 4, 1, 1, 1, 1, 1, - 1, 3, 3, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, -} -var yyR2 = []int{ - - 0, 0, 0, 3, 0, 4, 4, 4, 1, 2, - 2, 7, 6, 5, 5, 5, 4, 4, 3, 3, - 4, 6, 7, 7, 7, 6, 6, 3, 5, 7, - 4, 6, 6, 4, 3, 5, 5, 7, 6, 12, - 7, 9, 2, 4, 4, 2, 1, 2, 3, 4, - 0, 2, 2, 0, 2, 4, 2, 2, 2, 2, - 1, 2, 3, 1, 3, 3, 1, 1, 1, 4, - 1, 1, 1, 1, 1, 1, 1, 3, 1, 4, - 1, 4, 1, 1, 1, 1, 2, 1, 5, 4, - 4, 4, 4, 1, 1, 1, 1, 4, 1, 1, - 1, 4, 1, 1, 1, 4, 4, 5, 7, 0, - 2, 2, 1, 1, 1, 1, 1, 2, 2, 2, - 3, 0, 2, 1, 3, 3, 3, 3, 3, 4, - 4, 3, 3, 3, -} -var yyChk = []int{ - - -1000, -29, -30, -31, 60, 62, 65, -33, 2, 14, - 15, 16, 17, 36, 18, 19, 20, 21, 22, 23, - 24, 57, 25, 26, 29, 30, 32, 33, 31, 34, - 35, 37, 44, 45, 27, 63, 64, 64, 65, 65, - -10, -10, -10, -10, -34, 66, -34, -10, -10, -10, - -10, -10, -23, -1, 60, 38, 62, 10, 9, 72, - 70, -23, -23, -10, -34, -10, -10, -10, -10, -10, - -10, -24, -23, -27, -1, -25, 70, -12, -14, -22, - -17, 52, 53, -1, -24, -16, -7, 69, -18, 49, - 48, -6, 39, 47, 42, 46, -12, -34, -32, -2, - -1, -2, -28, 54, 55, -14, -21, -17, 69, -28, - -12, -34, -25, 70, -34, -13, -1, 60, -34, -28, - -27, 67, -1, -14, -34, -7, -34, 66, 70, -5, - 7, 9, 10, -1, -1, -1, -2, 66, 12, -14, - -22, -16, -19, -16, -18, 69, -16, -1, -14, -14, - 70, 70, -7, 66, 70, 7, 8, 10, 56, -1, - -24, 59, 58, 10, 70, 70, 66, -31, 65, 9, - 10, 11, 12, 13, 7, 8, 6, 5, 4, 65, - 66, -1, 66, 66, -13, -26, -1, 60, -25, -23, - 70, -5, -12, 66, 66, -11, -7, 70, 66, -25, - 69, -1, -4, 40, 39, 41, 70, 8, -1, -1, - 71, -21, -1, -1, -34, 66, 66, 10, 66, 66, - 66, 66, -6, -6, 71, -12, -7, 7, 8, 8, - 8, 58, -1, -2, -12, -2, -2, -2, -2, -2, - 7, 8, -2, -2, -2, -7, -14, -14, -12, 70, - -5, 42, -7, 67, 68, 10, -34, -25, 66, -20, - 38, 10, 66, 71, -4, -5, 66, 66, -16, -16, - 49, -16, -2, -14, -14, 71, 71, 71, -9, -7, - -1, -9, -9, -9, 71, 71, -2, -2, 66, 71, - -34, -11, 66, -7, -11, 66, -34, -14, 10, 38, - 69, 71, 70, -21, -22, 66, -34, 66, 66, 66, - -14, 68, -27, -14, 38, 10, -20, 40, -16, -7, - -15, 70, -14, 38, 71, 66, -7, 66, -8, 51, - 50, 66, -7, 66, 70, -7, -8, -2, 71, -3, - 66, 71, -2, -} -var yyDef = []int{ - - 1, -2, 0, 3, 0, 0, 8, 0, 0, 50, - 50, 50, 50, 53, 53, 50, 50, 50, 50, 50, - 0, 0, 0, 50, 53, 50, 50, 50, 50, 50, - 50, 0, 0, 0, 53, 4, 0, 0, 9, 10, - 0, 0, 0, 53, 0, 53, 0, 53, 0, 0, - 53, 53, 0, 0, 109, 115, 116, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 42, 80, 82, 0, 78, 0, 0, 66, 67, - 68, 70, 71, 72, 73, 74, 87, 0, 60, 104, - 0, 98, 99, 95, 96, 0, 0, 45, 0, 0, - 123, 0, 0, 51, 52, 83, 84, 85, 0, 0, - 0, 0, 18, 0, 54, 19, 0, 109, 0, 0, - 0, 0, 0, 0, 0, 87, 27, 0, 0, 0, - 0, 0, 0, 117, 118, 119, 0, 0, 0, 53, - 34, 0, 0, 102, 103, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, - 58, 59, 61, 0, 0, 0, 0, 5, 6, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, - 0, 86, 0, 0, 16, 17, 0, 109, 75, 76, - 0, 56, 20, 0, 0, 0, -2, 0, 0, 0, - 0, 0, 0, 112, 113, 114, 0, 109, 110, 111, - 120, 30, 0, 0, 33, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 43, 0, 0, 0, 0, - 0, 62, 0, 0, 44, 124, 125, 126, 127, 128, - 0, 0, 131, 132, 133, 87, 13, 14, 15, 0, - 56, 0, 53, 0, 0, 0, 0, 53, 0, 28, - 46, 0, 0, 106, 0, 0, 0, 0, 35, 36, - 104, 53, 0, 0, 0, 81, 79, 69, 89, 93, - 94, 90, 91, 92, 105, 97, 129, 130, 12, 55, - 21, 0, 0, 64, 65, 53, 25, 26, 0, 47, - 0, 107, 0, 31, 32, 0, 38, 0, 0, 0, - 11, 22, 23, 24, 48, 0, 29, 0, 37, 0, - 40, 0, 0, 49, 108, 0, 0, 0, 0, 100, - 0, 0, 41, 0, 0, 0, 121, 0, 88, 39, - 0, 101, 122, -} -var yyTok1 = []int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 69, 13, 6, 3, - 70, 71, 11, 9, 66, 10, 3, 12, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 63, 65, - 7, 64, 8, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 67, 3, 68, 5, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 3, 72, -} -var yyTok2 = []int{ - - 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, -} -var yyTok3 = []int{ - 0, -} - -//line yaccpar:1 - -/* parser for yacc output */ - -var yyDebug = 0 - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - // 4 is TOKSTART above - if c >= 4 && c-4 < len(yyToknames) { - if yyToknames[c-4] != "" { - return yyToknames[c-4] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yylex1(lex yyLexer, lval *yySymType) int { - c := 0 - char := lex.Lex(lval) - if char <= 0 { - c = yyTok1[0] - goto out - } - if char < len(yyTok1) { - c = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - c = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - c = yyTok3[i+0] - if c == char { - c = yyTok3[i+1] - goto out - } - } - -out: - if c == 0 { - c = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) - } - return c -} - -func yyParse(yylex yyLexer) int { - var yyn int - var yylval yySymType - var yyVAL yySymType - yyS := make([]yySymType, yyMaxDepth) - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yychar := -1 - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - yyn += yychar - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yychar { /* valid shift */ - yychar = -1 - yyVAL = yylval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yychar { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error("syntax error") - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) - } - if yychar == yyEofCode { - goto ret1 - } - yychar = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 2: - //line a.y:73 - { - stmtline = asm.Lineno - } - case 4: - //line a.y:80 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { - yyerror("redeclaration of %s", yyS[yypt-1].sym.Labelname) - } - yyS[yypt-1].sym.Type = LLAB - yyS[yypt-1].sym.Value = int64(asm.PC) - } - case 6: - //line a.y:90 - { - yyS[yypt-3].sym.Type = LVAR - yyS[yypt-3].sym.Value = int64(yyS[yypt-1].lval) - } - case 7: - //line a.y:95 - { - if yyS[yypt-3].sym.Value != int64(yyS[yypt-1].lval) { - yyerror("redeclaration of %s", yyS[yypt-3].sym.Name) - } - yyS[yypt-3].sym.Value = int64(yyS[yypt-1].lval) - } - case 11: - //line a.y:110 - { - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, yyS[yypt-2].lval, &yyS[yypt-0].addr) - } - case 12: - //line a.y:114 - { - outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, yyS[yypt-1].lval, &nullgen) - } - case 13: - //line a.y:118 - { - outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 14: - //line a.y:125 - { - outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 15: - //line a.y:132 - { - outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 16: - //line a.y:139 - { - outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) - } - case 17: - //line a.y:143 - { - outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) - } - case 18: - //line a.y:150 - { - outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) - } - case 19: - //line a.y:157 - { - outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) - } - case 20: - //line a.y:164 - { - outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &nullgen, 0, &yyS[yypt-0].addr) - } - case 21: - //line a.y:171 - { - outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, yyS[yypt-1].lval, &nullgen) - } - case 22: - //line a.y:178 - { - var g obj.Addr - - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = int64(yyS[yypt-1].lval) - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, 0, &g) - } - case 23: - //line a.y:187 - { - var g obj.Addr - - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = int64(yyS[yypt-3].lval) - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &g, 0, &yyS[yypt-0].addr) - } - case 24: - //line a.y:199 - { - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-2].addr, int32(yyS[yypt-4].addr.Reg), &yyS[yypt-0].addr) - } - case 25: - //line a.y:203 - { - outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-1].addr, int32(yyS[yypt-3].addr.Reg), &yyS[yypt-3].addr) - } - case 26: - //line a.y:207 - { - outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-2].addr, int32(yyS[yypt-0].addr.Reg), &yyS[yypt-0].addr) - } - case 27: - //line a.y:214 - { - outcode(yyS[yypt-2].lval, yyS[yypt-1].lval, &nullgen, 0, &nullgen) - } - case 28: - //line a.y:221 - { - asm.Settext(yyS[yypt-3].addr.Sym) - outcode(yyS[yypt-4].lval, Always, &yyS[yypt-3].addr, 0, &yyS[yypt-0].addr) - } - case 29: - //line a.y:226 - { - asm.Settext(yyS[yypt-5].addr.Sym) - outcode(yyS[yypt-6].lval, Always, &yyS[yypt-5].addr, 0, &yyS[yypt-0].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = int64(yyS[yypt-3].lval) - } - } - case 30: - //line a.y:238 - { - asm.Settext(yyS[yypt-2].addr.Sym) - outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 31: - //line a.y:243 - { - asm.Settext(yyS[yypt-4].addr.Sym) - outcode(yyS[yypt-5].lval, Always, &yyS[yypt-4].addr, 0, &yyS[yypt-0].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = int64(yyS[yypt-2].lval) - } - } - case 32: - //line a.y:256 - { - outcode(yyS[yypt-5].lval, Always, &yyS[yypt-4].addr, 0, &yyS[yypt-0].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = int64(yyS[yypt-2].lval) - } - } - case 33: - //line a.y:267 - { - outcode(yyS[yypt-3].lval, yyS[yypt-2].lval, &yyS[yypt-1].addr, 0, &nullgen) - } - case 34: - //line a.y:274 - { - outcode(yyS[yypt-2].lval, Always, &nullgen, 0, &yyS[yypt-0].addr) - } - case 35: - //line a.y:281 - { - outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 36: - //line a.y:285 - { - outcode(yyS[yypt-4].lval, yyS[yypt-3].lval, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 37: - //line a.y:289 - { - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, yyS[yypt-2].lval, &yyS[yypt-0].addr) - } - case 38: - //line a.y:293 - { - outcode(yyS[yypt-5].lval, yyS[yypt-4].lval, &yyS[yypt-3].addr, int32(yyS[yypt-1].addr.Reg), &nullgen) - } - case 39: - //line a.y:300 - { - var g obj.Addr - - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = int64( - (0xe << 24) | /* opcode */ - (yyS[yypt-11].lval << 20) | /* MCR/MRC */ - ((yyS[yypt-10].lval ^ C_SCOND_XOR) << 28) | /* scond */ - ((yyS[yypt-9].lval & 15) << 8) | /* coprocessor number */ - ((yyS[yypt-7].lval & 7) << 21) | /* coprocessor operation */ - ((yyS[yypt-5].lval & 15) << 12) | /* arm register */ - ((yyS[yypt-3].lval & 15) << 16) | /* Crn */ - ((yyS[yypt-1].lval & 15) << 0) | /* Crm */ - ((yyS[yypt-0].lval & 7) << 5) | /* coprocessor information */ - (1 << 4)) /* must be set */ - outcode(AMRC, Always, &nullgen, 0, &g) - } - case 40: - //line a.y:312 - { - outcode(yyS[yypt-6].lval, yyS[yypt-5].lval, &yyS[yypt-4].addr, int32(yyS[yypt-2].addr.Reg), &yyS[yypt-0].addr) - } - case 41: - //line a.y:320 - { - yyS[yypt-2].addr.Type = obj.TYPE_REGREG2 - yyS[yypt-2].addr.Offset = int64(yyS[yypt-0].lval) - outcode(yyS[yypt-8].lval, yyS[yypt-7].lval, &yyS[yypt-6].addr, int32(yyS[yypt-4].addr.Reg), &yyS[yypt-2].addr) - } - case 42: - //line a.y:329 - { - outcode(yyS[yypt-1].lval, Always, &yyS[yypt-0].addr, 0, &nullgen) - } - case 43: - //line a.y:336 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants") - } - outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 44: - //line a.y:346 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if yyS[yypt-0].addr.Type != obj.NAME_EXTERN && yyS[yypt-0].addr.Type != obj.NAME_STATIC && yyS[yypt-0].addr.Type != obj.TYPE_MEM { - yyerror("value for FUNCDATA must be symbol reference") - } - outcode(yyS[yypt-3].lval, Always, &yyS[yypt-2].addr, 0, &yyS[yypt-0].addr) - } - case 45: - //line a.y:359 - { - outcode(yyS[yypt-1].lval, Always, &nullgen, 0, &nullgen) - } - case 46: - //line a.y:365 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = int64(yyS[yypt-0].lval) - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 47: - //line a.y:372 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -int64(yyS[yypt-0].lval) - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 48: - //line a.y:379 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = int64(yyS[yypt-2].lval) - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 49: - //line a.y:386 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -int64(yyS[yypt-2].lval) - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 50: - //line a.y:394 - { - yyVAL.lval = Always - } - case 51: - //line a.y:398 - { - yyVAL.lval = (yyS[yypt-1].lval & ^C_SCOND) | yyS[yypt-0].lval - } - case 52: - //line a.y:402 - { - yyVAL.lval = yyS[yypt-1].lval | yyS[yypt-0].lval - } - case 55: - //line a.y:411 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = int64(yyS[yypt-3].lval) + int64(asm.PC) - } - case 56: - //line a.y:417 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - yyVAL.addr = nullgen - if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { - yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) - } - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyS[yypt-1].sym.Value + int64(yyS[yypt-0].lval) - } - case 57: - //line a.y:428 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - yyVAL.addr.Offset = int64(yyS[yypt-0].lval) - } - case 58: - //line a.y:434 - { - yyVAL.addr = yyS[yypt-0].addr - yyVAL.addr.Type = obj.TYPE_ADDR - } - case 59: - //line a.y:439 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SCONST - yyVAL.addr.U.Sval = yyS[yypt-0].sval - } - case 60: - yyVAL.addr = yyS[yypt-0].addr - case 61: - //line a.y:448 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyS[yypt-0].dval - } - case 62: - //line a.y:454 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyS[yypt-0].dval - } - case 63: - //line a.y:462 - { - yyVAL.lval = 1 << uint(yyS[yypt-0].lval&15) - } - case 64: - //line a.y:466 - { - yyVAL.lval = 0 - for i := yyS[yypt-2].lval; i <= yyS[yypt-0].lval; i++ { - yyVAL.lval |= 1 << uint(i&15) - } - for i := yyS[yypt-0].lval; i <= yyS[yypt-2].lval; i++ { - yyVAL.lval |= 1 << uint(i&15) - } - } - case 65: - //line a.y:476 - { - yyVAL.lval = (1 << uint(yyS[yypt-2].lval&15)) | yyS[yypt-0].lval - } - case 66: - yyVAL.addr = yyS[yypt-0].addr - case 67: - yyVAL.addr = yyS[yypt-0].addr - case 68: - yyVAL.addr = yyS[yypt-0].addr - case 69: - //line a.y:485 - { - yyVAL.addr = yyS[yypt-3].addr - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - } - case 70: - //line a.y:490 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 71: - //line a.y:496 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 72: - //line a.y:502 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Offset = int64(yyS[yypt-0].lval) - } - case 73: - yyVAL.addr = yyS[yypt-0].addr - case 74: - yyVAL.addr = yyS[yypt-0].addr - case 75: - yyVAL.addr = yyS[yypt-0].addr - case 76: - //line a.y:513 - { - yyVAL.addr = yyS[yypt-0].addr - if yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC { - } - } - case 77: - //line a.y:521 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = 0 - } - case 78: - yyVAL.addr = yyS[yypt-0].addr - case 79: - //line a.y:531 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = int64(yyS[yypt-3].lval) - } - case 80: - yyVAL.addr = yyS[yypt-0].addr - case 81: - //line a.y:541 - { - yyVAL.addr = yyS[yypt-3].addr - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - } - case 82: - yyVAL.addr = yyS[yypt-0].addr - case 83: - yyVAL.addr = yyS[yypt-0].addr - case 84: - yyVAL.addr = yyS[yypt-0].addr - case 85: - yyVAL.addr = yyS[yypt-0].addr - case 86: - //line a.y:554 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - yyVAL.addr.Offset = int64(yyS[yypt-0].lval) - } - case 87: - //line a.y:562 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 88: - //line a.y:570 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REGREG - yyVAL.addr.Reg = int16(yyS[yypt-3].lval) - yyVAL.addr.Offset = int64(yyS[yypt-1].lval) - } - case 89: - //line a.y:579 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SHIFT - yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (0 << 5) - } - case 90: - //line a.y:585 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SHIFT - yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (1 << 5) - } - case 91: - //line a.y:591 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SHIFT - yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (2 << 5) - } - case 92: - //line a.y:597 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SHIFT - yyVAL.addr.Offset = int64(yyS[yypt-3].lval&15) | int64(yyS[yypt-0].lval) | (3 << 5) - } - case 93: - //line a.y:605 - { - if yyVAL.lval < REG_R0 || yyVAL.lval > REG_R15 { - print("register value out of range\n") - } - yyVAL.lval = ((yyS[yypt-0].lval & 15) << 8) | (1 << 4) - } - case 94: - //line a.y:612 - { - if yyVAL.lval < 0 || yyVAL.lval >= 32 { - print("shift value out of range\n") - } - yyVAL.lval = (yyS[yypt-0].lval & 31) << 7 - } - case 95: - yyVAL.lval = yyS[yypt-0].lval - case 96: - //line a.y:622 - { - yyVAL.lval = REGPC - } - case 97: - //line a.y:626 - { - if yyS[yypt-1].lval < 0 || yyS[yypt-1].lval >= NREG { - print("register value out of range\n") - } - yyVAL.lval = REG_R0 + yyS[yypt-1].lval - } - case 98: - yyVAL.lval = yyS[yypt-0].lval - case 99: - //line a.y:636 - { - yyVAL.lval = REGSP - } - case 100: - yyVAL.lval = yyS[yypt-0].lval - case 101: - //line a.y:643 - { - if yyS[yypt-1].lval < 0 || yyS[yypt-1].lval >= NREG { - print("register value out of range\n") - } - yyVAL.lval = yyS[yypt-1].lval // TODO(rsc): REG_C0+$3 - } - case 102: - yyVAL.addr = yyS[yypt-0].addr - case 103: - yyVAL.addr = yyS[yypt-0].addr - case 104: - //line a.y:656 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 105: - //line a.y:662 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(REG_F0 + yyS[yypt-1].lval) - } - case 106: - //line a.y:670 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyS[yypt-1].lval) - yyVAL.addr.Sym = nil - yyVAL.addr.Offset = int64(yyS[yypt-3].lval) - } - case 107: - //line a.y:678 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyS[yypt-1].lval) - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) - yyVAL.addr.Offset = int64(yyS[yypt-3].lval) - } - case 108: - //line a.y:686 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = obj.NAME_STATIC - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) - yyVAL.addr.Offset = int64(yyS[yypt-3].lval) - } - case 109: - //line a.y:695 - { - yyVAL.lval = 0 - } - case 110: - //line a.y:699 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 111: - //line a.y:703 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 112: - yyVAL.lval = yyS[yypt-0].lval - case 113: - yyVAL.lval = yyS[yypt-0].lval - case 114: - yyVAL.lval = yyS[yypt-0].lval - case 115: - yyVAL.lval = yyS[yypt-0].lval - case 116: - //line a.y:715 - { - yyVAL.lval = int32(yyS[yypt-0].sym.Value) - } - case 117: - //line a.y:719 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 118: - //line a.y:723 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 119: - //line a.y:727 - { - yyVAL.lval = ^yyS[yypt-0].lval - } - case 120: - //line a.y:731 - { - yyVAL.lval = yyS[yypt-1].lval - } - case 121: - //line a.y:736 - { - yyVAL.lval = 0 - } - case 122: - //line a.y:740 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 123: - yyVAL.lval = yyS[yypt-0].lval - case 124: - //line a.y:747 - { - yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval - } - case 125: - //line a.y:751 - { - yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval - } - case 126: - //line a.y:755 - { - yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval - } - case 127: - //line a.y:759 - { - yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval - } - case 128: - //line a.y:763 - { - yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval - } - case 129: - //line a.y:767 - { - yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) - } - case 130: - //line a.y:771 - { - yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) - } - case 131: - //line a.y:775 - { - yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval - } - case 132: - //line a.y:779 - { - yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval - } - case 133: - //line a.y:783 - { - yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval - } - } - goto yystack /* stack new state and value */ -} diff --git a/src/cmd/new5g/cgen.go b/src/cmd/new5g/cgen.go deleted file mode 100644 index bdee52aca6..0000000000 --- a/src/cmd/new5g/cgen.go +++ /dev/null @@ -1,2003 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" - "fmt" -) -import "cmd/internal/gc" - -/* - * peep.c - */ -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -func cgen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var f0 gc.Node - var f1 gc.Node - var a int - var w int - var rg int - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var addr obj.Addr - - if gc.Debug['g'] != 0 { - gc.Dump("\ncgen-n", n) - gc.Dump("cgen-res", res) - } - - if n == nil || n.Type == nil { - goto ret - } - - if res == nil || res.Type == nil { - gc.Fatal("cgen: res nil") - } - - switch n.Op { - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_slice(n, res) - } - return - - case gc.OEFACE: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_eface(n, res) - } - return - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - if n.Ullman >= gc.UINF { - if n.Op == gc.OINDREG { - gc.Fatal("cgen: this is going to misscompile") - } - if res.Ullman >= gc.UINF { - gc.Tempname(&n1, n.Type) - cgen(n, &n1) - cgen(&n1, res) - goto ret - } - } - - if gc.Isfat(n.Type) { - if n.Type.Width < 0 { - gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) - } - sgen(n, res, n.Type.Width) - goto ret - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch n.Op { - case gc.OSPTR, - gc.OLEN: - if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { - n.Addable = n.Left.Addable - } - - case gc.OCAP: - if gc.Isslice(n.Left.Type) { - n.Addable = n.Left.Addable - } - - case gc.OITAB: - n.Addable = n.Left.Addable - } - - // if both are addressable, move - if n.Addable != 0 && res.Addable != 0 { - if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Op == gc.OREGISTER || res.Op == gc.OREGISTER || gc.Iscomplex[n.Type.Etype] != 0 || gc.Iscomplex[res.Type.Etype] != 0 { - gmove(n, res) - } else { - regalloc(&n1, n.Type, nil) - gmove(n, &n1) - cgen(&n1, res) - regfree(&n1) - } - - goto ret - } - - // if both are not addressable, use a temporary. - if n.Addable == 0 && res.Addable == 0 { - // could use regalloc here sometimes, - // but have to check for ullman >= UINF. - gc.Tempname(&n1, n.Type) - - cgen(n, &n1) - cgen(&n1, res) - return - } - - // if result is not addressable directly but n is, - // compute its address and then store via the address. - if res.Addable == 0 { - igen(res, &n1, nil) - cgen(n, &n1) - regfree(&n1) - return - } - - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - return - } - - // if n is sudoaddable generate addr and move - if !gc.Is64(n.Type) && !gc.Is64(res.Type) && gc.Iscomplex[n.Type.Etype] == 0 && gc.Iscomplex[res.Type.Etype] == 0 { - a = optoas(gc.OAS, n.Type) - if sudoaddable(a, n, &addr, &w) { - if res.Op != gc.OREGISTER { - regalloc(&n2, res.Type, nil) - p1 = gins(a, nil, &n2) - p1.From = addr - if gc.Debug['g'] != 0 { - fmt.Printf("%v [ignore previous line]\n", p1) - } - gmove(&n2, res) - regfree(&n2) - } else { - p1 = gins(a, nil, res) - p1.From = addr - if gc.Debug['g'] != 0 { - fmt.Printf("%v [ignore previous line]\n", p1) - } - } - - sudoclean() - goto ret - } - } - - // otherwise, the result is addressable but n is not. - // let's do some computation. - - nl = n.Left - - nr = n.Right - - if nl != nil && nl.Ullman >= gc.UINF { - if nr != nil && nr.Ullman >= gc.UINF { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - n2 = *n - n2.Left = &n1 - cgen(&n2, res) - goto ret - } - } - - // 64-bit ops are hard on 32-bit machine. - if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) { - switch n.Op { - // math goes to cgen64. - case gc.OMINUS, - gc.OCOM, - gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OLROT, - gc.OLSH, - gc.ORSH, - gc.OAND, - gc.OOR, - gc.OXOR: - cgen64(n, res) - - return - } - } - - if nl != nil && gc.Isfloat[n.Type.Etype] != 0 && gc.Isfloat[nl.Type.Etype] != 0 { - goto flt - } - switch n.Op { - default: - gc.Dump("cgen", n) - gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - case gc.OREAL, - gc.OIMAG, - gc.OCOMPLEX: - gc.Fatal("unexpected complex") - - // these call bgen to get a bool value - case gc.OOROR, - gc.OANDAND, - gc.OEQ, - gc.ONE, - gc.OLT, - gc.OLE, - gc.OGE, - gc.OGT, - gc.ONOT: - p1 = gc.Gbranch(arm.AB, nil, 0) - - p2 = gc.Pc - gmove(gc.Nodbool(true), res) - p3 = gc.Gbranch(arm.AB, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n, true, 0, p2) - gmove(gc.Nodbool(false), res) - gc.Patch(p3, gc.Pc) - goto ret - - case gc.OPLUS: - cgen(nl, res) - goto ret - - // unary - case gc.OCOM: - a = optoas(gc.OXOR, nl.Type) - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gc.Nodconst(&n2, nl.Type, -1) - gins(a, &n2, &n1) - goto norm - - case gc.OMINUS: - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gc.Nodconst(&n2, nl.Type, 0) - gins(optoas(gc.OMINUS, nl.Type), &n2, &n1) - goto norm - - // symmetric binary - case gc.OAND, - gc.OOR, - gc.OXOR, - gc.OADD, - gc.OMUL: - a = optoas(int(n.Op), nl.Type) - - goto sbop - - // asymmetric binary - case gc.OSUB: - a = optoas(int(n.Op), nl.Type) - - goto abop - - case gc.OHMUL: - cgen_hmul(nl, nr, res) - - case gc.OLROT, - gc.OLSH, - gc.ORSH: - cgen_shift(int(n.Op), n.Bounded, nl, nr, res) - - case gc.OCONV: - if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { - cgen(nl, res) - break - } - - if nl.Addable != 0 && !gc.Is64(nl.Type) { - regalloc(&n1, nl.Type, res) - gmove(nl, &n1) - } else { - if n.Type.Width > int64(gc.Widthptr) || gc.Is64(nl.Type) || gc.Isfloat[nl.Type.Etype] != 0 { - gc.Tempname(&n1, nl.Type) - } else { - regalloc(&n1, nl.Type, res) - } - cgen(nl, &n1) - } - - if n.Type.Width > int64(gc.Widthptr) || gc.Is64(n.Type) || gc.Isfloat[n.Type.Etype] != 0 { - gc.Tempname(&n2, n.Type) - } else { - regalloc(&n2, n.Type, nil) - } - gmove(&n1, &n2) - gmove(&n2, res) - if n1.Op == gc.OREGISTER { - regfree(&n1) - } - if n2.Op == gc.OREGISTER { - regfree(&n2) - } - - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res) - - gmove(&n1, res) - regfree(&n1) - - // interface table is first word of interface value - case gc.OITAB: - igen(nl, &n1, res) - - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - // pointer is the first word of string or slice. - case gc.OSPTR: - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n1, gc.Types[gc.Tptr], res) - p1 = gins(arm.AMOVW, nil, &n1) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - gmove(&n1, res) - regfree(&n1) - break - } - - igen(nl, &n1, res) - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - case gc.OLEN: - if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { - // map has len in the first 32-bit word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.TINT32] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { - // both slice and string have len one pointer into the struct. - igen(nl, &n1, res) - - n1.Type = gc.Types[gc.TUINT32] - n1.Xoffset += int64(gc.Array_nel) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OCAP: - if gc.Istype(nl.Type, gc.TCHAN) { - // chan has cap in the second 32-bit word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gcmp(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Xoffset = 4 - n2.Type = gc.Types[gc.TINT32] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Isslice(nl.Type) { - igen(nl, &n1, res) - n1.Type = gc.Types[gc.TUINT32] - n1.Xoffset += int64(gc.Array_cap) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OADDR: - agen(nl, res) - - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - case gc.OCALLMETH, - gc.OCALLFUNC: - rg = -1 - - if n.Ullman >= gc.UINF { - if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { - rg = int(res.Val.U.Reg) - reg[rg]-- - } - } - - if n.Op == gc.OCALLMETH { - gc.Cgen_callmeth(n, 0) - } else { - cgen_call(n, 0) - } - if rg >= 0 { - reg[rg]++ - } - cgen_callret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_callret(n, res) - - case gc.OMOD, - gc.ODIV: - a = optoas(int(n.Op), nl.Type) - goto abop - } - - goto ret - -sbop: // symmetric binary - if nl.Ullman < nr.Ullman { - r = nl - nl = nr - nr = r - } - - // TODO(kaib): use fewer registers here. -abop: // asymmetric binary - if nl.Ullman >= nr.Ullman { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - switch n.Op { - case gc.OADD, - gc.OSUB, - gc.OAND, - gc.OOR, - gc.OXOR: - if gc.Smallintconst(nr) { - n2 = *nr - break - } - fallthrough - - default: - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - } - } else { - switch n.Op { - case gc.OADD, - gc.OSUB, - gc.OAND, - gc.OOR, - gc.OXOR: - if gc.Smallintconst(nr) { - n2 = *nr - break - } - fallthrough - - default: - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - } - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - } - - gins(a, &n2, &n1) - - // Normalize result for types smaller than word. -norm: - if n.Type.Width < int64(gc.Widthptr) { - switch n.Op { - case gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OCOM, - gc.OMINUS: - gins(optoas(gc.OAS, n.Type), &n1, &n1) - } - } - - gmove(&n1, res) - regfree(&n1) - if n2.Op != gc.OLITERAL { - regfree(&n2) - } - goto ret - -flt: // floating-point. - regalloc(&f0, nl.Type, res) - - if nr != nil { - goto flt2 - } - - if n.Op == gc.OMINUS { - nr = gc.Nodintconst(-1) - gc.Convlit(&nr, n.Type) - n.Op = gc.OMUL - goto flt2 - } - - // unary - cgen(nl, &f0) - - if n.Op != gc.OCONV && n.Op != gc.OPLUS { - gins(optoas(int(n.Op), n.Type), &f0, &f0) - } - gmove(&f0, res) - regfree(&f0) - goto ret - -flt2: // binary - if nl.Ullman >= nr.Ullman { - cgen(nl, &f0) - regalloc(&f1, n.Type, nil) - gmove(&f0, &f1) - cgen(nr, &f0) - gins(optoas(int(n.Op), n.Type), &f0, &f1) - } else { - cgen(nr, &f0) - regalloc(&f1, n.Type, nil) - cgen(nl, &f1) - gins(optoas(int(n.Op), n.Type), &f0, &f1) - } - - gmove(&f1, res) - regfree(&f0) - regfree(&f1) - goto ret - -ret: -} - -/* - * generate array index into res. - * n might be any size; res is 32-bit. - * returns Prog* to patch to panic call. - */ -func cgenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog { - var tmp gc.Node - var lo gc.Node - var hi gc.Node - var zero gc.Node - var n1 gc.Node - var n2 gc.Node - - if !gc.Is64(n.Type) { - cgen(n, res) - return nil - } - - gc.Tempname(&tmp, gc.Types[gc.TINT64]) - cgen(n, &tmp) - split64(&tmp, &lo, &hi) - gmove(&lo, res) - if bounded { - splitclean() - return nil - } - - regalloc(&n1, gc.Types[gc.TINT32], nil) - regalloc(&n2, gc.Types[gc.TINT32], nil) - gc.Nodconst(&zero, gc.Types[gc.TINT32], 0) - gmove(&hi, &n1) - gmove(&zero, &n2) - gcmp(arm.ACMP, &n1, &n2) - regfree(&n2) - regfree(&n1) - splitclean() - return gc.Gbranch(arm.ABNE, nil, -1) -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -func agen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var r int - - if gc.Debug['g'] != 0 { - gc.Dump("\nagen-res", res) - gc.Dump("agen-r", n) - } - - if n == nil || n.Type == nil || res == nil || res.Type == nil { - gc.Fatal("agen") - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - gc.Tempname(&n1, n.Type) - - gc.Gvardef(&n1) - clearfat(&n1) - regalloc(&n2, gc.Types[gc.Tptr], res) - gins(arm.AMOVW, &n1, &n2) - gmove(&n2, res) - regfree(&n2) - goto ret - } - - if n.Addable != 0 { - n1 = gc.Node{} - n1.Op = gc.OADDR - n1.Left = n - regalloc(&n2, gc.Types[gc.Tptr], res) - gins(arm.AMOVW, &n1, &n2) - gmove(&n2, res) - regfree(&n2) - goto ret - } - - nl = n.Left - - switch n.Op { - default: - gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - case gc.OCALLMETH, - gc.OCALLFUNC: - r = -1 - - if n.Ullman >= gc.UINF { - if res.Op == gc.OREGISTER || res.Op == gc.OINDREG { - r = int(res.Val.U.Reg) - reg[r]-- - } - } - - if n.Op == gc.OCALLMETH { - gc.Cgen_callmeth(n, 0) - } else { - cgen_call(n, 0) - } - if r >= 0 { - reg[r]++ - } - cgen_aret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_aret(n, res) - - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - agen(&n1, res) - - case gc.OEFACE: - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - agen(&n1, res) - - case gc.OINDEX: - agenr(n, &n1, res) - gmove(&n1, res) - regfree(&n1) - - // should only get here with names in this func. - case gc.ONAME: - if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) - } - - // should only get here for heap vars or paramref - if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME class %#x", n.Class) - } - - cgen(n.Heapaddr, res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) - regalloc(&n2, n1.Type, nil) - regalloc(&n3, gc.Types[gc.TINT32], nil) - gmove(&n1, &n2) - gmove(res, &n3) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - gmove(&n3, res) - regfree(&n2) - regfree(&n3) - } - - case gc.OIND: - cgen(nl, res) - gc.Cgen_checknil(res) - - case gc.ODOT: - agen(nl, res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) - regalloc(&n2, n1.Type, nil) - regalloc(&n3, gc.Types[gc.TINT32], nil) - gmove(&n1, &n2) - gmove(res, &n3) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - gmove(&n3, res) - regfree(&n2) - regfree(&n3) - } - - case gc.ODOTPTR: - cgen(nl, res) - gc.Cgen_checknil(res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.TINT32], n.Xoffset) - regalloc(&n2, n1.Type, nil) - regalloc(&n3, gc.Types[gc.Tptr], nil) - gmove(&n1, &n2) - gmove(res, &n3) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - gmove(&n3, res) - regfree(&n2) - regfree(&n3) - } - } - -ret: -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -func igen(n *gc.Node, a *gc.Node, res *gc.Node) { - var n1 gc.Node - var r int - - if gc.Debug['g'] != 0 { - gc.Dump("\nigen-n", n) - } - - switch n.Op { - case gc.ONAME: - if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { - break - } - *a = *n - return - - // Increase the refcount of the register so that igen's caller - // has to call regfree. - case gc.OINDREG: - if n.Val.U.Reg != arm.REGSP { - reg[n.Val.U.Reg]++ - } - *a = *n - return - - case gc.ODOT: - igen(n.Left, a, res) - a.Xoffset += n.Xoffset - a.Type = n.Type - return - - case gc.ODOTPTR: - if n.Left.Addable != 0 || n.Left.Op == gc.OCALLFUNC || n.Left.Op == gc.OCALLMETH || n.Left.Op == gc.OCALLINTER { - // igen-able nodes. - igen(n.Left, &n1, res) - - regalloc(a, gc.Types[gc.Tptr], &n1) - gmove(&n1, a) - regfree(&n1) - } else { - regalloc(a, gc.Types[gc.Tptr], res) - cgen(n.Left, a) - } - - gc.Cgen_checknil(a) - a.Op = gc.OINDREG - a.Xoffset = n.Xoffset - a.Type = n.Type - return - - // Release res so that it is available for cgen_call. - // Pick it up again after the call. - case gc.OCALLMETH, - gc.OCALLFUNC, - gc.OCALLINTER: - r = -1 - - if n.Ullman >= gc.UINF { - if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { - r = int(res.Val.U.Reg) - reg[r]-- - } - } - - switch n.Op { - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - - case gc.OCALLFUNC: - cgen_call(n, 0) - - case gc.OCALLINTER: - cgen_callinter(n, nil, 0) - } - - if r >= 0 { - reg[r]++ - } - regalloc(a, gc.Types[gc.Tptr], res) - cgen_aret(n, a) - a.Op = gc.OINDREG - a.Type = n.Type - return - } - - agenr(n, a, res) - a.Op = gc.OINDREG - a.Type = n.Type -} - -/* - * allocate a register in res and generate - * newreg = &n - * The caller must call regfree(a). - */ -func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("cgenr-n", n) - } - - if gc.Isfat(n.Type) { - gc.Fatal("cgenr on fat node") - } - - if n.Addable != 0 { - regalloc(a, gc.Types[gc.Tptr], res) - gmove(n, a) - return - } - - switch n.Op { - case gc.ONAME, - gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - gmove(&n1, a) - regfree(&n1) - - default: - regalloc(a, n.Type, res) - cgen(n, a) - } -} - -/* - * generate: - * newreg = &n; - * - * caller must regfree(a). - * The generated code checks that the result is not nil. - */ -func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var tmp gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var w uint32 - var v uint64 - var bounded bool - - if gc.Debug['g'] != 0 { - gc.Dump("agenr-n", n) - } - - nl = n.Left - nr = n.Right - - switch n.Op { - case gc.ODOT, - gc.ODOTPTR, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - agen(&n1, a) - regfree(&n1) - - case gc.OIND: - cgenr(n.Left, a, res) - gc.Cgen_checknil(a) - - case gc.OINDEX: - p2 = nil // to be patched to panicindex. - w = uint32(n.Type.Width) - bounded = gc.Debug['B'] != 0 || n.Bounded - if nr.Addable != 0 { - if !gc.Isconst(nr, gc.CTINT) { - gc.Tempname(&tmp, gc.Types[gc.TINT32]) - } - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - if !gc.Isconst(nr, gc.CTINT) { - p2 = cgenindex(nr, &tmp, bounded) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - } else if nl.Addable != 0 { - if !gc.Isconst(nr, gc.CTINT) { - gc.Tempname(&tmp, gc.Types[gc.TINT32]) - p2 = cgenindex(nr, &tmp, bounded) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - } else { - gc.Tempname(&tmp, gc.Types[gc.TINT32]) - p2 = cgenindex(nr, &tmp, bounded) - nr = &tmp - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - regalloc(&n1, tmp.Type, nil) - gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) - } - - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // w is width - - // constant index - if gc.Isconst(nr, gc.CTINT) { - if gc.Isconst(nl, gc.CTSTR) { - gc.Fatal("constant string constant index") - } - v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - if gc.Debug['B'] == 0 && !n.Bounded { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - regalloc(&n4, n1.Type, nil) - gmove(&n1, &n4) - gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v)) - gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n4, &n2) - regfree(&n4) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, &n3) - } - - gc.Nodconst(&n2, gc.Types[gc.Tptr], int64(v*uint64(w))) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - *a = n3 - break - } - - regalloc(&n2, gc.Types[gc.TINT32], &n1) // i - gmove(&n1, &n2) - regfree(&n1) - - if gc.Debug['B'] == 0 && !n.Bounded { - // check bounds - if gc.Isconst(nl, gc.CTSTR) { - gc.Nodconst(&n4, gc.Types[gc.TUINT32], int64(len(nl.Val.U.Sval.S))) - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - regalloc(&n4, gc.Types[gc.TUINT32], nil) - gmove(&n1, &n4) - } else { - gc.Nodconst(&n4, gc.Types[gc.TUINT32], nl.Type.Bound) - } - - gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n2, &n4) - if n4.Op == gc.OREGISTER { - regfree(&n4) - } - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - if p2 != nil { - gc.Patch(p2, gc.Pc) - } - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n3, gc.Types[gc.Tptr], res) - p1 = gins(arm.AMOVW, nil, &n3) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - p1.From.Type = obj.TYPE_ADDR - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, &n3) - } - - if w == 0 { - } else // nothing to do - if w == 1 || w == 2 || w == 4 || w == 8 { - n4 = gc.Node{} - n4.Op = gc.OADDR - n4.Left = &n2 - cgen(&n4, &n3) - if w == 1 { - gins(arm.AADD, &n2, &n3) - } else if w == 2 { - gshift(arm.AADD, &n2, arm.SHIFT_LL, 1, &n3) - } else if w == 4 { - gshift(arm.AADD, &n2, arm.SHIFT_LL, 2, &n3) - } else if w == 8 { - gshift(arm.AADD, &n2, arm.SHIFT_LL, 3, &n3) - } - } else { - regalloc(&n4, gc.Types[gc.TUINT32], nil) - gc.Nodconst(&n1, gc.Types[gc.TUINT32], int64(w)) - gmove(&n1, &n4) - gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &n4, &n2) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - regfree(&n4) - } - - *a = n3 - regfree(&n2) - - default: - regalloc(a, gc.Types[gc.Tptr], res) - agen(n, a) - } -} - -func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var a int - - regalloc(&n1, t, nil) - cgen(n, &n1) - a = optoas(gc.OCMP, t) - if a != arm.ACMP { - gc.Nodconst(&n2, t, 0) - regalloc(&n3, t, nil) - gmove(&n2, &n3) - gcmp(a, &n1, &n3) - regfree(&n3) - } else { - gins(arm.ATST, &n1, nil) - } - a = optoas(o, t) - gc.Patch(gc.Gbranch(a, t, likely), to) - regfree(&n1) -} - -/* - * generate: - * if(n == true) goto to; - */ -func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { - var et int - var a int - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var tmp gc.Node - var ll *gc.NodeList - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['g'] != 0 { - gc.Dump("\nbgen", n) - } - - if n == nil { - n = gc.Nodbool(true) - } - - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - - if n.Type == nil { - gc.Convlit(&n, gc.Types[gc.TBOOL]) - if n.Type == nil { - goto ret - } - } - - et = int(n.Type.Etype) - if et != gc.TBOOL { - gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) - gc.Patch(gins(obj.AEND, nil, nil), to) - goto ret - } - - nr = nil - - switch n.Op { - default: - a = gc.ONE - if !true_ { - a = gc.OEQ - } - gencmp0(n, n.Type, a, likely, to) - goto ret - - // need to ask if it is bool? - case gc.OLITERAL: - if !true_ == (n.Val.U.Bval == 0) { - gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) - } - goto ret - - case gc.OANDAND, - gc.OOROR: - if (n.Op == gc.OANDAND) == true_ { - p1 = gc.Gbranch(obj.AJMP, nil, 0) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n.Left, !true_, -likely, p2) - bgen(n.Right, !true_, -likely, p2) - p1 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, to) - gc.Patch(p2, gc.Pc) - } else { - bgen(n.Left, true_, likely, to) - bgen(n.Right, true_, likely, to) - } - - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - nr = n.Right - if nr == nil || nr.Type == nil { - goto ret - } - fallthrough - - case gc.ONOT: // unary - nl = n.Left - - if nl == nil || nl.Type == nil { - goto ret - } - } - - switch n.Op { - case gc.ONOT: - bgen(nl, !true_, likely, to) - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - a = int(n.Op) - if !true_ { - if gc.Isfloat[nl.Type.Etype] != 0 { - // brcom is not valid on floats when NaN is involved. - p1 = gc.Gbranch(arm.AB, nil, 0) - - p2 = gc.Gbranch(arm.AB, nil, 0) - gc.Patch(p1, gc.Pc) - ll = n.Ninit - n.Ninit = nil - bgen(n, true, -likely, p2) - n.Ninit = ll - gc.Patch(gc.Gbranch(arm.AB, nil, 0), to) - gc.Patch(p2, gc.Pc) - goto ret - } - - a = gc.Brcom(a) - true_ = !true_ - } - - // make simplest on right - if nl.Op == gc.OLITERAL || (nl.Ullman < gc.UINF && nl.Ullman < nr.Ullman) { - a = gc.Brrev(a) - r = nl - nl = nr - nr = r - } - - if gc.Isslice(nl.Type) { - // only valid to cmp darray to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal array comparison") - break - } - - igen(nl, &n1, nil) - n1.Xoffset += int64(gc.Array_array) - n1.Type = gc.Types[gc.Tptr] - gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) - regfree(&n1) - break - } - - if gc.Isinter(nl.Type) { - // front end shold only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal interface comparison") - break - } - - igen(nl, &n1, nil) - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset += 0 - gencmp0(&n1, gc.Types[gc.Tptr], a, likely, to) - regfree(&n1) - break - } - - if gc.Iscomplex[nl.Type.Etype] != 0 { - gc.Complexbool(a, nl, nr, true_, likely, to) - break - } - - if gc.Is64(nr.Type) { - if nl.Addable == 0 { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - nl = &n1 - } - - if nr.Addable == 0 { - gc.Tempname(&n2, nr.Type) - cgen(nr, &n2) - nr = &n2 - } - - cmp64(nl, nr, a, likely, to) - break - } - - if nr.Op == gc.OLITERAL { - if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) == 0 { - gencmp0(nl, nl.Type, a, likely, to) - break - } - - if nr.Val.Ctype == gc.CTNIL { - gencmp0(nl, nl.Type, a, likely, to) - break - } - } - - a = optoas(a, nr.Type) - - if nr.Ullman >= gc.UINF { - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - - gc.Tempname(&tmp, nl.Type) - gmove(&n1, &tmp) - regfree(&n1) - - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - - regalloc(&n1, nl.Type, nil) - cgen(&tmp, &n1) - - gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) - gc.Patch(gc.Gbranch(a, nr.Type, likely), to) - - regfree(&n1) - regfree(&n2) - break - } - - gc.Tempname(&n3, nl.Type) - cgen(nl, &n3) - - gc.Tempname(&tmp, nr.Type) - cgen(nr, &tmp) - - regalloc(&n1, nl.Type, nil) - gmove(&n3, &n1) - - regalloc(&n2, nr.Type, nil) - gmove(&tmp, &n2) - - gcmp(optoas(gc.OCMP, nr.Type), &n1, &n2) - if gc.Isfloat[nl.Type.Etype] != 0 { - if n.Op == gc.ONE { - p1 = gc.Gbranch(arm.ABVS, nr.Type, likely) - gc.Patch(gc.Gbranch(a, nr.Type, likely), to) - gc.Patch(p1, to) - } else { - p1 = gc.Gbranch(arm.ABVS, nr.Type, -likely) - gc.Patch(gc.Gbranch(a, nr.Type, likely), to) - gc.Patch(p1, gc.Pc) - } - } else { - gc.Patch(gc.Gbranch(a, nr.Type, likely), to) - } - - regfree(&n1) - regfree(&n2) - } - - goto ret - -ret: -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -func stkof(n *gc.Node) int32 { - var t *gc.Type - var flist gc.Iter - var off int32 - - switch n.Op { - case gc.OINDREG: - return int32(n.Xoffset) - - case gc.ODOT: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - return int32(int64(off) + n.Xoffset) - - case gc.OINDEX: - t = n.Left.Type - if !gc.Isfixedarray(t) { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - if gc.Isconst(n.Right, gc.CTINT) { - return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)) - } - return 1000 - - case gc.OCALLMETH, - gc.OCALLINTER, - gc.OCALLFUNC: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - t = gc.Structfirst(&flist, gc.Getoutarg(t)) - if t != nil { - return int32(t.Width + 4) // correct for LR - } - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000 -} - -/* - * block copy: - * memmove(&res, &n, w); - * NB: character copy assumed little endian architecture - */ -func sgen(n *gc.Node, res *gc.Node, w int64) { - var dst gc.Node - var src gc.Node - var tmp gc.Node - var nend gc.Node - var r0 gc.Node - var r1 gc.Node - var r2 gc.Node - var f *gc.Node - var c int32 - var odst int32 - var osrc int32 - var dir int - var align int - var op int - var p *obj.Prog - var ploop *obj.Prog - var l *gc.NodeList - - if gc.Debug['g'] != 0 { - fmt.Printf("\nsgen w=%d\n", w) - gc.Dump("r", n) - gc.Dump("res", res) - } - - if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { - gc.Fatal("sgen UINF") - } - - if w < 0 || int64(int32(w)) != w { - gc.Fatal("sgen copy %d", w) - } - - if n.Type == nil { - gc.Fatal("sgen: missing type") - } - - if w == 0 { - // evaluate side effects only. - regalloc(&dst, gc.Types[gc.Tptr], nil) - - agen(res, &dst) - agen(n, &dst) - regfree(&dst) - return - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if res.Op == gc.ONAME && res.Sym.Name == ".args" { - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - if l.N.Class == gc.PPARAMOUT { - gc.Gvardef(l.N) - } - } - } - - // Avoid taking the address for simple enough types. - if componentgen(n, res) { - return - } - - // determine alignment. - // want to avoid unaligned access, so have to use - // smaller operations for less aligned types. - // for example moving [4]byte must use 4 MOVB not 1 MOVW. - align = int(n.Type.Align) - - switch align { - default: - gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0)) - - case 1: - op = arm.AMOVB - - case 2: - op = arm.AMOVH - - case 4: - op = arm.AMOVW - } - - if w%int64(align) != 0 { - gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0)) - } - c = int32(w / int64(align)) - - // offset on the stack - osrc = stkof(n) - - odst = stkof(res) - if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - gc.Tempname(&tmp, n.Type) - - sgen(n, &tmp, w) - sgen(&tmp, res, w) - return - } - - if osrc%int32(align) != 0 || odst%int32(align) != 0 { - gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align) - } - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - dir = align - - if osrc < odst && int64(odst) < int64(osrc)+w { - dir = -dir - } - - if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 { - r0.Op = gc.OREGISTER - r0.Val.U.Reg = REGALLOC_R0 - r1.Op = gc.OREGISTER - r1.Val.U.Reg = REGALLOC_R0 + 1 - r2.Op = gc.OREGISTER - r2.Val.U.Reg = REGALLOC_R0 + 2 - - regalloc(&src, gc.Types[gc.Tptr], &r1) - regalloc(&dst, gc.Types[gc.Tptr], &r2) - if n.Ullman >= res.Ullman { - // eval n first - agen(n, &src) - - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agen(res, &dst) - } else { - // eval res first - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agen(res, &dst) - agen(n, &src) - } - - regalloc(&tmp, gc.Types[gc.Tptr], &r0) - f = gc.Sysfunc("duffcopy") - p = gins(obj.ADUFFCOPY, nil, f) - gc.Afunclit(&p.To, f) - - // 8 and 128 = magic constants: see ../../runtime/asm_arm.s - p.To.Offset = 8 * (128 - int64(c)) - - regfree(&tmp) - regfree(&src) - regfree(&dst) - return - } - - if n.Ullman >= res.Ullman { - agenr(n, &dst, res) // temporarily use dst - regalloc(&src, gc.Types[gc.Tptr], nil) - gins(arm.AMOVW, &dst, &src) - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agen(res, &dst) - } else { - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agenr(res, &dst, res) - agenr(n, &src, nil) - } - - regalloc(&tmp, gc.Types[gc.TUINT32], nil) - - // set up end marker - nend = gc.Node{} - - if c >= 4 { - regalloc(&nend, gc.Types[gc.TUINT32], nil) - - p = gins(arm.AMOVW, &src, &nend) - p.From.Type = obj.TYPE_ADDR - if dir < 0 { - p.From.Offset = int64(dir) - } else { - p.From.Offset = w - } - } - - // move src and dest to the end of block if necessary - if dir < 0 { - p = gins(arm.AMOVW, &src, &src) - p.From.Type = obj.TYPE_ADDR - p.From.Offset = w + int64(dir) - - p = gins(arm.AMOVW, &dst, &dst) - p.From.Type = obj.TYPE_ADDR - p.From.Offset = w + int64(dir) - } - - // move - if c >= 4 { - p = gins(op, &src, &tmp) - p.From.Type = obj.TYPE_MEM - p.From.Offset = int64(dir) - p.Scond |= arm.C_PBIT - ploop = p - - p = gins(op, &tmp, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(dir) - p.Scond |= arm.C_PBIT - - p = gins(arm.ACMP, &src, nil) - raddr(&nend, p) - - gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), ploop) - regfree(&nend) - } else { - for { - tmp14 := c - c-- - if tmp14 <= 0 { - break - } - p = gins(op, &src, &tmp) - p.From.Type = obj.TYPE_MEM - p.From.Offset = int64(dir) - p.Scond |= arm.C_PBIT - - p = gins(op, &tmp, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(dir) - p.Scond |= arm.C_PBIT - } - } - - regfree(&dst) - regfree(&src) - regfree(&tmp) -} - -func cadable(n *gc.Node) bool { - if n.Addable == 0 { - // dont know how it happens, - // but it does - return false - } - - switch n.Op { - case gc.ONAME: - return true - } - - return false -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if cant. - */ -func componentgen(nr *gc.Node, nl *gc.Node) bool { - var nodl gc.Node - var nodr gc.Node - var tmp gc.Node - var t *gc.Type - var freel int - var freer int - var fldcount int64 - var loffset int64 - var roffset int64 - - freel = 0 - freer = 0 - - switch nl.Type.Etype { - default: - goto no - - case gc.TARRAY: - t = nl.Type - - // Slices are ok. - if gc.Isslice(t) { - break - } - - // Small arrays are ok. - if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { - break - } - - goto no - - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - case gc.TSTRUCT: - fldcount = 0 - - for t = nl.Type.Type; t != nil; t = t.Down { - if gc.Isfat(t.Type) { - goto no - } - if t.Etype != gc.TFIELD { - gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) - } - fldcount++ - } - - if fldcount == 0 || fldcount > 4 { - goto no - } - - case gc.TSTRING, - gc.TINTER: - break - } - - nodl = *nl - if !cadable(nl) { - if nr != nil && !cadable(nr) { - goto no - } - igen(nl, &nodl, nil) - freel = 1 - } - - if nr != nil { - nodr = *nr - if !cadable(nr) { - igen(nr, &nodr, nil) - freer = 1 - } - } else { - // When zeroing, prepare a register containing zero. - gc.Nodconst(&tmp, nl.Type, 0) - - regalloc(&nodr, gc.Types[gc.TUINT], nil) - gmove(&tmp, &nodr) - freer = 1 - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { - goto yes - } - - switch nl.Type.Etype { - // componentgen for arrays. - case gc.TARRAY: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - t = nl.Type - if !gc.Isslice(t) { - nodl.Type = t.Type - nodr.Type = nodl.Type - for fldcount = 0; fldcount < t.Bound; fldcount++ { - if nr == nil { - gc.Clearslim(&nodl) - } else { - gmove(&nodr, &nodl) - } - nodl.Xoffset += t.Type.Width - nodr.Xoffset += t.Type.Width - } - - goto yes - } - - // componentgen for slices. - nodl.Xoffset += int64(gc.Array_array) - - nodl.Type = gc.Ptrto(nl.Type.Type) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRING: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TINTER: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRUCT: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - loffset = nodl.Xoffset - roffset = nodr.Xoffset - - // funarg structs may not begin at offset zero. - if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { - loffset -= nl.Type.Type.Width - } - if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { - roffset -= nr.Type.Type.Width - } - - for t = nl.Type.Type; t != nil; t = t.Down { - nodl.Xoffset = loffset + t.Width - nodl.Type = t.Type - - if nr == nil { - gc.Clearslim(&nodl) - } else { - nodr.Xoffset = roffset + t.Width - nodr.Type = nodl.Type - gmove(&nodr, &nodl) - } - } - - goto yes - } - -no: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return false - -yes: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return true -} diff --git a/src/cmd/new5g/cgen64.go b/src/cmd/new5g/cgen64.go deleted file mode 100644 index f89c21cf08..0000000000 --- a/src/cmd/new5g/cgen64.go +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" -) -import "cmd/internal/gc" - -/* - * attempt to generate 64-bit - * res = n - * return 1 on success, 0 if op not handled. - */ -func cgen64(n *gc.Node, res *gc.Node) { - var t1 gc.Node - var t2 gc.Node - var l *gc.Node - var r *gc.Node - var lo1 gc.Node - var lo2 gc.Node - var hi1 gc.Node - var hi2 gc.Node - var al gc.Node - var ah gc.Node - var bl gc.Node - var bh gc.Node - var cl gc.Node - var ch gc.Node - var s gc.Node - var n1 gc.Node - var creg gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var p4 *obj.Prog - var p5 *obj.Prog - var p6 *obj.Prog - var v uint64 - - if res.Op != gc.OINDREG && res.Op != gc.ONAME { - gc.Dump("n", n) - gc.Dump("res", res) - gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) - } - - l = n.Left - if l.Addable == 0 { - gc.Tempname(&t1, l.Type) - cgen(l, &t1) - l = &t1 - } - - split64(l, &lo1, &hi1) - switch n.Op { - default: - gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0)) - - case gc.OMINUS: - split64(res, &lo2, &hi2) - - regalloc(&t1, lo1.Type, nil) - regalloc(&al, lo1.Type, nil) - regalloc(&ah, hi1.Type, nil) - - gins(arm.AMOVW, &lo1, &al) - gins(arm.AMOVW, &hi1, &ah) - - gmove(ncon(0), &t1) - p1 = gins(arm.ASUB, &al, &t1) - p1.Scond |= arm.C_SBIT - gins(arm.AMOVW, &t1, &lo2) - - gmove(ncon(0), &t1) - gins(arm.ASBC, &ah, &t1) - gins(arm.AMOVW, &t1, &hi2) - - regfree(&t1) - regfree(&al) - regfree(&ah) - splitclean() - splitclean() - return - - case gc.OCOM: - regalloc(&t1, lo1.Type, nil) - gmove(ncon(^uint32(0)), &t1) - - split64(res, &lo2, &hi2) - regalloc(&n1, lo1.Type, nil) - - gins(arm.AMOVW, &lo1, &n1) - gins(arm.AEOR, &t1, &n1) - gins(arm.AMOVW, &n1, &lo2) - - gins(arm.AMOVW, &hi1, &n1) - gins(arm.AEOR, &t1, &n1) - gins(arm.AMOVW, &n1, &hi2) - - regfree(&t1) - regfree(&n1) - splitclean() - splitclean() - return - - // binary operators. - // common setup below. - case gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OLSH, - gc.ORSH, - gc.OAND, - gc.OOR, - gc.OXOR, - gc.OLROT: - break - } - - // setup for binary operators - r = n.Right - - if r != nil && r.Addable == 0 { - gc.Tempname(&t2, r.Type) - cgen(r, &t2) - r = &t2 - } - - if gc.Is64(r.Type) { - split64(r, &lo2, &hi2) - } - - regalloc(&al, lo1.Type, nil) - regalloc(&ah, hi1.Type, nil) - - // Do op. Leave result in ah:al. - switch n.Op { - default: - gc.Fatal("cgen64: not implemented: %v\n", gc.Nconv(n, 0)) - - // TODO: Constants - case gc.OADD: - regalloc(&bl, gc.Types[gc.TPTR32], nil) - - regalloc(&bh, gc.Types[gc.TPTR32], nil) - gins(arm.AMOVW, &hi1, &ah) - gins(arm.AMOVW, &lo1, &al) - gins(arm.AMOVW, &hi2, &bh) - gins(arm.AMOVW, &lo2, &bl) - p1 = gins(arm.AADD, &bl, &al) - p1.Scond |= arm.C_SBIT - gins(arm.AADC, &bh, &ah) - regfree(&bl) - regfree(&bh) - - // TODO: Constants. - case gc.OSUB: - regalloc(&bl, gc.Types[gc.TPTR32], nil) - - regalloc(&bh, gc.Types[gc.TPTR32], nil) - gins(arm.AMOVW, &lo1, &al) - gins(arm.AMOVW, &hi1, &ah) - gins(arm.AMOVW, &lo2, &bl) - gins(arm.AMOVW, &hi2, &bh) - p1 = gins(arm.ASUB, &bl, &al) - p1.Scond |= arm.C_SBIT - gins(arm.ASBC, &bh, &ah) - regfree(&bl) - regfree(&bh) - - // TODO(kaib): this can be done with 4 regs and does not need 6 - case gc.OMUL: - regalloc(&bl, gc.Types[gc.TPTR32], nil) - - regalloc(&bh, gc.Types[gc.TPTR32], nil) - regalloc(&cl, gc.Types[gc.TPTR32], nil) - regalloc(&ch, gc.Types[gc.TPTR32], nil) - - // load args into bh:bl and bh:bl. - gins(arm.AMOVW, &hi1, &bh) - - gins(arm.AMOVW, &lo1, &bl) - gins(arm.AMOVW, &hi2, &ch) - gins(arm.AMOVW, &lo2, &cl) - - // bl * cl -> ah al - p1 = gins(arm.AMULLU, nil, nil) - - p1.From.Type = obj.TYPE_REG - p1.From.Reg = bl.Val.U.Reg - p1.Reg = cl.Val.U.Reg - p1.To.Type = obj.TYPE_REGREG - p1.To.Reg = ah.Val.U.Reg - p1.To.Offset = int64(al.Val.U.Reg) - - //print("%P\n", p1); - - // bl * ch + ah -> ah - p1 = gins(arm.AMULA, nil, nil) - - p1.From.Type = obj.TYPE_REG - p1.From.Reg = bl.Val.U.Reg - p1.Reg = ch.Val.U.Reg - p1.To.Type = obj.TYPE_REGREG2 - p1.To.Reg = ah.Val.U.Reg - p1.To.Offset = int64(ah.Val.U.Reg) - - //print("%P\n", p1); - - // bh * cl + ah -> ah - p1 = gins(arm.AMULA, nil, nil) - - p1.From.Type = obj.TYPE_REG - p1.From.Reg = bh.Val.U.Reg - p1.Reg = cl.Val.U.Reg - p1.To.Type = obj.TYPE_REGREG2 - p1.To.Reg = ah.Val.U.Reg - p1.To.Offset = int64(ah.Val.U.Reg) - - //print("%P\n", p1); - - regfree(&bh) - - regfree(&bl) - regfree(&ch) - regfree(&cl) - - // We only rotate by a constant c in [0,64). - // if c >= 32: - // lo, hi = hi, lo - // c -= 32 - // if c == 0: - // no-op - // else: - // t = hi - // shld hi:lo, c - // shld lo:t, c - case gc.OLROT: - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - - regalloc(&bl, lo1.Type, nil) - regalloc(&bh, hi1.Type, nil) - if v >= 32 { - // reverse during load to do the first 32 bits of rotate - v -= 32 - - gins(arm.AMOVW, &hi1, &bl) - gins(arm.AMOVW, &lo1, &bh) - } else { - gins(arm.AMOVW, &hi1, &bh) - gins(arm.AMOVW, &lo1, &bl) - } - - if v == 0 { - gins(arm.AMOVW, &bh, &ah) - gins(arm.AMOVW, &bl, &al) - } else { - // rotate by 1 <= v <= 31 - // MOVW bl<>(32-v), ah - // OR bh>>(32-v), al - gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al) - - gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah) - gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) - gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al) - } - - regfree(&bl) - regfree(&bh) - - case gc.OLSH: - regalloc(&bl, lo1.Type, nil) - regalloc(&bh, hi1.Type, nil) - gins(arm.AMOVW, &hi1, &bh) - gins(arm.AMOVW, &lo1, &bl) - - if r.Op == gc.OLITERAL { - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - if v >= 64 { - // TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al) - // here and below (verify it optimizes to EOR) - gins(arm.AEOR, &al, &al) - - gins(arm.AEOR, &ah, &ah) - } else if v > 32 { - gins(arm.AEOR, &al, &al) - - // MOVW bl<<(v-32), ah - gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah) - } else if v == 32 { - gins(arm.AEOR, &al, &al) - gins(arm.AMOVW, &bl, &ah) - } else if v > 0 { - // MOVW bl<>(32-v), ah - gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah) - } else { - gins(arm.AMOVW, &bl, &al) - gins(arm.AMOVW, &bh, &ah) - } - - goto olsh_break - } - - regalloc(&s, gc.Types[gc.TUINT32], nil) - regalloc(&creg, gc.Types[gc.TUINT32], nil) - if gc.Is64(r.Type) { - // shift is >= 1<<32 - split64(r, &cl, &ch) - - gmove(&ch, &s) - gins(arm.ATST, &s, nil) - p6 = gc.Gbranch(arm.ABNE, nil, 0) - gmove(&cl, &s) - splitclean() - } else { - gmove(r, &s) - p6 = nil - } - - gins(arm.ATST, &s, nil) - - // shift == 0 - p1 = gins(arm.AMOVW, &bl, &al) - - p1.Scond = arm.C_SCOND_EQ - p1 = gins(arm.AMOVW, &bh, &ah) - p1.Scond = arm.C_SCOND_EQ - p2 = gc.Gbranch(arm.ABEQ, nil, 0) - - // shift is < 32 - gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) - - gmove(&n1, &creg) - gcmp(arm.ACMP, &s, &creg) - - // MOVW.LO bl<>creg, ah - p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah) - - p1.Scond = arm.C_SCOND_LO - - // BLO end - p3 = gc.Gbranch(arm.ABLO, nil, 0) - - // shift == 32 - p1 = gins(arm.AEOR, &al, &al) - - p1.Scond = arm.C_SCOND_EQ - p1 = gins(arm.AMOVW, &bl, &ah) - p1.Scond = arm.C_SCOND_EQ - p4 = gc.Gbranch(arm.ABEQ, nil, 0) - - // shift is < 64 - gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) - - gmove(&n1, &creg) - gcmp(arm.ACMP, &s, &creg) - - // EOR.LO al, al - p1 = gins(arm.AEOR, &al, &al) - - p1.Scond = arm.C_SCOND_LO - - // MOVW.LO creg>>1, creg - p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) - - p1.Scond = arm.C_SCOND_LO - - // SUB.LO creg, s - p1 = gins(arm.ASUB, &creg, &s) - - p1.Scond = arm.C_SCOND_LO - - // MOVW bl<= 64 - if p6 != nil { - gc.Patch(p6, gc.Pc) - } - gins(arm.AEOR, &al, &al) - gins(arm.AEOR, &ah, &ah) - - gc.Patch(p2, gc.Pc) - gc.Patch(p3, gc.Pc) - gc.Patch(p4, gc.Pc) - gc.Patch(p5, gc.Pc) - regfree(&s) - regfree(&creg) - - olsh_break: - regfree(&bl) - regfree(&bh) - - case gc.ORSH: - regalloc(&bl, lo1.Type, nil) - regalloc(&bh, hi1.Type, nil) - gins(arm.AMOVW, &hi1, &bh) - gins(arm.AMOVW, &lo1, &bl) - - if r.Op == gc.OLITERAL { - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - if v >= 64 { - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->31, al - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) - - // MOVW bh->31, ah - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) - } else { - gins(arm.AEOR, &al, &al) - gins(arm.AEOR, &ah, &ah) - } - } else if v > 32 { - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->(v-32), al - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al) - - // MOVW bh->31, ah - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) - } else { - // MOVW bh>>(v-32), al - gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al) - - gins(arm.AEOR, &ah, &ah) - } - } else if v == 32 { - gins(arm.AMOVW, &bh, &al) - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->31, ah - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) - } else { - gins(arm.AEOR, &ah, &ah) - } - } else if v > 0 { - // MOVW bl>>v, al - gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al) - - // OR bh<<(32-v), al - gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al) - - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->v, ah - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah) - } else { - // MOVW bh>>v, ah - gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah) - } - } else { - gins(arm.AMOVW, &bl, &al) - gins(arm.AMOVW, &bh, &ah) - } - - goto orsh_break - } - - regalloc(&s, gc.Types[gc.TUINT32], nil) - regalloc(&creg, gc.Types[gc.TUINT32], nil) - if gc.Is64(r.Type) { - // shift is >= 1<<32 - split64(r, &cl, &ch) - - gmove(&ch, &s) - gins(arm.ATST, &s, nil) - if bh.Type.Etype == gc.TINT32 { - p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) - } else { - p1 = gins(arm.AEOR, &ah, &ah) - } - p1.Scond = arm.C_SCOND_NE - p6 = gc.Gbranch(arm.ABNE, nil, 0) - gmove(&cl, &s) - splitclean() - } else { - gmove(r, &s) - p6 = nil - } - - gins(arm.ATST, &s, nil) - - // shift == 0 - p1 = gins(arm.AMOVW, &bl, &al) - - p1.Scond = arm.C_SCOND_EQ - p1 = gins(arm.AMOVW, &bh, &ah) - p1.Scond = arm.C_SCOND_EQ - p2 = gc.Gbranch(arm.ABEQ, nil, 0) - - // check if shift is < 32 - gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32) - - gmove(&n1, &creg) - gcmp(arm.ACMP, &s, &creg) - - // MOVW.LO bl>>s, al - p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al) - - p1.Scond = arm.C_SCOND_LO - - // SUB.LO s,creg - p1 = gins(arm.ASUB, &s, &creg) - - p1.Scond = arm.C_SCOND_LO - - // OR.LO bh<<(32-s), al - p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al) - - p1.Scond = arm.C_SCOND_LO - - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->s, ah - p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah) - } else { - // MOVW bh>>s, ah - p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah) - } - - p1.Scond = arm.C_SCOND_LO - - // BLO end - p3 = gc.Gbranch(arm.ABLO, nil, 0) - - // shift == 32 - p1 = gins(arm.AMOVW, &bh, &al) - - p1.Scond = arm.C_SCOND_EQ - if bh.Type.Etype == gc.TINT32 { - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah) - } else { - gins(arm.AEOR, &ah, &ah) - } - p4 = gc.Gbranch(arm.ABEQ, nil, 0) - - // check if shift is < 64 - gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64) - - gmove(&n1, &creg) - gcmp(arm.ACMP, &s, &creg) - - // MOVW.LO creg>>1, creg - p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg) - - p1.Scond = arm.C_SCOND_LO - - // SUB.LO creg, s - p1 = gins(arm.ASUB, &creg, &s) - - p1.Scond = arm.C_SCOND_LO - - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->(s-32), al - p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al) - - p1.Scond = arm.C_SCOND_LO - } else { - // MOVW bh>>(v-32), al - p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al) - - p1.Scond = arm.C_SCOND_LO - } - - // BLO end - p5 = gc.Gbranch(arm.ABLO, nil, 0) - - // s >= 64 - if p6 != nil { - gc.Patch(p6, gc.Pc) - } - if bh.Type.Etype == gc.TINT32 { - // MOVW bh->31, al - gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al) - } else { - gins(arm.AEOR, &al, &al) - } - - gc.Patch(p2, gc.Pc) - gc.Patch(p3, gc.Pc) - gc.Patch(p4, gc.Pc) - gc.Patch(p5, gc.Pc) - regfree(&s) - regfree(&creg) - - orsh_break: - regfree(&bl) - regfree(&bh) - - // TODO(kaib): literal optimizations - // make constant the right side (it usually is anyway). - // if(lo1.op == OLITERAL) { - // nswap(&lo1, &lo2); - // nswap(&hi1, &hi2); - // } - // if(lo2.op == OLITERAL) { - // // special cases for constants. - // lv = mpgetfix(lo2.val.u.xval); - // hv = mpgetfix(hi2.val.u.xval); - // splitclean(); // right side - // split64(res, &lo2, &hi2); - // switch(n->op) { - // case OXOR: - // gmove(&lo1, &lo2); - // gmove(&hi1, &hi2); - // switch(lv) { - // case 0: - // break; - // case 0xffffffffu: - // gins(ANOTL, N, &lo2); - // break; - // default: - // gins(AXORL, ncon(lv), &lo2); - // break; - // } - // switch(hv) { - // case 0: - // break; - // case 0xffffffffu: - // gins(ANOTL, N, &hi2); - // break; - // default: - // gins(AXORL, ncon(hv), &hi2); - // break; - // } - // break; - - // case OAND: - // switch(lv) { - // case 0: - // gins(AMOVL, ncon(0), &lo2); - // break; - // default: - // gmove(&lo1, &lo2); - // if(lv != 0xffffffffu) - // gins(AANDL, ncon(lv), &lo2); - // break; - // } - // switch(hv) { - // case 0: - // gins(AMOVL, ncon(0), &hi2); - // break; - // default: - // gmove(&hi1, &hi2); - // if(hv != 0xffffffffu) - // gins(AANDL, ncon(hv), &hi2); - // break; - // } - // break; - - // case OOR: - // switch(lv) { - // case 0: - // gmove(&lo1, &lo2); - // break; - // case 0xffffffffu: - // gins(AMOVL, ncon(0xffffffffu), &lo2); - // break; - // default: - // gmove(&lo1, &lo2); - // gins(AORL, ncon(lv), &lo2); - // break; - // } - // switch(hv) { - // case 0: - // gmove(&hi1, &hi2); - // break; - // case 0xffffffffu: - // gins(AMOVL, ncon(0xffffffffu), &hi2); - // break; - // default: - // gmove(&hi1, &hi2); - // gins(AORL, ncon(hv), &hi2); - // break; - // } - // break; - // } - // splitclean(); - // splitclean(); - // goto out; - // } - case gc.OXOR, - gc.OAND, - gc.OOR: - regalloc(&n1, lo1.Type, nil) - - gins(arm.AMOVW, &lo1, &al) - gins(arm.AMOVW, &hi1, &ah) - gins(arm.AMOVW, &lo2, &n1) - gins(optoas(int(n.Op), lo1.Type), &n1, &al) - gins(arm.AMOVW, &hi2, &n1) - gins(optoas(int(n.Op), lo1.Type), &n1, &ah) - regfree(&n1) - } - - if gc.Is64(r.Type) { - splitclean() - } - splitclean() - - split64(res, &lo1, &hi1) - gins(arm.AMOVW, &al, &lo1) - gins(arm.AMOVW, &ah, &hi1) - splitclean() - - //out: - regfree(&al) - - regfree(&ah) -} - -/* - * generate comparison of nl, nr, both 64-bit. - * nl is memory; nr is constant or memory. - */ -func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) { - var lo1 gc.Node - var hi1 gc.Node - var lo2 gc.Node - var hi2 gc.Node - var r1 gc.Node - var r2 gc.Node - var br *obj.Prog - var t *gc.Type - - split64(nl, &lo1, &hi1) - split64(nr, &lo2, &hi2) - - // compare most significant word; - // if they differ, we're done. - t = hi1.Type - - regalloc(&r1, gc.Types[gc.TINT32], nil) - regalloc(&r2, gc.Types[gc.TINT32], nil) - gins(arm.AMOVW, &hi1, &r1) - gins(arm.AMOVW, &hi2, &r2) - gcmp(arm.ACMP, &r1, &r2) - regfree(&r1) - regfree(&r2) - - br = nil - switch op { - default: - gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - // cmp hi - // bne L - // cmp lo - // beq to - // L: - case gc.OEQ: - br = gc.Gbranch(arm.ABNE, nil, -likely) - - // cmp hi - // bne to - // cmp lo - // bne to - case gc.ONE: - gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to) - - // cmp hi - // bgt to - // blt L - // cmp lo - // bge to (or bgt to) - // L: - case gc.OGE, - gc.OGT: - gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) - - br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) - - // cmp hi - // blt to - // bgt L - // cmp lo - // ble to (or jlt to) - // L: - case gc.OLE, - gc.OLT: - gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) - - br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) - } - - // compare least significant word - t = lo1.Type - - regalloc(&r1, gc.Types[gc.TINT32], nil) - regalloc(&r2, gc.Types[gc.TINT32], nil) - gins(arm.AMOVW, &lo1, &r1) - gins(arm.AMOVW, &lo2, &r2) - gcmp(arm.ACMP, &r1, &r2) - regfree(&r1) - regfree(&r2) - - // jump again - gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) - - // point first branch down here if appropriate - if br != nil { - gc.Patch(br, gc.Pc) - } - - splitclean() - splitclean() -} diff --git a/src/cmd/new5g/galign.go b/src/cmd/new5g/galign.go deleted file mode 100644 index d2eeeab456..0000000000 --- a/src/cmd/new5g/galign.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" -) -import "cmd/internal/gc" - -var thechar int = '5' - -var thestring string = "arm" - -var thelinkarch *obj.LinkArch = &arm.Linkarm - -func linkarchinit() { -} - -var MAXWIDTH int64 = (1 << 32) - 1 - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -var typedefs = []gc.Typedef{ - gc.Typedef{"int", gc.TINT, gc.TINT32}, - gc.Typedef{"uint", gc.TUINT, gc.TUINT32}, - gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32}, -} - -func betypeinit() { - gc.Widthptr = 4 - gc.Widthint = 4 - gc.Widthreg = 4 - -} - -func main() { - gc.Thearch.Thechar = thechar - gc.Thearch.Thestring = thestring - gc.Thearch.Thelinkarch = thelinkarch - gc.Thearch.Typedefs = typedefs - gc.Thearch.REGSP = arm.REGSP - gc.Thearch.REGCTXT = arm.REGCTXT - gc.Thearch.MAXWIDTH = MAXWIDTH - gc.Thearch.Anyregalloc = anyregalloc - gc.Thearch.Betypeinit = betypeinit - gc.Thearch.Bgen = bgen - gc.Thearch.Cgen = cgen - gc.Thearch.Cgen_call = cgen_call - gc.Thearch.Cgen_callinter = cgen_callinter - gc.Thearch.Cgen_ret = cgen_ret - gc.Thearch.Clearfat = clearfat - gc.Thearch.Defframe = defframe - gc.Thearch.Excise = excise - gc.Thearch.Expandchecks = expandchecks - gc.Thearch.Gclean = gclean - gc.Thearch.Ginit = ginit - gc.Thearch.Gins = gins - gc.Thearch.Ginscall = ginscall - gc.Thearch.Igen = igen - gc.Thearch.Linkarchinit = linkarchinit - gc.Thearch.Peep = peep - gc.Thearch.Proginfo = proginfo - gc.Thearch.Regalloc = regalloc - gc.Thearch.Regfree = regfree - gc.Thearch.Regtyp = regtyp - gc.Thearch.Sameaddr = sameaddr - gc.Thearch.Smallindir = smallindir - gc.Thearch.Stackaddr = stackaddr - gc.Thearch.Excludedregs = excludedregs - gc.Thearch.RtoB = RtoB - gc.Thearch.FtoB = RtoB - gc.Thearch.BtoR = BtoR - gc.Thearch.BtoF = BtoF - gc.Thearch.Optoas = optoas - gc.Thearch.Doregbits = doregbits - gc.Thearch.Regnames = regnames - - gc.Main() - gc.Exit(0) -} diff --git a/src/cmd/new5g/gg.go b/src/cmd/new5g/gg.go deleted file mode 100644 index 7a7fb3b774..0000000000 --- a/src/cmd/new5g/gg.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "cmd/internal/obj/arm" - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -const ( - REGALLOC_R0 = arm.REG_R0 - REGALLOC_RMAX = arm.REGEXT - REGALLOC_F0 = arm.REG_F0 - REGALLOC_FMAX = arm.FREGEXT -) - -var reg [REGALLOC_FMAX + 1]uint8 - -/* - * cgen - */ - -/* - * list.c - */ - -/* - * reg.c - */ diff --git a/src/cmd/new5g/ggen.go b/src/cmd/new5g/ggen.go deleted file mode 100644 index 3b007d8484..0000000000 --- a/src/cmd/new5g/ggen.go +++ /dev/null @@ -1,822 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" -) -import "cmd/internal/gc" - -func defframe(ptxt *obj.Prog) { - var frame uint32 - var r0 uint32 - var p *obj.Prog - var hi int64 - var lo int64 - var l *gc.NodeList - var n *gc.Node - - // fill in argument size, stack size - ptxt.To.Type = obj.TYPE_TEXTSIZE - - ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) - frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) - ptxt.To.Offset = int64(frame) - - // insert code to contain ambiguously live variables - // so that garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt - - hi = 0 - lo = hi - r0 = 0 - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - n = l.N - if n.Needzero == 0 { - continue - } - if n.Class != gc.PAUTO { - gc.Fatal("needzero class %d", n.Class) - } - if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { - gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) - } - if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthptr) { - // merge with range we already have - lo = gc.Rnd(n.Xoffset, int64(gc.Widthptr)) - - continue - } - - // zero old range - p = zerorange(p, int64(frame), lo, hi, &r0) - - // set new range - hi = n.Xoffset + n.Type.Width - - lo = n.Xoffset - } - - // zero final range - zerorange(p, int64(frame), lo, hi, &r0) -} - -func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Prog { - var cnt int64 - var i int64 - var p1 *obj.Prog - var f *gc.Node - - cnt = hi - lo - if cnt == 0 { - return p - } - if *r0 == 0 { - p = appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0) - *r0 = 1 - } - - if cnt < int64(4*gc.Widthptr) { - for i = 0; i < cnt; i += int64(gc.Widthptr) { - p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, int32(4+frame+lo+i)) - } - } else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) { - p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0) - p.Reg = arm.REGSP - p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) - f = gc.Sysfunc("duffzero") - gc.Naddr(f, &p.To, 1) - gc.Afunclit(&p.To, f) - p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) - } else { - p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0) - p.Reg = arm.REGSP - p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(cnt), obj.TYPE_REG, arm.REG_R2, 0) - p.Reg = arm.REG_R1 - p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4) - p1 = p - p.Scond |= arm.C_PBIT - p = appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0) - p.Reg = arm.REG_R2 - p = appendpp(p, arm.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0) - gc.Patch(p, p1) - } - - return p -} - -func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int32, ttype int, treg int, toffset int32) *obj.Prog { - var q *obj.Prog - - q = gc.Ctxt.NewProg() - gc.Clearp(q) - q.As = int16(as) - q.Lineno = p.Lineno - q.From.Type = int16(ftype) - q.From.Reg = int16(freg) - q.From.Offset = int64(foffset) - q.To.Type = int16(ttype) - q.To.Reg = int16(treg) - q.To.Offset = int64(toffset) - q.Link = p.Link - p.Link = q - return q -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) -*/ -func ginscall(f *gc.Node, proc int) { - var p *obj.Prog - var r gc.Node - var r1 gc.Node - var con gc.Node - var extra int32 - - if f.Type != nil { - extra = 0 - if proc == 1 || proc == 2 { - extra = 2 * int32(gc.Widthptr) - } - gc.Setmaxarg(f.Type, extra) - } - - switch proc { - default: - gc.Fatal("ginscall: bad proc %d", proc) - - case 0, // normal call - -1: // normal call but no return - if f.Op == gc.ONAME && f.Class == gc.PFUNC { - if f == gc.Deferreturn { - // Deferred calls will appear to be returning to - // the BL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction before that return PC. - // To avoid that instruction being an unrelated instruction, - // insert a NOP so that we will have the right line number. - // ARM NOP 0x00000000 is really AND.EQ R0, R0, R0. - // Use the latter form because the NOP pseudo-instruction - // would be removed by the linker. - gc.Nodreg(&r, gc.Types[gc.TINT], arm.REG_R0) - - p = gins(arm.AAND, &r, &r) - p.Scond = arm.C_SCOND_EQ - } - - p = gins(arm.ABL, nil, f) - gc.Afunclit(&p.To, f) - if proc == -1 || gc.Noreturn(p) { - gins(obj.AUNDEF, nil, nil) - } - break - } - - gc.Nodreg(&r, gc.Types[gc.Tptr], arm.REG_R7) - gc.Nodreg(&r1, gc.Types[gc.Tptr], arm.REG_R1) - gmove(f, &r) - r.Op = gc.OINDREG - gmove(&r, &r1) - r.Op = gc.OREGISTER - r1.Op = gc.OINDREG - gins(arm.ABL, &r, &r1) - - case 3: // normal call of c function pointer - gins(arm.ABL, nil, f) - - case 1, // call in new proc (go) - 2: // deferred call (defer) - regalloc(&r, gc.Types[gc.Tptr], nil) - - gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type))) - gins(arm.AMOVW, &con, &r) - p = gins(arm.AMOVW, &r, nil) - p.To.Type = obj.TYPE_MEM - p.To.Reg = arm.REGSP - p.To.Offset = 4 - - gins(arm.AMOVW, f, &r) - p = gins(arm.AMOVW, &r, nil) - p.To.Type = obj.TYPE_MEM - p.To.Reg = arm.REGSP - p.To.Offset = 8 - - regfree(&r) - - if proc == 1 { - ginscall(gc.Newproc, 0) - } else { - ginscall(gc.Deferproc, 0) - } - - if proc == 2 { - gc.Nodconst(&con, gc.Types[gc.TINT32], 0) - p = gins(arm.ACMP, &con, nil) - p.Reg = arm.REG_R0 - p = gc.Gbranch(arm.ABEQ, nil, +1) - cgen_ret(nil) - gc.Patch(p, gc.Pc) - } - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { - var r int - var i *gc.Node - var f *gc.Node - var tmpi gc.Node - var nodo gc.Node - var nodr gc.Node - var nodsp gc.Node - var p *obj.Prog - - i = n.Left - if i.Op != gc.ODOTINTER { - gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) - } - - f = i.Right // field - if f.Op != gc.ONAME { - gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) - } - - i = i.Left // interface - - // Release res register during genlist and cgen, - // which might have their own function calls. - r = -1 - - if res != nil && (res.Op == gc.OREGISTER || res.Op == gc.OINDREG) { - r = int(res.Val.U.Reg) - reg[r]-- - } - - if i.Addable == 0 { - gc.Tempname(&tmpi, i.Type) - cgen(i, &tmpi) - i = &tmpi - } - - gc.Genlist(n.List) // args - if r >= 0 { - reg[r]++ - } - - regalloc(&nodr, gc.Types[gc.Tptr], res) - regalloc(&nodo, gc.Types[gc.Tptr], &nodr) - nodo.Op = gc.OINDREG - - agen(i, &nodr) // REG = &inter - - gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], arm.REGSP) - - nodsp.Xoffset = int64(gc.Widthptr) - if proc != 0 { - nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn - } - nodo.Xoffset += int64(gc.Widthptr) - cgen(&nodo, &nodsp) // {4 or 12}(SP) = 4(REG) -- i.data - - nodo.Xoffset -= int64(gc.Widthptr) - - cgen(&nodo, &nodr) // REG = 0(REG) -- i.tab - gc.Cgen_checknil(&nodr) // in case offset is huge - - nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 - - if proc == 0 { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] - nodr.Op = gc.OINDREG - proc = 3 - } else { - // go/defer. generate go func value. - p = gins(arm.AMOVW, &nodo, &nodr) - - p.From.Type = obj.TYPE_ADDR // REG = &(20+offset(REG)) -- i.tab->fun[f] - } - - nodr.Type = n.Left.Type - ginscall(&nodr, proc) - - regfree(&nodr) - regfree(&nodo) -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -func cgen_call(n *gc.Node, proc int) { - var t *gc.Type - var nod gc.Node - var afun gc.Node - - if n == nil { - return - } - - if n.Left.Ullman >= gc.UINF { - // if name involves a fn call - // precompute the address of the fn - gc.Tempname(&afun, gc.Types[gc.Tptr]) - - cgen(n.Left, &afun) - } - - gc.Genlist(n.List) // assign the args - t = n.Left.Type - - // call tempname pointer - if n.Left.Ullman >= gc.UINF { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, &afun) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - goto ret - } - - // call pointer - if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, n.Left) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - goto ret - } - - // call direct - n.Left.Method = 1 - - ginscall(n.Left, proc) - -ret: -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -func cgen_callret(n *gc.Node, res *gc.Node) { - var nod gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_callret: nil") - } - - nod = gc.Node{} - nod.Op = gc.OINDREG - nod.Val.U.Reg = arm.REGSP - nod.Addable = 1 - - nod.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP) - nod.Type = fp.Type - gc.Cgen_as(res, &nod) -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -func cgen_aret(n *gc.Node, res *gc.Node) { - var nod1 gc.Node - var nod2 gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_aret: nil") - } - - nod1 = gc.Node{} - nod1.Op = gc.OINDREG - nod1.Val.U.Reg = arm.REGSP - nod1.Addable = 1 - - nod1.Xoffset = fp.Width + 4 // +4: saved lr at 0(SP) - nod1.Type = fp.Type - - if res.Op != gc.OREGISTER { - regalloc(&nod2, gc.Types[gc.Tptr], res) - agen(&nod1, &nod2) - gins(arm.AMOVW, &nod2, res) - regfree(&nod2) - } else { - agen(&nod1, res) - } -} - -/* - * generate return. - * n->left is assignments to return values. - */ -func cgen_ret(n *gc.Node) { - var p *obj.Prog - - if n != nil { - gc.Genlist(n.List) // copy out args - } - if gc.Hasdefer != 0 { - ginscall(gc.Deferreturn, 0) - } - gc.Genlist(gc.Curfn.Exit) - p = gins(obj.ARET, nil, nil) - if n != nil && n.Op == gc.ORETJMP { - p.To.Name = obj.NAME_EXTERN - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(n.Left.Sym) - } -} - -/* - * generate high multiply - * res = (nl * nr) >> wordsize - */ -func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { - var w int - var n1 gc.Node - var n2 gc.Node - var tmp *gc.Node - var t *gc.Type - var p *obj.Prog - - if nl.Ullman < nr.Ullman { - tmp = nl - nl = nr - nr = tmp - } - - t = nl.Type - w = int(t.Width * 8) - regalloc(&n1, t, res) - cgen(nl, &n1) - regalloc(&n2, t, nil) - cgen(nr, &n2) - switch gc.Simtype[t.Etype] { - case gc.TINT8, - gc.TINT16: - gins(optoas(gc.OMUL, t), &n2, &n1) - gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1) - - case gc.TUINT8, - gc.TUINT16: - gins(optoas(gc.OMUL, t), &n2, &n1) - gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(w), &n1) - - // perform a long multiplication. - case gc.TINT32, - gc.TUINT32: - if gc.Issigned[t.Etype] != 0 { - p = gins(arm.AMULL, &n2, nil) - } else { - p = gins(arm.AMULLU, &n2, nil) - } - - // n2 * n1 -> (n1 n2) - p.Reg = n1.Val.U.Reg - - p.To.Type = obj.TYPE_REGREG - p.To.Reg = n1.Val.U.Reg - p.To.Offset = int64(n2.Val.U.Reg) - - default: - gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0)) - } - - cgen(&n1, res) - regfree(&n1) - regfree(&n2) -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var nt gc.Node - var t gc.Node - var lo gc.Node - var hi gc.Node - var w int - var v int - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var tr *gc.Type - var sc uint64 - - if nl.Type.Width > 4 { - gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0)) - } - - w = int(nl.Type.Width * 8) - - if op == gc.OLROT { - v = int(gc.Mpgetfix(nr.Val.U.Xval)) - regalloc(&n1, nl.Type, res) - if w == 32 { - cgen(nl, &n1) - gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1) - } else { - regalloc(&n2, nl.Type, nil) - cgen(nl, &n2) - gshift(arm.AMOVW, &n2, arm.SHIFT_LL, int32(v), &n1) - gshift(arm.AORR, &n2, arm.SHIFT_LR, int32(w)-int32(v), &n1) - regfree(&n2) - - // Ensure sign/zero-extended result. - gins(optoas(gc.OAS, nl.Type), &n1, &n1) - } - - gmove(&n1, res) - regfree(&n1) - return - } - - if nr.Op == gc.OLITERAL { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if sc == 0 { - } else // nothing to do - if sc >= uint64(nl.Type.Width*8) { - if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { - gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1) - } else { - gins(arm.AEOR, &n1, &n1) - } - } else { - if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { - gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(sc), &n1) - } else if op == gc.ORSH { - gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(sc), &n1) // OLSH - } else { - gshift(arm.AMOVW, &n1, arm.SHIFT_LL, int32(sc), &n1) - } - } - - if w < 32 && op == gc.OLSH { - gins(optoas(gc.OAS, nl.Type), &n1, &n1) - } - gmove(&n1, res) - regfree(&n1) - return - } - - tr = nr.Type - if tr.Width > 4 { - gc.Tempname(&nt, nr.Type) - if nl.Ullman >= nr.Ullman { - regalloc(&n2, nl.Type, res) - cgen(nl, &n2) - cgen(nr, &nt) - n1 = nt - } else { - cgen(nr, &nt) - regalloc(&n2, nl.Type, res) - cgen(nl, &n2) - } - - split64(&nt, &lo, &hi) - regalloc(&n1, gc.Types[gc.TUINT32], nil) - regalloc(&n3, gc.Types[gc.TUINT32], nil) - gmove(&lo, &n1) - gmove(&hi, &n3) - splitclean() - gins(arm.ATST, &n3, nil) - gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w)) - p1 = gins(arm.AMOVW, &t, &n1) - p1.Scond = arm.C_SCOND_NE - tr = gc.Types[gc.TUINT32] - regfree(&n3) - } else { - if nl.Ullman >= nr.Ullman { - regalloc(&n2, nl.Type, res) - cgen(nl, &n2) - regalloc(&n1, nr.Type, nil) - cgen(nr, &n1) - } else { - regalloc(&n1, nr.Type, nil) - cgen(nr, &n1) - regalloc(&n2, nl.Type, res) - cgen(nl, &n2) - } - } - - // test for shift being 0 - gins(arm.ATST, &n1, nil) - - p3 = gc.Gbranch(arm.ABEQ, nil, -1) - - // test and fix up large shifts - // TODO: if(!bounded), don't emit some of this. - regalloc(&n3, tr, nil) - - gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w)) - gmove(&t, &n3) - gcmp(arm.ACMP, &n1, &n3) - if op == gc.ORSH { - if gc.Issigned[nl.Type.Etype] != 0 { - p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2) - p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2) - } else { - p1 = gins(arm.AEOR, &n2, &n2) - p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LR, &n1, &n2) - } - - p1.Scond = arm.C_SCOND_HS - p2.Scond = arm.C_SCOND_LO - } else { - p1 = gins(arm.AEOR, &n2, &n2) - p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LL, &n1, &n2) - p1.Scond = arm.C_SCOND_HS - p2.Scond = arm.C_SCOND_LO - } - - regfree(&n3) - - gc.Patch(p3, gc.Pc) - - // Left-shift of smaller word must be sign/zero-extended. - if w < 32 && op == gc.OLSH { - gins(optoas(gc.OAS, nl.Type), &n2, &n2) - } - gmove(&n2, res) - - regfree(&n1) - regfree(&n2) -} - -func clearfat(nl *gc.Node) { - var w uint32 - var c uint32 - var q uint32 - var dst gc.Node - var nc gc.Node - var nz gc.Node - var end gc.Node - var r0 gc.Node - var r1 gc.Node - var f *gc.Node - var p *obj.Prog - var pl *obj.Prog - - /* clear a fat object */ - if gc.Debug['g'] != 0 { - gc.Dump("\nclearfat", nl) - } - - w = uint32(nl.Type.Width) - - // Avoid taking the address for simple enough types. - if componentgen(nil, nl) { - return - } - - c = w % 4 // bytes - q = w / 4 // quads - - r0.Op = gc.OREGISTER - - r0.Val.U.Reg = REGALLOC_R0 - r1.Op = gc.OREGISTER - r1.Val.U.Reg = REGALLOC_R0 + 1 - regalloc(&dst, gc.Types[gc.Tptr], &r1) - agen(nl, &dst) - gc.Nodconst(&nc, gc.Types[gc.TUINT32], 0) - regalloc(&nz, gc.Types[gc.TUINT32], &r0) - cgen(&nc, &nz) - - if q > 128 { - regalloc(&end, gc.Types[gc.Tptr], nil) - p = gins(arm.AMOVW, &dst, &end) - p.From.Type = obj.TYPE_ADDR - p.From.Offset = int64(q) * 4 - - p = gins(arm.AMOVW, &nz, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = 4 - p.Scond |= arm.C_PBIT - pl = p - - p = gins(arm.ACMP, &dst, nil) - raddr(&end, p) - gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl) - - regfree(&end) - } else if q >= 4 && !gc.Nacl { - f = gc.Sysfunc("duffzero") - p = gins(obj.ADUFFZERO, nil, f) - gc.Afunclit(&p.To, f) - - // 4 and 128 = magic constants: see ../../runtime/asm_arm.s - p.To.Offset = 4 * (128 - int64(q)) - } else { - for q > 0 { - p = gins(arm.AMOVW, &nz, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = 4 - p.Scond |= arm.C_PBIT - - //print("1. %P\n", p); - q-- - } - } - - for c > 0 { - p = gins(arm.AMOVB, &nz, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = 1 - p.Scond |= arm.C_PBIT - - //print("2. %P\n", p); - c-- - } - - regfree(&dst) - regfree(&nz) -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -func expandchecks(firstp *obj.Prog) { - var reg int - var p *obj.Prog - var p1 *obj.Prog - - for p = firstp; p != nil; p = p.Link { - if p.As != obj.ACHECKNIL { - continue - } - if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers - gc.Warnl(int(p.Lineno), "generated nil check") - } - if p.From.Type != obj.TYPE_REG { - gc.Fatal("invalid nil check %v", p) - } - reg = int(p.From.Reg) - - // check is - // CMP arg, $0 - // MOV.EQ arg, 0(arg) - p1 = gc.Ctxt.NewProg() - - gc.Clearp(p1) - p1.Link = p.Link - p.Link = p1 - p1.Lineno = p.Lineno - p1.Pc = 9999 - p1.As = arm.AMOVW - p1.From.Type = obj.TYPE_REG - p1.From.Reg = int16(reg) - p1.To.Type = obj.TYPE_MEM - p1.To.Reg = int16(reg) - p1.To.Offset = 0 - p1.Scond = arm.C_SCOND_EQ - p.As = arm.ACMP - p.From.Type = obj.TYPE_CONST - p.From.Reg = 0 - p.From.Offset = 0 - p.Reg = int16(reg) - } -} diff --git a/src/cmd/new5g/gsubr.go b/src/cmd/new5g/gsubr.go deleted file mode 100644 index 857bafaf64..0000000000 --- a/src/cmd/new5g/gsubr.go +++ /dev/null @@ -1,1599 +0,0 @@ -// Derived from Inferno utils/5c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" - "fmt" -) -import "cmd/internal/gc" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 5l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -var unmappedzero int = 4096 - -var resvd = []int{ - 9, // reserved for m - 10, // reserved for g - arm.REGSP, // reserved for SP -} - -func ginit() { - var i int - - for i = 0; i < len(reg); i++ { - reg[i] = 0 - } - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]++ - } -} - -func gclean() { - var i int - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]-- - } - - for i = 0; i < len(reg); i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) - } - } -} - -func anyregalloc() bool { - var i int - var j int - - for i = 0; i < len(reg); i++ { - if reg[i] == 0 { - goto ok - } - for j = 0; j < len(resvd); j++ { - if resvd[j] == i { - goto ok - } - } - return true - ok: - } - - return false -} - -var regpc [REGALLOC_FMAX + 1]uint32 - -/* - * allocate register of type t, leave in n. - * if o != N, o is desired fixed register. - * caller must regfree(n). - */ -func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { - var i int - var et int - var fixfree int - var floatfree int - - if false && gc.Debug['r'] != 0 { - fixfree = 0 - for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { - if reg[i] == 0 { - fixfree++ - } - } - floatfree = 0 - for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { - if reg[i] == 0 { - floatfree++ - } - } - fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree) - } - - if t == nil { - gc.Fatal("regalloc: t nil") - } - et = int(gc.Simtype[t.Etype]) - if gc.Is64(t) { - gc.Fatal("regalloc: 64 bit type %v") - } - - switch et { - case gc.TINT8, - gc.TUINT8, - gc.TINT16, - gc.TUINT16, - gc.TINT32, - gc.TUINT32, - gc.TPTR32, - gc.TBOOL: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= REGALLOC_R0 && i <= REGALLOC_RMAX { - goto out - } - } - - for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { - if reg[i] == 0 { - regpc[i] = uint32(obj.Getcallerpc(&n)) - goto out - } - } - - fmt.Printf("registers allocated at\n") - for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { - fmt.Printf("%d %p\n", i, regpc[i]) - } - gc.Fatal("out of fixed registers") - goto err - - case gc.TFLOAT32, - gc.TFLOAT64: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= REGALLOC_F0 && i <= REGALLOC_FMAX { - goto out - } - } - - for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { - if reg[i] == 0 { - goto out - } - } - gc.Fatal("out of floating point registers") - goto err - - case gc.TCOMPLEX64, - gc.TCOMPLEX128: - gc.Tempname(n, t) - return - } - - gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0)) - -err: - gc.Nodreg(n, t, arm.REG_R0) - return - -out: - reg[i]++ - gc.Nodreg(n, t, i) -} - -func regfree(n *gc.Node) { - var i int - var fixfree int - var floatfree int - - if false && gc.Debug['r'] != 0 { - fixfree = 0 - for i = REGALLOC_R0; i <= REGALLOC_RMAX; i++ { - if reg[i] == 0 { - fixfree++ - } - } - floatfree = 0 - for i = REGALLOC_F0; i <= REGALLOC_FMAX; i++ { - if reg[i] == 0 { - floatfree++ - } - } - fmt.Printf("regalloc fix %d float %d\n", fixfree, floatfree) - } - - if n.Op == gc.ONAME { - return - } - if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { - gc.Fatal("regfree: not a register") - } - i = int(n.Val.U.Reg) - if i == arm.REGSP { - return - } - if i < 0 || i >= len(reg) || i >= len(regpc) { - gc.Fatal("regfree: reg out of range") - } - if reg[i] <= 0 { - gc.Fatal("regfree: reg %v not allocated", gc.Ctxt.Rconv(i)) - } - reg[i]-- - if reg[i] == 0 { - regpc[i] = 0 - } -} - -/* - * return constant i node. - * overwritten by next call, but useful in calls to gins. - */ - -var ncon_n gc.Node - -func ncon(i uint32) *gc.Node { - if ncon_n.Type == nil { - gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) - } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) - return &ncon_n -} - -var sclean [10]gc.Node - -var nsclean int - -/* - * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. - */ -func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { - var n1 gc.Node - var i int64 - - if !gc.Is64(n.Type) { - gc.Fatal("split64 %v", gc.Tconv(n.Type, 0)) - } - - if nsclean >= len(sclean) { - gc.Fatal("split64 clean") - } - sclean[nsclean].Op = gc.OEMPTY - nsclean++ - switch n.Op { - default: - switch n.Op { - default: - if !dotaddable(n, &n1) { - igen(n, &n1, nil) - sclean[nsclean-1] = n1 - } - - n = &n1 - - case gc.ONAME: - if n.Class == gc.PPARAMREF { - cgen(n.Heapaddr, &n1) - sclean[nsclean-1] = n1 - n = &n1 - } - - // nothing - case gc.OINDREG: - break - } - - *lo = *n - *hi = *n - lo.Type = gc.Types[gc.TUINT32] - if n.Type.Etype == gc.TINT64 { - hi.Type = gc.Types[gc.TINT32] - } else { - hi.Type = gc.Types[gc.TUINT32] - } - hi.Xoffset += 4 - - case gc.OLITERAL: - gc.Convconst(&n1, n.Type, &n.Val) - i = gc.Mpgetfix(n1.Val.U.Xval) - gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) - i >>= 32 - if n.Type.Etype == gc.TINT64 { - gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i))) - } else { - gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i))) - } - } -} - -func splitclean() { - if nsclean <= 0 { - gc.Fatal("splitclean") - } - nsclean-- - if sclean[nsclean].Op != gc.OEMPTY { - regfree(&sclean[nsclean]) - } -} - -func gmove(f *gc.Node, t *gc.Node) { - var a int - var ft int - var tt int - var fa int - var ta int - var cvt *gc.Type - var r1 gc.Node - var r2 gc.Node - var flo gc.Node - var fhi gc.Node - var tlo gc.Node - var thi gc.Node - var con gc.Node - var p1 *obj.Prog - - if gc.Debug['M'] != 0 { - fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0)) - } - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { - gc.Complexmove(f, t) - return - } - - // cannot have two memory operands; - // except 64-bit, which always copies via registers anyway. - if !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - - // convert constant to desired type - if f.Op == gc.OLITERAL { - switch tt { - default: - gc.Convconst(&con, t.Type, &f.Val) - - case gc.TINT16, - gc.TINT8: - gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val) - regalloc(&r1, con.Type, t) - gins(arm.AMOVW, &con, &r1) - gmove(&r1, t) - regfree(&r1) - return - - case gc.TUINT16, - gc.TUINT8: - gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val) - regalloc(&r1, con.Type, t) - gins(arm.AMOVW, &con, &r1) - gmove(&r1, t) - regfree(&r1) - return - } - - f = &con - ft = gc.Simsimtype(con.Type) - - // constants can't move directly to memory - if gc.Ismem(t) && !gc.Is64(t.Type) { - goto hard - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch uint32(ft)<<16 | uint32(tt) { - default: - goto fatal - - /* - * integer copy and truncate - */ - case gc.TINT8<<16 | gc.TINT8: // same size - if !gc.Ismem(f) { - a = arm.AMOVB - break - } - fallthrough - - case gc.TUINT8<<16 | gc.TINT8, - gc.TINT16<<16 | gc.TINT8, // truncate - gc.TUINT16<<16 | gc.TINT8, - gc.TINT32<<16 | gc.TINT8, - gc.TUINT32<<16 | gc.TINT8: - a = arm.AMOVBS - - case gc.TUINT8<<16 | gc.TUINT8: - if !gc.Ismem(f) { - a = arm.AMOVB - break - } - fallthrough - - case gc.TINT8<<16 | gc.TUINT8, - gc.TINT16<<16 | gc.TUINT8, - gc.TUINT16<<16 | gc.TUINT8, - gc.TINT32<<16 | gc.TUINT8, - gc.TUINT32<<16 | gc.TUINT8: - a = arm.AMOVBU - - case gc.TINT64<<16 | gc.TINT8, // truncate low word - gc.TUINT64<<16 | gc.TINT8: - a = arm.AMOVBS - - goto trunc64 - - case gc.TINT64<<16 | gc.TUINT8, - gc.TUINT64<<16 | gc.TUINT8: - a = arm.AMOVBU - goto trunc64 - - case gc.TINT16<<16 | gc.TINT16: // same size - if !gc.Ismem(f) { - a = arm.AMOVH - break - } - fallthrough - - case gc.TUINT16<<16 | gc.TINT16, - gc.TINT32<<16 | gc.TINT16, // truncate - gc.TUINT32<<16 | gc.TINT16: - a = arm.AMOVHS - - case gc.TUINT16<<16 | gc.TUINT16: - if !gc.Ismem(f) { - a = arm.AMOVH - break - } - fallthrough - - case gc.TINT16<<16 | gc.TUINT16, - gc.TINT32<<16 | gc.TUINT16, - gc.TUINT32<<16 | gc.TUINT16: - a = arm.AMOVHU - - case gc.TINT64<<16 | gc.TINT16, // truncate low word - gc.TUINT64<<16 | gc.TINT16: - a = arm.AMOVHS - - goto trunc64 - - case gc.TINT64<<16 | gc.TUINT16, - gc.TUINT64<<16 | gc.TUINT16: - a = arm.AMOVHU - goto trunc64 - - case gc.TINT32<<16 | gc.TINT32, // same size - gc.TINT32<<16 | gc.TUINT32, - gc.TUINT32<<16 | gc.TINT32, - gc.TUINT32<<16 | gc.TUINT32: - a = arm.AMOVW - - case gc.TINT64<<16 | gc.TINT32, // truncate - gc.TUINT64<<16 | gc.TINT32, - gc.TINT64<<16 | gc.TUINT32, - gc.TUINT64<<16 | gc.TUINT32: - split64(f, &flo, &fhi) - - regalloc(&r1, t.Type, nil) - gins(arm.AMOVW, &flo, &r1) - gins(arm.AMOVW, &r1, t) - regfree(&r1) - splitclean() - return - - case gc.TINT64<<16 | gc.TINT64, // same size - gc.TINT64<<16 | gc.TUINT64, - gc.TUINT64<<16 | gc.TINT64, - gc.TUINT64<<16 | gc.TUINT64: - split64(f, &flo, &fhi) - - split64(t, &tlo, &thi) - regalloc(&r1, flo.Type, nil) - regalloc(&r2, fhi.Type, nil) - gins(arm.AMOVW, &flo, &r1) - gins(arm.AMOVW, &fhi, &r2) - gins(arm.AMOVW, &r1, &tlo) - gins(arm.AMOVW, &r2, &thi) - regfree(&r1) - regfree(&r2) - splitclean() - splitclean() - return - - /* - * integer up-conversions - */ - case gc.TINT8<<16 | gc.TINT16, // sign extend int8 - gc.TINT8<<16 | gc.TUINT16, - gc.TINT8<<16 | gc.TINT32, - gc.TINT8<<16 | gc.TUINT32: - a = arm.AMOVBS - - goto rdst - - case gc.TINT8<<16 | gc.TINT64, // convert via int32 - gc.TINT8<<16 | gc.TUINT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 - gc.TUINT8<<16 | gc.TUINT16, - gc.TUINT8<<16 | gc.TINT32, - gc.TUINT8<<16 | gc.TUINT32: - a = arm.AMOVBU - - goto rdst - - case gc.TUINT8<<16 | gc.TINT64, // convert via uint32 - gc.TUINT8<<16 | gc.TUINT64: - cvt = gc.Types[gc.TUINT32] - - goto hard - - case gc.TINT16<<16 | gc.TINT32, // sign extend int16 - gc.TINT16<<16 | gc.TUINT32: - a = arm.AMOVHS - - goto rdst - - case gc.TINT16<<16 | gc.TINT64, // convert via int32 - gc.TINT16<<16 | gc.TUINT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 - gc.TUINT16<<16 | gc.TUINT32: - a = arm.AMOVHU - - goto rdst - - case gc.TUINT16<<16 | gc.TINT64, // convert via uint32 - gc.TUINT16<<16 | gc.TUINT64: - cvt = gc.Types[gc.TUINT32] - - goto hard - - case gc.TINT32<<16 | gc.TINT64, // sign extend int32 - gc.TINT32<<16 | gc.TUINT64: - split64(t, &tlo, &thi) - - regalloc(&r1, tlo.Type, nil) - regalloc(&r2, thi.Type, nil) - gmove(f, &r1) - p1 = gins(arm.AMOVW, &r1, &r2) - p1.From.Type = obj.TYPE_SHIFT - p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Val.U.Reg)&15 // r1->31 - p1.From.Reg = 0 - - //print("gmove: %P\n", p1); - gins(arm.AMOVW, &r1, &tlo) - - gins(arm.AMOVW, &r2, &thi) - regfree(&r1) - regfree(&r2) - splitclean() - return - - case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 - gc.TUINT32<<16 | gc.TUINT64: - split64(t, &tlo, &thi) - - gmove(f, &tlo) - regalloc(&r1, thi.Type, nil) - gins(arm.AMOVW, ncon(0), &r1) - gins(arm.AMOVW, &r1, &thi) - regfree(&r1) - splitclean() - return - - // case CASE(TFLOAT64, TUINT64): - /* - * float to integer - */ - case gc.TFLOAT32<<16 | gc.TINT8, - gc.TFLOAT32<<16 | gc.TUINT8, - gc.TFLOAT32<<16 | gc.TINT16, - gc.TFLOAT32<<16 | gc.TUINT16, - gc.TFLOAT32<<16 | gc.TINT32, - gc.TFLOAT32<<16 | gc.TUINT32, - - // case CASE(TFLOAT32, TUINT64): - - gc.TFLOAT64<<16 | gc.TINT8, - gc.TFLOAT64<<16 | gc.TUINT8, - gc.TFLOAT64<<16 | gc.TINT16, - gc.TFLOAT64<<16 | gc.TUINT16, - gc.TFLOAT64<<16 | gc.TINT32, - gc.TFLOAT64<<16 | gc.TUINT32: - fa = arm.AMOVF - - a = arm.AMOVFW - if ft == gc.TFLOAT64 { - fa = arm.AMOVD - a = arm.AMOVDW - } - - ta = arm.AMOVW - switch tt { - case gc.TINT8: - ta = arm.AMOVBS - - case gc.TUINT8: - ta = arm.AMOVBU - - case gc.TINT16: - ta = arm.AMOVHS - - case gc.TUINT16: - ta = arm.AMOVHU - } - - regalloc(&r1, gc.Types[ft], f) - regalloc(&r2, gc.Types[tt], t) - gins(fa, f, &r1) // load to fpu - p1 = gins(a, &r1, &r1) // convert to w - switch tt { - case gc.TUINT8, - gc.TUINT16, - gc.TUINT32: - p1.Scond |= arm.C_UBIT - } - - gins(arm.AMOVW, &r1, &r2) // copy to cpu - gins(ta, &r2, t) // store - regfree(&r1) - regfree(&r2) - return - - /* - * integer to float - */ - case gc.TINT8<<16 | gc.TFLOAT32, - gc.TUINT8<<16 | gc.TFLOAT32, - gc.TINT16<<16 | gc.TFLOAT32, - gc.TUINT16<<16 | gc.TFLOAT32, - gc.TINT32<<16 | gc.TFLOAT32, - gc.TUINT32<<16 | gc.TFLOAT32, - gc.TINT8<<16 | gc.TFLOAT64, - gc.TUINT8<<16 | gc.TFLOAT64, - gc.TINT16<<16 | gc.TFLOAT64, - gc.TUINT16<<16 | gc.TFLOAT64, - gc.TINT32<<16 | gc.TFLOAT64, - gc.TUINT32<<16 | gc.TFLOAT64: - fa = arm.AMOVW - - switch ft { - case gc.TINT8: - fa = arm.AMOVBS - - case gc.TUINT8: - fa = arm.AMOVBU - - case gc.TINT16: - fa = arm.AMOVHS - - case gc.TUINT16: - fa = arm.AMOVHU - } - - a = arm.AMOVWF - ta = arm.AMOVF - if tt == gc.TFLOAT64 { - a = arm.AMOVWD - ta = arm.AMOVD - } - - regalloc(&r1, gc.Types[ft], f) - regalloc(&r2, gc.Types[tt], t) - gins(fa, f, &r1) // load to cpu - gins(arm.AMOVW, &r1, &r2) // copy to fpu - p1 = gins(a, &r2, &r2) // convert - switch ft { - case gc.TUINT8, - gc.TUINT16, - gc.TUINT32: - p1.Scond |= arm.C_UBIT - } - - gins(ta, &r2, t) // store - regfree(&r1) - regfree(&r2) - return - - case gc.TUINT64<<16 | gc.TFLOAT32, - gc.TUINT64<<16 | gc.TFLOAT64: - gc.Fatal("gmove UINT64, TFLOAT not implemented") - return - - /* - * float to float - */ - case gc.TFLOAT32<<16 | gc.TFLOAT32: - a = arm.AMOVF - - case gc.TFLOAT64<<16 | gc.TFLOAT64: - a = arm.AMOVD - - case gc.TFLOAT32<<16 | gc.TFLOAT64: - regalloc(&r1, gc.Types[gc.TFLOAT64], t) - gins(arm.AMOVF, f, &r1) - gins(arm.AMOVFD, &r1, &r1) - gins(arm.AMOVD, &r1, t) - regfree(&r1) - return - - case gc.TFLOAT64<<16 | gc.TFLOAT32: - regalloc(&r1, gc.Types[gc.TFLOAT64], t) - gins(arm.AMOVD, f, &r1) - gins(arm.AMOVDF, &r1, &r1) - gins(arm.AMOVF, &r1, t) - regfree(&r1) - return - } - - gins(a, f, t) - return - - // TODO(kaib): we almost always require a register dest anyway, this can probably be - // removed. - // requires register destination -rdst: - regalloc(&r1, t.Type, t) - - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // truncate 64 bit integer -trunc64: - split64(f, &flo, &fhi) - - regalloc(&r1, t.Type, nil) - gins(a, &flo, &r1) - gins(a, &r1, t) - regfree(&r1) - splitclean() - return - - // should not happen -fatal: - gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) -} - -func samaddr(f *gc.Node, t *gc.Node) bool { - if f.Op != t.Op { - return false - } - - switch f.Op { - case gc.OREGISTER: - if f.Val.U.Reg != t.Val.U.Reg { - break - } - return true - } - - return false -} - -/* - * generate one instruction: - * as f, t - */ -func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { - var p *obj.Prog - var af obj.Addr - // Node nod; - // int32 v; - - var at obj.Addr - - if f != nil && f.Op == gc.OINDEX { - gc.Fatal("gins OINDEX not implemented") - } - - // regalloc(&nod, ®node, Z); - // v = constnode.vconst; - // cgen(f->right, &nod); - // constnode.vconst = v; - // idx.reg = nod.reg; - // regfree(&nod); - if t != nil && t.Op == gc.OINDEX { - gc.Fatal("gins OINDEX not implemented") - } - - // regalloc(&nod, ®node, Z); - // v = constnode.vconst; - // cgen(t->right, &nod); - // constnode.vconst = v; - // idx.reg = nod.reg; - // regfree(&nod); - af = obj.Addr{} - - at = obj.Addr{} - if f != nil { - gc.Naddr(f, &af, 1) - } - if t != nil { - gc.Naddr(t, &at, 1) - } - p = gc.Prog(as) - if f != nil { - p.From = af - } - if t != nil { - p.To = at - } - if gc.Debug['g'] != 0 { - fmt.Printf("%v\n", p) - } - return p -} - -/* - * insert n into reg slot of p - */ -func raddr(n *gc.Node, p *obj.Prog) { - var a obj.Addr - - gc.Naddr(n, &a, 1) - if a.Type != obj.TYPE_REG { - if n != nil { - gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0)) - } else { - gc.Fatal("bad in raddr: ") - } - p.Reg = 0 - } else { - p.Reg = a.Reg - } -} - -/* generate a comparison -TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites. -*/ -func gcmp(as int, lhs *gc.Node, rhs *gc.Node) *obj.Prog { - var p *obj.Prog - - if lhs.Op != gc.OREGISTER { - gc.Fatal("bad operands to gcmp: %v %v", gc.Oconv(int(lhs.Op), 0), gc.Oconv(int(rhs.Op), 0)) - } - - p = gins(as, rhs, nil) - raddr(lhs, p) - return p -} - -/* generate a constant shift - * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal. - */ -func gshift(as int, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Prog { - var p *obj.Prog - - if sval <= 0 || sval > 32 { - gc.Fatal("bad shift value: %d", sval) - } - - sval = sval & 0x1f - - p = gins(as, nil, rhs) - p.From.Type = obj.TYPE_SHIFT - p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Val.U.Reg)&15 - return p -} - -/* generate a register shift - */ -func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog { - var p *obj.Prog - p = gins(as, nil, rhs) - p.From.Type = obj.TYPE_SHIFT - p.From.Offset = int64(stype) | (int64(reg.Val.U.Reg)&15)<<8 | 1<<4 | int64(lhs.Val.U.Reg)&15 - return p -} - -/* - * return Axxx for Oxxx on type t. - */ -func optoas(op int, t *gc.Type) int { - var a int - - if t == nil { - gc.Fatal("optoas: t is nil") - } - - a = obj.AXXX - switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { - default: - gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0), gc.Tconv(gc.Types[t.Etype], 0), gc.Tconv(gc.Types[gc.Simtype[t.Etype]], 0)) - - /* case CASE(OADDR, TPTR32): - a = ALEAL; - break; - - case CASE(OADDR, TPTR64): - a = ALEAQ; - break; - */ - // TODO(kaib): make sure the conditional branches work on all edge cases - case gc.OEQ<<16 | gc.TBOOL, - gc.OEQ<<16 | gc.TINT8, - gc.OEQ<<16 | gc.TUINT8, - gc.OEQ<<16 | gc.TINT16, - gc.OEQ<<16 | gc.TUINT16, - gc.OEQ<<16 | gc.TINT32, - gc.OEQ<<16 | gc.TUINT32, - gc.OEQ<<16 | gc.TINT64, - gc.OEQ<<16 | gc.TUINT64, - gc.OEQ<<16 | gc.TPTR32, - gc.OEQ<<16 | gc.TPTR64, - gc.OEQ<<16 | gc.TFLOAT32, - gc.OEQ<<16 | gc.TFLOAT64: - a = arm.ABEQ - - case gc.ONE<<16 | gc.TBOOL, - gc.ONE<<16 | gc.TINT8, - gc.ONE<<16 | gc.TUINT8, - gc.ONE<<16 | gc.TINT16, - gc.ONE<<16 | gc.TUINT16, - gc.ONE<<16 | gc.TINT32, - gc.ONE<<16 | gc.TUINT32, - gc.ONE<<16 | gc.TINT64, - gc.ONE<<16 | gc.TUINT64, - gc.ONE<<16 | gc.TPTR32, - gc.ONE<<16 | gc.TPTR64, - gc.ONE<<16 | gc.TFLOAT32, - gc.ONE<<16 | gc.TFLOAT64: - a = arm.ABNE - - case gc.OLT<<16 | gc.TINT8, - gc.OLT<<16 | gc.TINT16, - gc.OLT<<16 | gc.TINT32, - gc.OLT<<16 | gc.TINT64, - gc.OLT<<16 | gc.TFLOAT32, - gc.OLT<<16 | gc.TFLOAT64: - a = arm.ABLT - - case gc.OLT<<16 | gc.TUINT8, - gc.OLT<<16 | gc.TUINT16, - gc.OLT<<16 | gc.TUINT32, - gc.OLT<<16 | gc.TUINT64: - a = arm.ABLO - - case gc.OLE<<16 | gc.TINT8, - gc.OLE<<16 | gc.TINT16, - gc.OLE<<16 | gc.TINT32, - gc.OLE<<16 | gc.TINT64, - gc.OLE<<16 | gc.TFLOAT32, - gc.OLE<<16 | gc.TFLOAT64: - a = arm.ABLE - - case gc.OLE<<16 | gc.TUINT8, - gc.OLE<<16 | gc.TUINT16, - gc.OLE<<16 | gc.TUINT32, - gc.OLE<<16 | gc.TUINT64: - a = arm.ABLS - - case gc.OGT<<16 | gc.TINT8, - gc.OGT<<16 | gc.TINT16, - gc.OGT<<16 | gc.TINT32, - gc.OGT<<16 | gc.TINT64, - gc.OGT<<16 | gc.TFLOAT32, - gc.OGT<<16 | gc.TFLOAT64: - a = arm.ABGT - - case gc.OGT<<16 | gc.TUINT8, - gc.OGT<<16 | gc.TUINT16, - gc.OGT<<16 | gc.TUINT32, - gc.OGT<<16 | gc.TUINT64: - a = arm.ABHI - - case gc.OGE<<16 | gc.TINT8, - gc.OGE<<16 | gc.TINT16, - gc.OGE<<16 | gc.TINT32, - gc.OGE<<16 | gc.TINT64, - gc.OGE<<16 | gc.TFLOAT32, - gc.OGE<<16 | gc.TFLOAT64: - a = arm.ABGE - - case gc.OGE<<16 | gc.TUINT8, - gc.OGE<<16 | gc.TUINT16, - gc.OGE<<16 | gc.TUINT32, - gc.OGE<<16 | gc.TUINT64: - a = arm.ABHS - - case gc.OCMP<<16 | gc.TBOOL, - gc.OCMP<<16 | gc.TINT8, - gc.OCMP<<16 | gc.TUINT8, - gc.OCMP<<16 | gc.TINT16, - gc.OCMP<<16 | gc.TUINT16, - gc.OCMP<<16 | gc.TINT32, - gc.OCMP<<16 | gc.TUINT32, - gc.OCMP<<16 | gc.TPTR32: - a = arm.ACMP - - case gc.OCMP<<16 | gc.TFLOAT32: - a = arm.ACMPF - - case gc.OCMP<<16 | gc.TFLOAT64: - a = arm.ACMPD - - case gc.OAS<<16 | gc.TBOOL: - a = arm.AMOVB - - case gc.OAS<<16 | gc.TINT8: - a = arm.AMOVBS - - case gc.OAS<<16 | gc.TUINT8: - a = arm.AMOVBU - - case gc.OAS<<16 | gc.TINT16: - a = arm.AMOVHS - - case gc.OAS<<16 | gc.TUINT16: - a = arm.AMOVHU - - case gc.OAS<<16 | gc.TINT32, - gc.OAS<<16 | gc.TUINT32, - gc.OAS<<16 | gc.TPTR32: - a = arm.AMOVW - - case gc.OAS<<16 | gc.TFLOAT32: - a = arm.AMOVF - - case gc.OAS<<16 | gc.TFLOAT64: - a = arm.AMOVD - - case gc.OADD<<16 | gc.TINT8, - gc.OADD<<16 | gc.TUINT8, - gc.OADD<<16 | gc.TINT16, - gc.OADD<<16 | gc.TUINT16, - gc.OADD<<16 | gc.TINT32, - gc.OADD<<16 | gc.TUINT32, - gc.OADD<<16 | gc.TPTR32: - a = arm.AADD - - case gc.OADD<<16 | gc.TFLOAT32: - a = arm.AADDF - - case gc.OADD<<16 | gc.TFLOAT64: - a = arm.AADDD - - case gc.OSUB<<16 | gc.TINT8, - gc.OSUB<<16 | gc.TUINT8, - gc.OSUB<<16 | gc.TINT16, - gc.OSUB<<16 | gc.TUINT16, - gc.OSUB<<16 | gc.TINT32, - gc.OSUB<<16 | gc.TUINT32, - gc.OSUB<<16 | gc.TPTR32: - a = arm.ASUB - - case gc.OSUB<<16 | gc.TFLOAT32: - a = arm.ASUBF - - case gc.OSUB<<16 | gc.TFLOAT64: - a = arm.ASUBD - - case gc.OMINUS<<16 | gc.TINT8, - gc.OMINUS<<16 | gc.TUINT8, - gc.OMINUS<<16 | gc.TINT16, - gc.OMINUS<<16 | gc.TUINT16, - gc.OMINUS<<16 | gc.TINT32, - gc.OMINUS<<16 | gc.TUINT32, - gc.OMINUS<<16 | gc.TPTR32: - a = arm.ARSB - - case gc.OAND<<16 | gc.TINT8, - gc.OAND<<16 | gc.TUINT8, - gc.OAND<<16 | gc.TINT16, - gc.OAND<<16 | gc.TUINT16, - gc.OAND<<16 | gc.TINT32, - gc.OAND<<16 | gc.TUINT32, - gc.OAND<<16 | gc.TPTR32: - a = arm.AAND - - case gc.OOR<<16 | gc.TINT8, - gc.OOR<<16 | gc.TUINT8, - gc.OOR<<16 | gc.TINT16, - gc.OOR<<16 | gc.TUINT16, - gc.OOR<<16 | gc.TINT32, - gc.OOR<<16 | gc.TUINT32, - gc.OOR<<16 | gc.TPTR32: - a = arm.AORR - - case gc.OXOR<<16 | gc.TINT8, - gc.OXOR<<16 | gc.TUINT8, - gc.OXOR<<16 | gc.TINT16, - gc.OXOR<<16 | gc.TUINT16, - gc.OXOR<<16 | gc.TINT32, - gc.OXOR<<16 | gc.TUINT32, - gc.OXOR<<16 | gc.TPTR32: - a = arm.AEOR - - case gc.OLSH<<16 | gc.TINT8, - gc.OLSH<<16 | gc.TUINT8, - gc.OLSH<<16 | gc.TINT16, - gc.OLSH<<16 | gc.TUINT16, - gc.OLSH<<16 | gc.TINT32, - gc.OLSH<<16 | gc.TUINT32, - gc.OLSH<<16 | gc.TPTR32: - a = arm.ASLL - - case gc.ORSH<<16 | gc.TUINT8, - gc.ORSH<<16 | gc.TUINT16, - gc.ORSH<<16 | gc.TUINT32, - gc.ORSH<<16 | gc.TPTR32: - a = arm.ASRL - - case gc.ORSH<<16 | gc.TINT8, - gc.ORSH<<16 | gc.TINT16, - gc.ORSH<<16 | gc.TINT32: - a = arm.ASRA - - case gc.OMUL<<16 | gc.TUINT8, - gc.OMUL<<16 | gc.TUINT16, - gc.OMUL<<16 | gc.TUINT32, - gc.OMUL<<16 | gc.TPTR32: - a = arm.AMULU - - case gc.OMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TINT32: - a = arm.AMUL - - case gc.OMUL<<16 | gc.TFLOAT32: - a = arm.AMULF - - case gc.OMUL<<16 | gc.TFLOAT64: - a = arm.AMULD - - case gc.ODIV<<16 | gc.TUINT8, - gc.ODIV<<16 | gc.TUINT16, - gc.ODIV<<16 | gc.TUINT32, - gc.ODIV<<16 | gc.TPTR32: - a = arm.ADIVU - - case gc.ODIV<<16 | gc.TINT8, - gc.ODIV<<16 | gc.TINT16, - gc.ODIV<<16 | gc.TINT32: - a = arm.ADIV - - case gc.OMOD<<16 | gc.TUINT8, - gc.OMOD<<16 | gc.TUINT16, - gc.OMOD<<16 | gc.TUINT32, - gc.OMOD<<16 | gc.TPTR32: - a = arm.AMODU - - case gc.OMOD<<16 | gc.TINT8, - gc.OMOD<<16 | gc.TINT16, - gc.OMOD<<16 | gc.TINT32: - a = arm.AMOD - - // case CASE(OEXTEND, TINT16): - // a = ACWD; - // break; - - // case CASE(OEXTEND, TINT32): - // a = ACDQ; - // break; - - // case CASE(OEXTEND, TINT64): - // a = ACQO; - // break; - - case gc.ODIV<<16 | gc.TFLOAT32: - a = arm.ADIVF - - case gc.ODIV<<16 | gc.TFLOAT64: - a = arm.ADIVD - } - - return a -} - -const ( - ODynam = 1 << 0 - OPtrto = 1 << 1 -) - -var clean [20]gc.Node - -var cleani int = 0 - -func sudoclean() { - if clean[cleani-1].Op != gc.OEMPTY { - regfree(&clean[cleani-1]) - } - if clean[cleani-2].Op != gc.OEMPTY { - regfree(&clean[cleani-2]) - } - cleani -= 2 -} - -func dotaddable(n *gc.Node, n1 *gc.Node) bool { - var o int - var oary [10]int64 - var nn *gc.Node - - if n.Op != gc.ODOT { - return false - } - - o = gc.Dotoffset(n, oary[:], &nn) - if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 { - *n1 = *nn - n1.Type = n.Type - n1.Xoffset += oary[0] - return true - } - - return false -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -func sudoaddable(as int, n *gc.Node, a *obj.Addr, w *int) bool { - var o int - var i int - var oary [10]int64 - var v int64 - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var nn *gc.Node - var l *gc.Node - var r *gc.Node - var reg *gc.Node - var reg1 *gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var t *gc.Type - - if n.Type == nil { - return false - } - - *a = obj.Addr{} - - switch n.Op { - case gc.OLITERAL: - if !gc.Isconst(n, gc.CTINT) { - break - } - v = gc.Mpgetfix(n.Val.U.Xval) - if v >= 32000 || v <= -32000 { - break - } - goto lit - - case gc.ODOT, - gc.ODOTPTR: - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - goto odot - - case gc.OINDEX: - return false - - // disabled: OINDEX case is now covered by agenr - // for a more suitable register allocation pattern. - if n.Left.Type.Etype == gc.TSTRING { - return false - } - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - goto oindex - } - - return false - -lit: - switch as { - default: - return false - - case arm.AADD, - arm.ASUB, - arm.AAND, - arm.AORR, - arm.AEOR, - arm.AMOVB, - arm.AMOVBS, - arm.AMOVBU, - arm.AMOVH, - arm.AMOVHS, - arm.AMOVHU, - arm.AMOVW: - break - } - - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - gc.Naddr(n, a, 1) - goto yes - -odot: - o = gc.Dotoffset(n, oary[:], &nn) - if nn == nil { - goto no - } - - if nn.Addable != 0 && o == 1 && oary[0] >= 0 { - // directly addressable set of DOTs - n1 = *nn - - n1.Type = n.Type - n1.Xoffset += oary[0] - gc.Naddr(&n1, a, 1) - goto yes - } - - regalloc(reg, gc.Types[gc.Tptr], nil) - n1 = *reg - n1.Op = gc.OINDREG - if oary[0] >= 0 { - agen(nn, reg) - n1.Xoffset = oary[0] - } else { - cgen(nn, reg) - gc.Cgen_checknil(reg) - n1.Xoffset = -(oary[0] + 1) - } - - for i = 1; i < o; i++ { - if oary[i] >= 0 { - gc.Fatal("can't happen") - } - gins(arm.AMOVW, &n1, reg) - gc.Cgen_checknil(reg) - n1.Xoffset = -(oary[i] + 1) - } - - a.Type = obj.TYPE_NONE - a.Name = obj.NAME_NONE - n1.Type = n.Type - gc.Naddr(&n1, a, 1) - goto yes - -oindex: - l = n.Left - r = n.Right - if l.Ullman >= gc.UINF && r.Ullman >= gc.UINF { - goto no - } - - // set o to type of array - o = 0 - - if gc.Isptr[l.Type.Etype] != 0 { - o += OPtrto - if l.Type.Type.Etype != gc.TARRAY { - gc.Fatal("not ptr ary") - } - if l.Type.Type.Bound < 0 { - o += ODynam - } - } else { - if l.Type.Etype != gc.TARRAY { - gc.Fatal("not ary") - } - if l.Type.Bound < 0 { - o += ODynam - } - } - - *w = int(n.Type.Width) - if gc.Isconst(r, gc.CTINT) { - goto oindex_const - } - - switch *w { - default: - goto no - - case 1, - 2, - 4, - 8: - break - } - - // load the array (reg) - if l.Ullman > r.Ullman { - regalloc(reg, gc.Types[gc.Tptr], nil) - if o&OPtrto != 0 { - cgen(l, reg) - gc.Cgen_checknil(reg) - } else { - agen(l, reg) - } - } - - // load the index (reg1) - t = gc.Types[gc.TUINT32] - - if gc.Issigned[r.Type.Etype] != 0 { - t = gc.Types[gc.TINT32] - } - regalloc(reg1, t, nil) - regalloc(&n3, gc.Types[gc.TINT32], reg1) - p2 = cgenindex(r, &n3, gc.Debug['B'] != 0 || n.Bounded) - gmove(&n3, reg1) - regfree(&n3) - - // load the array (reg) - if l.Ullman <= r.Ullman { - regalloc(reg, gc.Types[gc.Tptr], nil) - if o&OPtrto != 0 { - cgen(l, reg) - gc.Cgen_checknil(reg) - } else { - agen(l, reg) - } - } - - // check bounds - if gc.Debug['B'] == 0 { - if o&ODynam != 0 { - n2 = *reg - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.Tptr] - n2.Xoffset = int64(gc.Array_nel) - } else { - if o&OPtrto != 0 { - gc.Nodconst(&n2, gc.Types[gc.TUINT32], l.Type.Type.Bound) - } else { - gc.Nodconst(&n2, gc.Types[gc.TUINT32], l.Type.Bound) - } - } - - regalloc(&n3, n2.Type, nil) - cgen(&n2, &n3) - gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), reg1, &n3) - regfree(&n3) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - if p2 != nil { - gc.Patch(p2, gc.Pc) - } - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - if o&ODynam != 0 { - n2 = *reg - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.Tptr] - n2.Xoffset = int64(gc.Array_array) - gmove(&n2, reg) - } - - switch *w { - case 1: - gins(arm.AADD, reg1, reg) - - case 2: - gshift(arm.AADD, reg1, arm.SHIFT_LL, 1, reg) - - case 4: - gshift(arm.AADD, reg1, arm.SHIFT_LL, 2, reg) - - case 8: - gshift(arm.AADD, reg1, arm.SHIFT_LL, 3, reg) - } - - gc.Naddr(reg1, a, 1) - a.Type = obj.TYPE_MEM - a.Reg = reg.Val.U.Reg - a.Offset = 0 - goto yes - - // index is constant - // can check statically and - // can multiply by width statically - -oindex_const: - regalloc(reg, gc.Types[gc.Tptr], nil) - - if o&OPtrto != 0 { - cgen(l, reg) - gc.Cgen_checknil(reg) - } else { - agen(l, reg) - } - - v = gc.Mpgetfix(r.Val.U.Xval) - if o&ODynam != 0 { - if gc.Debug['B'] == 0 && !n.Bounded { - n1 = *reg - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - gc.Nodconst(&n2, gc.Types[gc.TUINT32], v) - regalloc(&n3, gc.Types[gc.TUINT32], nil) - cgen(&n2, &n3) - regalloc(&n4, n1.Type, nil) - cgen(&n1, &n4) - gcmp(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n4, &n3) - regfree(&n4) - regfree(&n3) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - n1 = *reg - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, reg) - } - - n2 = *reg - n2.Op = gc.OINDREG - n2.Xoffset = v * int64(*w) - a.Type = obj.TYPE_NONE - a.Name = obj.NAME_NONE - gc.Naddr(&n2, a, 1) - goto yes - -yes: - return true - -no: - sudoclean() - return false -} diff --git a/src/cmd/new5g/peep.go b/src/cmd/new5g/peep.go deleted file mode 100644 index 2fbb1e5285..0000000000 --- a/src/cmd/new5g/peep.go +++ /dev/null @@ -1,1868 +0,0 @@ -// Inferno utils/5c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" - "fmt" -) -import "cmd/internal/gc" - -var gactive uint32 - -// UNUSED -func peep(firstp *obj.Prog) { - var r *gc.Flow - var g *gc.Graph - var p *obj.Prog - var t int - - g = gc.Flowstart(firstp, nil) - if g == nil { - return - } - gactive = 0 - -loop1: - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - gc.Dumpit("loop1", g.Start, 0) - } - - t = 0 - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - /* - * elide shift into TYPE_SHIFT operand of subsequent instruction - */ - // if(shiftprop(r)) { - // excise(r); - // t++; - // break; - // } - case arm.ASLL, - arm.ASRL, - arm.ASRA: - break - - case arm.AMOVB, - arm.AMOVH, - arm.AMOVW, - arm.AMOVF, - arm.AMOVD: - if regtyp(&p.From) { - if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) { - if p.Scond == arm.C_SCOND_NONE { - if copyprop(g, r) { - excise(r) - t++ - break - } - - if subprop(r) && copyprop(g, r) { - excise(r) - t++ - break - } - } - } - } - - case arm.AMOVHS, - arm.AMOVHU, - arm.AMOVBS, - arm.AMOVBU: - if p.From.Type == obj.TYPE_REG { - if shortprop(r) { - t++ - } - } - } - } - - /* - if(p->scond == C_SCOND_NONE) - if(regtyp(&p->to)) - if(isdconst(&p->from)) { - constprop(&p->from, &p->to, r->s1); - } - break; - */ - if t != 0 { - goto loop1 - } - - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - /* - * EOR -1,x,y => MVN x,y - */ - case arm.AEOR: - if isdconst(&p.From) && p.From.Offset == -1 { - p.As = arm.AMVN - p.From.Type = obj.TYPE_REG - if p.Reg != 0 { - p.From.Reg = p.Reg - } else { - p.From.Reg = p.To.Reg - } - p.Reg = 0 - } - } - } - - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case arm.AMOVW, - arm.AMOVB, - arm.AMOVBS, - arm.AMOVBU: - if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 { - xtramodes(g, r, &p.From) - } else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 { - xtramodes(g, r, &p.To) - } else { - continue - } - } - } - - // case ACMP: - // /* - // * elide CMP $0,x if calculation of x can set condition codes - // */ - // if(isdconst(&p->from) || p->from.offset != 0) - // continue; - // r2 = r->s1; - // if(r2 == nil) - // continue; - // t = r2->prog->as; - // switch(t) { - // default: - // continue; - // case ABEQ: - // case ABNE: - // case ABMI: - // case ABPL: - // break; - // case ABGE: - // t = ABPL; - // break; - // case ABLT: - // t = ABMI; - // break; - // case ABHI: - // t = ABNE; - // break; - // case ABLS: - // t = ABEQ; - // break; - // } - // r1 = r; - // do - // r1 = uniqp(r1); - // while (r1 != nil && r1->prog->as == ANOP); - // if(r1 == nil) - // continue; - // p1 = r1->prog; - // if(p1->to.type != TYPE_REG) - // continue; - // if(p1->to.reg != p->reg) - // if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg)) - // continue; - // - // switch(p1->as) { - // default: - // continue; - // case AMOVW: - // if(p1->from.type != TYPE_REG) - // continue; - // case AAND: - // case AEOR: - // case AORR: - // case ABIC: - // case AMVN: - // case ASUB: - // case ARSB: - // case AADD: - // case AADC: - // case ASBC: - // case ARSC: - // break; - // } - // p1->scond |= C_SBIT; - // r2->prog->as = t; - // excise(r); - // continue; - - // predicate(g); - - gc.Flowend(g) -} - -func regtyp(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15) -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -func subprop(r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - var r *gc.Flow - var t int - var info gc.ProgInfo - - p = r0.Prog - v1 = &p.From - if !regtyp(v1) { - return false - } - v2 = &p.To - if !regtyp(v2) { - return false - } - for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { - if gc.Uniqs(r) == nil { - break - } - p = r.Prog - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - continue - } - proginfo(&info, p) - if info.Flags&gc.Call != 0 { - return false - } - - if (info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG { - info.Flags |= gc.RegRead - info.Flags &^= (gc.CanRegRead | gc.RightRead) - p.Reg = p.To.Reg - } - - switch p.As { - case arm.AMULLU, - arm.AMULA, - arm.AMVN: - return false - } - - if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite { - if p.To.Type == v1.Type { - if p.To.Reg == v1.Reg { - if p.Scond == arm.C_SCOND_NONE { - goto gotit - } - } - } - } - - if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) { - break - } - if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { - break - } - } - - return false - -gotit: - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) - if p.From.Type == v2.Type { - fmt.Printf(" excise") - } - fmt.Printf("\n") - } - - for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { - p = r.Prog - copysub(&p.From, v1, v2, 1) - copysub1(p, v1, v2, 1) - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("%v\n", r.Prog) - } - } - - t = int(v1.Reg) - v1.Reg = v2.Reg - v2.Reg = int16(t) - if gc.Debug['P'] != 0 { - fmt.Printf("%v last\n", r.Prog) - } - return true -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -func copyprop(g *gc.Graph, r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - - p = r0.Prog - v1 = &p.From - v2 = &p.To - if copyas(v1, v2) { - return true - } - gactive++ - return copy1(v1, v2, r0.S1, 0) -} - -func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { - var t int - var p *obj.Prog - - if uint32(r.Active) == gactive { - if gc.Debug['P'] != 0 { - fmt.Printf("act set; return 1\n") - } - return true - } - - r.Active = int32(gactive) - if gc.Debug['P'] != 0 { - fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) - } - for ; r != nil; r = r.S1 { - p = r.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("%v", p) - } - if f == 0 && gc.Uniqp(r) == nil { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; merge; f=%d", f) - } - } - - t = copyu(p, v2, nil) - switch t { - case 2: /* rar, can't split */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2)) - } - return false - - case 3: /* set */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - - case 1, /* used, substitute */ - 4: /* use and set */ - if f != 0 { - if gc.Debug['P'] == 0 { - return false - } - if t == 4 { - fmt.Printf("; %vused+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } else { - fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } - return false - } - - if copyu(p, v2, v1) != 0 { - if gc.Debug['P'] != 0 { - fmt.Printf("; sub fail; return 0\n") - } - return false - } - - if gc.Debug['P'] != 0 { - fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) - } - if t == 4 { - if gc.Debug['P'] != 0 { - fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - } - } - - if f == 0 { - t = copyu(p, v1, nil) - if f == 0 && (t == 2 || t == 3 || t == 4) { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f) - } - } - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\n") - } - if r.S2 != nil { - if !copy1(v1, v2, r.S2, f) { - return false - } - } - } - - return true -} - -// UNUSED -/* - * The idea is to remove redundant constants. - * $c1->v1 - * ($c1->v2 s/$c1/v1)* - * set v1 return - * The v1->v2 should be eliminated by copy propagation. - */ -func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) { - var p *obj.Prog - - if gc.Debug['P'] != 0 { - fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1)) - } - for ; r != nil; r = r.S1 { - p = r.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("%v", p) - } - if gc.Uniqp(r) == nil { - if gc.Debug['P'] != 0 { - fmt.Printf("; merge; return\n") - } - return - } - - if p.As == arm.AMOVW && copyas(&p.From, c1) { - if gc.Debug['P'] != 0 { - fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1)) - } - p.From = *v1 - } else if copyu(p, v1, nil) > 1 { - if gc.Debug['P'] != 0 { - fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1)) - } - return - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\n") - } - if r.S2 != nil { - constprop(c1, v1, r.S2) - } - } -} - -/* - * shortprop eliminates redundant zero/sign extensions. - * - * MOVBS x, R - * - * MOVBS R, R' - * - * changed to - * - * MOVBS x, R - * ... - * MOVB R, R' (compiled to mov) - * - * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU. - */ -func shortprop(r *gc.Flow) bool { - var p *obj.Prog - var p1 *obj.Prog - var r1 *gc.Flow - - p = r.Prog - r1 = findpre(r, &p.From) - if r1 == nil { - return false - } - - p1 = r1.Prog - if p1.As == p.As { - // Two consecutive extensions. - goto gotit - } - - if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 { - // Loaded an immediate. - goto gotit - } - - return false - -gotit: - if gc.Debug['P'] != 0 { - fmt.Printf("shortprop\n%v\n%v", p1, p) - } - switch p.As { - case arm.AMOVBS, - arm.AMOVBU: - p.As = arm.AMOVB - - case arm.AMOVHS, - arm.AMOVHU: - p.As = arm.AMOVH - } - - if gc.Debug['P'] != 0 { - fmt.Printf(" => %v\n", arm.Aconv(int(p.As))) - } - return true -} - -// UNUSED -/* - * ASLL x,y,w - * .. (not use w, not set x y w) - * AXXX w,a,b (a != w) - * .. (not use w) - * (set w) - * ----------- changed to - * .. - * AXXX (x< 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) { - if gc.Debug['P'] != 0 { - fmt.Printf("\targs modified; FAILURE\n") - } - return false - } - - continue - case 3: /* set, not used */ - { - if gc.Debug['P'] != 0 { - fmt.Printf("\tBOTCH: noref; FAILURE\n") - } - return false - } - } - - break - } - - /* check whether substitution can be done */ - switch p1.As { - default: - if gc.Debug['P'] != 0 { - fmt.Printf("\tnon-dpi; FAILURE\n") - } - return false - - case arm.AAND, - arm.AEOR, - arm.AADD, - arm.AADC, - arm.AORR, - arm.ASUB, - arm.ASBC, - arm.ARSB, - arm.ARSC: - if int(p1.Reg) == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && int(p1.To.Reg) == n) { - if p1.From.Type != obj.TYPE_REG { - if gc.Debug['P'] != 0 { - fmt.Printf("\tcan't swap; FAILURE\n") - } - return false - } - - p1.Reg = p1.From.Reg - p1.From.Reg = int16(n) - switch p1.As { - case arm.ASUB: - p1.As = arm.ARSB - - case arm.ARSB: - p1.As = arm.ASUB - - case arm.ASBC: - p1.As = arm.ARSC - - case arm.ARSC: - p1.As = arm.ASBC - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\t=>%v", p1) - } - } - fallthrough - - case arm.ABIC, - arm.ATST, - arm.ACMP, - arm.ACMN: - if int(p1.Reg) == n { - if gc.Debug['P'] != 0 { - fmt.Printf("\tcan't swap; FAILURE\n") - } - return false - } - - if p1.Reg == 0 && int(p1.To.Reg) == n { - if gc.Debug['P'] != 0 { - fmt.Printf("\tshift result used twice; FAILURE\n") - } - return false - } - - // case AMVN: - if p1.From.Type == obj.TYPE_SHIFT { - if gc.Debug['P'] != 0 { - fmt.Printf("\tshift result used in shift; FAILURE\n") - } - return false - } - - if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n { - if gc.Debug['P'] != 0 { - fmt.Printf("\tBOTCH: where is it used?; FAILURE\n") - } - return false - } - } - - /* check whether shift result is used subsequently */ - p2 = p1 - - if int(p1.To.Reg) != n { - for { - r1 = gc.Uniqs(r1) - if r1 == nil { - if gc.Debug['P'] != 0 { - fmt.Printf("\tinconclusive; FAILURE\n") - } - return false - } - - p1 = r1.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("\n%v", p1) - } - switch copyu(p1, &p.To, nil) { - case 0: /* not used or set */ - continue - - case 3: /* set, not used */ - break - - default: /* used */ - if gc.Debug['P'] != 0 { - fmt.Printf("\treused; FAILURE\n") - } - return false - } - - break - } - } - - /* make the substitution */ - p2.From.Reg = 0 - - o = int(p.Reg) - if o == 0 { - o = int(p.To.Reg) - } - o &= 15 - - switch p.From.Type { - case obj.TYPE_CONST: - o |= int((p.From.Offset & 0x1f) << 7) - - case obj.TYPE_REG: - o |= 1<<4 | (int(p.From.Reg)&15)<<8 - } - - switch p.As { - case arm.ASLL: - o |= 0 << 5 - - case arm.ASRL: - o |= 1 << 5 - - case arm.ASRA: - o |= 2 << 5 - } - - p2.From = obj.Addr{} - p2.From.Type = obj.TYPE_SHIFT - p2.From.Offset = int64(o) - if gc.Debug['P'] != 0 { - fmt.Printf("\t=>%v\tSUCCEED\n", p2) - } - return true -} - -/* - * findpre returns the last instruction mentioning v - * before r. It must be a set, and there must be - * a unique path from that instruction to r. - */ -func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow { - var r1 *gc.Flow - - for r1 = gc.Uniqp(r); r1 != nil; (func() { r = r1; r1 = gc.Uniqp(r) })() { - if gc.Uniqs(r1) != r { - return nil - } - switch copyu(r1.Prog, v, nil) { - case 1, /* used */ - 2: /* read-alter-rewrite */ - return nil - - case 3, /* set */ - 4: /* set and used */ - return r1 - } - } - - return nil -} - -/* - * findinc finds ADD instructions with a constant - * argument which falls within the immed_12 range. - */ -func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow { - var r1 *gc.Flow - var p *obj.Prog - - for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; (func() { r = r1; r1 = gc.Uniqs(r) })() { - if gc.Uniqp(r1) != r { - return nil - } - switch copyu(r1.Prog, v, nil) { - case 0: /* not touched */ - continue - - case 4: /* set and used */ - p = r1.Prog - - if p.As == arm.AADD { - if isdconst(&p.From) { - if p.From.Offset > -4096 && p.From.Offset < 4096 { - return r1 - } - } - } - fallthrough - - default: - return nil - } - } - - return nil -} - -func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool { - var a [3]obj.Addr - var i int - var n int - - if r == r2 { - return true - } - n = 0 - if p.Reg != 0 && p.Reg != p.To.Reg { - a[n].Type = obj.TYPE_REG - a[n].Reg = p.Reg - n++ - } - - switch p.From.Type { - case obj.TYPE_SHIFT: - a[n].Type = obj.TYPE_REG - a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf)) - n++ - fallthrough - - case obj.TYPE_REG: - a[n].Type = obj.TYPE_REG - a[n].Reg = p.From.Reg - n++ - } - - if n == 0 { - return true - } - for ; r != nil && r != r2; r = gc.Uniqs(r) { - p = r.Prog - for i = 0; i < n; i++ { - if copyu(p, &a[i], nil) > 1 { - return false - } - } - } - - return true -} - -func findu1(r *gc.Flow, v *obj.Addr) bool { - for ; r != nil; r = r.S1 { - if r.Active != 0 { - return false - } - r.Active = 1 - switch copyu(r.Prog, v, nil) { - case 1, /* used */ - 2, /* read-alter-rewrite */ - 4: /* set and used */ - return true - - case 3: /* set */ - return false - } - - if r.S2 != nil { - if findu1(r.S2, v) { - return true - } - } - } - - return false -} - -func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool { - var r1 *gc.Flow - - for r1 = g.Start; r1 != nil; r1 = r1.Link { - r1.Active = 0 - } - return findu1(r, v) -} - -/* - * xtramodes enables the ARM post increment and - * shift offset addressing modes to transform - * MOVW 0(R3),R1 - * ADD $4,R3,R3 - * into - * MOVW.P 4(R3),R1 - * and - * ADD R0,R1 - * MOVBU 0(R1),R0 - * into - * MOVBU R0<<0(R1),R0 - */ -func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool { - var r1 *gc.Flow - var r2 *gc.Flow - var r3 *gc.Flow - var p *obj.Prog - var p1 *obj.Prog - var v obj.Addr - - p = r.Prog - v = *a - v.Type = obj.TYPE_REG - r1 = findpre(r, &v) - if r1 != nil { - p1 = r1.Prog - if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg { - switch p1.As { - case arm.AADD: - if p1.Scond&arm.C_SBIT != 0 { - // avoid altering ADD.S/ADC sequences. - break - } - - if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) { - if nochange(gc.Uniqs(r1), r, p1) { - if a != &p.From || v.Reg != p.To.Reg { - if finduse(g, r.S1, &v) { - if p1.Reg == 0 || p1.Reg == v.Reg { - /* pre-indexing */ - p.Scond |= arm.C_WBIT - } else { - return false - } - } - } - - switch p1.From.Type { - /* register offset */ - case obj.TYPE_REG: - if gc.Nacl { - return false - } - *a = obj.Addr{} - a.Type = obj.TYPE_SHIFT - a.Offset = int64(p1.From.Reg) & 15 - - /* scaled register offset */ - case obj.TYPE_SHIFT: - if gc.Nacl { - return false - } - *a = obj.Addr{} - a.Type = obj.TYPE_SHIFT - fallthrough - - /* immediate offset */ - case obj.TYPE_CONST, - obj.TYPE_ADDR: - a.Offset = p1.From.Offset - } - - if p1.Reg != 0 { - a.Reg = p1.Reg - } - excise(r1) - return true - } - } - - case arm.AMOVW: - if p1.From.Type == obj.TYPE_REG { - r2 = findinc(r1, r, &p1.From) - if r2 != nil { - for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) { - } - if r3 == r { - /* post-indexing */ - p1 = r2.Prog - - a.Reg = p1.To.Reg - a.Offset = p1.From.Offset - p.Scond |= arm.C_PBIT - if !finduse(g, r, &r1.Prog.To) { - excise(r1) - } - excise(r2) - return true - } - } - } - } - } - } - - if a != &p.From || a.Reg != p.To.Reg { - r1 = findinc(r, nil, &v) - if r1 != nil { - /* post-indexing */ - p1 = r1.Prog - - a.Offset = p1.From.Offset - p.Scond |= arm.C_PBIT - excise(r1) - return true - } - } - - return false -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { - switch p.As { - default: - fmt.Printf("copyu: can't find %v\n", arm.Aconv(int(p.As))) - return 2 - - case arm.AMOVM: - if v.Type != obj.TYPE_REG { - return 0 - } - if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */ - if s != nil { - if p.From.Offset&(1<type to v->name and enable. - //if(v->type == NAME_AUTO || v->type == NAME_PARAM) { - // if(v->offset == a->offset) - // return 1; - //} - return false -} - -/* - * either direct or indirect - */ -func copyau(a *obj.Addr, v *obj.Addr) bool { - if copyas(a, v) { - return true - } - if v.Type == obj.TYPE_REG { - if a.Type == obj.TYPE_ADDR && a.Reg != 0 { - if a.Reg == v.Reg { - return true - } - } else if a.Type == obj.TYPE_MEM { - if a.Reg == v.Reg { - return true - } - } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 { - if a.Reg == v.Reg { - return true - } - if a.Offset == int64(v.Reg) { - return true - } - } else if a.Type == obj.TYPE_SHIFT { - if a.Offset&0xf == int64(v.Reg-arm.REG_R0) { - return true - } - if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) { - return true - } - } - } - - return false -} - -/* - * compare v to the center - * register in p (p->reg) - */ -func copyau1(p *obj.Prog, v *obj.Addr) bool { - if v.Type == obj.TYPE_REG && v.Reg == 0 { - return false - } - return p.Reg == v.Reg -} - -/* - * substitute s for v in a - * return failure to substitute - */ -func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { - if f != 0 { - if copyau(a, v) { - if a.Type == obj.TYPE_SHIFT { - if a.Offset&0xf == int64(v.Reg-arm.REG_R0) { - a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf - } - if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) { - a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8 - } - } else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 { - if a.Offset == int64(v.Reg) { - a.Offset = int64(s.Reg) - } - if a.Reg == v.Reg { - a.Reg = s.Reg - } - } else { - a.Reg = s.Reg - } - } - } - - return 0 -} - -func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int { - if f != 0 { - if copyau1(p1, v) { - p1.Reg = s.Reg - } - } - return 0 -} - -var predinfo = []struct { - opcode int - notopcode int - scond int - notscond int -}{ - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABEQ, arm.ABNE, 0x0, 0x1}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABNE, arm.ABEQ, 0x1, 0x0}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABCS, arm.ABCC, 0x2, 0x3}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABHS, arm.ABLO, 0x2, 0x3}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABCC, arm.ABCS, 0x3, 0x2}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABLO, arm.ABHS, 0x3, 0x2}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABMI, arm.ABPL, 0x4, 0x5}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABPL, arm.ABMI, 0x5, 0x4}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABVS, arm.ABVC, 0x6, 0x7}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABVC, arm.ABVS, 0x7, 0x6}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABHI, arm.ABLS, 0x8, 0x9}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABLS, arm.ABHI, 0x9, 0x8}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABGE, arm.ABLT, 0xA, 0xB}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABLT, arm.ABGE, 0xB, 0xA}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABGT, arm.ABLE, 0xC, 0xD}, - struct { - opcode int - notopcode int - scond int - notscond int - }{arm.ABLE, arm.ABGT, 0xD, 0xC}, -} - -type Joininfo struct { - start *gc.Flow - last *gc.Flow - end *gc.Flow - len int -} - -const ( - Join = iota - Split - End - Branch - Setcond - Toolong -) - -const ( - Falsecond = iota - Truecond - Delbranch - Keepbranch -) - -func isbranch(p *obj.Prog) bool { - return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE) -} - -func predicable(p *obj.Prog) bool { - switch p.As { - case obj.ANOP, - obj.AXXX, - obj.ADATA, - obj.AGLOBL, - obj.ATEXT, - arm.AWORD, - arm.ABCASE, - arm.ACASE: - return false - } - - if isbranch(p) { - return false - } - return true -} - -/* - * Depends on an analysis of the encodings performed by 5l. - * These seem to be all of the opcodes that lead to the "S" bit - * being set in the instruction encodings. - * - * C_SBIT may also have been set explicitly in p->scond. - */ -func modifiescpsr(p *obj.Prog) bool { - switch p.As { - case arm.AMULLU, - arm.AMULA, - arm.AMULU, - arm.ADIVU, - arm.ATEQ, - arm.ACMN, - arm.ATST, - arm.ACMP, - arm.AMUL, - arm.ADIV, - arm.AMOD, - arm.AMODU, - arm.ABL: - return true - } - - if p.Scond&arm.C_SBIT != 0 { - return true - } - return false -} - -/* - * Find the maximal chain of instructions starting with r which could - * be executed conditionally - */ -func joinsplit(r *gc.Flow, j *Joininfo) int { - j.start = r - j.last = r - j.len = 0 - for { - if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) { - j.end = r - return Join - } - - if r.S1 != nil && r.S2 != nil { - j.end = r - return Split - } - - j.last = r - if r.Prog.As != obj.ANOP { - j.len++ - } - if r.S1 == nil && r.S2 == nil { - j.end = r.Link - return End - } - - if r.S2 != nil { - j.end = r.S2 - return Branch - } - - if modifiescpsr(r.Prog) { - j.end = r.S1 - return Setcond - } - - r = r.S1 - if j.len >= 4 { - break - } - } - - j.end = r - return Toolong -} - -func successor(r *gc.Flow) *gc.Flow { - if r.S1 != nil { - return r.S1 - } else { - return r.S2 - } -} - -func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) { - var pred int - var r *gc.Flow - - if j.len == 0 { - return - } - if cond == Truecond { - pred = predinfo[rstart.Prog.As-arm.ABEQ].scond - } else { - pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond - } - - for r = j.start; ; r = successor(r) { - if r.Prog.As == arm.AB { - if r != j.last || branch == Delbranch { - excise(r) - } else { - if cond == Truecond { - r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode) - } else { - r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode) - } - } - } else if predicable(r.Prog) { - r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred) - } - if r.S1 != r.Link { - r.S1 = r.Link - r.Link.P1 = r - } - - if r == j.last { - break - } - } -} - -func predicate(g *gc.Graph) { - var r *gc.Flow - var t1 int - var t2 int - var j1 Joininfo - var j2 Joininfo - - for r = g.Start; r != nil; r = r.Link { - if isbranch(r.Prog) { - t1 = joinsplit(r.S1, &j1) - t2 = joinsplit(r.S2, &j2) - if j1.last.Link != j2.start { - continue - } - if j1.end == j2.end { - if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) { - applypred(r, &j1, Falsecond, Delbranch) - applypred(r, &j2, Truecond, Delbranch) - excise(r) - continue - } - } - - if t1 == End || t1 == Branch { - applypred(r, &j1, Falsecond, Keepbranch) - excise(r) - continue - } - } - } -} - -func isdconst(a *obj.Addr) bool { - return a.Type == obj.TYPE_CONST -} - -func isfloatreg(a *obj.Addr) bool { - return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15 -} - -func stackaddr(a *obj.Addr) bool { - return regtyp(a) && a.Reg == arm.REGSP -} - -func smallindir(a *obj.Addr, reg *obj.Addr) bool { - return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096 -} - -func excise(r *gc.Flow) { - var p *obj.Prog - - p = r.Prog - obj.Nopout(p) -} diff --git a/src/cmd/new5g/prog.go b/src/cmd/new5g/prog.go deleted file mode 100644 index 3f7715f1fc..0000000000 --- a/src/cmd/new5g/prog.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/arm" -) -import "cmd/internal/gc" - -const ( - RightRdwr = gc.RightRead | gc.RightWrite -) - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -var progtable = [arm.ALAST]gc.ProgInfo{ - obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, - obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, - obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, - obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, - obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, - - // Integer. - arm.AADC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AADD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AAND: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ABIC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ACMN: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, - arm.ACMP: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, - arm.ADIVU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ADIV: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AEOR: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMODU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMOD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMULALU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, - arm.AMULAL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, - arm.AMULA: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0}, - arm.AMULU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMUL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMULLU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.AMVN: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite, 0, 0, 0}, - arm.AORR: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ARSB: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ARSC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ASBC: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ASLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ASRA: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ASRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ASUB: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - arm.ATEQ: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, - arm.ATST: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0}, - - // Floating point. - arm.AADDD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.AADDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.ACMPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, - arm.ACMPF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, - arm.ADIVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.ADIVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.AMULD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.AMULF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.ASUBD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - arm.ASUBF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - - // Conversions. - arm.AMOVWD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVWF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVDW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVFD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVFW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - - // Moves. - arm.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - arm.AMOVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - arm.AMOVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - arm.AMOVH: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - arm.AMOVW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - - // In addtion, duffzero reads R0,R1 and writes R1. This fact is - // encoded in peep.c - obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0}, - - // In addtion, duffcopy reads R1,R2 and writes R0,R1,R2. This fact is - // encoded in peep.c - obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0}, - - // These should be split into the two different conversions instead - // of overloading the one. - arm.AMOVBS: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVHS: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - arm.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - - // Jumps. - arm.AB: gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0}, - arm.ABL: gc.ProgInfo{gc.Call, 0, 0, 0}, - arm.ABEQ: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABNE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABCS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABHS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABCC: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABLO: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABMI: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABPL: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABVS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABVC: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABHI: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABLS: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABGE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABLT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABGT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - arm.ABLE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - obj.ARET: gc.ProgInfo{gc.Break, 0, 0, 0}, -} - -func proginfo(info *gc.ProgInfo, p *obj.Prog) { - *info = progtable[p.As] - if info.Flags == 0 { - gc.Fatal("unknown instruction %v", p) - } - - if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) { - info.Flags &^= gc.LeftRead - info.Flags |= gc.LeftAddr - } - - if (info.Flags&gc.RegRead != 0) && p.Reg == 0 { - info.Flags &^= gc.RegRead - info.Flags |= gc.CanRegRead | gc.RightRead - } - - if (p.Scond&arm.C_SCOND != arm.C_SCOND_NONE) && (info.Flags&gc.RightWrite != 0) { - info.Flags |= gc.RightRead - } - - switch p.As { - case arm.ADIV, - arm.ADIVU, - arm.AMOD, - arm.AMODU: - info.Regset |= RtoB(arm.REG_R12) - } -} diff --git a/src/cmd/new5g/reg.go b/src/cmd/new5g/reg.go deleted file mode 100644 index 2afdf12416..0000000000 --- a/src/cmd/new5g/reg.go +++ /dev/null @@ -1,136 +0,0 @@ -// Inferno utils/5c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import "cmd/internal/obj/arm" -import "cmd/internal/gc" - -const ( - NREGVAR = 32 -) - -var regname = []string{ - ".R0", - ".R1", - ".R2", - ".R3", - ".R4", - ".R5", - ".R6", - ".R7", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".F0", - ".F1", - ".F2", - ".F3", - ".F4", - ".F5", - ".F6", - ".F7", - ".F8", - ".F9", - ".F10", - ".F11", - ".F12", - ".F13", - ".F14", - ".F15", -} - -func regnames(n *int) []string { - *n = NREGVAR - return regname -} - -func excludedregs() uint64 { - return RtoB(arm.REGSP) | RtoB(arm.REGLINK) | RtoB(arm.REGPC) -} - -func doregbits(r int) uint64 { - return 0 -} - -/* - * bit reg - * 0 R0 - * 1 R1 - * ... ... - * 10 R10 - * 12 R12 - * - * bit reg - * 18 F2 - * 19 F3 - * ... ... - * 31 F15 - */ -func RtoB(r int) uint64 { - if arm.REG_R0 <= r && r <= arm.REG_R15 { - if r >= arm.REGTMP-2 && r != arm.REG_R12 { // excluded R9 and R10 for m and g, but not R12 - return 0 - } - return 1 << uint(r-arm.REG_R0) - } - - if arm.REG_F0 <= r && r <= arm.REG_F15 { - if r < arm.REG_F2 || r > arm.REG_F0+arm.NFREG-1 { - return 0 - } - return 1 << uint((r-arm.REG_F0)+16) - } - - return 0 -} - -func BtoR(b uint64) int { - // TODO Allow R0 and R1, but be careful with a 0 return - // TODO Allow R9. Only R10 is reserved now (just g, not m). - b &= 0x11fc // excluded R9 and R10 for m and g, but not R12 - if b == 0 { - return 0 - } - return gc.Bitno(b) + arm.REG_R0 -} - -func BtoF(b uint64) int { - b &= 0xfffc0000 - if b == 0 { - return 0 - } - return gc.Bitno(b) - 16 + arm.REG_F0 -} diff --git a/src/cmd/new5g/util.go b/src/cmd/new5g/util.go deleted file mode 100644 index bb5eedb15a..0000000000 --- a/src/cmd/new5g/util.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func bool2int(b bool) int { - if b { - return 1 - } - return 0 -} diff --git a/src/cmd/new6a/a.y b/src/cmd/new6a/a.y deleted file mode 100644 index bd59a1faba..0000000000 --- a/src/cmd/new6a/a.y +++ /dev/null @@ -1,723 +0,0 @@ -// Inferno utils/6a/a.y -// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -%{ -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/x86" -) -%} - -%union { - sym *asm.Sym - lval int64 - dval float64 - sval string - addr obj.Addr - addr2 Addr2 -} - -%left '|' -%left '^' -%left '&' -%left '<' '>' -%left '+' '-' -%left '*' '/' '%' -%token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 -%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG LTYPEPC -%token LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT LTYPEF -%token LCONST LFP LPC LSB -%token LBREG LLREG LSREG LFREG LMREG LXREG -%token LFCONST -%token LSCONST LSP -%token LNAME LLAB LVAR -%type con expr pointer offset -%type mem imm textsize reg nam rel rem rim rom omem nmem -%type nonnon nonrel nonrem rimnon rimrem remrim -%type spec3 spec4 spec5 spec6 spec7 spec8 spec9 -%type spec10 spec12 spec13 -%% -prog: -| prog - { - stmtline = asm.Lineno; - } - line - -line: - LNAME ':' - { - $1 = asm.LabelLookup($1); - if $1.Type == LLAB && $1.Value != int64(asm.PC) { - yyerror("redeclaration of %s (%s)", $1.Labelname, $1.Name); - } - $1.Type = LLAB; - $1.Value = int64(asm.PC) - } - line -| ';' -| inst ';' -| error ';' - -inst: - LNAME '=' expr - { - $1.Type = LVAR; - $1.Value = $3; - } -| LVAR '=' expr - { - if $1.Value != $3 { - yyerror("redeclaration of %s", $1.Name); - } - $1.Value = $3; - } -| LTYPE0 nonnon { outcode(int($1), &$2); } -| LTYPE1 nonrem { outcode(int($1), &$2); } -| LTYPE2 rimnon { outcode(int($1), &$2); } -| LTYPE3 rimrem { outcode(int($1), &$2); } -| LTYPE4 remrim { outcode(int($1), &$2); } -| LTYPER nonrel { outcode(int($1), &$2); } -| spec1 -| spec2 -| LTYPEC spec3 { outcode(int($1), &$2); } -| LTYPEN spec4 { outcode(int($1), &$2); } -| LTYPES spec5 { outcode(int($1), &$2); } -| LTYPEM spec6 { outcode(int($1), &$2); } -| LTYPEI spec7 { outcode(int($1), &$2); } -| LTYPEXC spec8 { outcode(int($1), &$2); } -| LTYPEX spec9 { outcode(int($1), &$2); } -| LTYPERT spec10 { outcode(int($1), &$2); } -| spec11 -| LTYPEPC spec12 { outcode(int($1), &$2); } -| LTYPEF spec13 { outcode(int($1), &$2); } - -nonnon: - { - $$.from = nullgen; - $$.to = nullgen; - } -| ',' - { - $$.from = nullgen; - $$.to = nullgen; - } - -rimrem: - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } - -remrim: - rem ',' rim - { - $$.from = $1; - $$.to = $3; - } - -rimnon: - rim ',' - { - $$.from = $1; - $$.to = nullgen; - } -| rim - { - $$.from = $1; - $$.to = nullgen; - } - -nonrem: - ',' rem - { - $$.from = nullgen; - $$.to = $2; - } -| rem - { - $$.from = nullgen; - $$.to = $1; - } - -nonrel: - ',' rel - { - $$.from = nullgen; - $$.to = $2; - } -| rel - { - $$.from = nullgen; - $$.to = $1; - } -| imm ',' rel - { - $$.from = $1; - $$.to = $3; - } - -spec1: /* DATA */ - LTYPED nam '/' con ',' imm - { - var a Addr2 - a.from = $2 - a.to = $6 - outcode(obj.ADATA, &a) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -spec2: /* TEXT */ - LTYPET mem ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(obj.ATEXT, &Addr2{$2, $5}) - } -| LTYPET mem ',' con ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(obj.ATEXT, &Addr2{$2, $7}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -spec11: /* GLOBL */ - LTYPEG mem ',' imm - { - asm.Settext($2.Sym) - outcode(obj.AGLOBL, &Addr2{$2, $4}) - } -| LTYPEG mem ',' con ',' imm - { - asm.Settext($2.Sym) - outcode(obj.AGLOBL, &Addr2{$2, $6}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -spec3: /* JMP/CALL */ - ',' rom - { - $$.from = nullgen; - $$.to = $2; - } -| rom - { - $$.from = nullgen; - $$.to = $1; - } - -spec4: /* NOP */ - nonnon -| nonrem - -spec5: /* SHL/SHR */ - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } -| rim ',' rem ':' LLREG - { - $$.from = $1; - $$.to = $3; - if $$.from.Index != obj.TYPE_NONE { - yyerror("dp shift with lhs index"); - } - $$.from.Index = int16($5); - } - -spec6: /* MOVW/MOVL */ - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } -| rim ',' rem ':' LSREG - { - $$.from = $1; - $$.to = $3; - if $$.to.Index != obj.TYPE_NONE { - yyerror("dp move with lhs index"); - } - $$.to.Index = int16($5); - } - -spec7: - rim ',' - { - $$.from = $1; - $$.to = nullgen; - } -| rim - { - $$.from = $1; - $$.to = nullgen; - } -| rim ',' rem - { - $$.from = $1; - $$.to = $3; - } - -spec8: /* CMPPS/CMPPD */ - reg ',' rem ',' con - { - $$.from = $1; - $$.to = $3; - $$.to.Offset = $5; - } - -spec9: /* shufl */ - imm ',' rem ',' reg - { - $$.from = $3; - $$.to = $5; - if $1.Type != obj.TYPE_CONST { - yyerror("illegal constant"); - } - $$.to.Offset = $1.Offset; - } - -spec10: /* RET/RETF */ - { - $$.from = nullgen; - $$.to = nullgen; - } -| imm - { - $$.from = $1; - $$.to = nullgen; - } - -spec12: /* asm.PCDATA */ - rim ',' rim - { - if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST { - yyerror("arguments to asm.PCDATA must be integer constants"); - } - $$.from = $1; - $$.to = $3; - } - -spec13: /* FUNCDATA */ - rim ',' rim - { - if $1.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant"); - } - if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference"); - } - $$.from = $1; - $$.to = $3; - } - -rem: - reg -| mem - -rom: - rel -| nmem -| '*' reg - { - $$ = $2; - } -| '*' omem - { - $$ = $2; - } -| reg -| omem - -rim: - rem -| imm - -rel: - con '(' LPC ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1 + int64(asm.PC); - } -| LNAME offset - { - $1 = asm.LabelLookup($1); - $$ = nullgen; - if asm.Pass == 2 && $1.Type != LLAB { - yyerror("undefined label: %s", $1.Labelname); - } - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1.Value + $2; - } - -reg: - LBREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LFREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LLREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LMREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LSP - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = x86.REG_SP; - } -| LSREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LXREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } - -imm: - '$' con - { - $$ = nullgen; - $$.Type = obj.TYPE_CONST; - $$.Offset = $2; - } -| '$' nam - { - $$ = $2; - $$.Type = obj.TYPE_ADDR; - /* - if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM) - yyerror("constant cannot be automatic: %s", - $2.sym.Name); - */ - } -| '$' LSCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_SCONST; - $$.U.Sval = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8] - } -| '$' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = $2; - } -| '$' '(' LFCONST ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = $3; - } -| '$' '(' '-' LFCONST ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = -$4; - } -| '$' '-' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = -$3; - } - -mem: - omem -| nmem - -omem: - con - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Offset = $1; - } -| con '(' LLREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - } -| con '(' LSP ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = x86.REG_SP - $$.Offset = $1; - } -| con '(' LSREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - } -| con '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Offset = $1; - $$.Index = int16($3); - $$.Scale = int8($5); - checkscale($$.Scale); - } -| con '(' LLREG ')' '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - $$.Index = int16($6); - $$.Scale = int8($8); - checkscale($$.Scale); - } -| con '(' LLREG ')' '(' LSREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - $$.Index = int16($6); - $$.Scale = int8($8); - checkscale($$.Scale); - } -| '(' LLREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($2) - } -| '(' LSP ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = x86.REG_SP - } -| '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Index = int16($2); - $$.Scale = int8($4); - checkscale($$.Scale); - } -| '(' LLREG ')' '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($2) - $$.Index = int16($5); - $$.Scale = int8($7); - checkscale($$.Scale); - } - -nmem: - nam - { - $$ = $1; - } -| nam '(' LLREG '*' con ')' - { - $$ = $1; - $$.Index = int16($3); - $$.Scale = int8($5); - checkscale($$.Scale); - } - -nam: - LNAME offset '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Name = int8($4) - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); - $$.Offset = $2; - } -| LNAME '<' '>' offset '(' LSB ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Name = obj.NAME_STATIC - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); - $$.Offset = $4; - } - -offset: - { - $$ = 0; - } -| '+' con - { - $$ = $2; - } -| '-' con - { - $$ = -$2; - } - -pointer: - LSB -| LSP - { - $$ = obj.NAME_AUTO; - } -| LFP - -con: - LCONST -| LVAR - { - $$ = $1.Value; - } -| '-' con - { - $$ = -$2; - } -| '+' con - { - $$ = $2; - } -| '~' con - { - $$ = ^$2; - } -| '(' expr ')' - { - $$ = $2; - } - -textsize: - LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = $1; - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -$2; - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = $1; - $$.U.Argsize = int32($3); - } -| '-' LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -$2; - $$.U.Argsize = int32($4); - } - -expr: - con -| expr '+' expr - { - $$ = $1 + $3; - } -| expr '-' expr - { - $$ = $1 - $3; - } -| expr '*' expr - { - $$ = $1 * $3; - } -| expr '/' expr - { - $$ = $1 / $3; - } -| expr '%' expr - { - $$ = $1 % $3; - } -| expr '<' '<' expr - { - $$ = $1 << uint($4); - } -| expr '>' '>' expr - { - $$ = $1 >> uint($4); - } -| expr '&' expr - { - $$ = $1 & $3; - } -| expr '^' expr - { - $$ = $1 ^ $3; - } -| expr '|' expr - { - $$ = $1 | $3; - } diff --git a/src/cmd/new6a/lex.go b/src/cmd/new6a/lex.go deleted file mode 100644 index db4247f045..0000000000 --- a/src/cmd/new6a/lex.go +++ /dev/null @@ -1,978 +0,0 @@ -// Inferno utils/6a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -//go:generate go tool yacc a.y - -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/x86" -) - -var ( - yyerror = asm.Yyerror - nullgen obj.Addr - stmtline int32 -) - -func main() { - cinit() - - asm.LSCONST = LSCONST - asm.LCONST = LCONST - asm.LFCONST = LFCONST - asm.LNAME = LNAME - asm.LVAR = LVAR - asm.LLAB = LLAB - - asm.Thechar = '6' - asm.Thestring = "amd64" - asm.Thelinkarch = &x86.Linkamd64 - asm.Arches = map[string]*obj.LinkArch{ - "amd64p32": &x86.Linkamd64p32, - } - - asm.Lexinit = lexinit - asm.Cclean = cclean - asm.Yyparse = yyparse - - asm.Main() -} - -type yy struct{} - -func (yy) Lex(v *yySymType) int { - var av asm.Yylval - tok := asm.Yylex(&av) - v.sym = av.Sym - v.lval = av.Lval - v.sval = av.Sval - v.dval = av.Dval - return tok -} - -func (yy) Error(msg string) { - asm.Yyerror("%s", msg) -} - -func yyparse() { - yyParse(yy{}) -} - -var lexinit = []asm.Lextab{ - {"SP", LSP, obj.NAME_AUTO}, - {"SB", LSB, obj.NAME_EXTERN}, - {"FP", LFP, obj.NAME_PARAM}, - {"PC", LPC, obj.TYPE_BRANCH}, - - {"AL", LBREG, x86.REG_AL}, - {"CL", LBREG, x86.REG_CL}, - {"DL", LBREG, x86.REG_DL}, - {"BL", LBREG, x86.REG_BL}, - /* "SPB", LBREG, REG_SPB, */ - {"SIB", LBREG, x86.REG_SIB}, - {"DIB", LBREG, x86.REG_DIB}, - {"BPB", LBREG, x86.REG_BPB}, - {"R8B", LBREG, x86.REG_R8B}, - {"R9B", LBREG, x86.REG_R9B}, - {"R10B", LBREG, x86.REG_R10B}, - {"R11B", LBREG, x86.REG_R11B}, - {"R12B", LBREG, x86.REG_R12B}, - {"R13B", LBREG, x86.REG_R13B}, - {"R14B", LBREG, x86.REG_R14B}, - {"R15B", LBREG, x86.REG_R15B}, - {"AH", LBREG, x86.REG_AH}, - {"CH", LBREG, x86.REG_CH}, - {"DH", LBREG, x86.REG_DH}, - {"BH", LBREG, x86.REG_BH}, - {"AX", LLREG, x86.REG_AX}, - {"CX", LLREG, x86.REG_CX}, - {"DX", LLREG, x86.REG_DX}, - {"BX", LLREG, x86.REG_BX}, - - /* "SP", LLREG, REG_SP, */ - {"BP", LLREG, x86.REG_BP}, - {"SI", LLREG, x86.REG_SI}, - {"DI", LLREG, x86.REG_DI}, - {"R8", LLREG, x86.REG_R8}, - {"R9", LLREG, x86.REG_R9}, - {"R10", LLREG, x86.REG_R10}, - {"R11", LLREG, x86.REG_R11}, - {"R12", LLREG, x86.REG_R12}, - {"R13", LLREG, x86.REG_R13}, - {"R14", LLREG, x86.REG_R14}, - {"R15", LLREG, x86.REG_R15}, - {"RARG", LLREG, x86.REGARG}, - {"F0", LFREG, x86.REG_F0 + 0}, - {"F1", LFREG, x86.REG_F0 + 1}, - {"F2", LFREG, x86.REG_F0 + 2}, - {"F3", LFREG, x86.REG_F0 + 3}, - {"F4", LFREG, x86.REG_F0 + 4}, - {"F5", LFREG, x86.REG_F0 + 5}, - {"F6", LFREG, x86.REG_F0 + 6}, - {"F7", LFREG, x86.REG_F0 + 7}, - {"M0", LMREG, x86.REG_M0 + 0}, - {"M1", LMREG, x86.REG_M0 + 1}, - {"M2", LMREG, x86.REG_M0 + 2}, - {"M3", LMREG, x86.REG_M0 + 3}, - {"M4", LMREG, x86.REG_M0 + 4}, - {"M5", LMREG, x86.REG_M0 + 5}, - {"M6", LMREG, x86.REG_M0 + 6}, - {"M7", LMREG, x86.REG_M0 + 7}, - {"X0", LXREG, x86.REG_X0 + 0}, - {"X1", LXREG, x86.REG_X0 + 1}, - {"X2", LXREG, x86.REG_X0 + 2}, - {"X3", LXREG, x86.REG_X0 + 3}, - {"X4", LXREG, x86.REG_X0 + 4}, - {"X5", LXREG, x86.REG_X0 + 5}, - {"X6", LXREG, x86.REG_X0 + 6}, - {"X7", LXREG, x86.REG_X0 + 7}, - {"X8", LXREG, x86.REG_X0 + 8}, - {"X9", LXREG, x86.REG_X0 + 9}, - {"X10", LXREG, x86.REG_X0 + 10}, - {"X11", LXREG, x86.REG_X0 + 11}, - {"X12", LXREG, x86.REG_X0 + 12}, - {"X13", LXREG, x86.REG_X0 + 13}, - {"X14", LXREG, x86.REG_X0 + 14}, - {"X15", LXREG, x86.REG_X0 + 15}, - {"CS", LSREG, x86.REG_CS}, - {"SS", LSREG, x86.REG_SS}, - {"DS", LSREG, x86.REG_DS}, - {"ES", LSREG, x86.REG_ES}, - {"FS", LSREG, x86.REG_FS}, - {"GS", LSREG, x86.REG_GS}, - {"GDTR", LBREG, x86.REG_GDTR}, - {"IDTR", LBREG, x86.REG_IDTR}, - {"LDTR", LBREG, x86.REG_LDTR}, - {"MSW", LBREG, x86.REG_MSW}, - {"TASK", LBREG, x86.REG_TASK}, - {"CR0", LBREG, x86.REG_CR + 0}, - {"CR1", LBREG, x86.REG_CR + 1}, - {"CR2", LBREG, x86.REG_CR + 2}, - {"CR3", LBREG, x86.REG_CR + 3}, - {"CR4", LBREG, x86.REG_CR + 4}, - {"CR5", LBREG, x86.REG_CR + 5}, - {"CR6", LBREG, x86.REG_CR + 6}, - {"CR7", LBREG, x86.REG_CR + 7}, - {"CR8", LBREG, x86.REG_CR + 8}, - {"CR9", LBREG, x86.REG_CR + 9}, - {"CR10", LBREG, x86.REG_CR + 10}, - {"CR11", LBREG, x86.REG_CR + 11}, - {"CR12", LBREG, x86.REG_CR + 12}, - {"CR13", LBREG, x86.REG_CR + 13}, - {"CR14", LBREG, x86.REG_CR + 14}, - {"CR15", LBREG, x86.REG_CR + 15}, - {"DR0", LBREG, x86.REG_DR + 0}, - {"DR1", LBREG, x86.REG_DR + 1}, - {"DR2", LBREG, x86.REG_DR + 2}, - {"DR3", LBREG, x86.REG_DR + 3}, - {"DR4", LBREG, x86.REG_DR + 4}, - {"DR5", LBREG, x86.REG_DR + 5}, - {"DR6", LBREG, x86.REG_DR + 6}, - {"DR7", LBREG, x86.REG_DR + 7}, - {"TR0", LBREG, x86.REG_TR + 0}, - {"TR1", LBREG, x86.REG_TR + 1}, - {"TR2", LBREG, x86.REG_TR + 2}, - {"TR3", LBREG, x86.REG_TR + 3}, - {"TR4", LBREG, x86.REG_TR + 4}, - {"TR5", LBREG, x86.REG_TR + 5}, - {"TR6", LBREG, x86.REG_TR + 6}, - {"TR7", LBREG, x86.REG_TR + 7}, - {"TLS", LSREG, x86.REG_TLS}, - {"AAA", LTYPE0, x86.AAAA}, - {"AAD", LTYPE0, x86.AAAD}, - {"AAM", LTYPE0, x86.AAAM}, - {"AAS", LTYPE0, x86.AAAS}, - {"ADCB", LTYPE3, x86.AADCB}, - {"ADCL", LTYPE3, x86.AADCL}, - {"ADCQ", LTYPE3, x86.AADCQ}, - {"ADCW", LTYPE3, x86.AADCW}, - {"ADDB", LTYPE3, x86.AADDB}, - {"ADDL", LTYPE3, x86.AADDL}, - {"ADDQ", LTYPE3, x86.AADDQ}, - {"ADDW", LTYPE3, x86.AADDW}, - {"ADJSP", LTYPE2, x86.AADJSP}, - {"ANDB", LTYPE3, x86.AANDB}, - {"ANDL", LTYPE3, x86.AANDL}, - {"ANDQ", LTYPE3, x86.AANDQ}, - {"ANDW", LTYPE3, x86.AANDW}, - {"ARPL", LTYPE3, x86.AARPL}, - {"BOUNDL", LTYPE3, x86.ABOUNDL}, - {"BOUNDW", LTYPE3, x86.ABOUNDW}, - {"BSFL", LTYPE3, x86.ABSFL}, - {"BSFQ", LTYPE3, x86.ABSFQ}, - {"BSFW", LTYPE3, x86.ABSFW}, - {"BSRL", LTYPE3, x86.ABSRL}, - {"BSRQ", LTYPE3, x86.ABSRQ}, - {"BSRW", LTYPE3, x86.ABSRW}, - {"BSWAPL", LTYPE1, x86.ABSWAPL}, - {"BSWAPQ", LTYPE1, x86.ABSWAPQ}, - {"BTCL", LTYPE3, x86.ABTCL}, - {"BTCQ", LTYPE3, x86.ABTCQ}, - {"BTCW", LTYPE3, x86.ABTCW}, - {"BTL", LTYPE3, x86.ABTL}, - {"BTQ", LTYPE3, x86.ABTQ}, - {"BTRL", LTYPE3, x86.ABTRL}, - {"BTRQ", LTYPE3, x86.ABTRQ}, - {"BTRW", LTYPE3, x86.ABTRW}, - {"BTSL", LTYPE3, x86.ABTSL}, - {"BTSQ", LTYPE3, x86.ABTSQ}, - {"BTSW", LTYPE3, x86.ABTSW}, - {"BTW", LTYPE3, x86.ABTW}, - {"BYTE", LTYPE2, x86.ABYTE}, - {"CALL", LTYPEC, obj.ACALL}, - {"CLC", LTYPE0, x86.ACLC}, - {"CLD", LTYPE0, x86.ACLD}, - {"CLI", LTYPE0, x86.ACLI}, - {"CLTS", LTYPE0, x86.ACLTS}, - {"CMC", LTYPE0, x86.ACMC}, - {"CMPB", LTYPE4, x86.ACMPB}, - {"CMPL", LTYPE4, x86.ACMPL}, - {"CMPQ", LTYPE4, x86.ACMPQ}, - {"CMPW", LTYPE4, x86.ACMPW}, - {"CMPSB", LTYPE0, x86.ACMPSB}, - {"CMPSL", LTYPE0, x86.ACMPSL}, - {"CMPSQ", LTYPE0, x86.ACMPSQ}, - {"CMPSW", LTYPE0, x86.ACMPSW}, - {"CMPXCHG8B", LTYPE1, x86.ACMPXCHG8B}, - {"CMPXCHGB", LTYPE3, x86.ACMPXCHGB}, /* LTYPE3? */ - {"CMPXCHGL", LTYPE3, x86.ACMPXCHGL}, - {"CMPXCHGQ", LTYPE3, x86.ACMPXCHGQ}, - {"CMPXCHGW", LTYPE3, x86.ACMPXCHGW}, - {"CPUID", LTYPE0, x86.ACPUID}, - {"DAA", LTYPE0, x86.ADAA}, - {"DAS", LTYPE0, x86.ADAS}, - {"DATA", LTYPED, obj.ADATA}, - {"DECB", LTYPE1, x86.ADECB}, - {"DECL", LTYPE1, x86.ADECL}, - {"DECQ", LTYPE1, x86.ADECQ}, - {"DECW", LTYPE1, x86.ADECW}, - {"DIVB", LTYPE2, x86.ADIVB}, - {"DIVL", LTYPE2, x86.ADIVL}, - {"DIVQ", LTYPE2, x86.ADIVQ}, - {"DIVW", LTYPE2, x86.ADIVW}, - {"EMMS", LTYPE0, x86.AEMMS}, - {"END", LTYPE0, obj.AEND}, - {"ENTER", LTYPE2, x86.AENTER}, - {"GLOBL", LTYPEG, obj.AGLOBL}, - {"HLT", LTYPE0, x86.AHLT}, - {"IDIVB", LTYPE2, x86.AIDIVB}, - {"IDIVL", LTYPE2, x86.AIDIVL}, - {"IDIVQ", LTYPE2, x86.AIDIVQ}, - {"IDIVW", LTYPE2, x86.AIDIVW}, - {"IMULB", LTYPEI, x86.AIMULB}, - {"IMULL", LTYPEI, x86.AIMULL}, - {"IMULQ", LTYPEI, x86.AIMULQ}, - {"IMUL3Q", LTYPEX, x86.AIMUL3Q}, - {"IMULW", LTYPEI, x86.AIMULW}, - {"INB", LTYPE0, x86.AINB}, - {"INL", LTYPE0, x86.AINL}, - {"INW", LTYPE0, x86.AINW}, - {"INCB", LTYPE1, x86.AINCB}, - {"INCL", LTYPE1, x86.AINCL}, - {"INCQ", LTYPE1, x86.AINCQ}, - {"INCW", LTYPE1, x86.AINCW}, - {"INSB", LTYPE0, x86.AINSB}, - {"INSL", LTYPE0, x86.AINSL}, - {"INSW", LTYPE0, x86.AINSW}, - {"INT", LTYPE2, x86.AINT}, - {"INTO", LTYPE0, x86.AINTO}, - {"INVD", LTYPE0, x86.AINVD}, - {"INVLPG", LTYPE2, x86.AINVLPG}, - {"IRETL", LTYPE0, x86.AIRETL}, - {"IRETQ", LTYPE0, x86.AIRETQ}, - {"IRETW", LTYPE0, x86.AIRETW}, - {"JOS", LTYPER, x86.AJOS}, /* overflow set (OF = 1) */ - {"JO", LTYPER, x86.AJOS}, /* alternate */ - {"JOC", LTYPER, x86.AJOC}, /* overflow clear (OF = 0) */ - {"JNO", LTYPER, x86.AJOC}, /* alternate */ - {"JCS", LTYPER, x86.AJCS}, /* carry set (CF = 1) */ - {"JB", LTYPER, x86.AJCS}, /* alternate */ - {"JC", LTYPER, x86.AJCS}, /* alternate */ - {"JNAE", LTYPER, x86.AJCS}, /* alternate */ - {"JLO", LTYPER, x86.AJCS}, /* alternate */ - {"JCC", LTYPER, x86.AJCC}, /* carry clear (CF = 0) */ - {"JAE", LTYPER, x86.AJCC}, /* alternate */ - {"JNB", LTYPER, x86.AJCC}, /* alternate */ - {"JNC", LTYPER, x86.AJCC}, /* alternate */ - {"JHS", LTYPER, x86.AJCC}, /* alternate */ - {"JEQ", LTYPER, x86.AJEQ}, /* equal (ZF = 1) */ - {"JE", LTYPER, x86.AJEQ}, /* alternate */ - {"JZ", LTYPER, x86.AJEQ}, /* alternate */ - {"JNE", LTYPER, x86.AJNE}, /* not equal (ZF = 0) */ - {"JNZ", LTYPER, x86.AJNE}, /* alternate */ - {"JLS", LTYPER, x86.AJLS}, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ - {"JBE", LTYPER, x86.AJLS}, /* alternate */ - {"JNA", LTYPER, x86.AJLS}, /* alternate */ - {"JHI", LTYPER, x86.AJHI}, /* higher (unsigned) (CF = 0 && ZF = 0) */ - {"JA", LTYPER, x86.AJHI}, /* alternate */ - {"JNBE", LTYPER, x86.AJHI}, /* alternate */ - {"JMI", LTYPER, x86.AJMI}, /* negative (minus) (SF = 1) */ - {"JS", LTYPER, x86.AJMI}, /* alternate */ - {"JPL", LTYPER, x86.AJPL}, /* non-negative (plus) (SF = 0) */ - {"JNS", LTYPER, x86.AJPL}, /* alternate */ - {"JPS", LTYPER, x86.AJPS}, /* parity set (PF = 1) */ - {"JP", LTYPER, x86.AJPS}, /* alternate */ - {"JPE", LTYPER, x86.AJPS}, /* alternate */ - {"JPC", LTYPER, x86.AJPC}, /* parity clear (PF = 0) */ - {"JNP", LTYPER, x86.AJPC}, /* alternate */ - {"JPO", LTYPER, x86.AJPC}, /* alternate */ - {"JLT", LTYPER, x86.AJLT}, /* less than (signed) (SF != OF) */ - {"JL", LTYPER, x86.AJLT}, /* alternate */ - {"JNGE", LTYPER, x86.AJLT}, /* alternate */ - {"JGE", LTYPER, x86.AJGE}, /* greater than or equal (signed) (SF = OF) */ - {"JNL", LTYPER, x86.AJGE}, /* alternate */ - {"JLE", LTYPER, x86.AJLE}, /* less than or equal (signed) (ZF = 1 || SF != OF) */ - {"JNG", LTYPER, x86.AJLE}, /* alternate */ - {"JGT", LTYPER, x86.AJGT}, /* greater than (signed) (ZF = 0 && SF = OF) */ - {"JG", LTYPER, x86.AJGT}, /* alternate */ - {"JNLE", LTYPER, x86.AJGT}, /* alternate */ - {"JCXZL", LTYPER, x86.AJCXZL}, - {"JCXZQ", LTYPER, x86.AJCXZQ}, - {"JMP", LTYPEC, obj.AJMP}, - {"LAHF", LTYPE0, x86.ALAHF}, - {"LARL", LTYPE3, x86.ALARL}, - {"LARW", LTYPE3, x86.ALARW}, - {"LEAL", LTYPE3, x86.ALEAL}, - {"LEAQ", LTYPE3, x86.ALEAQ}, - {"LEAW", LTYPE3, x86.ALEAW}, - {"LEAVEL", LTYPE0, x86.ALEAVEL}, - {"LEAVEQ", LTYPE0, x86.ALEAVEQ}, - {"LEAVEW", LTYPE0, x86.ALEAVEW}, - {"LFENCE", LTYPE0, x86.ALFENCE}, - {"LOCK", LTYPE0, x86.ALOCK}, - {"LODSB", LTYPE0, x86.ALODSB}, - {"LODSL", LTYPE0, x86.ALODSL}, - {"LODSQ", LTYPE0, x86.ALODSQ}, - {"LODSW", LTYPE0, x86.ALODSW}, - {"LONG", LTYPE2, x86.ALONG}, - {"LOOP", LTYPER, x86.ALOOP}, - {"LOOPEQ", LTYPER, x86.ALOOPEQ}, - {"LOOPNE", LTYPER, x86.ALOOPNE}, - {"LSLL", LTYPE3, x86.ALSLL}, - {"LSLW", LTYPE3, x86.ALSLW}, - {"MFENCE", LTYPE0, x86.AMFENCE}, - {"MODE", LTYPE2, x86.AMODE}, - {"MOVB", LTYPE3, x86.AMOVB}, - {"MOVL", LTYPEM, x86.AMOVL}, - {"MOVQ", LTYPEM, x86.AMOVQ}, - {"MOVW", LTYPEM, x86.AMOVW}, - {"MOVBLSX", LTYPE3, x86.AMOVBLSX}, - {"MOVBLZX", LTYPE3, x86.AMOVBLZX}, - {"MOVBQSX", LTYPE3, x86.AMOVBQSX}, - {"MOVBQZX", LTYPE3, x86.AMOVBQZX}, - {"MOVBWSX", LTYPE3, x86.AMOVBWSX}, - {"MOVBWZX", LTYPE3, x86.AMOVBWZX}, - {"MOVLQSX", LTYPE3, x86.AMOVLQSX}, - {"MOVLQZX", LTYPE3, x86.AMOVLQZX}, - {"MOVNTIL", LTYPE3, x86.AMOVNTIL}, - {"MOVNTIQ", LTYPE3, x86.AMOVNTIQ}, - {"MOVQL", LTYPE3, x86.AMOVQL}, - {"MOVWLSX", LTYPE3, x86.AMOVWLSX}, - {"MOVWLZX", LTYPE3, x86.AMOVWLZX}, - {"MOVWQSX", LTYPE3, x86.AMOVWQSX}, - {"MOVWQZX", LTYPE3, x86.AMOVWQZX}, - {"MOVSB", LTYPE0, x86.AMOVSB}, - {"MOVSL", LTYPE0, x86.AMOVSL}, - {"MOVSQ", LTYPE0, x86.AMOVSQ}, - {"MOVSW", LTYPE0, x86.AMOVSW}, - {"MULB", LTYPE2, x86.AMULB}, - {"MULL", LTYPE2, x86.AMULL}, - {"MULQ", LTYPE2, x86.AMULQ}, - {"MULW", LTYPE2, x86.AMULW}, - {"NEGB", LTYPE1, x86.ANEGB}, - {"NEGL", LTYPE1, x86.ANEGL}, - {"NEGQ", LTYPE1, x86.ANEGQ}, - {"NEGW", LTYPE1, x86.ANEGW}, - {"NOP", LTYPEN, obj.ANOP}, - {"NOTB", LTYPE1, x86.ANOTB}, - {"NOTL", LTYPE1, x86.ANOTL}, - {"NOTQ", LTYPE1, x86.ANOTQ}, - {"NOTW", LTYPE1, x86.ANOTW}, - {"ORB", LTYPE3, x86.AORB}, - {"ORL", LTYPE3, x86.AORL}, - {"ORQ", LTYPE3, x86.AORQ}, - {"ORW", LTYPE3, x86.AORW}, - {"OUTB", LTYPE0, x86.AOUTB}, - {"OUTL", LTYPE0, x86.AOUTL}, - {"OUTW", LTYPE0, x86.AOUTW}, - {"OUTSB", LTYPE0, x86.AOUTSB}, - {"OUTSL", LTYPE0, x86.AOUTSL}, - {"OUTSW", LTYPE0, x86.AOUTSW}, - {"PAUSE", LTYPEN, x86.APAUSE}, - {"POPAL", LTYPE0, x86.APOPAL}, - {"POPAW", LTYPE0, x86.APOPAW}, - {"POPFL", LTYPE0, x86.APOPFL}, - {"POPFQ", LTYPE0, x86.APOPFQ}, - {"POPFW", LTYPE0, x86.APOPFW}, - {"POPL", LTYPE1, x86.APOPL}, - {"POPQ", LTYPE1, x86.APOPQ}, - {"POPW", LTYPE1, x86.APOPW}, - {"PUSHAL", LTYPE0, x86.APUSHAL}, - {"PUSHAW", LTYPE0, x86.APUSHAW}, - {"PUSHFL", LTYPE0, x86.APUSHFL}, - {"PUSHFQ", LTYPE0, x86.APUSHFQ}, - {"PUSHFW", LTYPE0, x86.APUSHFW}, - {"PUSHL", LTYPE2, x86.APUSHL}, - {"PUSHQ", LTYPE2, x86.APUSHQ}, - {"PUSHW", LTYPE2, x86.APUSHW}, - {"RCLB", LTYPE3, x86.ARCLB}, - {"RCLL", LTYPE3, x86.ARCLL}, - {"RCLQ", LTYPE3, x86.ARCLQ}, - {"RCLW", LTYPE3, x86.ARCLW}, - {"RCRB", LTYPE3, x86.ARCRB}, - {"RCRL", LTYPE3, x86.ARCRL}, - {"RCRQ", LTYPE3, x86.ARCRQ}, - {"RCRW", LTYPE3, x86.ARCRW}, - {"RDMSR", LTYPE0, x86.ARDMSR}, - {"RDPMC", LTYPE0, x86.ARDPMC}, - {"RDTSC", LTYPE0, x86.ARDTSC}, - {"REP", LTYPE0, x86.AREP}, - {"REPN", LTYPE0, x86.AREPN}, - {"RET", LTYPE0, obj.ARET}, - {"RETFL", LTYPERT, x86.ARETFL}, - {"RETFW", LTYPERT, x86.ARETFW}, - {"RETFQ", LTYPERT, x86.ARETFQ}, - {"ROLB", LTYPE3, x86.AROLB}, - {"ROLL", LTYPE3, x86.AROLL}, - {"ROLQ", LTYPE3, x86.AROLQ}, - {"ROLW", LTYPE3, x86.AROLW}, - {"RORB", LTYPE3, x86.ARORB}, - {"RORL", LTYPE3, x86.ARORL}, - {"RORQ", LTYPE3, x86.ARORQ}, - {"RORW", LTYPE3, x86.ARORW}, - {"RSM", LTYPE0, x86.ARSM}, - {"SAHF", LTYPE0, x86.ASAHF}, - {"SALB", LTYPE3, x86.ASALB}, - {"SALL", LTYPE3, x86.ASALL}, - {"SALQ", LTYPE3, x86.ASALQ}, - {"SALW", LTYPE3, x86.ASALW}, - {"SARB", LTYPE3, x86.ASARB}, - {"SARL", LTYPE3, x86.ASARL}, - {"SARQ", LTYPE3, x86.ASARQ}, - {"SARW", LTYPE3, x86.ASARW}, - {"SBBB", LTYPE3, x86.ASBBB}, - {"SBBL", LTYPE3, x86.ASBBL}, - {"SBBQ", LTYPE3, x86.ASBBQ}, - {"SBBW", LTYPE3, x86.ASBBW}, - {"SCASB", LTYPE0, x86.ASCASB}, - {"SCASL", LTYPE0, x86.ASCASL}, - {"SCASQ", LTYPE0, x86.ASCASQ}, - {"SCASW", LTYPE0, x86.ASCASW}, - {"SETCC", LTYPE1, x86.ASETCC}, /* see JCC etc above for condition codes */ - {"SETCS", LTYPE1, x86.ASETCS}, - {"SETEQ", LTYPE1, x86.ASETEQ}, - {"SETGE", LTYPE1, x86.ASETGE}, - {"SETGT", LTYPE1, x86.ASETGT}, - {"SETHI", LTYPE1, x86.ASETHI}, - {"SETLE", LTYPE1, x86.ASETLE}, - {"SETLS", LTYPE1, x86.ASETLS}, - {"SETLT", LTYPE1, x86.ASETLT}, - {"SETMI", LTYPE1, x86.ASETMI}, - {"SETNE", LTYPE1, x86.ASETNE}, - {"SETOC", LTYPE1, x86.ASETOC}, - {"SETOS", LTYPE1, x86.ASETOS}, - {"SETPC", LTYPE1, x86.ASETPC}, - {"SETPL", LTYPE1, x86.ASETPL}, - {"SETPS", LTYPE1, x86.ASETPS}, - {"SFENCE", LTYPE0, x86.ASFENCE}, - {"CDQ", LTYPE0, x86.ACDQ}, - {"CWD", LTYPE0, x86.ACWD}, - {"CQO", LTYPE0, x86.ACQO}, - {"SHLB", LTYPE3, x86.ASHLB}, - {"SHLL", LTYPES, x86.ASHLL}, - {"SHLQ", LTYPES, x86.ASHLQ}, - {"SHLW", LTYPES, x86.ASHLW}, - {"SHRB", LTYPE3, x86.ASHRB}, - {"SHRL", LTYPES, x86.ASHRL}, - {"SHRQ", LTYPES, x86.ASHRQ}, - {"SHRW", LTYPES, x86.ASHRW}, - {"STC", LTYPE0, x86.ASTC}, - {"STD", LTYPE0, x86.ASTD}, - {"STI", LTYPE0, x86.ASTI}, - {"STOSB", LTYPE0, x86.ASTOSB}, - {"STOSL", LTYPE0, x86.ASTOSL}, - {"STOSQ", LTYPE0, x86.ASTOSQ}, - {"STOSW", LTYPE0, x86.ASTOSW}, - {"SUBB", LTYPE3, x86.ASUBB}, - {"SUBL", LTYPE3, x86.ASUBL}, - {"SUBQ", LTYPE3, x86.ASUBQ}, - {"SUBW", LTYPE3, x86.ASUBW}, - {"SYSCALL", LTYPE0, x86.ASYSCALL}, - {"SYSRET", LTYPE0, x86.ASYSRET}, - {"SWAPGS", LTYPE0, x86.ASWAPGS}, - {"TESTB", LTYPE3, x86.ATESTB}, - {"TESTL", LTYPE3, x86.ATESTL}, - {"TESTQ", LTYPE3, x86.ATESTQ}, - {"TESTW", LTYPE3, x86.ATESTW}, - {"TEXT", LTYPET, obj.ATEXT}, - {"VERR", LTYPE2, x86.AVERR}, - {"VERW", LTYPE2, x86.AVERW}, - {"QUAD", LTYPE2, x86.AQUAD}, - {"WAIT", LTYPE0, x86.AWAIT}, - {"WBINVD", LTYPE0, x86.AWBINVD}, - {"WRMSR", LTYPE0, x86.AWRMSR}, - {"WORD", LTYPE2, x86.AWORD}, - {"XADDB", LTYPE3, x86.AXADDB}, - {"XADDL", LTYPE3, x86.AXADDL}, - {"XADDQ", LTYPE3, x86.AXADDQ}, - {"XADDW", LTYPE3, x86.AXADDW}, - {"XCHGB", LTYPE3, x86.AXCHGB}, - {"XCHGL", LTYPE3, x86.AXCHGL}, - {"XCHGQ", LTYPE3, x86.AXCHGQ}, - {"XCHGW", LTYPE3, x86.AXCHGW}, - {"XLAT", LTYPE2, x86.AXLAT}, - {"XORB", LTYPE3, x86.AXORB}, - {"XORL", LTYPE3, x86.AXORL}, - {"XORQ", LTYPE3, x86.AXORQ}, - {"XORW", LTYPE3, x86.AXORW}, - {"CMOVLCC", LTYPE3, x86.ACMOVLCC}, - {"CMOVLCS", LTYPE3, x86.ACMOVLCS}, - {"CMOVLEQ", LTYPE3, x86.ACMOVLEQ}, - {"CMOVLGE", LTYPE3, x86.ACMOVLGE}, - {"CMOVLGT", LTYPE3, x86.ACMOVLGT}, - {"CMOVLHI", LTYPE3, x86.ACMOVLHI}, - {"CMOVLLE", LTYPE3, x86.ACMOVLLE}, - {"CMOVLLS", LTYPE3, x86.ACMOVLLS}, - {"CMOVLLT", LTYPE3, x86.ACMOVLLT}, - {"CMOVLMI", LTYPE3, x86.ACMOVLMI}, - {"CMOVLNE", LTYPE3, x86.ACMOVLNE}, - {"CMOVLOC", LTYPE3, x86.ACMOVLOC}, - {"CMOVLOS", LTYPE3, x86.ACMOVLOS}, - {"CMOVLPC", LTYPE3, x86.ACMOVLPC}, - {"CMOVLPL", LTYPE3, x86.ACMOVLPL}, - {"CMOVLPS", LTYPE3, x86.ACMOVLPS}, - {"CMOVQCC", LTYPE3, x86.ACMOVQCC}, - {"CMOVQCS", LTYPE3, x86.ACMOVQCS}, - {"CMOVQEQ", LTYPE3, x86.ACMOVQEQ}, - {"CMOVQGE", LTYPE3, x86.ACMOVQGE}, - {"CMOVQGT", LTYPE3, x86.ACMOVQGT}, - {"CMOVQHI", LTYPE3, x86.ACMOVQHI}, - {"CMOVQLE", LTYPE3, x86.ACMOVQLE}, - {"CMOVQLS", LTYPE3, x86.ACMOVQLS}, - {"CMOVQLT", LTYPE3, x86.ACMOVQLT}, - {"CMOVQMI", LTYPE3, x86.ACMOVQMI}, - {"CMOVQNE", LTYPE3, x86.ACMOVQNE}, - {"CMOVQOC", LTYPE3, x86.ACMOVQOC}, - {"CMOVQOS", LTYPE3, x86.ACMOVQOS}, - {"CMOVQPC", LTYPE3, x86.ACMOVQPC}, - {"CMOVQPL", LTYPE3, x86.ACMOVQPL}, - {"CMOVQPS", LTYPE3, x86.ACMOVQPS}, - {"CMOVWCC", LTYPE3, x86.ACMOVWCC}, - {"CMOVWCS", LTYPE3, x86.ACMOVWCS}, - {"CMOVWEQ", LTYPE3, x86.ACMOVWEQ}, - {"CMOVWGE", LTYPE3, x86.ACMOVWGE}, - {"CMOVWGT", LTYPE3, x86.ACMOVWGT}, - {"CMOVWHI", LTYPE3, x86.ACMOVWHI}, - {"CMOVWLE", LTYPE3, x86.ACMOVWLE}, - {"CMOVWLS", LTYPE3, x86.ACMOVWLS}, - {"CMOVWLT", LTYPE3, x86.ACMOVWLT}, - {"CMOVWMI", LTYPE3, x86.ACMOVWMI}, - {"CMOVWNE", LTYPE3, x86.ACMOVWNE}, - {"CMOVWOC", LTYPE3, x86.ACMOVWOC}, - {"CMOVWOS", LTYPE3, x86.ACMOVWOS}, - {"CMOVWPC", LTYPE3, x86.ACMOVWPC}, - {"CMOVWPL", LTYPE3, x86.ACMOVWPL}, - {"CMOVWPS", LTYPE3, x86.ACMOVWPS}, - {"FMOVB", LTYPE3, x86.AFMOVB}, - {"FMOVBP", LTYPE3, x86.AFMOVBP}, - {"FMOVD", LTYPE3, x86.AFMOVD}, - {"FMOVDP", LTYPE3, x86.AFMOVDP}, - {"FMOVF", LTYPE3, x86.AFMOVF}, - {"FMOVFP", LTYPE3, x86.AFMOVFP}, - {"FMOVL", LTYPE3, x86.AFMOVL}, - {"FMOVLP", LTYPE3, x86.AFMOVLP}, - {"FMOVV", LTYPE3, x86.AFMOVV}, - {"FMOVVP", LTYPE3, x86.AFMOVVP}, - {"FMOVW", LTYPE3, x86.AFMOVW}, - {"FMOVWP", LTYPE3, x86.AFMOVWP}, - {"FMOVX", LTYPE3, x86.AFMOVX}, - {"FMOVXP", LTYPE3, x86.AFMOVXP}, - {"FCOMB", LTYPE3, x86.AFCOMB}, - {"FCOMBP", LTYPE3, x86.AFCOMBP}, - {"FCOMD", LTYPE3, x86.AFCOMD}, - {"FCOMDP", LTYPE3, x86.AFCOMDP}, - {"FCOMDPP", LTYPE3, x86.AFCOMDPP}, - {"FCOMF", LTYPE3, x86.AFCOMF}, - {"FCOMFP", LTYPE3, x86.AFCOMFP}, - {"FCOML", LTYPE3, x86.AFCOML}, - {"FCOMLP", LTYPE3, x86.AFCOMLP}, - {"FCOMW", LTYPE3, x86.AFCOMW}, - {"FCOMWP", LTYPE3, x86.AFCOMWP}, - {"FUCOM", LTYPE3, x86.AFUCOM}, - {"FUCOMP", LTYPE3, x86.AFUCOMP}, - {"FUCOMPP", LTYPE3, x86.AFUCOMPP}, - {"FADDW", LTYPE3, x86.AFADDW}, - {"FADDL", LTYPE3, x86.AFADDL}, - {"FADDF", LTYPE3, x86.AFADDF}, - {"FADDD", LTYPE3, x86.AFADDD}, - {"FADDDP", LTYPE3, x86.AFADDDP}, - {"FSUBDP", LTYPE3, x86.AFSUBDP}, - {"FSUBW", LTYPE3, x86.AFSUBW}, - {"FSUBL", LTYPE3, x86.AFSUBL}, - {"FSUBF", LTYPE3, x86.AFSUBF}, - {"FSUBD", LTYPE3, x86.AFSUBD}, - {"FSUBRDP", LTYPE3, x86.AFSUBRDP}, - {"FSUBRW", LTYPE3, x86.AFSUBRW}, - {"FSUBRL", LTYPE3, x86.AFSUBRL}, - {"FSUBRF", LTYPE3, x86.AFSUBRF}, - {"FSUBRD", LTYPE3, x86.AFSUBRD}, - {"FMULDP", LTYPE3, x86.AFMULDP}, - {"FMULW", LTYPE3, x86.AFMULW}, - {"FMULL", LTYPE3, x86.AFMULL}, - {"FMULF", LTYPE3, x86.AFMULF}, - {"FMULD", LTYPE3, x86.AFMULD}, - {"FDIVDP", LTYPE3, x86.AFDIVDP}, - {"FDIVW", LTYPE3, x86.AFDIVW}, - {"FDIVL", LTYPE3, x86.AFDIVL}, - {"FDIVF", LTYPE3, x86.AFDIVF}, - {"FDIVD", LTYPE3, x86.AFDIVD}, - {"FDIVRDP", LTYPE3, x86.AFDIVRDP}, - {"FDIVRW", LTYPE3, x86.AFDIVRW}, - {"FDIVRL", LTYPE3, x86.AFDIVRL}, - {"FDIVRF", LTYPE3, x86.AFDIVRF}, - {"FDIVRD", LTYPE3, x86.AFDIVRD}, - {"FXCHD", LTYPE3, x86.AFXCHD}, - {"FFREE", LTYPE1, x86.AFFREE}, - {"FLDCW", LTYPE2, x86.AFLDCW}, - {"FLDENV", LTYPE1, x86.AFLDENV}, - {"FRSTOR", LTYPE2, x86.AFRSTOR}, - {"FSAVE", LTYPE1, x86.AFSAVE}, - {"FSTCW", LTYPE1, x86.AFSTCW}, - {"FSTENV", LTYPE1, x86.AFSTENV}, - {"FSTSW", LTYPE1, x86.AFSTSW}, - {"F2XM1", LTYPE0, x86.AF2XM1}, - {"FABS", LTYPE0, x86.AFABS}, - {"FCHS", LTYPE0, x86.AFCHS}, - {"FCLEX", LTYPE0, x86.AFCLEX}, - {"FCOS", LTYPE0, x86.AFCOS}, - {"FDECSTP", LTYPE0, x86.AFDECSTP}, - {"FINCSTP", LTYPE0, x86.AFINCSTP}, - {"FINIT", LTYPE0, x86.AFINIT}, - {"FLD1", LTYPE0, x86.AFLD1}, - {"FLDL2E", LTYPE0, x86.AFLDL2E}, - {"FLDL2T", LTYPE0, x86.AFLDL2T}, - {"FLDLG2", LTYPE0, x86.AFLDLG2}, - {"FLDLN2", LTYPE0, x86.AFLDLN2}, - {"FLDPI", LTYPE0, x86.AFLDPI}, - {"FLDZ", LTYPE0, x86.AFLDZ}, - {"FNOP", LTYPE0, x86.AFNOP}, - {"FPATAN", LTYPE0, x86.AFPATAN}, - {"FPREM", LTYPE0, x86.AFPREM}, - {"FPREM1", LTYPE0, x86.AFPREM1}, - {"FPTAN", LTYPE0, x86.AFPTAN}, - {"FRNDINT", LTYPE0, x86.AFRNDINT}, - {"FSCALE", LTYPE0, x86.AFSCALE}, - {"FSIN", LTYPE0, x86.AFSIN}, - {"FSINCOS", LTYPE0, x86.AFSINCOS}, - {"FSQRT", LTYPE0, x86.AFSQRT}, - {"FTST", LTYPE0, x86.AFTST}, - {"FXAM", LTYPE0, x86.AFXAM}, - {"FXTRACT", LTYPE0, x86.AFXTRACT}, - {"FYL2X", LTYPE0, x86.AFYL2X}, - {"FYL2XP1", LTYPE0, x86.AFYL2XP1}, - {"ADDPD", LTYPE3, x86.AADDPD}, - {"ADDPS", LTYPE3, x86.AADDPS}, - {"ADDSD", LTYPE3, x86.AADDSD}, - {"ADDSS", LTYPE3, x86.AADDSS}, - {"ANDNPD", LTYPE3, x86.AANDNPD}, - {"ANDNPS", LTYPE3, x86.AANDNPS}, - {"ANDPD", LTYPE3, x86.AANDPD}, - {"ANDPS", LTYPE3, x86.AANDPS}, - {"CMPPD", LTYPEXC, x86.ACMPPD}, - {"CMPPS", LTYPEXC, x86.ACMPPS}, - {"CMPSD", LTYPEXC, x86.ACMPSD}, - {"CMPSS", LTYPEXC, x86.ACMPSS}, - {"COMISD", LTYPE3, x86.ACOMISD}, - {"COMISS", LTYPE3, x86.ACOMISS}, - {"CVTPL2PD", LTYPE3, x86.ACVTPL2PD}, - {"CVTPL2PS", LTYPE3, x86.ACVTPL2PS}, - {"CVTPD2PL", LTYPE3, x86.ACVTPD2PL}, - {"CVTPD2PS", LTYPE3, x86.ACVTPD2PS}, - {"CVTPS2PL", LTYPE3, x86.ACVTPS2PL}, - {"PF2IW", LTYPE3, x86.APF2IW}, - {"PF2IL", LTYPE3, x86.APF2IL}, - {"PF2ID", LTYPE3, x86.APF2IL}, /* syn */ - {"PI2FL", LTYPE3, x86.API2FL}, - {"PI2FD", LTYPE3, x86.API2FL}, /* syn */ - {"PI2FW", LTYPE3, x86.API2FW}, - {"CVTPS2PD", LTYPE3, x86.ACVTPS2PD}, - {"CVTSD2SL", LTYPE3, x86.ACVTSD2SL}, - {"CVTSD2SQ", LTYPE3, x86.ACVTSD2SQ}, - {"CVTSD2SS", LTYPE3, x86.ACVTSD2SS}, - {"CVTSL2SD", LTYPE3, x86.ACVTSL2SD}, - {"CVTSQ2SD", LTYPE3, x86.ACVTSQ2SD}, - {"CVTSL2SS", LTYPE3, x86.ACVTSL2SS}, - {"CVTSQ2SS", LTYPE3, x86.ACVTSQ2SS}, - {"CVTSS2SD", LTYPE3, x86.ACVTSS2SD}, - {"CVTSS2SL", LTYPE3, x86.ACVTSS2SL}, - {"CVTSS2SQ", LTYPE3, x86.ACVTSS2SQ}, - {"CVTTPD2PL", LTYPE3, x86.ACVTTPD2PL}, - {"CVTTPS2PL", LTYPE3, x86.ACVTTPS2PL}, - {"CVTTSD2SL", LTYPE3, x86.ACVTTSD2SL}, - {"CVTTSD2SQ", LTYPE3, x86.ACVTTSD2SQ}, - {"CVTTSS2SL", LTYPE3, x86.ACVTTSS2SL}, - {"CVTTSS2SQ", LTYPE3, x86.ACVTTSS2SQ}, - {"DIVPD", LTYPE3, x86.ADIVPD}, - {"DIVPS", LTYPE3, x86.ADIVPS}, - {"DIVSD", LTYPE3, x86.ADIVSD}, - {"DIVSS", LTYPE3, x86.ADIVSS}, - {"FXRSTOR", LTYPE2, x86.AFXRSTOR}, - {"FXRSTOR64", LTYPE2, x86.AFXRSTOR64}, - {"FXSAVE", LTYPE1, x86.AFXSAVE}, - {"FXSAVE64", LTYPE1, x86.AFXSAVE64}, - {"LDMXCSR", LTYPE2, x86.ALDMXCSR}, - {"MASKMOVOU", LTYPE3, x86.AMASKMOVOU}, - {"MASKMOVDQU", LTYPE3, x86.AMASKMOVOU}, /* syn */ - {"MASKMOVQ", LTYPE3, x86.AMASKMOVQ}, - {"MAXPD", LTYPE3, x86.AMAXPD}, - {"MAXPS", LTYPE3, x86.AMAXPS}, - {"MAXSD", LTYPE3, x86.AMAXSD}, - {"MAXSS", LTYPE3, x86.AMAXSS}, - {"MINPD", LTYPE3, x86.AMINPD}, - {"MINPS", LTYPE3, x86.AMINPS}, - {"MINSD", LTYPE3, x86.AMINSD}, - {"MINSS", LTYPE3, x86.AMINSS}, - {"MOVAPD", LTYPE3, x86.AMOVAPD}, - {"MOVAPS", LTYPE3, x86.AMOVAPS}, - {"MOVD", LTYPE3, x86.AMOVQ}, /* syn */ - {"MOVDQ2Q", LTYPE3, x86.AMOVQ}, /* syn */ - {"MOVO", LTYPE3, x86.AMOVO}, - {"MOVOA", LTYPE3, x86.AMOVO}, /* syn */ - {"MOVOU", LTYPE3, x86.AMOVOU}, - {"MOVHLPS", LTYPE3, x86.AMOVHLPS}, - {"MOVHPD", LTYPE3, x86.AMOVHPD}, - {"MOVHPS", LTYPE3, x86.AMOVHPS}, - {"MOVLHPS", LTYPE3, x86.AMOVLHPS}, - {"MOVLPD", LTYPE3, x86.AMOVLPD}, - {"MOVLPS", LTYPE3, x86.AMOVLPS}, - {"MOVMSKPD", LTYPE3, x86.AMOVMSKPD}, - {"MOVMSKPS", LTYPE3, x86.AMOVMSKPS}, - {"MOVNTO", LTYPE3, x86.AMOVNTO}, - {"MOVNTDQ", LTYPE3, x86.AMOVNTO}, /* syn */ - {"MOVNTPD", LTYPE3, x86.AMOVNTPD}, - {"MOVNTPS", LTYPE3, x86.AMOVNTPS}, - {"MOVNTQ", LTYPE3, x86.AMOVNTQ}, - {"MOVQOZX", LTYPE3, x86.AMOVQOZX}, - {"MOVSD", LTYPE3, x86.AMOVSD}, - {"MOVSS", LTYPE3, x86.AMOVSS}, - {"MOVUPD", LTYPE3, x86.AMOVUPD}, - {"MOVUPS", LTYPE3, x86.AMOVUPS}, - {"MULPD", LTYPE3, x86.AMULPD}, - {"MULPS", LTYPE3, x86.AMULPS}, - {"MULSD", LTYPE3, x86.AMULSD}, - {"MULSS", LTYPE3, x86.AMULSS}, - {"ORPD", LTYPE3, x86.AORPD}, - {"ORPS", LTYPE3, x86.AORPS}, - {"PACKSSLW", LTYPE3, x86.APACKSSLW}, - {"PACKSSWB", LTYPE3, x86.APACKSSWB}, - {"PACKUSWB", LTYPE3, x86.APACKUSWB}, - {"PADDB", LTYPE3, x86.APADDB}, - {"PADDL", LTYPE3, x86.APADDL}, - {"PADDQ", LTYPE3, x86.APADDQ}, - {"PADDSB", LTYPE3, x86.APADDSB}, - {"PADDSW", LTYPE3, x86.APADDSW}, - {"PADDUSB", LTYPE3, x86.APADDUSB}, - {"PADDUSW", LTYPE3, x86.APADDUSW}, - {"PADDW", LTYPE3, x86.APADDW}, - {"PAND", LTYPE3, x86.APAND}, - {"PANDB", LTYPE3, x86.APANDB}, - {"PANDL", LTYPE3, x86.APANDL}, - {"PANDSB", LTYPE3, x86.APANDSB}, - {"PANDSW", LTYPE3, x86.APANDSW}, - {"PANDUSB", LTYPE3, x86.APANDUSB}, - {"PANDUSW", LTYPE3, x86.APANDUSW}, - {"PANDW", LTYPE3, x86.APANDW}, - {"PANDN", LTYPE3, x86.APANDN}, - {"PAVGB", LTYPE3, x86.APAVGB}, - {"PAVGW", LTYPE3, x86.APAVGW}, - {"PCMPEQB", LTYPE3, x86.APCMPEQB}, - {"PCMPEQL", LTYPE3, x86.APCMPEQL}, - {"PCMPEQW", LTYPE3, x86.APCMPEQW}, - {"PCMPGTB", LTYPE3, x86.APCMPGTB}, - {"PCMPGTL", LTYPE3, x86.APCMPGTL}, - {"PCMPGTW", LTYPE3, x86.APCMPGTW}, - {"PEXTRW", LTYPEX, x86.APEXTRW}, - {"PINSRW", LTYPEX, x86.APINSRW}, - {"PINSRD", LTYPEX, x86.APINSRD}, - {"PINSRQ", LTYPEX, x86.APINSRQ}, - {"PMADDWL", LTYPE3, x86.APMADDWL}, - {"PMAXSW", LTYPE3, x86.APMAXSW}, - {"PMAXUB", LTYPE3, x86.APMAXUB}, - {"PMINSW", LTYPE3, x86.APMINSW}, - {"PMINUB", LTYPE3, x86.APMINUB}, - {"PMOVMSKB", LTYPE3, x86.APMOVMSKB}, - {"PMULHRW", LTYPE3, x86.APMULHRW}, - {"PMULHUW", LTYPE3, x86.APMULHUW}, - {"PMULHW", LTYPE3, x86.APMULHW}, - {"PMULLW", LTYPE3, x86.APMULLW}, - {"PMULULQ", LTYPE3, x86.APMULULQ}, - {"POR", LTYPE3, x86.APOR}, - {"PSADBW", LTYPE3, x86.APSADBW}, - {"PSHUFHW", LTYPEX, x86.APSHUFHW}, - {"PSHUFL", LTYPEX, x86.APSHUFL}, - {"PSHUFLW", LTYPEX, x86.APSHUFLW}, - {"PSHUFW", LTYPEX, x86.APSHUFW}, - {"PSHUFB", LTYPEM, x86.APSHUFB}, - {"PSLLO", LTYPE3, x86.APSLLO}, - {"PSLLDQ", LTYPE3, x86.APSLLO}, /* syn */ - {"PSLLL", LTYPE3, x86.APSLLL}, - {"PSLLQ", LTYPE3, x86.APSLLQ}, - {"PSLLW", LTYPE3, x86.APSLLW}, - {"PSRAL", LTYPE3, x86.APSRAL}, - {"PSRAW", LTYPE3, x86.APSRAW}, - {"PSRLO", LTYPE3, x86.APSRLO}, - {"PSRLDQ", LTYPE3, x86.APSRLO}, /* syn */ - {"PSRLL", LTYPE3, x86.APSRLL}, - {"PSRLQ", LTYPE3, x86.APSRLQ}, - {"PSRLW", LTYPE3, x86.APSRLW}, - {"PSUBB", LTYPE3, x86.APSUBB}, - {"PSUBL", LTYPE3, x86.APSUBL}, - {"PSUBQ", LTYPE3, x86.APSUBQ}, - {"PSUBSB", LTYPE3, x86.APSUBSB}, - {"PSUBSW", LTYPE3, x86.APSUBSW}, - {"PSUBUSB", LTYPE3, x86.APSUBUSB}, - {"PSUBUSW", LTYPE3, x86.APSUBUSW}, - {"PSUBW", LTYPE3, x86.APSUBW}, - {"PUNPCKHBW", LTYPE3, x86.APUNPCKHBW}, - {"PUNPCKHLQ", LTYPE3, x86.APUNPCKHLQ}, - {"PUNPCKHQDQ", LTYPE3, x86.APUNPCKHQDQ}, - {"PUNPCKHWL", LTYPE3, x86.APUNPCKHWL}, - {"PUNPCKLBW", LTYPE3, x86.APUNPCKLBW}, - {"PUNPCKLLQ", LTYPE3, x86.APUNPCKLLQ}, - {"PUNPCKLQDQ", LTYPE3, x86.APUNPCKLQDQ}, - {"PUNPCKLWL", LTYPE3, x86.APUNPCKLWL}, - {"PXOR", LTYPE3, x86.APXOR}, - {"RCPPS", LTYPE3, x86.ARCPPS}, - {"RCPSS", LTYPE3, x86.ARCPSS}, - {"RSQRTPS", LTYPE3, x86.ARSQRTPS}, - {"RSQRTSS", LTYPE3, x86.ARSQRTSS}, - {"SHUFPD", LTYPEX, x86.ASHUFPD}, - {"SHUFPS", LTYPEX, x86.ASHUFPS}, - {"SQRTPD", LTYPE3, x86.ASQRTPD}, - {"SQRTPS", LTYPE3, x86.ASQRTPS}, - {"SQRTSD", LTYPE3, x86.ASQRTSD}, - {"SQRTSS", LTYPE3, x86.ASQRTSS}, - {"STMXCSR", LTYPE1, x86.ASTMXCSR}, - {"SUBPD", LTYPE3, x86.ASUBPD}, - {"SUBPS", LTYPE3, x86.ASUBPS}, - {"SUBSD", LTYPE3, x86.ASUBSD}, - {"SUBSS", LTYPE3, x86.ASUBSS}, - {"UCOMISD", LTYPE3, x86.AUCOMISD}, - {"UCOMISS", LTYPE3, x86.AUCOMISS}, - {"UNPCKHPD", LTYPE3, x86.AUNPCKHPD}, - {"UNPCKHPS", LTYPE3, x86.AUNPCKHPS}, - {"UNPCKLPD", LTYPE3, x86.AUNPCKLPD}, - {"UNPCKLPS", LTYPE3, x86.AUNPCKLPS}, - {"XORPD", LTYPE3, x86.AXORPD}, - {"XORPS", LTYPE3, x86.AXORPS}, - {"CRC32B", LTYPE4, x86.ACRC32B}, - {"CRC32Q", LTYPE4, x86.ACRC32Q}, - {"PREFETCHT0", LTYPE2, x86.APREFETCHT0}, - {"PREFETCHT1", LTYPE2, x86.APREFETCHT1}, - {"PREFETCHT2", LTYPE2, x86.APREFETCHT2}, - {"PREFETCHNTA", LTYPE2, x86.APREFETCHNTA}, - {"UNDEF", LTYPE0, obj.AUNDEF}, - {"AESENC", LTYPE3, x86.AAESENC}, - {"AESENCLAST", LTYPE3, x86.AAESENCLAST}, - {"AESDEC", LTYPE3, x86.AAESDEC}, - {"AESDECLAST", LTYPE3, x86.AAESDECLAST}, - {"AESIMC", LTYPE3, x86.AAESIMC}, - {"AESKEYGENASSIST", LTYPEX, x86.AAESKEYGENASSIST}, - {"PSHUFD", LTYPEX, x86.APSHUFD}, - {"USEFIELD", LTYPEN, obj.AUSEFIELD}, - {"PCLMULQDQ", LTYPEX, x86.APCLMULQDQ}, - {"PCDATA", LTYPEPC, obj.APCDATA}, - {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, -} - -func cinit() { -} - -func checkscale(scale int8) { - switch scale { - case 1, - 2, - 4, - 8: - return - } - - yyerror("scale must be 1248: %d", scale) -} - -func cclean() { - var g2 Addr2 - - g2.from = nullgen - g2.to = nullgen - outcode(obj.AEND, &g2) -} - -var lastpc *obj.Prog - -type Addr2 struct { - from obj.Addr - to obj.Addr -} - -func outcode(a int, g2 *Addr2) { - var p *obj.Prog - var pl *obj.Plist - - if asm.Pass == 1 { - goto out - } - - p = new(obj.Prog) - *p = obj.Prog{} - p.Ctxt = asm.Ctxt - p.As = int16(a) - p.Lineno = stmtline - p.From = g2.from - p.To = g2.to - p.Pc = int64(asm.PC) - - if lastpc == nil { - pl = obj.Linknewplist(asm.Ctxt) - pl.Firstpc = p - } else { - - lastpc.Link = p - } - lastpc = p - -out: - if a != obj.AGLOBL && a != obj.ADATA { - asm.PC++ - } -} diff --git a/src/cmd/new6a/y.go b/src/cmd/new6a/y.go deleted file mode 100644 index 0b78d2e1e2..0000000000 --- a/src/cmd/new6a/y.go +++ /dev/null @@ -1,1330 +0,0 @@ -//line a.y:32 -package main - -import __yyfmt__ "fmt" - -//line a.y:32 -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/x86" -) - -//line a.y:41 -type yySymType struct { - yys int - sym *asm.Sym - lval int64 - dval float64 - sval string - addr obj.Addr - addr2 Addr2 -} - -const LTYPE0 = 57346 -const LTYPE1 = 57347 -const LTYPE2 = 57348 -const LTYPE3 = 57349 -const LTYPE4 = 57350 -const LTYPEC = 57351 -const LTYPED = 57352 -const LTYPEN = 57353 -const LTYPER = 57354 -const LTYPET = 57355 -const LTYPEG = 57356 -const LTYPEPC = 57357 -const LTYPES = 57358 -const LTYPEM = 57359 -const LTYPEI = 57360 -const LTYPEXC = 57361 -const LTYPEX = 57362 -const LTYPERT = 57363 -const LTYPEF = 57364 -const LCONST = 57365 -const LFP = 57366 -const LPC = 57367 -const LSB = 57368 -const LBREG = 57369 -const LLREG = 57370 -const LSREG = 57371 -const LFREG = 57372 -const LMREG = 57373 -const LXREG = 57374 -const LFCONST = 57375 -const LSCONST = 57376 -const LSP = 57377 -const LNAME = 57378 -const LLAB = 57379 -const LVAR = 57380 - -var yyToknames = []string{ - "'|'", - "'^'", - "'&'", - "'<'", - "'>'", - "'+'", - "'-'", - "'*'", - "'/'", - "'%'", - "LTYPE0", - "LTYPE1", - "LTYPE2", - "LTYPE3", - "LTYPE4", - "LTYPEC", - "LTYPED", - "LTYPEN", - "LTYPER", - "LTYPET", - "LTYPEG", - "LTYPEPC", - "LTYPES", - "LTYPEM", - "LTYPEI", - "LTYPEXC", - "LTYPEX", - "LTYPERT", - "LTYPEF", - "LCONST", - "LFP", - "LPC", - "LSB", - "LBREG", - "LLREG", - "LSREG", - "LFREG", - "LMREG", - "LXREG", - "LFCONST", - "LSCONST", - "LSP", - "LNAME", - "LLAB", - "LVAR", -} -var yyStatenames = []string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyMaxDepth = 200 - -//line yacctab:1 -var yyExca = []int{ - -1, 1, - 1, -1, - -2, 2, -} - -const yyNprod = 133 -const yyPrivate = 57344 - -var yyTokenNames []string -var yyStates []string - -const yyLast = 593 - -var yyAct = []int{ - - 52, 227, 41, 3, 80, 208, 269, 64, 123, 50, - 51, 79, 54, 170, 268, 74, 267, 118, 85, 72, - 83, 263, 73, 255, 253, 98, 241, 84, 81, 239, - 237, 100, 102, 112, 221, 219, 112, 210, 209, 171, - 240, 107, 234, 62, 211, 174, 143, 138, 65, 207, - 111, 119, 115, 113, 112, 231, 67, 169, 120, 121, - 122, 249, 230, 92, 94, 96, 128, 226, 225, 224, - 104, 106, 74, 58, 57, 154, 136, 112, 129, 85, - 153, 83, 151, 150, 139, 141, 149, 148, 84, 81, - 140, 147, 142, 146, 145, 144, 63, 55, 58, 57, - 137, 43, 45, 48, 44, 46, 49, 40, 135, 47, - 69, 134, 56, 127, 155, 40, 34, 37, 53, 31, - 59, 32, 55, 35, 33, 223, 176, 177, 222, 217, - 60, 215, 220, 112, 120, 243, 114, 56, 74, 242, - 216, 236, 183, 76, 173, 59, 58, 57, 256, 166, - 168, 251, 252, 192, 194, 196, 167, 112, 112, 112, - 112, 112, 195, 184, 112, 112, 112, 264, 58, 57, - 55, 212, 257, 248, 197, 198, 199, 200, 201, 182, - 120, 204, 205, 206, 218, 56, 42, 114, 152, 38, - 65, 76, 55, 59, 190, 191, 184, 261, 260, 166, - 168, 229, 258, 112, 112, 75, 167, 56, 89, 235, - 36, 71, 65, 76, 238, 59, 108, 109, 254, 213, - 232, 233, 125, 126, 228, 244, 247, 203, 245, 88, - 124, 181, 125, 126, 246, 158, 159, 160, 175, 250, - 202, 25, 185, 186, 187, 188, 189, 16, 15, 6, - 110, 259, 7, 2, 1, 262, 156, 157, 158, 159, - 160, 265, 266, 105, 9, 10, 11, 12, 13, 17, - 28, 18, 14, 29, 30, 26, 19, 20, 21, 22, - 23, 24, 27, 58, 57, 82, 165, 164, 163, 161, - 162, 156, 157, 158, 159, 160, 4, 103, 8, 101, - 5, 99, 97, 58, 57, 95, 93, 55, 91, 87, - 77, 43, 45, 48, 44, 46, 49, 68, 66, 47, - 86, 61, 56, 70, 214, 0, 78, 55, 53, 0, - 59, 43, 45, 48, 44, 46, 49, 172, 0, 47, - 60, 0, 56, 58, 57, 82, 0, 65, 53, 0, - 59, 43, 45, 48, 44, 46, 49, 0, 0, 47, - 0, 0, 0, 58, 57, 0, 0, 55, 0, 0, - 0, 43, 45, 48, 44, 46, 49, 0, 0, 47, - 86, 0, 56, 58, 57, 0, 0, 55, 53, 0, - 59, 43, 45, 48, 44, 46, 49, 0, 0, 47, - 60, 0, 56, 58, 57, 0, 90, 55, 53, 0, - 59, 43, 45, 48, 44, 46, 49, 58, 133, 47, - 60, 0, 56, 0, 0, 0, 39, 55, 53, 0, - 59, 43, 45, 48, 44, 46, 49, 58, 57, 47, - 60, 55, 56, 0, 58, 57, 0, 0, 53, 0, - 59, 131, 130, 0, 60, 0, 56, 58, 57, 0, - 0, 55, 132, 0, 59, 0, 116, 0, 55, 58, - 57, 0, 0, 117, 0, 0, 56, 0, 0, 0, - 0, 55, 76, 56, 59, 58, 179, 0, 193, 76, - 0, 59, 0, 55, 75, 0, 56, 58, 57, 0, - 0, 0, 76, 180, 59, 0, 0, 0, 56, 55, - 0, 58, 57, 0, 76, 0, 59, 0, 0, 178, - 0, 55, 0, 0, 56, 0, 0, 0, 0, 0, - 76, 0, 59, 0, 60, 55, 56, 0, 0, 0, - 0, 0, 53, 0, 59, 0, 0, 0, 0, 0, - 56, 0, 0, 0, 0, 0, 76, 0, 59, 165, - 164, 163, 161, 162, 156, 157, 158, 159, 160, 164, - 163, 161, 162, 156, 157, 158, 159, 160, 163, 161, - 162, 156, 157, 158, 159, 160, 161, 162, 156, 157, - 158, 159, 160, -} -var yyPact = []int{ - - -1000, -1000, 250, -1000, 70, -1000, 74, 66, 72, 65, - 374, 294, 294, 394, 159, -1000, -1000, 274, 354, 294, - 294, 294, 314, -5, -5, -1000, 294, 294, 84, 488, - 488, -1000, 502, -1000, -1000, 502, -1000, -1000, -1000, 394, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -2, 428, -3, -1000, -1000, 502, 502, 502, - 223, -1000, 61, -1000, -1000, 408, -1000, 59, -1000, 56, - -1000, 448, -1000, 48, -7, 213, 502, -1000, 334, -1000, - -1000, -1000, 64, -1000, -1000, -8, 223, -1000, -1000, -1000, - 394, -1000, 42, -1000, 41, -1000, 39, -1000, 35, -1000, - 34, -1000, -1000, -1000, 31, -1000, 30, 176, 28, 23, - 250, 555, -1000, 555, -1000, 111, 2, -16, 282, 106, - -1000, -1000, -1000, -9, 230, 502, 502, -1000, -1000, -1000, - -1000, -1000, 476, 460, 394, 294, -1000, 448, 128, -1000, - -1000, -1000, -1000, 161, -9, 394, 394, 394, 394, 394, - 294, 294, 502, 435, 137, -1000, 502, 502, 502, 502, - 502, 233, 219, 502, 502, 502, -6, -17, -18, -10, - 502, -1000, -1000, 208, 95, 213, -1000, -1000, -20, 89, - -1000, -1000, -1000, -1000, -21, 79, 76, -1000, 17, 16, - -1000, -1000, 15, 191, 10, -1000, 3, 224, 224, -1000, - -1000, -1000, 502, 502, 579, 572, 564, -12, 502, -1000, - -1000, 103, -25, 502, -26, -1000, -1000, -1000, -14, -1000, - -29, -1000, 101, 96, 502, 314, -5, -1000, 216, 140, - 8, -5, 247, 247, 113, -31, 207, -1000, -32, -1000, - 112, -1000, -1000, -1000, -1000, -1000, -1000, 139, 192, 191, - -1000, 187, 186, -1000, 502, -1000, -34, -1000, 134, -1000, - 502, 502, -39, -1000, -1000, -41, -49, -1000, -1000, -1000, -} -var yyPgo = []int{ - - 0, 0, 17, 324, 8, 186, 7, 1, 2, 12, - 4, 96, 43, 11, 9, 10, 210, 323, 189, 321, - 318, 317, 310, 309, 308, 306, 305, 302, 301, 299, - 297, 263, 254, 253, 3, 250, 249, 248, 247, 241, -} -var yyR1 = []int{ - - 0, 32, 33, 32, 35, 34, 34, 34, 34, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 16, 16, 20, 21, 19, 19, 18, 18, 17, 17, - 17, 37, 38, 38, 39, 39, 22, 22, 23, 23, - 24, 24, 25, 25, 26, 26, 26, 27, 28, 29, - 29, 30, 31, 11, 11, 13, 13, 13, 13, 13, - 13, 12, 12, 10, 10, 8, 8, 8, 8, 8, - 8, 8, 6, 6, 6, 6, 6, 6, 6, 5, - 5, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 15, 15, 9, 9, 4, 4, 4, 3, - 3, 3, 1, 1, 1, 1, 1, 1, 7, 7, - 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, -} -var yyR2 = []int{ - - 0, 0, 0, 3, 0, 4, 1, 2, 2, 3, - 3, 2, 2, 2, 2, 2, 2, 1, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, - 0, 1, 3, 3, 2, 1, 2, 1, 2, 1, - 3, 6, 5, 7, 4, 6, 2, 1, 1, 1, - 3, 5, 3, 5, 2, 1, 3, 5, 5, 0, - 1, 3, 3, 1, 1, 1, 1, 2, 2, 1, - 1, 1, 1, 4, 2, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 2, 2, 4, 5, 3, 1, - 1, 1, 4, 4, 4, 6, 9, 9, 3, 3, - 5, 8, 1, 6, 5, 7, 0, 2, 2, 1, - 1, 1, 1, 1, 2, 2, 2, 3, 1, 2, - 3, 4, 1, 3, 3, 3, 3, 3, 4, 4, - 3, 3, 3, -} -var yyChk = []int{ - - -1000, -32, -33, -34, 46, 50, -36, 2, 48, 14, - 15, 16, 17, 18, 22, -37, -38, 19, 21, 26, - 27, 28, 29, 30, 31, -39, 25, 32, 20, 23, - 24, 49, 51, 50, 50, 51, -16, 52, -18, 52, - -11, -8, -5, 37, 40, 38, 41, 45, 39, 42, - -14, -15, -1, 54, -9, 33, 48, 10, 9, 56, - 46, -19, -12, -11, -6, 53, -20, -12, -21, -11, - -17, 52, -10, -6, -1, 46, 54, -22, 52, -13, - -10, -15, 11, -8, -14, -1, 46, -23, -16, -18, - 52, -24, -12, -25, -12, -26, -12, -27, -8, -28, - -6, -29, -6, -30, -12, -31, -12, -9, -5, -5, - -35, -2, -1, -2, -11, 54, 38, 45, -2, 54, - -1, -1, -1, -4, 7, 9, 10, 52, -1, -9, - 44, 43, 54, 10, 52, 52, -10, 52, 54, -4, - -13, -8, -14, 54, -4, 52, 52, 52, 52, 52, - 52, 52, 12, 52, 52, -34, 9, 10, 11, 12, - 13, 7, 8, 6, 5, 4, 38, 45, 39, 55, - 11, 55, 55, 38, 54, 8, -1, -1, 43, 10, - 43, -11, -12, -10, 35, -11, -11, -11, -11, -11, - -12, -12, -1, 53, -1, -6, -1, -2, -2, -2, - -2, -2, 7, 8, -2, -2, -2, 55, 11, 55, - 55, 54, -1, 11, -3, 36, 45, 34, -4, 55, - 43, 55, 49, 49, 52, 52, 52, -7, 33, 10, - 52, 52, -2, -2, 54, -1, 38, 55, -1, 55, - 54, 55, 38, 39, -1, -8, -6, 10, 33, 53, - -6, 38, 39, 55, 11, 55, 36, 33, 10, -7, - 11, 11, -1, 55, 33, -1, -1, 55, 55, 55, -} -var yyDef = []int{ - - 1, -2, 0, 3, 0, 6, 0, 0, 0, 30, - 0, 0, 0, 0, 0, 17, 18, 0, 30, 0, - 0, 0, 0, 0, 59, 27, 0, 0, 0, 0, - 0, 4, 0, 7, 8, 0, 11, 31, 12, 0, - 37, 63, 64, 75, 76, 77, 78, 79, 80, 81, - 89, 90, 91, 0, 102, 112, 113, 0, 0, 0, - 106, 13, 35, 71, 72, 0, 14, 0, 15, 0, - 16, 0, 39, 0, 0, 106, 0, 19, 0, 47, - 65, 66, 0, 69, 70, 91, 106, 20, 48, 49, - 31, 21, 0, 22, 0, 23, 55, 24, 0, 25, - 0, 26, 60, 28, 0, 29, 0, 0, 0, 0, - 0, 9, 122, 10, 36, 0, 0, 0, 0, 0, - 114, 115, 116, 0, 0, 0, 0, 34, 82, 83, - 84, 85, 0, 0, 0, 0, 38, 0, 0, 74, - 46, 67, 68, 0, 74, 0, 0, 54, 0, 0, - 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, - 0, 99, 117, 0, 0, 106, 107, 108, 0, 0, - 88, 32, 33, 40, 0, 50, 52, 56, 0, 0, - 61, 62, 0, 0, 0, 44, 0, 123, 124, 125, - 126, 127, 0, 0, 130, 131, 132, 92, 0, 93, - 94, 0, 0, 0, 0, 109, 110, 111, 0, 86, - 0, 73, 0, 0, 0, 0, 0, 42, 118, 0, - 0, 0, 128, 129, 0, 0, 0, 100, 0, 104, - 0, 87, 51, 53, 57, 58, 41, 0, 119, 0, - 45, 0, 0, 95, 0, 103, 0, 120, 0, 43, - 0, 0, 0, 105, 121, 0, 0, 101, 96, 97, -} -var yyTok1 = []int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 53, 13, 6, 3, - 54, 55, 11, 9, 52, 10, 3, 12, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 49, 50, - 7, 51, 8, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 3, 56, -} -var yyTok2 = []int{ - - 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, -} -var yyTok3 = []int{ - 0, -} - -//line yaccpar:1 - -/* parser for yacc output */ - -var yyDebug = 0 - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - // 4 is TOKSTART above - if c >= 4 && c-4 < len(yyToknames) { - if yyToknames[c-4] != "" { - return yyToknames[c-4] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yylex1(lex yyLexer, lval *yySymType) int { - c := 0 - char := lex.Lex(lval) - if char <= 0 { - c = yyTok1[0] - goto out - } - if char < len(yyTok1) { - c = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - c = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - c = yyTok3[i+0] - if c == char { - c = yyTok3[i+1] - goto out - } - } - -out: - if c == 0 { - c = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) - } - return c -} - -func yyParse(yylex yyLexer) int { - var yyn int - var yylval yySymType - var yyVAL yySymType - yyS := make([]yySymType, yyMaxDepth) - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yychar := -1 - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - yyn += yychar - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yychar { /* valid shift */ - yychar = -1 - yyVAL = yylval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yychar { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error("syntax error") - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) - } - if yychar == yyEofCode { - goto ret1 - } - yychar = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 2: - //line a.y:72 - { - stmtline = asm.Lineno - } - case 4: - //line a.y:79 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { - yyerror("redeclaration of %s (%s)", yyS[yypt-1].sym.Labelname, yyS[yypt-1].sym.Name) - } - yyS[yypt-1].sym.Type = LLAB - yyS[yypt-1].sym.Value = int64(asm.PC) - } - case 9: - //line a.y:94 - { - yyS[yypt-2].sym.Type = LVAR - yyS[yypt-2].sym.Value = yyS[yypt-0].lval - } - case 10: - //line a.y:99 - { - if yyS[yypt-2].sym.Value != yyS[yypt-0].lval { - yyerror("redeclaration of %s", yyS[yypt-2].sym.Name) - } - yyS[yypt-2].sym.Value = yyS[yypt-0].lval - } - case 11: - //line a.y:105 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 12: - //line a.y:106 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 13: - //line a.y:107 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 14: - //line a.y:108 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 15: - //line a.y:109 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 16: - //line a.y:110 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 19: - //line a.y:113 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 20: - //line a.y:114 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 21: - //line a.y:115 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 22: - //line a.y:116 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 23: - //line a.y:117 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 24: - //line a.y:118 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 25: - //line a.y:119 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 26: - //line a.y:120 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 28: - //line a.y:122 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 29: - //line a.y:123 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 30: - //line a.y:126 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = nullgen - } - case 31: - //line a.y:131 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = nullgen - } - case 32: - //line a.y:138 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 33: - //line a.y:145 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 34: - //line a.y:152 - { - yyVAL.addr2.from = yyS[yypt-1].addr - yyVAL.addr2.to = nullgen - } - case 35: - //line a.y:157 - { - yyVAL.addr2.from = yyS[yypt-0].addr - yyVAL.addr2.to = nullgen - } - case 36: - //line a.y:164 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 37: - //line a.y:169 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 38: - //line a.y:176 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 39: - //line a.y:181 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 40: - //line a.y:186 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 41: - //line a.y:193 - { - var a Addr2 - a.from = yyS[yypt-4].addr - a.to = yyS[yypt-0].addr - outcode(obj.ADATA, &a) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-2].lval - } - } - case 42: - //line a.y:206 - { - asm.Settext(yyS[yypt-3].addr.Sym) - outcode(obj.ATEXT, &Addr2{yyS[yypt-3].addr, yyS[yypt-0].addr}) - } - case 43: - //line a.y:211 - { - asm.Settext(yyS[yypt-5].addr.Sym) - outcode(obj.ATEXT, &Addr2{yyS[yypt-5].addr, yyS[yypt-0].addr}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-3].lval - } - } - case 44: - //line a.y:222 - { - asm.Settext(yyS[yypt-2].addr.Sym) - outcode(obj.AGLOBL, &Addr2{yyS[yypt-2].addr, yyS[yypt-0].addr}) - } - case 45: - //line a.y:227 - { - asm.Settext(yyS[yypt-4].addr.Sym) - outcode(obj.AGLOBL, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-2].lval - } - } - case 46: - //line a.y:238 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 47: - //line a.y:243 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 48: - yyVAL.addr2 = yyS[yypt-0].addr2 - case 49: - yyVAL.addr2 = yyS[yypt-0].addr2 - case 50: - //line a.y:254 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 51: - //line a.y:259 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - if yyVAL.addr2.from.Index != obj.TYPE_NONE { - yyerror("dp shift with lhs index") - } - yyVAL.addr2.from.Index = int16(yyS[yypt-0].lval) - } - case 52: - //line a.y:270 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 53: - //line a.y:275 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - if yyVAL.addr2.to.Index != obj.TYPE_NONE { - yyerror("dp move with lhs index") - } - yyVAL.addr2.to.Index = int16(yyS[yypt-0].lval) - } - case 54: - //line a.y:286 - { - yyVAL.addr2.from = yyS[yypt-1].addr - yyVAL.addr2.to = nullgen - } - case 55: - //line a.y:291 - { - yyVAL.addr2.from = yyS[yypt-0].addr - yyVAL.addr2.to = nullgen - } - case 56: - //line a.y:296 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 57: - //line a.y:303 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - yyVAL.addr2.to.Offset = yyS[yypt-0].lval - } - case 58: - //line a.y:311 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - if yyS[yypt-4].addr.Type != obj.TYPE_CONST { - yyerror("illegal constant") - } - yyVAL.addr2.to.Offset = yyS[yypt-4].addr.Offset - } - case 59: - //line a.y:321 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = nullgen - } - case 60: - //line a.y:326 - { - yyVAL.addr2.from = yyS[yypt-0].addr - yyVAL.addr2.to = nullgen - } - case 61: - //line a.y:333 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { - yyerror("arguments to asm.PCDATA must be integer constants") - } - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 62: - //line a.y:343 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if yyS[yypt-0].addr.Type != obj.TYPE_MEM || (yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference") - } - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 63: - yyVAL.addr = yyS[yypt-0].addr - case 64: - yyVAL.addr = yyS[yypt-0].addr - case 65: - yyVAL.addr = yyS[yypt-0].addr - case 66: - yyVAL.addr = yyS[yypt-0].addr - case 67: - //line a.y:362 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 68: - //line a.y:366 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 69: - yyVAL.addr = yyS[yypt-0].addr - case 70: - yyVAL.addr = yyS[yypt-0].addr - case 71: - yyVAL.addr = yyS[yypt-0].addr - case 72: - yyVAL.addr = yyS[yypt-0].addr - case 73: - //line a.y:378 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyS[yypt-3].lval + int64(asm.PC) - } - case 74: - //line a.y:384 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - yyVAL.addr = nullgen - if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { - yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) - } - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyS[yypt-1].sym.Value + yyS[yypt-0].lval - } - case 75: - //line a.y:396 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 76: - //line a.y:402 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 77: - //line a.y:408 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 78: - //line a.y:414 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 79: - //line a.y:420 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = x86.REG_SP - } - case 80: - //line a.y:426 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 81: - //line a.y:432 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 82: - //line a.y:440 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - yyVAL.addr.Offset = yyS[yypt-0].lval - } - case 83: - //line a.y:446 - { - yyVAL.addr = yyS[yypt-0].addr - yyVAL.addr.Type = obj.TYPE_ADDR - /* - if($2.Type == x86.D_AUTO || $2.Type == x86.D_PARAM) - yyerror("constant cannot be automatic: %s", - $2.sym.Name); - */ - } - case 84: - //line a.y:455 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SCONST - yyVAL.addr.U.Sval = (yyS[yypt-0].sval + "\x00\x00\x00\x00\x00\x00\x00\x00")[:8] - } - case 85: - //line a.y:461 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyS[yypt-0].dval - } - case 86: - //line a.y:467 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyS[yypt-1].dval - } - case 87: - //line a.y:473 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyS[yypt-1].dval - } - case 88: - //line a.y:479 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyS[yypt-0].dval - } - case 89: - yyVAL.addr = yyS[yypt-0].addr - case 90: - yyVAL.addr = yyS[yypt-0].addr - case 91: - //line a.y:491 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Offset = yyS[yypt-0].lval - } - case 92: - //line a.y:497 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 93: - //line a.y:504 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = x86.REG_SP - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 94: - //line a.y:511 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 95: - //line a.y:518 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Offset = yyS[yypt-5].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 96: - //line a.y:527 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Offset = yyS[yypt-8].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 97: - //line a.y:537 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Offset = yyS[yypt-8].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 98: - //line a.y:547 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - } - case 99: - //line a.y:553 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = x86.REG_SP - } - case 100: - //line a.y:559 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 101: - //line a.y:567 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 102: - //line a.y:578 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 103: - //line a.y:582 - { - yyVAL.addr = yyS[yypt-5].addr - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 104: - //line a.y:591 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyS[yypt-1].lval) - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 105: - //line a.y:599 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = obj.NAME_STATIC - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 106: - //line a.y:608 - { - yyVAL.lval = 0 - } - case 107: - //line a.y:612 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 108: - //line a.y:616 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 109: - yyVAL.lval = yyS[yypt-0].lval - case 110: - //line a.y:623 - { - yyVAL.lval = obj.NAME_AUTO - } - case 111: - yyVAL.lval = yyS[yypt-0].lval - case 112: - yyVAL.lval = yyS[yypt-0].lval - case 113: - //line a.y:631 - { - yyVAL.lval = yyS[yypt-0].sym.Value - } - case 114: - //line a.y:635 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 115: - //line a.y:639 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 116: - //line a.y:643 - { - yyVAL.lval = ^yyS[yypt-0].lval - } - case 117: - //line a.y:647 - { - yyVAL.lval = yyS[yypt-1].lval - } - case 118: - //line a.y:653 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = yyS[yypt-0].lval - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 119: - //line a.y:660 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -yyS[yypt-0].lval - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 120: - //line a.y:667 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = yyS[yypt-2].lval - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 121: - //line a.y:674 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -yyS[yypt-2].lval - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 122: - yyVAL.lval = yyS[yypt-0].lval - case 123: - //line a.y:684 - { - yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval - } - case 124: - //line a.y:688 - { - yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval - } - case 125: - //line a.y:692 - { - yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval - } - case 126: - //line a.y:696 - { - yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval - } - case 127: - //line a.y:700 - { - yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval - } - case 128: - //line a.y:704 - { - yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) - } - case 129: - //line a.y:708 - { - yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) - } - case 130: - //line a.y:712 - { - yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval - } - case 131: - //line a.y:716 - { - yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval - } - case 132: - //line a.y:720 - { - yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval - } - } - goto yystack /* stack new state and value */ -} diff --git a/src/cmd/new6g/cgen.go b/src/cmd/new6g/cgen.go deleted file mode 100644 index 36fa62c469..0000000000 --- a/src/cmd/new6g/cgen.go +++ /dev/null @@ -1,1889 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" - "fmt" -) -import "cmd/internal/gc" - -/* - * reg.c - */ - -/* - * peep.c - */ -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -func cgen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var a int - var f int - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var addr obj.Addr - - if gc.Debug['g'] != 0 { - gc.Dump("\ncgen-n", n) - gc.Dump("cgen-res", res) - } - - if n == nil || n.Type == nil { - goto ret - } - - if res == nil || res.Type == nil { - gc.Fatal("cgen: res nil") - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - switch n.Op { - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_slice(n, res) - } - goto ret - - case gc.OEFACE: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_eface(n, res) - } - goto ret - } - - if n.Ullman >= gc.UINF { - if n.Op == gc.OINDREG { - gc.Fatal("cgen: this is going to misscompile") - } - if res.Ullman >= gc.UINF { - gc.Tempname(&n1, n.Type) - cgen(n, &n1) - cgen(&n1, res) - goto ret - } - } - - if gc.Isfat(n.Type) { - if n.Type.Width < 0 { - gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) - } - sgen(n, res, n.Type.Width) - goto ret - } - - if res.Addable == 0 { - if n.Ullman > res.Ullman { - regalloc(&n1, n.Type, res) - cgen(n, &n1) - if n1.Ullman > res.Ullman { - gc.Dump("n1", &n1) - gc.Dump("res", res) - gc.Fatal("loop in cgen") - } - - cgen(&n1, res) - regfree(&n1) - goto ret - } - - if res.Ullman >= gc.UINF { - goto gen - } - - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - goto ret - } - - f = 1 // gen thru register - switch n.Op { - case gc.OLITERAL: - if gc.Smallintconst(n) { - f = 0 - } - - case gc.OREGISTER: - f = 0 - } - - if gc.Iscomplex[n.Type.Etype] == 0 { - a = optoas(gc.OAS, res.Type) - if sudoaddable(a, res, &addr) { - if f != 0 { - regalloc(&n2, res.Type, nil) - cgen(n, &n2) - p1 = gins(a, &n2, nil) - regfree(&n2) - } else { - p1 = gins(a, n, nil) - } - p1.To = addr - if gc.Debug['g'] != 0 { - fmt.Printf("%v [ignore previous line]\n", p1) - } - sudoclean() - goto ret - } - } - - gen: - igen(res, &n1, nil) - cgen(n, &n1) - regfree(&n1) - goto ret - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch n.Op { - case gc.OSPTR, - gc.OLEN: - if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { - n.Addable = n.Left.Addable - } - - case gc.OCAP: - if gc.Isslice(n.Left.Type) { - n.Addable = n.Left.Addable - } - - case gc.OITAB: - n.Addable = n.Left.Addable - } - - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - goto ret - } - - if n.Addable != 0 { - gmove(n, res) - goto ret - } - - nl = n.Left - nr = n.Right - - if nl != nil && nl.Ullman >= gc.UINF { - if nr != nil && nr.Ullman >= gc.UINF { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - n2 = *n - n2.Left = &n1 - cgen(&n2, res) - goto ret - } - } - - if gc.Iscomplex[n.Type.Etype] == 0 { - a = optoas(gc.OAS, n.Type) - if sudoaddable(a, n, &addr) { - if res.Op == gc.OREGISTER { - p1 = gins(a, nil, res) - p1.From = addr - } else { - regalloc(&n2, n.Type, nil) - p1 = gins(a, nil, &n2) - p1.From = addr - gins(a, &n2, res) - regfree(&n2) - } - - sudoclean() - goto ret - } - } - - switch n.Op { - default: - gc.Dump("cgen", n) - gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - // these call bgen to get a bool value - case gc.OOROR, - gc.OANDAND, - gc.OEQ, - gc.ONE, - gc.OLT, - gc.OLE, - gc.OGE, - gc.OGT, - gc.ONOT: - p1 = gc.Gbranch(obj.AJMP, nil, 0) - - p2 = gc.Pc - gmove(gc.Nodbool(true), res) - p3 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n, true, 0, p2) - gmove(gc.Nodbool(false), res) - gc.Patch(p3, gc.Pc) - goto ret - - case gc.OPLUS: - cgen(nl, res) - goto ret - - // unary - case gc.OCOM: - a = optoas(gc.OXOR, nl.Type) - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gc.Nodconst(&n2, nl.Type, -1) - gins(a, &n2, &n1) - gmove(&n1, res) - regfree(&n1) - goto ret - - case gc.OMINUS: - if gc.Isfloat[nl.Type.Etype] != 0 { - nr = gc.Nodintconst(-1) - gc.Convlit(&nr, n.Type) - a = optoas(gc.OMUL, nl.Type) - goto sbop - } - - a = optoas(int(n.Op), nl.Type) - goto uop - - // symmetric binary - case gc.OAND, - gc.OOR, - gc.OXOR, - gc.OADD, - gc.OMUL: - a = optoas(int(n.Op), nl.Type) - - if a == x86.AIMULB { - cgen_bmul(int(n.Op), nl, nr, res) - break - } - - goto sbop - - // asymmetric binary - case gc.OSUB: - a = optoas(int(n.Op), nl.Type) - - goto abop - - case gc.OHMUL: - cgen_hmul(nl, nr, res) - - case gc.OCONV: - if n.Type.Width > nl.Type.Width { - // If loading from memory, do conversion during load, - // so as to avoid use of 8-bit register in, say, int(*byteptr). - switch nl.Op { - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: - igen(nl, &n1, res) - regalloc(&n2, n.Type, res) - gmove(&n1, &n2) - gmove(&n2, res) - regfree(&n2) - regfree(&n1) - goto ret - } - } - - regalloc(&n1, nl.Type, res) - regalloc(&n2, n.Type, &n1) - cgen(nl, &n1) - - // if we do the conversion n1 -> n2 here - // reusing the register, then gmove won't - // have to allocate its own register. - gmove(&n1, &n2) - - gmove(&n2, res) - regfree(&n2) - regfree(&n1) - - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res) - - gmove(&n1, res) - regfree(&n1) - - // interface table is first word of interface value - case gc.OITAB: - igen(nl, &n1, res) - - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - // pointer is the first word of string or slice. - case gc.OSPTR: - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n1, gc.Types[gc.Tptr], res) - p1 = gins(x86.ALEAQ, nil, &n1) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - gmove(&n1, res) - regfree(&n1) - break - } - - igen(nl, &n1, res) - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - case gc.OLEN: - if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { - // map and chan have len in the first int-sized word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.Simtype[gc.TINT]] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { - // both slice and string have len one pointer into the struct. - // a zero pointer means zero length - igen(nl, &n1, res) - - n1.Type = gc.Types[gc.Simtype[gc.TUINT]] - n1.Xoffset += int64(gc.Array_nel) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OCAP: - if gc.Istype(nl.Type, gc.TCHAN) { - // chan has cap in the second int-sized word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Xoffset = int64(gc.Widthint) - n2.Type = gc.Types[gc.Simtype[gc.TINT]] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Isslice(nl.Type) { - igen(nl, &n1, res) - n1.Type = gc.Types[gc.Simtype[gc.TUINT]] - n1.Xoffset += int64(gc.Array_cap) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OADDR: - if n.Bounded { // let race detector avoid nil checks - gc.Disable_checknil++ - } - agen(nl, res) - if n.Bounded { - gc.Disable_checknil-- - } - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - cgen_callret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_callret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_callret(n, res) - - case gc.OMOD, - gc.ODIV: - if gc.Isfloat[n.Type.Etype] != 0 { - a = optoas(int(n.Op), nl.Type) - goto abop - } - - if nl.Ullman >= nr.Ullman { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - cgen_div(int(n.Op), &n1, nr, res) - regfree(&n1) - } else { - if !gc.Smallintconst(nr) { - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - } else { - n2 = *nr - } - - cgen_div(int(n.Op), nl, &n2, res) - if n2.Op != gc.OLITERAL { - regfree(&n2) - } - } - - case gc.OLSH, - gc.ORSH, - gc.OLROT: - cgen_shift(int(n.Op), n.Bounded, nl, nr, res) - } - - goto ret - - /* - * put simplest on right - we'll generate into left - * and then adjust it using the computation of right. - * constants and variables have the same ullman - * count, so look for constants specially. - * - * an integer constant we can use as an immediate - * is simpler than a variable - we can use the immediate - * in the adjustment instruction directly - so it goes - * on the right. - * - * other constants, like big integers or floating point - * constants, require a mov into a register, so those - * might as well go on the left, so we can reuse that - * register for the computation. - */ -sbop: // symmetric binary - if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) { - r = nl - nl = nr - nr = r - } - -abop: // asymmetric binary - if nl.Ullman >= nr.Ullman { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - - /* - * This generates smaller code - it avoids a MOV - but it's - * easily 10% slower due to not being able to - * optimize/manipulate the move. - * To see, run: go test -bench . crypto/md5 - * with and without. - * - if(sudoaddable(a, nr, &addr)) { - p1 = gins(a, N, &n1); - p1->from = addr; - gmove(&n1, res); - sudoclean(); - regfree(&n1); - goto ret; - } - * - */ - if gc.Smallintconst(nr) { - n2 = *nr - } else { - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - } - } else { - if gc.Smallintconst(nr) { - n2 = *nr - } else { - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - } - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - } - - gins(a, &n2, &n1) - gmove(&n1, res) - regfree(&n1) - if n2.Op != gc.OLITERAL { - regfree(&n2) - } - goto ret - -uop: // unary - regalloc(&n1, nl.Type, res) - - cgen(nl, &n1) - gins(a, nil, &n1) - gmove(&n1, res) - regfree(&n1) - goto ret - -ret: -} - -/* - * allocate a register (reusing res if possible) and generate - * a = n - * The caller must call regfree(a). - */ -func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("cgenr-n", n) - } - - if gc.Isfat(n.Type) { - gc.Fatal("cgenr on fat node") - } - - if n.Addable != 0 { - regalloc(a, n.Type, res) - gmove(n, a) - return - } - - switch n.Op { - case gc.ONAME, - gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - gmove(&n1, a) - regfree(&n1) - - default: - regalloc(a, n.Type, res) - cgen(n, a) - } -} - -/* - * allocate a register (reusing res if possible) and generate - * a = &n - * The caller must call regfree(a). - * The generated code checks that the result is not nil. - */ -func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n5 gc.Node - var tmp gc.Node - var tmp2 gc.Node - var nlen gc.Node - var p1 *obj.Prog - var t *gc.Type - var w uint64 - var v uint64 - var freelen int - - if gc.Debug['g'] != 0 { - gc.Dump("\nagenr-n", n) - } - - nl = n.Left - nr = n.Right - - switch n.Op { - case gc.ODOT, - gc.ODOTPTR, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - agen(&n1, a) - regfree(&n1) - - case gc.OIND: - cgenr(n.Left, a, res) - gc.Cgen_checknil(a) - - case gc.OINDEX: - freelen = 0 - w = uint64(n.Type.Width) - - // Generate the non-addressable child first. - if nr.Addable != 0 { - goto irad - } - if nl.Addable != 0 { - cgenr(nr, &n1, nil) - if !gc.Isconst(nl, gc.CTSTR) { - if gc.Isfixedarray(nl.Type) { - agenr(nl, &n3, res) - } else { - igen(nl, &nlen, res) - freelen = 1 - nlen.Type = gc.Types[gc.Tptr] - nlen.Xoffset += int64(gc.Array_array) - regalloc(&n3, gc.Types[gc.Tptr], res) - gmove(&nlen, &n3) - nlen.Type = gc.Types[gc.Simtype[gc.TUINT]] - nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - } - } - - goto index - } - - gc.Tempname(&tmp, nr.Type) - cgen(nr, &tmp) - nr = &tmp - - irad: - if !gc.Isconst(nl, gc.CTSTR) { - if gc.Isfixedarray(nl.Type) { - agenr(nl, &n3, res) - } else { - if nl.Addable == 0 { - // igen will need an addressable node. - gc.Tempname(&tmp2, nl.Type) - - cgen(nl, &tmp2) - nl = &tmp2 - } - - igen(nl, &nlen, res) - freelen = 1 - nlen.Type = gc.Types[gc.Tptr] - nlen.Xoffset += int64(gc.Array_array) - regalloc(&n3, gc.Types[gc.Tptr], res) - gmove(&nlen, &n3) - nlen.Type = gc.Types[gc.Simtype[gc.TUINT]] - nlen.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - } - } - - if !gc.Isconst(nr, gc.CTINT) { - cgenr(nr, &n1, nil) - } - - goto index - - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // len(a) is in nlen (if needed) - // w is width - - // constant index - index: - if gc.Isconst(nr, gc.CTINT) { - if gc.Isconst(nl, gc.CTSTR) { - gc.Fatal("constant string constant index") // front end should handle - } - v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - if gc.Debug['B'] == 0 && !n.Bounded { - gc.Nodconst(&n2, gc.Types[gc.Simtype[gc.TUINT]], int64(v)) - if gc.Smallintconst(nr) { - gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &n2) - } else { - regalloc(&tmp, gc.Types[gc.Simtype[gc.TUINT]], nil) - gmove(&n2, &tmp) - gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &nlen, &tmp) - regfree(&tmp) - } - - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - - regfree(&nlen) - } - - if v*w != 0 { - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*w), &n3) - } - *a = n3 - break - } - - // type of the index - t = gc.Types[gc.TUINT64] - - if gc.Issigned[n1.Type.Etype] != 0 { - t = gc.Types[gc.TINT64] - } - - regalloc(&n2, t, &n1) // i - gmove(&n1, &n2) - regfree(&n1) - - if gc.Debug['B'] == 0 && !n.Bounded { - // check bounds - t = gc.Types[gc.Simtype[gc.TUINT]] - - if gc.Is64(nr.Type) { - t = gc.Types[gc.TUINT64] - } - if gc.Isconst(nl, gc.CTSTR) { - gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval.S))) - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - if gc.Is64(nr.Type) { - regalloc(&n5, t, nil) - gmove(&nlen, &n5) - regfree(&nlen) - nlen = n5 - } - } else { - gc.Nodconst(&nlen, t, nl.Type.Bound) - if !gc.Smallintconst(&nlen) { - regalloc(&n5, t, nil) - gmove(&nlen, &n5) - nlen = n5 - freelen = 1 - } - } - - gins(optoas(gc.OCMP, t), &n2, &nlen) - p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n3, gc.Types[gc.Tptr], res) - p1 = gins(x86.ALEAQ, nil, &n3) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - gins(x86.AADDQ, &n2, &n3) - goto indexdone - } - - if w == 0 { - } else // nothing to do - if w == 1 || w == 2 || w == 4 || w == 8 { - p1 = gins(x86.ALEAQ, &n2, &n3) - p1.From.Type = obj.TYPE_MEM - p1.From.Scale = int8(w) - p1.From.Index = p1.From.Reg - p1.From.Reg = p1.To.Reg - } else { - ginscon(optoas(gc.OMUL, t), int64(w), &n2) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - } - - indexdone: - *a = n3 - regfree(&n2) - if freelen != 0 { - regfree(&nlen) - } - - default: - regalloc(a, gc.Types[gc.Tptr], res) - agen(n, a) - } -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -func agen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var n1 gc.Node - var n2 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("\nagen-res", res) - gc.Dump("agen-r", n) - } - - if n == nil || n.Type == nil { - return - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - gc.Tempname(&n1, n.Type) - - gc.Gvardef(&n1) - clearfat(&n1) - regalloc(&n2, gc.Types[gc.Tptr], res) - gins(x86.ALEAQ, &n1, &n2) - gmove(&n2, res) - regfree(&n2) - goto ret - } - - if n.Addable != 0 { - regalloc(&n1, gc.Types[gc.Tptr], res) - gins(x86.ALEAQ, n, &n1) - gmove(&n1, res) - regfree(&n1) - goto ret - } - - nl = n.Left - - switch n.Op { - default: - gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - cgen_aret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_aret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_aret(n, res) - - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - agen(&n1, res) - - case gc.OEFACE: - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - agen(&n1, res) - - case gc.OINDEX: - agenr(n, &n1, res) - gmove(&n1, res) - regfree(&n1) - - // should only get here with names in this func. - case gc.ONAME: - if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) - } - - // should only get here for heap vars or paramref - if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME class %#x", n.Class) - } - - cgen(n.Heapaddr, res) - if n.Xoffset != 0 { - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - - case gc.OIND: - cgen(nl, res) - gc.Cgen_checknil(res) - - case gc.ODOT: - agen(nl, res) - if n.Xoffset != 0 { - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - - case gc.ODOTPTR: - cgen(nl, res) - gc.Cgen_checknil(res) - if n.Xoffset != 0 { - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - } - -ret: -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -func igen(n *gc.Node, a *gc.Node, res *gc.Node) { - var fp *gc.Type - var flist gc.Iter - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("\nigen-n", n) - } - - switch n.Op { - case gc.ONAME: - if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { - break - } - *a = *n - return - - // Increase the refcount of the register so that igen's caller - // has to call regfree. - case gc.OINDREG: - if n.Val.U.Reg != x86.REG_SP { - reg[n.Val.U.Reg]++ - } - *a = *n - return - - case gc.ODOT: - igen(n.Left, a, res) - a.Xoffset += n.Xoffset - a.Type = n.Type - fixlargeoffset(a) - return - - case gc.ODOTPTR: - cgenr(n.Left, a, res) - gc.Cgen_checknil(a) - a.Op = gc.OINDREG - a.Xoffset += n.Xoffset - a.Type = n.Type - fixlargeoffset(a) - return - - case gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - switch n.Op { - case gc.OCALLFUNC: - cgen_call(n, 0) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - - case gc.OCALLINTER: - cgen_callinter(n, nil, 0) - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) - *a = gc.Node{} - a.Op = gc.OINDREG - a.Val.U.Reg = x86.REG_SP - a.Addable = 1 - a.Xoffset = fp.Width - a.Type = n.Type - return - - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - case gc.OINDEX: - if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { - if gc.Isconst(n.Right, gc.CTINT) { - // Compute &a. - if gc.Isptr[n.Left.Type.Etype] == 0 { - igen(n.Left, a, res) - } else { - igen(n.Left, &n1, res) - gc.Cgen_checknil(&n1) - regalloc(a, gc.Types[gc.Tptr], res) - gmove(&n1, a) - regfree(&n1) - a.Op = gc.OINDREG - } - - // Compute &a[i] as &a + i*width. - a.Type = n.Type - - a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width - fixlargeoffset(a) - return - } - } - } - - agenr(n, a, res) - a.Op = gc.OINDREG - a.Type = n.Type -} - -/* - * generate: - * if(n == true) goto to; - */ -func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { - var et int - var a int - var nl *gc.Node - var nr *gc.Node - var l *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var tmp gc.Node - var ll *gc.NodeList - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['g'] != 0 { - gc.Dump("\nbgen", n) - } - - if n == nil { - n = gc.Nodbool(true) - } - - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - - if n.Type == nil { - gc.Convlit(&n, gc.Types[gc.TBOOL]) - if n.Type == nil { - goto ret - } - } - - et = int(n.Type.Etype) - if et != gc.TBOOL { - gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) - gc.Patch(gins(obj.AEND, nil, nil), to) - goto ret - } - - nr = nil - - for n.Op == gc.OCONVNOP { - n = n.Left - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - } - - switch n.Op { - default: - goto def - - // need to ask if it is bool? - case gc.OLITERAL: - if !true_ == (n.Val.U.Bval == 0) { - gc.Patch(gc.Gbranch(obj.AJMP, nil, likely), to) - } - goto ret - - case gc.ONAME: - if n.Addable == 0 { - goto def - } - gc.Nodconst(&n1, n.Type, 0) - gins(optoas(gc.OCMP, n.Type), n, &n1) - a = x86.AJNE - if !true_ { - a = x86.AJEQ - } - gc.Patch(gc.Gbranch(a, n.Type, likely), to) - goto ret - - case gc.OANDAND, - gc.OOROR: - if (n.Op == gc.OANDAND) == true_ { - p1 = gc.Gbranch(obj.AJMP, nil, 0) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n.Left, !true_, -likely, p2) - bgen(n.Right, !true_, -likely, p2) - p1 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, to) - gc.Patch(p2, gc.Pc) - } else { - bgen(n.Left, true_, likely, to) - bgen(n.Right, true_, likely, to) - } - - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - nr = n.Right - if nr == nil || nr.Type == nil { - goto ret - } - fallthrough - - case gc.ONOT: // unary - nl = n.Left - - if nl == nil || nl.Type == nil { - goto ret - } - } - - switch n.Op { - case gc.ONOT: - bgen(nl, !true_, likely, to) - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - a = int(n.Op) - if !true_ { - if gc.Isfloat[nr.Type.Etype] != 0 { - // brcom is not valid on floats when NaN is involved. - p1 = gc.Gbranch(obj.AJMP, nil, 0) - - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - ll = n.Ninit // avoid re-genning ninit - n.Ninit = nil - bgen(n, true, -likely, p2) - n.Ninit = ll - gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) - gc.Patch(p2, gc.Pc) - goto ret - } - - a = gc.Brcom(a) - true_ = !true_ - } - - // make simplest on right - if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { - a = gc.Brrev(a) - r = nl - nl = nr - nr = r - } - - if gc.Isslice(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal slice comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Xoffset += int64(gc.Array_array) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Isinter(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal interface comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Iscomplex[nl.Type.Etype] != 0 { - gc.Complexbool(a, nl, nr, true_, likely, to) - break - } - - if nr.Ullman >= gc.UINF { - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - - gc.Tempname(&tmp, nl.Type) - gmove(&n1, &tmp) - regfree(&n1) - - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - - regalloc(&n1, nl.Type, nil) - cgen(&tmp, &n1) - - goto cmp - } - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - - if gc.Smallintconst(nr) { - gins(optoas(gc.OCMP, nr.Type), &n1, nr) - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - regfree(&n1) - break - } - - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - - // only < and <= work right with NaN; reverse if needed - cmp: - l = &n1 - - r = &n2 - if gc.Isfloat[nl.Type.Etype] != 0 && (a == gc.OGT || a == gc.OGE) { - l = &n2 - r = &n1 - a = gc.Brrev(a) - } - - gins(optoas(gc.OCMP, nr.Type), l, r) - - if gc.Isfloat[nr.Type.Etype] != 0 && (n.Op == gc.OEQ || n.Op == gc.ONE) { - if n.Op == gc.OEQ { - // neither NE nor P - p1 = gc.Gbranch(x86.AJNE, nil, -likely) - - p2 = gc.Gbranch(x86.AJPS, nil, -likely) - gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) - gc.Patch(p1, gc.Pc) - gc.Patch(p2, gc.Pc) - } else { - // either NE or P - gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to) - - gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to) - } - } else { - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - } - regfree(&n1) - regfree(&n2) - } - - goto ret - -def: - regalloc(&n1, n.Type, nil) - cgen(n, &n1) - gc.Nodconst(&n2, n.Type, 0) - gins(optoas(gc.OCMP, n.Type), &n1, &n2) - a = x86.AJNE - if !true_ { - a = x86.AJEQ - } - gc.Patch(gc.Gbranch(a, n.Type, likely), to) - regfree(&n1) - goto ret - -ret: -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -func stkof(n *gc.Node) int64 { - var t *gc.Type - var flist gc.Iter - var off int64 - - switch n.Op { - case gc.OINDREG: - return n.Xoffset - - case gc.ODOT: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - return off + n.Xoffset - - case gc.OINDEX: - t = n.Left.Type - if !gc.Isfixedarray(t) { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - if gc.Isconst(n.Right, gc.CTINT) { - return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval) - } - return 1000 - - case gc.OCALLMETH, - gc.OCALLINTER, - gc.OCALLFUNC: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - t = gc.Structfirst(&flist, gc.Getoutarg(t)) - if t != nil { - return t.Width - } - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000 -} - -/* - * block copy: - * memmove(&ns, &n, w); - */ -func sgen(n *gc.Node, ns *gc.Node, w int64) { - var nodl gc.Node - var nodr gc.Node - var nodsi gc.Node - var noddi gc.Node - var cx gc.Node - var oldcx gc.Node - var tmp gc.Node - var c int64 - var q int64 - var odst int64 - var osrc int64 - var l *gc.NodeList - var p *obj.Prog - - if gc.Debug['g'] != 0 { - fmt.Printf("\nsgen w=%d\n", w) - gc.Dump("r", n) - gc.Dump("res", ns) - } - - if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF { - gc.Fatal("sgen UINF") - } - - if w < 0 { - gc.Fatal("sgen copy %d", w) - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if ns.Op == gc.ONAME && ns.Sym.Name == ".args" { - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - if l.N.Class == gc.PPARAMOUT { - gc.Gvardef(l.N) - } - } - } - - // Avoid taking the address for simple enough types. - if componentgen(n, ns) { - return - } - - if w == 0 { - // evaluate side effects only - regalloc(&nodr, gc.Types[gc.Tptr], nil) - - agen(ns, &nodr) - agen(n, &nodr) - regfree(&nodr) - return - } - - // offset on the stack - osrc = stkof(n) - - odst = stkof(ns) - - if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - gc.Tempname(&tmp, n.Type) - - sgen(n, &tmp, w) - sgen(&tmp, ns, w) - return - } - - gc.Nodreg(&noddi, gc.Types[gc.Tptr], x86.REG_DI) - gc.Nodreg(&nodsi, gc.Types[gc.Tptr], x86.REG_SI) - - if n.Ullman >= ns.Ullman { - agenr(n, &nodr, &nodsi) - if ns.Op == gc.ONAME { - gc.Gvardef(ns) - } - agenr(ns, &nodl, &noddi) - } else { - if ns.Op == gc.ONAME { - gc.Gvardef(ns) - } - agenr(ns, &nodl, &noddi) - agenr(n, &nodr, &nodsi) - } - - if nodl.Val.U.Reg != x86.REG_DI { - gmove(&nodl, &noddi) - } - if nodr.Val.U.Reg != x86.REG_SI { - gmove(&nodr, &nodsi) - } - regfree(&nodl) - regfree(&nodr) - - c = w % 8 // bytes - q = w / 8 // quads - - savex(x86.REG_CX, &cx, &oldcx, nil, gc.Types[gc.TINT64]) - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - if osrc < odst && odst < osrc+w { - // reverse direction - gins(x86.ASTD, nil, nil) // set direction flag - if c > 0 { - gconreg(addptr, w-1, x86.REG_SI) - gconreg(addptr, w-1, x86.REG_DI) - - gconreg(movptr, c, x86.REG_CX) - gins(x86.AREP, nil, nil) // repeat - gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)- - } - - if q > 0 { - if c > 0 { - gconreg(addptr, -7, x86.REG_SI) - gconreg(addptr, -7, x86.REG_DI) - } else { - gconreg(addptr, w-8, x86.REG_SI) - gconreg(addptr, w-8, x86.REG_DI) - } - - gconreg(movptr, q, x86.REG_CX) - gins(x86.AREP, nil, nil) // repeat - gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)-,*(DI)- - } - - // we leave with the flag clear - gins(x86.ACLD, nil, nil) - } else { - // normal direction - if q > 128 || (gc.Nacl && q >= 4) { - gconreg(movptr, q, x86.REG_CX) - gins(x86.AREP, nil, nil) // repeat - gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+ - } else if q >= 4 { - p = gins(obj.ADUFFCOPY, nil, nil) - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg)) - - // 14 and 128 = magic constants: see ../../runtime/asm_amd64.s - p.To.Offset = 14 * (128 - q) - } else if !gc.Nacl && c == 0 { - // We don't need the MOVSQ side-effect of updating SI and DI, - // and issuing a sequence of MOVQs directly is faster. - nodsi.Op = gc.OINDREG - - noddi.Op = gc.OINDREG - for q > 0 { - gmove(&nodsi, &cx) // MOVQ x+(SI),CX - gmove(&cx, &noddi) // MOVQ CX,x+(DI) - nodsi.Xoffset += 8 - noddi.Xoffset += 8 - q-- - } - } else { - for q > 0 { - gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+ - q-- - } - } - - // copy the remaining c bytes - if w < 4 || c <= 1 || (odst < osrc && osrc < odst+w) { - for c > 0 { - gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+ - c-- - } - } else if w < 8 || c <= 4 { - nodsi.Op = gc.OINDREG - noddi.Op = gc.OINDREG - cx.Type = gc.Types[gc.TINT32] - nodsi.Type = gc.Types[gc.TINT32] - noddi.Type = gc.Types[gc.TINT32] - if c > 4 { - nodsi.Xoffset = 0 - noddi.Xoffset = 0 - gmove(&nodsi, &cx) - gmove(&cx, &noddi) - } - - nodsi.Xoffset = c - 4 - noddi.Xoffset = c - 4 - gmove(&nodsi, &cx) - gmove(&cx, &noddi) - } else { - nodsi.Op = gc.OINDREG - noddi.Op = gc.OINDREG - cx.Type = gc.Types[gc.TINT64] - nodsi.Type = gc.Types[gc.TINT64] - noddi.Type = gc.Types[gc.TINT64] - nodsi.Xoffset = c - 8 - noddi.Xoffset = c - 8 - gmove(&nodsi, &cx) - gmove(&cx, &noddi) - } - } - - restx(&cx, &oldcx) -} - -func cadable(n *gc.Node) bool { - if n.Addable == 0 { - // dont know how it happens, - // but it does - return false - } - - switch n.Op { - case gc.ONAME: - return true - } - - return false -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -func componentgen(nr *gc.Node, nl *gc.Node) bool { - var nodl gc.Node - var nodr gc.Node - var tmp gc.Node - var t *gc.Type - var freel int - var freer int - var fldcount int64 - var loffset int64 - var roffset int64 - - freel = 0 - freer = 0 - - switch nl.Type.Etype { - default: - goto no - - case gc.TARRAY: - t = nl.Type - - // Slices are ok. - if gc.Isslice(t) { - break - } - - // Small arrays are ok. - if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { - break - } - - goto no - - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - case gc.TSTRUCT: - fldcount = 0 - - for t = nl.Type.Type; t != nil; t = t.Down { - if gc.Isfat(t.Type) { - goto no - } - if t.Etype != gc.TFIELD { - gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) - } - fldcount++ - } - - if fldcount == 0 || fldcount > 4 { - goto no - } - - case gc.TSTRING, - gc.TINTER: - break - } - - nodl = *nl - if !cadable(nl) { - if nr != nil && !cadable(nr) { - goto no - } - igen(nl, &nodl, nil) - freel = 1 - } - - if nr != nil { - nodr = *nr - if !cadable(nr) { - igen(nr, &nodr, nil) - freer = 1 - } - } else { - // When zeroing, prepare a register containing zero. - gc.Nodconst(&tmp, nl.Type, 0) - - regalloc(&nodr, gc.Types[gc.TUINT], nil) - gmove(&tmp, &nodr) - freer = 1 - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { - goto yes - } - - switch nl.Type.Etype { - // componentgen for arrays. - case gc.TARRAY: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - t = nl.Type - if !gc.Isslice(t) { - nodl.Type = t.Type - nodr.Type = nodl.Type - for fldcount = 0; fldcount < t.Bound; fldcount++ { - if nr == nil { - gc.Clearslim(&nodl) - } else { - gmove(&nodr, &nodl) - } - nodl.Xoffset += t.Type.Width - nodr.Xoffset += t.Type.Width - } - - goto yes - } - - // componentgen for slices. - nodl.Xoffset += int64(gc.Array_array) - - nodl.Type = gc.Ptrto(nl.Type.Type) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRING: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TINTER: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRUCT: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - loffset = nodl.Xoffset - roffset = nodr.Xoffset - - // funarg structs may not begin at offset zero. - if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { - loffset -= nl.Type.Type.Width - } - if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { - roffset -= nr.Type.Type.Width - } - - for t = nl.Type.Type; t != nil; t = t.Down { - nodl.Xoffset = loffset + t.Width - nodl.Type = t.Type - - if nr == nil { - gc.Clearslim(&nodl) - } else { - nodr.Xoffset = roffset + t.Width - nodr.Type = nodl.Type - gmove(&nodr, &nodl) - } - } - - goto yes - } - -no: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return false - -yes: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return true -} diff --git a/src/cmd/new6g/galign.go b/src/cmd/new6g/galign.go deleted file mode 100644 index bdd8a3c226..0000000000 --- a/src/cmd/new6g/galign.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" -) -import "cmd/internal/gc" - -var thechar int = '6' - -var thestring string = "amd64" - -var thelinkarch *obj.LinkArch = &x86.Linkamd64 - -func linkarchinit() { - if obj.Getgoarch() == "amd64p32" { - thelinkarch = &x86.Linkamd64p32 - gc.Thearch.Thelinkarch = thelinkarch - thestring = "amd64p32" - gc.Thearch.Thestring = "amd64p32" - } -} - -var MAXWIDTH int64 = 1 << 50 - -var addptr int = x86.AADDQ - -var movptr int = x86.AMOVQ - -var leaptr int = x86.ALEAQ - -var cmpptr int = x86.ACMPQ - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -var typedefs = []gc.Typedef{ - gc.Typedef{"int", gc.TINT, gc.TINT64}, - gc.Typedef{"uint", gc.TUINT, gc.TUINT64}, - gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64}, -} - -func betypeinit() { - gc.Widthptr = 8 - gc.Widthint = 8 - gc.Widthreg = 8 - if obj.Getgoarch() == "amd64p32" { - gc.Widthptr = 4 - gc.Widthint = 4 - addptr = x86.AADDL - movptr = x86.AMOVL - leaptr = x86.ALEAL - cmpptr = x86.ACMPL - typedefs[0].Sameas = gc.TINT32 - typedefs[1].Sameas = gc.TUINT32 - typedefs[2].Sameas = gc.TUINT32 - } - -} - -func main() { - gc.Thearch.Thechar = thechar - gc.Thearch.Thestring = thestring - gc.Thearch.Thelinkarch = thelinkarch - gc.Thearch.Typedefs = typedefs - gc.Thearch.REGSP = x86.REGSP - gc.Thearch.REGCTXT = x86.REGCTXT - gc.Thearch.MAXWIDTH = MAXWIDTH - gc.Thearch.Anyregalloc = anyregalloc - gc.Thearch.Betypeinit = betypeinit - gc.Thearch.Bgen = bgen - gc.Thearch.Cgen = cgen - gc.Thearch.Cgen_call = cgen_call - gc.Thearch.Cgen_callinter = cgen_callinter - gc.Thearch.Cgen_ret = cgen_ret - gc.Thearch.Clearfat = clearfat - gc.Thearch.Defframe = defframe - gc.Thearch.Excise = excise - gc.Thearch.Expandchecks = expandchecks - gc.Thearch.Gclean = gclean - gc.Thearch.Ginit = ginit - gc.Thearch.Gins = gins - gc.Thearch.Ginscall = ginscall - gc.Thearch.Igen = igen - gc.Thearch.Linkarchinit = linkarchinit - gc.Thearch.Peep = peep - gc.Thearch.Proginfo = proginfo - gc.Thearch.Regalloc = regalloc - gc.Thearch.Regfree = regfree - gc.Thearch.Regtyp = regtyp - gc.Thearch.Sameaddr = sameaddr - gc.Thearch.Smallindir = smallindir - gc.Thearch.Stackaddr = stackaddr - gc.Thearch.Excludedregs = excludedregs - gc.Thearch.RtoB = RtoB - gc.Thearch.FtoB = FtoB - gc.Thearch.BtoR = BtoR - gc.Thearch.BtoF = BtoF - gc.Thearch.Optoas = optoas - gc.Thearch.Doregbits = doregbits - gc.Thearch.Regnames = regnames - - gc.Main() - gc.Exit(0) -} diff --git a/src/cmd/new6g/gg.go b/src/cmd/new6g/gg.go deleted file mode 100644 index 2deed5deb9..0000000000 --- a/src/cmd/new6g/gg.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "cmd/internal/obj/x86" -import "cmd/internal/gc" - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -var reg [x86.MAXREG]uint8 - -var panicdiv *gc.Node - -/* - * cgen.c - */ - -/* - * list.c - */ diff --git a/src/cmd/new6g/ggen.go b/src/cmd/new6g/ggen.go deleted file mode 100644 index be6ff2152e..0000000000 --- a/src/cmd/new6g/ggen.go +++ /dev/null @@ -1,1169 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" -) -import "cmd/internal/gc" - -func defframe(ptxt *obj.Prog) { - var frame uint32 - var ax uint32 - var p *obj.Prog - var hi int64 - var lo int64 - var l *gc.NodeList - var n *gc.Node - - // fill in argument size, stack size - ptxt.To.Type = obj.TYPE_TEXTSIZE - - ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) - frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) - ptxt.To.Offset = int64(frame) - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt - - hi = 0 - lo = hi - ax = 0 - - // iterate through declarations - they are sorted in decreasing xoffset order. - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - n = l.N - if n.Needzero == 0 { - continue - } - if n.Class != gc.PAUTO { - gc.Fatal("needzero class %d", n.Class) - } - if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { - gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) - } - - if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) { - // merge with range we already have - lo = n.Xoffset - - continue - } - - // zero old range - p = zerorange(p, int64(frame), lo, hi, &ax) - - // set new range - hi = n.Xoffset + n.Type.Width - - lo = n.Xoffset - } - - // zero final range - zerorange(p, int64(frame), lo, hi, &ax) -} - -func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog { - var cnt int64 - var i int64 - - cnt = hi - lo - if cnt == 0 { - return p - } - if *ax == 0 { - p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0) - *ax = 1 - } - - if cnt%int64(gc.Widthreg) != 0 { - // should only happen with nacl - if cnt%int64(gc.Widthptr) != 0 { - gc.Fatal("zerorange count not a multiple of widthptr %d", cnt) - } - p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo) - lo += int64(gc.Widthptr) - cnt -= int64(gc.Widthptr) - } - - if cnt <= int64(4*gc.Widthreg) { - for i = 0; i < cnt; i += int64(gc.Widthreg) { - p = appendpp(p, x86.AMOVQ, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i) - } - } else if !gc.Nacl && (cnt <= int64(128*gc.Widthreg)) { - p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0) - p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 2*(128-cnt/int64(gc.Widthreg))) - p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) - } else { - p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0) - p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0) - p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) - p = appendpp(p, x86.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) - } - - return p -} - -func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { - var q *obj.Prog - q = gc.Ctxt.NewProg() - gc.Clearp(q) - q.As = int16(as) - q.Lineno = p.Lineno - q.From.Type = int16(ftype) - q.From.Reg = int16(freg) - q.From.Offset = foffset - q.To.Type = int16(ttype) - q.To.Reg = int16(treg) - q.To.Offset = toffset - q.Link = p.Link - p.Link = q - return q -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) -*/ -func ginscall(f *gc.Node, proc int) { - var p *obj.Prog - var reg gc.Node - var stk gc.Node - var r1 gc.Node - var extra int32 - - if f.Type != nil { - extra = 0 - if proc == 1 || proc == 2 { - extra = 2 * int32(gc.Widthptr) - } - gc.Setmaxarg(f.Type, extra) - } - - switch proc { - default: - gc.Fatal("ginscall: bad proc %d", proc) - - case 0, // normal call - -1: // normal call but no return - if f.Op == gc.ONAME && f.Class == gc.PFUNC { - if f == gc.Deferreturn { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an x86 NOP that we will have the right line number. - // x86 NOP 0x90 is really XCHG AX, AX; use that description - // because the NOP pseudo-instruction would be removed by - // the linker. - gc.Nodreg(®, gc.Types[gc.TINT], x86.REG_AX) - - gins(x86.AXCHGL, ®, ®) - } - - p = gins(obj.ACALL, nil, f) - gc.Afunclit(&p.To, f) - if proc == -1 || gc.Noreturn(p) { - gins(obj.AUNDEF, nil, nil) - } - break - } - - gc.Nodreg(®, gc.Types[gc.Tptr], x86.REG_DX) - gc.Nodreg(&r1, gc.Types[gc.Tptr], x86.REG_BX) - gmove(f, ®) - reg.Op = gc.OINDREG - gmove(®, &r1) - reg.Op = gc.OREGISTER - gins(obj.ACALL, ®, &r1) - - case 3: // normal call of c function pointer - gins(obj.ACALL, nil, f) - - case 1, // call in new proc (go) - 2: // deferred call (defer) - stk = gc.Node{} - - stk.Op = gc.OINDREG - stk.Val.U.Reg = x86.REG_SP - stk.Xoffset = 0 - - if gc.Widthptr == 8 { - // size of arguments at 0(SP) - ginscon(x86.AMOVQ, int64(gc.Argsize(f.Type)), &stk) - - // FuncVal* at 8(SP) - stk.Xoffset = int64(gc.Widthptr) - - gc.Nodreg(®, gc.Types[gc.TINT64], x86.REG_AX) - gmove(f, ®) - gins(x86.AMOVQ, ®, &stk) - } else { - // size of arguments at 0(SP) - ginscon(x86.AMOVL, int64(gc.Argsize(f.Type)), &stk) - - // FuncVal* at 4(SP) - stk.Xoffset = int64(gc.Widthptr) - - gc.Nodreg(®, gc.Types[gc.TINT32], x86.REG_AX) - gmove(f, ®) - gins(x86.AMOVL, ®, &stk) - } - - if proc == 1 { - ginscall(gc.Newproc, 0) - } else { - if gc.Hasdefer == 0 { - gc.Fatal("hasdefer=0 but has defer") - } - ginscall(gc.Deferproc, 0) - } - - if proc == 2 { - gc.Nodreg(®, gc.Types[gc.TINT32], x86.REG_AX) - gins(x86.ATESTL, ®, ®) - p = gc.Gbranch(x86.AJEQ, nil, +1) - cgen_ret(nil) - gc.Patch(p, gc.Pc) - } - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { - var i *gc.Node - var f *gc.Node - var tmpi gc.Node - var nodi gc.Node - var nodo gc.Node - var nodr gc.Node - var nodsp gc.Node - - i = n.Left - if i.Op != gc.ODOTINTER { - gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) - } - - f = i.Right // field - if f.Op != gc.ONAME { - gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) - } - - i = i.Left // interface - - if i.Addable == 0 { - gc.Tempname(&tmpi, i.Type) - cgen(i, &tmpi) - i = &tmpi - } - - gc.Genlist(n.List) // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res) // REG = &inter - - gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], x86.REG_SP) - - nodsp.Xoffset = 0 - if proc != 0 { - nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn - } - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset += int64(gc.Widthptr) - cgen(&nodi, &nodsp) // {0, 8(nacl), or 16}(SP) = 8(REG) -- i.data - - regalloc(&nodo, gc.Types[gc.Tptr], res) - - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset -= int64(gc.Widthptr) - cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab - regfree(&nodi) - - regalloc(&nodr, gc.Types[gc.Tptr], &nodo) - if n.Left.Xoffset == gc.BADWIDTH { - gc.Fatal("cgen_callinter: badwidth") - } - gc.Cgen_checknil(&nodo) // in case offset is huge - nodo.Op = gc.OINDREG - nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 - if proc == 0 { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] - proc = 3 - } else { - // go/defer. generate go func value. - gins(x86.ALEAQ, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] - } - - nodr.Type = n.Left.Type - ginscall(&nodr, proc) - - regfree(&nodr) - regfree(&nodo) -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -func cgen_call(n *gc.Node, proc int) { - var t *gc.Type - var nod gc.Node - var afun gc.Node - - if n == nil { - return - } - - if n.Left.Ullman >= gc.UINF { - // if name involves a fn call - // precompute the address of the fn - gc.Tempname(&afun, gc.Types[gc.Tptr]) - - cgen(n.Left, &afun) - } - - gc.Genlist(n.List) // assign the args - t = n.Left.Type - - // call tempname pointer - if n.Left.Ullman >= gc.UINF { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, &afun) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call pointer - if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, n.Left) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call direct - n.Left.Method = 1 - - ginscall(n.Left, proc) -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -func cgen_callret(n *gc.Node, res *gc.Node) { - var nod gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_callret: nil") - } - - nod = gc.Node{} - nod.Op = gc.OINDREG - nod.Val.U.Reg = x86.REG_SP - nod.Addable = 1 - - nod.Xoffset = fp.Width - nod.Type = fp.Type - gc.Cgen_as(res, &nod) -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -func cgen_aret(n *gc.Node, res *gc.Node) { - var nod1 gc.Node - var nod2 gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_aret: nil") - } - - nod1 = gc.Node{} - nod1.Op = gc.OINDREG - nod1.Val.U.Reg = x86.REG_SP - nod1.Addable = 1 - - nod1.Xoffset = fp.Width - nod1.Type = fp.Type - - if res.Op != gc.OREGISTER { - regalloc(&nod2, gc.Types[gc.Tptr], res) - gins(leaptr, &nod1, &nod2) - gins(movptr, &nod2, res) - regfree(&nod2) - } else { - gins(leaptr, &nod1, res) - } -} - -/* - * generate return. - * n->left is assignments to return values. - */ -func cgen_ret(n *gc.Node) { - var p *obj.Prog - - if n != nil { - gc.Genlist(n.List) // copy out args - } - if gc.Hasdefer != 0 { - ginscall(gc.Deferreturn, 0) - } - gc.Genlist(gc.Curfn.Exit) - p = gins(obj.ARET, nil, nil) - if n != nil && n.Op == gc.ORETJMP { - p.To.Type = obj.TYPE_MEM - p.To.Name = obj.NAME_EXTERN - p.To.Sym = gc.Linksym(n.Left.Sym) - } -} - -/* - * generate division. - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var a int - var check int - var n3 gc.Node - var n4 gc.Node - var t *gc.Type - var t0 *gc.Type - var ax gc.Node - var dx gc.Node - var ax1 gc.Node - var n31 gc.Node - var oldax gc.Node - var olddx gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will trap. - // Also the byte divide instruction needs AH, - // which we otherwise don't have to deal with. - // Easiest way to avoid for int8, int16: use int32. - // For int32 and int64, use explicit test. - // Could use int64 hw for int32. - t = nl.Type - - t0 = t - check = 0 - if gc.Issigned[t.Etype] != 0 { - check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= nr.Ullman { - savex(x86.REG_AX, &ax, &oldax, res, t0) - cgen(nl, &ax) - regalloc(&ax, t0, &ax) // mark ax live during cgen - cgen(nr, &n3) - regfree(&ax) - } else { - cgen(nr, &n3) - savex(x86.REG_AX, &ax, &oldax, res, t0) - cgen(nl, &ax) - } - - if t != t0 { - // Convert - ax1 = ax - - n31 = n3 - ax.Type = t - n3.Type = t - gmove(&ax1, &ax) - gmove(&n31, &n3) - } - - p2 = nil - if gc.Nacl { - // Native Client does not relay the divide-by-zero trap - // to the executing program, so we must insert a check - // for ourselves. - gc.Nodconst(&n4, t, 0) - - gins(optoas(gc.OCMP, t), &n3, &n4) - p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) - if panicdiv == nil { - panicdiv = gc.Sysfunc("panicdivide") - } - ginscall(panicdiv, -1) - gc.Patch(p1, gc.Pc) - } - - if check != 0 { - gc.Nodconst(&n4, t, -1) - gins(optoas(gc.OCMP, t), &n3, &n4) - p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) - if op == gc.ODIV { - // a / (-1) is -a. - gins(optoas(gc.OMINUS, t), nil, &ax) - - gmove(&ax, res) - } else { - // a % (-1) is 0. - gc.Nodconst(&n4, t, 0) - - gmove(&n4, res) - } - - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - } - - savex(x86.REG_DX, &dx, &olddx, res, t) - if gc.Issigned[t.Etype] == 0 { - gc.Nodconst(&n4, t, 0) - gmove(&n4, &dx) - } else { - gins(optoas(gc.OEXTEND, t), nil, nil) - } - gins(a, &n3, nil) - regfree(&n3) - if op == gc.ODIV { - gmove(&ax, res) - } else { - gmove(&dx, res) - } - restx(&dx, &olddx) - if check != 0 { - gc.Patch(p2, gc.Pc) - } - restx(&ax, &oldax) -} - -/* - * register dr is one of the special ones (AX, CX, DI, SI, etc.). - * we need to use it. if it is already allocated as a temporary - * (r > 1; can only happen if a routine like sgen passed a - * special as cgen's res and then cgen used regalloc to reuse - * it as its own temporary), then move it for now to another - * register. caller must call restx to move it back. - * the move is not necessary if dr == res, because res is - * known to be dead. - */ -func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) { - var r int - - r = int(reg[dr]) - - // save current ax and dx if they are live - // and not the destination - *oldx = gc.Node{} - - gc.Nodreg(x, t, dr) - if r > 1 && !gc.Samereg(x, res) { - regalloc(oldx, gc.Types[gc.TINT64], nil) - x.Type = gc.Types[gc.TINT64] - gmove(x, oldx) - x.Type = t - oldx.Ostk = int32(r) // squirrel away old r value - reg[dr] = 1 - } -} - -func restx(x *gc.Node, oldx *gc.Node) { - if oldx.Op != 0 { - x.Type = gc.Types[gc.TINT64] - reg[x.Val.U.Reg] = uint8(oldx.Ostk) - gmove(oldx, x) - regfree(oldx) - } -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var w int - var a int - var m gc.Magic - - if nr.Op != gc.OLITERAL { - goto longdiv - } - w = int(nl.Type.Width * 8) - - // Front end handled 32-bit division. We only need to handle 64-bit. - // try to do division by multiply by (2^w)/d - // see hacker's delight chapter 10 - switch gc.Simtype[nl.Type.Etype] { - default: - goto longdiv - - case gc.TUINT64: - m.W = w - m.Ud = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - gc.Umagic(&m) - if m.Bad != 0 { - break - } - if op == gc.OMOD { - goto longmod - } - - cgenr(nl, &n1, nil) - gc.Nodconst(&n2, nl.Type, int64(m.Um)) - regalloc(&n3, nl.Type, res) - cgen_hmul(&n1, &n2, &n3) - - if m.Ua != 0 { - // need to add numerator accounting for overflow - gins(optoas(gc.OADD, nl.Type), &n1, &n3) - - gc.Nodconst(&n2, nl.Type, 1) - gins(optoas(gc.ORROTC, nl.Type), &n2, &n3) - gc.Nodconst(&n2, nl.Type, int64(m.S)-1) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) - } else { - gc.Nodconst(&n2, nl.Type, int64(m.S)) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift dx - } - - gmove(&n3, res) - regfree(&n1) - regfree(&n3) - return - - case gc.TINT64: - m.W = w - m.Sd = gc.Mpgetfix(nr.Val.U.Xval) - gc.Smagic(&m) - if m.Bad != 0 { - break - } - if op == gc.OMOD { - goto longmod - } - - cgenr(nl, &n1, res) - gc.Nodconst(&n2, nl.Type, m.Sm) - regalloc(&n3, nl.Type, nil) - cgen_hmul(&n1, &n2, &n3) - - if m.Sm < 0 { - // need to add numerator - gins(optoas(gc.OADD, nl.Type), &n1, &n3) - } - - gc.Nodconst(&n2, nl.Type, int64(m.S)) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift n3 - - gc.Nodconst(&n2, nl.Type, int64(w)-1) - - gins(optoas(gc.ORSH, nl.Type), &n2, &n1) // -1 iff num is neg - gins(optoas(gc.OSUB, nl.Type), &n1, &n3) // added - - if m.Sd < 0 { - // this could probably be removed - // by factoring it into the multiplier - gins(optoas(gc.OMINUS, nl.Type), nil, &n3) - } - - gmove(&n3, res) - regfree(&n1) - regfree(&n3) - return - } - - goto longdiv - - // division and mod using (slow) hardware instruction -longdiv: - dodiv(op, nl, nr, res) - - return - - // mod using formula A%B = A-(A/B*B) but - // we know that there is a fast algorithm for A/B -longmod: - regalloc(&n1, nl.Type, res) - - cgen(nl, &n1) - regalloc(&n2, nl.Type, nil) - cgen_div(gc.ODIV, &n1, nr, &n2) - a = optoas(gc.OMUL, nl.Type) - if w == 8 { - // use 2-operand 16-bit multiply - // because there is no 2-operand 8-bit multiply - a = x86.AIMULW - } - - if !gc.Smallintconst(nr) { - regalloc(&n3, nl.Type, nil) - cgen(nr, &n3) - gins(a, &n3, &n2) - regfree(&n3) - } else { - gins(a, nr, &n2) - } - gins(optoas(gc.OSUB, nl.Type), &n2, &n1) - gmove(&n1, res) - regfree(&n1) - regfree(&n2) -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { - var t *gc.Type - var a int - var n1 gc.Node - var n2 gc.Node - var ax gc.Node - var dx gc.Node - var tmp *gc.Node - - t = nl.Type - a = optoas(gc.OHMUL, t) - if nl.Ullman < nr.Ullman { - tmp = nl - nl = nr - nr = tmp - } - - cgenr(nl, &n1, res) - cgenr(nr, &n2, nil) - gc.Nodreg(&ax, t, x86.REG_AX) - gmove(&n1, &ax) - gins(a, &n2, nil) - regfree(&n2) - regfree(&n1) - - if t.Width == 1 { - // byte multiply behaves differently. - gc.Nodreg(&ax, t, x86.REG_AH) - - gc.Nodreg(&dx, t, x86.REG_DX) - gmove(&ax, &dx) - } - - gc.Nodreg(&dx, t, x86.REG_DX) - gmove(&dx, res) -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var n5 gc.Node - var cx gc.Node - var oldcx gc.Node - var a int - var rcx int - var p1 *obj.Prog - var sc uint64 - var tcount *gc.Type - - a = optoas(op, nl.Type) - - if nr.Op == gc.OLITERAL { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if sc >= uint64(nl.Type.Width*8) { - // large shift gets 2 shifts by width-1 - gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) - - gins(a, &n3, &n1) - gins(a, &n3, &n1) - } else { - gins(a, nr, &n1) - } - gmove(&n1, res) - regfree(&n1) - goto ret - } - - if nl.Ullman >= gc.UINF { - gc.Tempname(&n4, nl.Type) - cgen(nl, &n4) - nl = &n4 - } - - if nr.Ullman >= gc.UINF { - gc.Tempname(&n5, nr.Type) - cgen(nr, &n5) - nr = &n5 - } - - rcx = int(reg[x86.REG_CX]) - gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX) - - // Allow either uint32 or uint64 as shift type, - // to avoid unnecessary conversion from uint32 to uint64 - // just to do the comparison. - tcount = gc.Types[gc.Simtype[nr.Type.Etype]] - - if tcount.Etype < gc.TUINT32 { - tcount = gc.Types[gc.TUINT32] - } - - regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX - regalloc(&n3, tcount, &n1) // to clear high bits of CX - - gc.Nodreg(&cx, gc.Types[gc.TUINT64], x86.REG_CX) - - oldcx = gc.Node{} - if rcx > 0 && !gc.Samereg(&cx, res) { - regalloc(&oldcx, gc.Types[gc.TUINT64], nil) - gmove(&cx, &oldcx) - } - - cx.Type = tcount - - if gc.Samereg(&cx, res) { - regalloc(&n2, nl.Type, nil) - } else { - regalloc(&n2, nl.Type, res) - } - if nl.Ullman >= nr.Ullman { - cgen(nl, &n2) - cgen(nr, &n1) - gmove(&n1, &n3) - } else { - cgen(nr, &n1) - gmove(&n1, &n3) - cgen(nl, &n2) - } - - regfree(&n3) - - // test and fix up large shifts - if !bounded { - gc.Nodconst(&n3, tcount, nl.Type.Width*8) - gins(optoas(gc.OCMP, tcount), &n1, &n3) - p1 = gc.Gbranch(optoas(gc.OLT, tcount), nil, +1) - if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { - gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) - gins(a, &n3, &n2) - } else { - gc.Nodconst(&n3, nl.Type, 0) - gmove(&n3, &n2) - } - - gc.Patch(p1, gc.Pc) - } - - gins(a, &n1, &n2) - - if oldcx.Op != 0 { - cx.Type = gc.Types[gc.TUINT64] - gmove(&oldcx, &cx) - regfree(&oldcx) - } - - gmove(&n2, res) - - regfree(&n1) - regfree(&n2) - -ret: -} - -/* - * generate byte multiply: - * res = nl * nr - * there is no 2-operand byte multiply instruction so - * we do a full-width multiplication and truncate afterwards. - */ -func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n1b gc.Node - var n2b gc.Node - var tmp *gc.Node - var t *gc.Type - var a int - - // largest ullman on left. - if nl.Ullman < nr.Ullman { - tmp = nl - nl = nr - nr = tmp - } - - // generate operands in "8-bit" registers. - regalloc(&n1b, nl.Type, res) - - cgen(nl, &n1b) - regalloc(&n2b, nr.Type, nil) - cgen(nr, &n2b) - - // perform full-width multiplication. - t = gc.Types[gc.TUINT64] - - if gc.Issigned[nl.Type.Etype] != 0 { - t = gc.Types[gc.TINT64] - } - gc.Nodreg(&n1, t, int(n1b.Val.U.Reg)) - gc.Nodreg(&n2, t, int(n2b.Val.U.Reg)) - a = optoas(op, t) - gins(a, &n2, &n1) - - // truncate. - gmove(&n1, res) - - regfree(&n1b) - regfree(&n2b) -} - -func clearfat(nl *gc.Node) { - var w int64 - var c int64 - var q int64 - var n1 gc.Node - var oldn1 gc.Node - var ax gc.Node - var oldax gc.Node - var di gc.Node - var z gc.Node - var p *obj.Prog - - /* clear a fat object */ - if gc.Debug['g'] != 0 { - gc.Dump("\nclearfat", nl) - } - - w = nl.Type.Width - - // Avoid taking the address for simple enough types. - if componentgen(nil, nl) { - return - } - - c = w % 8 // bytes - q = w / 8 // quads - - if q < 4 { - // Write sequence of MOV 0, off(base) instead of using STOSQ. - // The hope is that although the code will be slightly longer, - // the MOVs will have no dependencies and pipeline better - // than the unrolled STOSQ loop. - // NOTE: Must use agen, not igen, so that optimizer sees address - // being taken. We are not writing on field boundaries. - agenr(nl, &n1, nil) - - n1.Op = gc.OINDREG - gc.Nodconst(&z, gc.Types[gc.TUINT64], 0) - for { - tmp14 := q - q-- - if tmp14 <= 0 { - break - } - n1.Type = z.Type - gins(x86.AMOVQ, &z, &n1) - n1.Xoffset += 8 - } - - if c >= 4 { - gc.Nodconst(&z, gc.Types[gc.TUINT32], 0) - n1.Type = z.Type - gins(x86.AMOVL, &z, &n1) - n1.Xoffset += 4 - c -= 4 - } - - gc.Nodconst(&z, gc.Types[gc.TUINT8], 0) - for { - tmp15 := c - c-- - if tmp15 <= 0 { - break - } - n1.Type = z.Type - gins(x86.AMOVB, &z, &n1) - n1.Xoffset++ - } - - regfree(&n1) - return - } - - savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr]) - agen(nl, &n1) - - savex(x86.REG_AX, &ax, &oldax, nil, gc.Types[gc.Tptr]) - gconreg(x86.AMOVL, 0, x86.REG_AX) - - if q > 128 || gc.Nacl { - gconreg(movptr, q, x86.REG_CX) - gins(x86.AREP, nil, nil) // repeat - gins(x86.ASTOSQ, nil, nil) // STOQ AL,*(DI)+ - } else { - p = gins(obj.ADUFFZERO, nil, nil) - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) - - // 2 and 128 = magic constants: see ../../runtime/asm_amd64.s - p.To.Offset = 2 * (128 - q) - } - - z = ax - di = n1 - if w >= 8 && c >= 4 { - di.Op = gc.OINDREG - z.Type = gc.Types[gc.TINT64] - di.Type = z.Type - p = gins(x86.AMOVQ, &z, &di) - p.To.Scale = 1 - p.To.Offset = c - 8 - } else if c >= 4 { - di.Op = gc.OINDREG - z.Type = gc.Types[gc.TINT32] - di.Type = z.Type - p = gins(x86.AMOVL, &z, &di) - if c > 4 { - p = gins(x86.AMOVL, &z, &di) - p.To.Scale = 1 - p.To.Offset = c - 4 - } - } else { - for c > 0 { - gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+ - c-- - } - } - - restx(&n1, &oldn1) - restx(&ax, &oldax) -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -func expandchecks(firstp *obj.Prog) { - var p *obj.Prog - var p1 *obj.Prog - var p2 *obj.Prog - - for p = firstp; p != nil; p = p.Link { - if p.As != obj.ACHECKNIL { - continue - } - if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers - gc.Warnl(int(p.Lineno), "generated nil check") - } - - // check is - // CMP arg, $0 - // JNE 2(PC) (likely) - // MOV AX, 0 - p1 = gc.Ctxt.NewProg() - - p2 = gc.Ctxt.NewProg() - gc.Clearp(p1) - gc.Clearp(p2) - p1.Link = p2 - p2.Link = p.Link - p.Link = p1 - p1.Lineno = p.Lineno - p2.Lineno = p.Lineno - p1.Pc = 9999 - p2.Pc = 9999 - p.As = int16(cmpptr) - p.To.Type = obj.TYPE_CONST - p.To.Offset = 0 - p1.As = x86.AJNE - p1.From.Type = obj.TYPE_CONST - p1.From.Offset = 1 // likely - p1.To.Type = obj.TYPE_BRANCH - p1.To.U.Branch = p2.Link - - // crash by write to memory address 0. - // if possible, since we know arg is 0, use 0(arg), - // which will be shorter to encode than plain 0. - p2.As = x86.AMOVL - - p2.From.Type = obj.TYPE_REG - p2.From.Reg = x86.REG_AX - if regtyp(&p.From) { - p2.To.Type = obj.TYPE_MEM - p2.To.Reg = p.From.Reg - } else { - p2.To.Type = obj.TYPE_MEM - p2.To.Reg = x86.REG_NONE - } - - p2.To.Offset = 0 - } -} diff --git a/src/cmd/new6g/gsubr.go b/src/cmd/new6g/gsubr.go deleted file mode 100644 index c440f8c5f7..0000000000 --- a/src/cmd/new6g/gsubr.go +++ /dev/null @@ -1,1752 +0,0 @@ -// Derived from Inferno utils/6c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" - "fmt" -) -import "cmd/internal/gc" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 6l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -var unmappedzero int64 = 4096 - -var resvd = []int{ - x86.REG_DI, // for movstring - x86.REG_SI, // for movstring - - x86.REG_AX, // for divide - x86.REG_CX, // for shift - x86.REG_DX, // for divide - x86.REG_SP, // for stack -} - -func ginit() { - var i int - - for i = 0; i < len(reg); i++ { - reg[i] = 1 - } - for i = x86.REG_AX; i <= x86.REG_R15; i++ { - reg[i] = 0 - } - for i = x86.REG_X0; i <= x86.REG_X15; i++ { - reg[i] = 0 - } - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]++ - } - - if gc.Nacl { - reg[x86.REG_BP]++ - reg[x86.REG_R15]++ - } else if obj.Framepointer_enabled != 0 { - // BP is part of the calling convention of framepointer_enabled. - reg[x86.REG_BP]++ - } -} - -func gclean() { - var i int - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]-- - } - if gc.Nacl { - reg[x86.REG_BP]-- - reg[x86.REG_R15]-- - } else if obj.Framepointer_enabled != 0 { - reg[x86.REG_BP]-- - } - - for i = x86.REG_AX; i <= x86.REG_R15; i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) - } - } - for i = x86.REG_X0; i <= x86.REG_X15; i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) - } - } -} - -func anyregalloc() bool { - var i int - var j int - - for i = x86.REG_AX; i <= x86.REG_R15; i++ { - if reg[i] == 0 { - goto ok - } - for j = 0; j < len(resvd); j++ { - if resvd[j] == i { - goto ok - } - } - return true - ok: - } - - return false -} - -var regpc [x86.REG_R15 + 1 - x86.REG_AX]uint32 - -/* - * allocate register of type t, leave in n. - * if o != N, o is desired fixed register. - * caller must regfree(n). - */ -func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { - var i int - var et int - - if t == nil { - gc.Fatal("regalloc: t nil") - } - et = int(gc.Simtype[t.Etype]) - - switch et { - case gc.TINT8, - gc.TUINT8, - gc.TINT16, - gc.TUINT16, - gc.TINT32, - gc.TUINT32, - gc.TINT64, - gc.TUINT64, - gc.TPTR32, - gc.TPTR64, - gc.TBOOL: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= x86.REG_AX && i <= x86.REG_R15 { - goto out - } - } - - for i = x86.REG_AX; i <= x86.REG_R15; i++ { - if reg[i] == 0 { - regpc[i-x86.REG_AX] = uint32(obj.Getcallerpc(&n)) - goto out - } - } - - gc.Flusherrors() - for i = 0; i+x86.REG_AX <= x86.REG_R15; i++ { - fmt.Printf("%d %p\n", i, regpc[i]) - } - gc.Fatal("out of fixed registers") - - case gc.TFLOAT32, - gc.TFLOAT64: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= x86.REG_X0 && i <= x86.REG_X15 { - goto out - } - } - - for i = x86.REG_X0; i <= x86.REG_X15; i++ { - if reg[i] == 0 { - goto out - } - } - gc.Fatal("out of floating registers") - - case gc.TCOMPLEX64, - gc.TCOMPLEX128: - gc.Tempname(n, t) - return - } - - gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0)) - return - -out: - reg[i]++ - gc.Nodreg(n, t, i) -} - -func regfree(n *gc.Node) { - var i int - - if n.Op == gc.ONAME { - return - } - if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { - gc.Fatal("regfree: not a register") - } - i = int(n.Val.U.Reg) - if i == x86.REG_SP { - return - } - if i < 0 || i >= len(reg) { - gc.Fatal("regfree: reg out of range") - } - if reg[i] <= 0 { - gc.Fatal("regfree: reg not allocated") - } - reg[i]-- - if reg[i] == 0 && x86.REG_AX <= i && i <= x86.REG_R15 { - regpc[i-x86.REG_AX] = 0 - } -} - -/* - * generate - * as $c, reg - */ -func gconreg(as int, c int64, reg int) { - var nr gc.Node - - switch as { - case x86.AADDL, - x86.AMOVL, - x86.ALEAL: - gc.Nodreg(&nr, gc.Types[gc.TINT32], reg) - - default: - gc.Nodreg(&nr, gc.Types[gc.TINT64], reg) - } - - ginscon(as, c, &nr) -} - -/* - * generate - * as $c, n - */ -func ginscon(as int, c int64, n2 *gc.Node) { - var n1 gc.Node - var ntmp gc.Node - - switch as { - case x86.AADDL, - x86.AMOVL, - x86.ALEAL: - gc.Nodconst(&n1, gc.Types[gc.TINT32], c) - - default: - gc.Nodconst(&n1, gc.Types[gc.TINT64], c) - } - - if as != x86.AMOVQ && (c < -(1<<31) || c >= 1<<31) { - // cannot have 64-bit immediate in ADD, etc. - // instead, MOV into register first. - regalloc(&ntmp, gc.Types[gc.TINT64], nil) - - gins(x86.AMOVQ, &n1, &ntmp) - gins(as, &ntmp, n2) - regfree(&ntmp) - return - } - - gins(as, &n1, n2) -} - -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node - -var bigf gc.Node - -var bignodes_did int - -func bignodes() { - if bignodes_did != 0 { - return - } - bignodes_did = 1 - - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) - - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) -} - -/* - * generate move: - * t = f - * hard part is conversions. - */ -func gmove(f *gc.Node, t *gc.Node) { - var a int - var ft int - var tt int - var cvt *gc.Type - var r1 gc.Node - var r2 gc.Node - var r3 gc.Node - var r4 gc.Node - var zero gc.Node - var one gc.Node - var con gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['M'] != 0 { - fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) - } - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { - gc.Complexmove(f, t) - return - } - - // cannot have two memory operands - if gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - - // convert constant to desired type - if f.Op == gc.OLITERAL { - gc.Convconst(&con, t.Type, &f.Val) - f = &con - ft = tt // so big switch will choose a simple mov - - // some constants can't move directly to memory. - if gc.Ismem(t) { - // float constants come from memory. - if gc.Isfloat[tt] != 0 { - goto hard - } - - // 64-bit immediates are really 32-bit sign-extended - // unless moving into a register. - if gc.Isint[tt] != 0 { - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 { - goto hard - } - if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 { - goto hard - } - } - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch uint32(ft)<<16 | uint32(tt) { - default: - gc.Fatal("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong)) - - /* - * integer copy and truncate - */ - case gc.TINT8<<16 | gc.TINT8, // same size - gc.TINT8<<16 | gc.TUINT8, - gc.TUINT8<<16 | gc.TINT8, - gc.TUINT8<<16 | gc.TUINT8, - gc.TINT16<<16 | gc.TINT8, - // truncate - gc.TUINT16<<16 | gc.TINT8, - gc.TINT32<<16 | gc.TINT8, - gc.TUINT32<<16 | gc.TINT8, - gc.TINT64<<16 | gc.TINT8, - gc.TUINT64<<16 | gc.TINT8, - gc.TINT16<<16 | gc.TUINT8, - gc.TUINT16<<16 | gc.TUINT8, - gc.TINT32<<16 | gc.TUINT8, - gc.TUINT32<<16 | gc.TUINT8, - gc.TINT64<<16 | gc.TUINT8, - gc.TUINT64<<16 | gc.TUINT8: - a = x86.AMOVB - - case gc.TINT16<<16 | gc.TINT16, // same size - gc.TINT16<<16 | gc.TUINT16, - gc.TUINT16<<16 | gc.TINT16, - gc.TUINT16<<16 | gc.TUINT16, - gc.TINT32<<16 | gc.TINT16, - // truncate - gc.TUINT32<<16 | gc.TINT16, - gc.TINT64<<16 | gc.TINT16, - gc.TUINT64<<16 | gc.TINT16, - gc.TINT32<<16 | gc.TUINT16, - gc.TUINT32<<16 | gc.TUINT16, - gc.TINT64<<16 | gc.TUINT16, - gc.TUINT64<<16 | gc.TUINT16: - a = x86.AMOVW - - case gc.TINT32<<16 | gc.TINT32, // same size - gc.TINT32<<16 | gc.TUINT32, - gc.TUINT32<<16 | gc.TINT32, - gc.TUINT32<<16 | gc.TUINT32: - a = x86.AMOVL - - case gc.TINT64<<16 | gc.TINT32, // truncate - gc.TUINT64<<16 | gc.TINT32, - gc.TINT64<<16 | gc.TUINT32, - gc.TUINT64<<16 | gc.TUINT32: - a = x86.AMOVQL - - case gc.TINT64<<16 | gc.TINT64, // same size - gc.TINT64<<16 | gc.TUINT64, - gc.TUINT64<<16 | gc.TINT64, - gc.TUINT64<<16 | gc.TUINT64: - a = x86.AMOVQ - - /* - * integer up-conversions - */ - case gc.TINT8<<16 | gc.TINT16, // sign extend int8 - gc.TINT8<<16 | gc.TUINT16: - a = x86.AMOVBWSX - - goto rdst - - case gc.TINT8<<16 | gc.TINT32, - gc.TINT8<<16 | gc.TUINT32: - a = x86.AMOVBLSX - goto rdst - - case gc.TINT8<<16 | gc.TINT64, - gc.TINT8<<16 | gc.TUINT64: - a = x86.AMOVBQSX - goto rdst - - case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 - gc.TUINT8<<16 | gc.TUINT16: - a = x86.AMOVBWZX - - goto rdst - - case gc.TUINT8<<16 | gc.TINT32, - gc.TUINT8<<16 | gc.TUINT32: - a = x86.AMOVBLZX - goto rdst - - case gc.TUINT8<<16 | gc.TINT64, - gc.TUINT8<<16 | gc.TUINT64: - a = x86.AMOVBQZX - goto rdst - - case gc.TINT16<<16 | gc.TINT32, // sign extend int16 - gc.TINT16<<16 | gc.TUINT32: - a = x86.AMOVWLSX - - goto rdst - - case gc.TINT16<<16 | gc.TINT64, - gc.TINT16<<16 | gc.TUINT64: - a = x86.AMOVWQSX - goto rdst - - case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 - gc.TUINT16<<16 | gc.TUINT32: - a = x86.AMOVWLZX - - goto rdst - - case gc.TUINT16<<16 | gc.TINT64, - gc.TUINT16<<16 | gc.TUINT64: - a = x86.AMOVWQZX - goto rdst - - case gc.TINT32<<16 | gc.TINT64, // sign extend int32 - gc.TINT32<<16 | gc.TUINT64: - a = x86.AMOVLQSX - - goto rdst - - // AMOVL into a register zeros the top of the register, - // so this is not always necessary, but if we rely on AMOVL - // the optimizer is almost certain to screw with us. - case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 - gc.TUINT32<<16 | gc.TUINT64: - a = x86.AMOVLQZX - - goto rdst - - /* - * float to integer - */ - case gc.TFLOAT32<<16 | gc.TINT32: - a = x86.ACVTTSS2SL - - goto rdst - - case gc.TFLOAT64<<16 | gc.TINT32: - a = x86.ACVTTSD2SL - goto rdst - - case gc.TFLOAT32<<16 | gc.TINT64: - a = x86.ACVTTSS2SQ - goto rdst - - case gc.TFLOAT64<<16 | gc.TINT64: - a = x86.ACVTTSD2SQ - goto rdst - - // convert via int32. - case gc.TFLOAT32<<16 | gc.TINT16, - gc.TFLOAT32<<16 | gc.TINT8, - gc.TFLOAT32<<16 | gc.TUINT16, - gc.TFLOAT32<<16 | gc.TUINT8, - gc.TFLOAT64<<16 | gc.TINT16, - gc.TFLOAT64<<16 | gc.TINT8, - gc.TFLOAT64<<16 | gc.TUINT16, - gc.TFLOAT64<<16 | gc.TUINT8: - cvt = gc.Types[gc.TINT32] - - goto hard - - // convert via int64. - case gc.TFLOAT32<<16 | gc.TUINT32, - gc.TFLOAT64<<16 | gc.TUINT32: - cvt = gc.Types[gc.TINT64] - - goto hard - - // algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - case gc.TFLOAT32<<16 | gc.TUINT64, - gc.TFLOAT64<<16 | gc.TUINT64: - a = x86.ACVTTSS2SQ - - if ft == gc.TFLOAT64 { - a = x86.ACVTTSD2SQ - } - bignodes() - regalloc(&r1, gc.Types[ft], nil) - regalloc(&r2, gc.Types[tt], t) - regalloc(&r3, gc.Types[ft], nil) - regalloc(&r4, gc.Types[tt], nil) - gins(optoas(gc.OAS, f.Type), f, &r1) - gins(optoas(gc.OCMP, f.Type), &bigf, &r1) - p1 = gc.Gbranch(optoas(gc.OLE, f.Type), nil, +1) - gins(a, &r1, &r2) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - gins(optoas(gc.OAS, f.Type), &bigf, &r3) - gins(optoas(gc.OSUB, f.Type), &r3, &r1) - gins(a, &r1, &r2) - gins(x86.AMOVQ, &bigi, &r4) - gins(x86.AXORQ, &r4, &r2) - gc.Patch(p2, gc.Pc) - gmove(&r2, t) - regfree(&r4) - regfree(&r3) - regfree(&r2) - regfree(&r1) - return - - /* - * integer to float - */ - case gc.TINT32<<16 | gc.TFLOAT32: - a = x86.ACVTSL2SS - - goto rdst - - case gc.TINT32<<16 | gc.TFLOAT64: - a = x86.ACVTSL2SD - goto rdst - - case gc.TINT64<<16 | gc.TFLOAT32: - a = x86.ACVTSQ2SS - goto rdst - - case gc.TINT64<<16 | gc.TFLOAT64: - a = x86.ACVTSQ2SD - goto rdst - - // convert via int32 - case gc.TINT16<<16 | gc.TFLOAT32, - gc.TINT16<<16 | gc.TFLOAT64, - gc.TINT8<<16 | gc.TFLOAT32, - gc.TINT8<<16 | gc.TFLOAT64, - gc.TUINT16<<16 | gc.TFLOAT32, - gc.TUINT16<<16 | gc.TFLOAT64, - gc.TUINT8<<16 | gc.TFLOAT32, - gc.TUINT8<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - // convert via int64. - case gc.TUINT32<<16 | gc.TFLOAT32, - gc.TUINT32<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT64] - - goto hard - - // algorithm is: - // if small enough, use native int64 -> uint64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - case gc.TUINT64<<16 | gc.TFLOAT32, - gc.TUINT64<<16 | gc.TFLOAT64: - a = x86.ACVTSQ2SS - - if tt == gc.TFLOAT64 { - a = x86.ACVTSQ2SD - } - gc.Nodconst(&zero, gc.Types[gc.TUINT64], 0) - gc.Nodconst(&one, gc.Types[gc.TUINT64], 1) - regalloc(&r1, f.Type, f) - regalloc(&r2, t.Type, t) - regalloc(&r3, f.Type, nil) - regalloc(&r4, f.Type, nil) - gmove(f, &r1) - gins(x86.ACMPQ, &r1, &zero) - p1 = gc.Gbranch(x86.AJLT, nil, +1) - gins(a, &r1, &r2) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - gmove(&r1, &r3) - gins(x86.ASHRQ, &one, &r3) - gmove(&r1, &r4) - gins(x86.AANDL, &one, &r4) - gins(x86.AORQ, &r4, &r3) - gins(a, &r3, &r2) - gins(optoas(gc.OADD, t.Type), &r2, &r2) - gc.Patch(p2, gc.Pc) - gmove(&r2, t) - regfree(&r4) - regfree(&r3) - regfree(&r2) - regfree(&r1) - return - - /* - * float to float - */ - case gc.TFLOAT32<<16 | gc.TFLOAT32: - a = x86.AMOVSS - - case gc.TFLOAT64<<16 | gc.TFLOAT64: - a = x86.AMOVSD - - case gc.TFLOAT32<<16 | gc.TFLOAT64: - a = x86.ACVTSS2SD - goto rdst - - case gc.TFLOAT64<<16 | gc.TFLOAT32: - a = x86.ACVTSD2SS - goto rdst - } - - gins(a, f, t) - return - - // requires register destination -rdst: - regalloc(&r1, t.Type, t) - - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return -} - -func samaddr(f *gc.Node, t *gc.Node) bool { - if f.Op != t.Op { - return false - } - - switch f.Op { - case gc.OREGISTER: - if f.Val.U.Reg != t.Val.U.Reg { - break - } - return true - } - - return false -} - -/* - * generate one instruction: - * as f, t - */ -func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { - var w int32 - var p *obj.Prog - // Node nod; - - var af obj.Addr - var at obj.Addr - - // if(f != N && f->op == OINDEX) { - // regalloc(&nod, ®node, Z); - // v = constnode.vconst; - // cgen(f->right, &nod); - // constnode.vconst = v; - // idx.reg = nod.reg; - // regfree(&nod); - // } - // if(t != N && t->op == OINDEX) { - // regalloc(&nod, ®node, Z); - // v = constnode.vconst; - // cgen(t->right, &nod); - // constnode.vconst = v; - // idx.reg = nod.reg; - // regfree(&nod); - // } - - switch as { - case x86.AMOVB, - x86.AMOVW, - x86.AMOVL, - x86.AMOVQ, - x86.AMOVSS, - x86.AMOVSD: - if f != nil && t != nil && samaddr(f, t) { - return nil - } - - case x86.ALEAQ: - if f != nil && gc.Isconst(f, gc.CTNIL) { - gc.Fatal("gins LEAQ nil %v", gc.Tconv(f.Type, 0)) - } - } - - af = obj.Addr{} - at = obj.Addr{} - if f != nil { - gc.Naddr(f, &af, 1) - } - if t != nil { - gc.Naddr(t, &at, 1) - } - p = gc.Prog(as) - if f != nil { - p.From = af - } - if t != nil { - p.To = at - } - if gc.Debug['g'] != 0 { - fmt.Printf("%v\n", p) - } - - w = 0 - switch as { - case x86.AMOVB: - w = 1 - - case x86.AMOVW: - w = 2 - - case x86.AMOVL: - w = 4 - - case x86.AMOVQ: - w = 8 - } - - if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Width > int64(w))) { - gc.Dump("f", f) - gc.Dump("t", t) - gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) - } - - if p.To.Type == obj.TYPE_ADDR && w > 0 { - gc.Fatal("bad use of addr: %v", p) - } - - return p -} - -func fixlargeoffset(n *gc.Node) { - var a gc.Node - - if n == nil { - return - } - if n.Op != gc.OINDREG { - return - } - if n.Val.U.Reg == x86.REG_SP { // stack offset cannot be large - return - } - if n.Xoffset != int64(int32(n.Xoffset)) { - // offset too large, add to register instead. - a = *n - - a.Op = gc.OREGISTER - a.Type = gc.Types[gc.Tptr] - a.Xoffset = 0 - gc.Cgen_checknil(&a) - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a) - n.Xoffset = 0 - } -} - -/* - * return Axxx for Oxxx on type t. - */ -func optoas(op int, t *gc.Type) int { - var a int - - if t == nil { - gc.Fatal("optoas: t is nil") - } - - a = obj.AXXX - switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { - default: - gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - case gc.OADDR<<16 | gc.TPTR32: - a = x86.ALEAL - - case gc.OADDR<<16 | gc.TPTR64: - a = x86.ALEAQ - - case gc.OEQ<<16 | gc.TBOOL, - gc.OEQ<<16 | gc.TINT8, - gc.OEQ<<16 | gc.TUINT8, - gc.OEQ<<16 | gc.TINT16, - gc.OEQ<<16 | gc.TUINT16, - gc.OEQ<<16 | gc.TINT32, - gc.OEQ<<16 | gc.TUINT32, - gc.OEQ<<16 | gc.TINT64, - gc.OEQ<<16 | gc.TUINT64, - gc.OEQ<<16 | gc.TPTR32, - gc.OEQ<<16 | gc.TPTR64, - gc.OEQ<<16 | gc.TFLOAT32, - gc.OEQ<<16 | gc.TFLOAT64: - a = x86.AJEQ - - case gc.ONE<<16 | gc.TBOOL, - gc.ONE<<16 | gc.TINT8, - gc.ONE<<16 | gc.TUINT8, - gc.ONE<<16 | gc.TINT16, - gc.ONE<<16 | gc.TUINT16, - gc.ONE<<16 | gc.TINT32, - gc.ONE<<16 | gc.TUINT32, - gc.ONE<<16 | gc.TINT64, - gc.ONE<<16 | gc.TUINT64, - gc.ONE<<16 | gc.TPTR32, - gc.ONE<<16 | gc.TPTR64, - gc.ONE<<16 | gc.TFLOAT32, - gc.ONE<<16 | gc.TFLOAT64: - a = x86.AJNE - - case gc.OLT<<16 | gc.TINT8, - gc.OLT<<16 | gc.TINT16, - gc.OLT<<16 | gc.TINT32, - gc.OLT<<16 | gc.TINT64: - a = x86.AJLT - - case gc.OLT<<16 | gc.TUINT8, - gc.OLT<<16 | gc.TUINT16, - gc.OLT<<16 | gc.TUINT32, - gc.OLT<<16 | gc.TUINT64: - a = x86.AJCS - - case gc.OLE<<16 | gc.TINT8, - gc.OLE<<16 | gc.TINT16, - gc.OLE<<16 | gc.TINT32, - gc.OLE<<16 | gc.TINT64: - a = x86.AJLE - - case gc.OLE<<16 | gc.TUINT8, - gc.OLE<<16 | gc.TUINT16, - gc.OLE<<16 | gc.TUINT32, - gc.OLE<<16 | gc.TUINT64: - a = x86.AJLS - - case gc.OGT<<16 | gc.TINT8, - gc.OGT<<16 | gc.TINT16, - gc.OGT<<16 | gc.TINT32, - gc.OGT<<16 | gc.TINT64: - a = x86.AJGT - - case gc.OGT<<16 | gc.TUINT8, - gc.OGT<<16 | gc.TUINT16, - gc.OGT<<16 | gc.TUINT32, - gc.OGT<<16 | gc.TUINT64, - gc.OLT<<16 | gc.TFLOAT32, - gc.OLT<<16 | gc.TFLOAT64: - a = x86.AJHI - - case gc.OGE<<16 | gc.TINT8, - gc.OGE<<16 | gc.TINT16, - gc.OGE<<16 | gc.TINT32, - gc.OGE<<16 | gc.TINT64: - a = x86.AJGE - - case gc.OGE<<16 | gc.TUINT8, - gc.OGE<<16 | gc.TUINT16, - gc.OGE<<16 | gc.TUINT32, - gc.OGE<<16 | gc.TUINT64, - gc.OLE<<16 | gc.TFLOAT32, - gc.OLE<<16 | gc.TFLOAT64: - a = x86.AJCC - - case gc.OCMP<<16 | gc.TBOOL, - gc.OCMP<<16 | gc.TINT8, - gc.OCMP<<16 | gc.TUINT8: - a = x86.ACMPB - - case gc.OCMP<<16 | gc.TINT16, - gc.OCMP<<16 | gc.TUINT16: - a = x86.ACMPW - - case gc.OCMP<<16 | gc.TINT32, - gc.OCMP<<16 | gc.TUINT32, - gc.OCMP<<16 | gc.TPTR32: - a = x86.ACMPL - - case gc.OCMP<<16 | gc.TINT64, - gc.OCMP<<16 | gc.TUINT64, - gc.OCMP<<16 | gc.TPTR64: - a = x86.ACMPQ - - case gc.OCMP<<16 | gc.TFLOAT32: - a = x86.AUCOMISS - - case gc.OCMP<<16 | gc.TFLOAT64: - a = x86.AUCOMISD - - case gc.OAS<<16 | gc.TBOOL, - gc.OAS<<16 | gc.TINT8, - gc.OAS<<16 | gc.TUINT8: - a = x86.AMOVB - - case gc.OAS<<16 | gc.TINT16, - gc.OAS<<16 | gc.TUINT16: - a = x86.AMOVW - - case gc.OAS<<16 | gc.TINT32, - gc.OAS<<16 | gc.TUINT32, - gc.OAS<<16 | gc.TPTR32: - a = x86.AMOVL - - case gc.OAS<<16 | gc.TINT64, - gc.OAS<<16 | gc.TUINT64, - gc.OAS<<16 | gc.TPTR64: - a = x86.AMOVQ - - case gc.OAS<<16 | gc.TFLOAT32: - a = x86.AMOVSS - - case gc.OAS<<16 | gc.TFLOAT64: - a = x86.AMOVSD - - case gc.OADD<<16 | gc.TINT8, - gc.OADD<<16 | gc.TUINT8: - a = x86.AADDB - - case gc.OADD<<16 | gc.TINT16, - gc.OADD<<16 | gc.TUINT16: - a = x86.AADDW - - case gc.OADD<<16 | gc.TINT32, - gc.OADD<<16 | gc.TUINT32, - gc.OADD<<16 | gc.TPTR32: - a = x86.AADDL - - case gc.OADD<<16 | gc.TINT64, - gc.OADD<<16 | gc.TUINT64, - gc.OADD<<16 | gc.TPTR64: - a = x86.AADDQ - - case gc.OADD<<16 | gc.TFLOAT32: - a = x86.AADDSS - - case gc.OADD<<16 | gc.TFLOAT64: - a = x86.AADDSD - - case gc.OSUB<<16 | gc.TINT8, - gc.OSUB<<16 | gc.TUINT8: - a = x86.ASUBB - - case gc.OSUB<<16 | gc.TINT16, - gc.OSUB<<16 | gc.TUINT16: - a = x86.ASUBW - - case gc.OSUB<<16 | gc.TINT32, - gc.OSUB<<16 | gc.TUINT32, - gc.OSUB<<16 | gc.TPTR32: - a = x86.ASUBL - - case gc.OSUB<<16 | gc.TINT64, - gc.OSUB<<16 | gc.TUINT64, - gc.OSUB<<16 | gc.TPTR64: - a = x86.ASUBQ - - case gc.OSUB<<16 | gc.TFLOAT32: - a = x86.ASUBSS - - case gc.OSUB<<16 | gc.TFLOAT64: - a = x86.ASUBSD - - case gc.OINC<<16 | gc.TINT8, - gc.OINC<<16 | gc.TUINT8: - a = x86.AINCB - - case gc.OINC<<16 | gc.TINT16, - gc.OINC<<16 | gc.TUINT16: - a = x86.AINCW - - case gc.OINC<<16 | gc.TINT32, - gc.OINC<<16 | gc.TUINT32, - gc.OINC<<16 | gc.TPTR32: - a = x86.AINCL - - case gc.OINC<<16 | gc.TINT64, - gc.OINC<<16 | gc.TUINT64, - gc.OINC<<16 | gc.TPTR64: - a = x86.AINCQ - - case gc.ODEC<<16 | gc.TINT8, - gc.ODEC<<16 | gc.TUINT8: - a = x86.ADECB - - case gc.ODEC<<16 | gc.TINT16, - gc.ODEC<<16 | gc.TUINT16: - a = x86.ADECW - - case gc.ODEC<<16 | gc.TINT32, - gc.ODEC<<16 | gc.TUINT32, - gc.ODEC<<16 | gc.TPTR32: - a = x86.ADECL - - case gc.ODEC<<16 | gc.TINT64, - gc.ODEC<<16 | gc.TUINT64, - gc.ODEC<<16 | gc.TPTR64: - a = x86.ADECQ - - case gc.OMINUS<<16 | gc.TINT8, - gc.OMINUS<<16 | gc.TUINT8: - a = x86.ANEGB - - case gc.OMINUS<<16 | gc.TINT16, - gc.OMINUS<<16 | gc.TUINT16: - a = x86.ANEGW - - case gc.OMINUS<<16 | gc.TINT32, - gc.OMINUS<<16 | gc.TUINT32, - gc.OMINUS<<16 | gc.TPTR32: - a = x86.ANEGL - - case gc.OMINUS<<16 | gc.TINT64, - gc.OMINUS<<16 | gc.TUINT64, - gc.OMINUS<<16 | gc.TPTR64: - a = x86.ANEGQ - - case gc.OAND<<16 | gc.TINT8, - gc.OAND<<16 | gc.TUINT8: - a = x86.AANDB - - case gc.OAND<<16 | gc.TINT16, - gc.OAND<<16 | gc.TUINT16: - a = x86.AANDW - - case gc.OAND<<16 | gc.TINT32, - gc.OAND<<16 | gc.TUINT32, - gc.OAND<<16 | gc.TPTR32: - a = x86.AANDL - - case gc.OAND<<16 | gc.TINT64, - gc.OAND<<16 | gc.TUINT64, - gc.OAND<<16 | gc.TPTR64: - a = x86.AANDQ - - case gc.OOR<<16 | gc.TINT8, - gc.OOR<<16 | gc.TUINT8: - a = x86.AORB - - case gc.OOR<<16 | gc.TINT16, - gc.OOR<<16 | gc.TUINT16: - a = x86.AORW - - case gc.OOR<<16 | gc.TINT32, - gc.OOR<<16 | gc.TUINT32, - gc.OOR<<16 | gc.TPTR32: - a = x86.AORL - - case gc.OOR<<16 | gc.TINT64, - gc.OOR<<16 | gc.TUINT64, - gc.OOR<<16 | gc.TPTR64: - a = x86.AORQ - - case gc.OXOR<<16 | gc.TINT8, - gc.OXOR<<16 | gc.TUINT8: - a = x86.AXORB - - case gc.OXOR<<16 | gc.TINT16, - gc.OXOR<<16 | gc.TUINT16: - a = x86.AXORW - - case gc.OXOR<<16 | gc.TINT32, - gc.OXOR<<16 | gc.TUINT32, - gc.OXOR<<16 | gc.TPTR32: - a = x86.AXORL - - case gc.OXOR<<16 | gc.TINT64, - gc.OXOR<<16 | gc.TUINT64, - gc.OXOR<<16 | gc.TPTR64: - a = x86.AXORQ - - case gc.OLROT<<16 | gc.TINT8, - gc.OLROT<<16 | gc.TUINT8: - a = x86.AROLB - - case gc.OLROT<<16 | gc.TINT16, - gc.OLROT<<16 | gc.TUINT16: - a = x86.AROLW - - case gc.OLROT<<16 | gc.TINT32, - gc.OLROT<<16 | gc.TUINT32, - gc.OLROT<<16 | gc.TPTR32: - a = x86.AROLL - - case gc.OLROT<<16 | gc.TINT64, - gc.OLROT<<16 | gc.TUINT64, - gc.OLROT<<16 | gc.TPTR64: - a = x86.AROLQ - - case gc.OLSH<<16 | gc.TINT8, - gc.OLSH<<16 | gc.TUINT8: - a = x86.ASHLB - - case gc.OLSH<<16 | gc.TINT16, - gc.OLSH<<16 | gc.TUINT16: - a = x86.ASHLW - - case gc.OLSH<<16 | gc.TINT32, - gc.OLSH<<16 | gc.TUINT32, - gc.OLSH<<16 | gc.TPTR32: - a = x86.ASHLL - - case gc.OLSH<<16 | gc.TINT64, - gc.OLSH<<16 | gc.TUINT64, - gc.OLSH<<16 | gc.TPTR64: - a = x86.ASHLQ - - case gc.ORSH<<16 | gc.TUINT8: - a = x86.ASHRB - - case gc.ORSH<<16 | gc.TUINT16: - a = x86.ASHRW - - case gc.ORSH<<16 | gc.TUINT32, - gc.ORSH<<16 | gc.TPTR32: - a = x86.ASHRL - - case gc.ORSH<<16 | gc.TUINT64, - gc.ORSH<<16 | gc.TPTR64: - a = x86.ASHRQ - - case gc.ORSH<<16 | gc.TINT8: - a = x86.ASARB - - case gc.ORSH<<16 | gc.TINT16: - a = x86.ASARW - - case gc.ORSH<<16 | gc.TINT32: - a = x86.ASARL - - case gc.ORSH<<16 | gc.TINT64: - a = x86.ASARQ - - case gc.ORROTC<<16 | gc.TINT8, - gc.ORROTC<<16 | gc.TUINT8: - a = x86.ARCRB - - case gc.ORROTC<<16 | gc.TINT16, - gc.ORROTC<<16 | gc.TUINT16: - a = x86.ARCRW - - case gc.ORROTC<<16 | gc.TINT32, - gc.ORROTC<<16 | gc.TUINT32: - a = x86.ARCRL - - case gc.ORROTC<<16 | gc.TINT64, - gc.ORROTC<<16 | gc.TUINT64: - a = x86.ARCRQ - - case gc.OHMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TUINT8: - a = x86.AIMULB - - case gc.OHMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TUINT16: - a = x86.AIMULW - - case gc.OHMUL<<16 | gc.TINT32, - gc.OMUL<<16 | gc.TINT32, - gc.OMUL<<16 | gc.TUINT32, - gc.OMUL<<16 | gc.TPTR32: - a = x86.AIMULL - - case gc.OHMUL<<16 | gc.TINT64, - gc.OMUL<<16 | gc.TINT64, - gc.OMUL<<16 | gc.TUINT64, - gc.OMUL<<16 | gc.TPTR64: - a = x86.AIMULQ - - case gc.OHMUL<<16 | gc.TUINT8: - a = x86.AMULB - - case gc.OHMUL<<16 | gc.TUINT16: - a = x86.AMULW - - case gc.OHMUL<<16 | gc.TUINT32, - gc.OHMUL<<16 | gc.TPTR32: - a = x86.AMULL - - case gc.OHMUL<<16 | gc.TUINT64, - gc.OHMUL<<16 | gc.TPTR64: - a = x86.AMULQ - - case gc.OMUL<<16 | gc.TFLOAT32: - a = x86.AMULSS - - case gc.OMUL<<16 | gc.TFLOAT64: - a = x86.AMULSD - - case gc.ODIV<<16 | gc.TINT8, - gc.OMOD<<16 | gc.TINT8: - a = x86.AIDIVB - - case gc.ODIV<<16 | gc.TUINT8, - gc.OMOD<<16 | gc.TUINT8: - a = x86.ADIVB - - case gc.ODIV<<16 | gc.TINT16, - gc.OMOD<<16 | gc.TINT16: - a = x86.AIDIVW - - case gc.ODIV<<16 | gc.TUINT16, - gc.OMOD<<16 | gc.TUINT16: - a = x86.ADIVW - - case gc.ODIV<<16 | gc.TINT32, - gc.OMOD<<16 | gc.TINT32: - a = x86.AIDIVL - - case gc.ODIV<<16 | gc.TUINT32, - gc.ODIV<<16 | gc.TPTR32, - gc.OMOD<<16 | gc.TUINT32, - gc.OMOD<<16 | gc.TPTR32: - a = x86.ADIVL - - case gc.ODIV<<16 | gc.TINT64, - gc.OMOD<<16 | gc.TINT64: - a = x86.AIDIVQ - - case gc.ODIV<<16 | gc.TUINT64, - gc.ODIV<<16 | gc.TPTR64, - gc.OMOD<<16 | gc.TUINT64, - gc.OMOD<<16 | gc.TPTR64: - a = x86.ADIVQ - - case gc.OEXTEND<<16 | gc.TINT16: - a = x86.ACWD - - case gc.OEXTEND<<16 | gc.TINT32: - a = x86.ACDQ - - case gc.OEXTEND<<16 | gc.TINT64: - a = x86.ACQO - - case gc.ODIV<<16 | gc.TFLOAT32: - a = x86.ADIVSS - - case gc.ODIV<<16 | gc.TFLOAT64: - a = x86.ADIVSD - } - - return a -} - -const ( - ODynam = 1 << 0 - OAddable = 1 << 1 -) - -var clean [20]gc.Node - -var cleani int = 0 - -func xgen(n *gc.Node, a *gc.Node, o int) bool { - regalloc(a, gc.Types[gc.Tptr], nil) - - if o&ODynam != 0 { - if n.Addable != 0 { - if n.Op != gc.OINDREG { - if n.Op != gc.OREGISTER { - return true - } - } - } - } - - agen(n, a) - return false -} - -func sudoclean() { - if clean[cleani-1].Op != gc.OEMPTY { - regfree(&clean[cleani-1]) - } - if clean[cleani-2].Op != gc.OEMPTY { - regfree(&clean[cleani-2]) - } - cleani -= 2 -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { - var o int - var i int - var oary [10]int64 - var v int64 - var w int64 - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var nn *gc.Node - var l *gc.Node - var r *gc.Node - var reg *gc.Node - var reg1 *gc.Node - var p1 *obj.Prog - var t *gc.Type - - if n.Type == nil { - return false - } - - *a = obj.Addr{} - - switch n.Op { - case gc.OLITERAL: - if !gc.Isconst(n, gc.CTINT) { - break - } - v = gc.Mpgetfix(n.Val.U.Xval) - if v >= 32000 || v <= -32000 { - break - } - goto lit - - case gc.ODOT, - gc.ODOTPTR: - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - goto odot - - case gc.OINDEX: - return false - - // disabled: OINDEX case is now covered by agenr - // for a more suitable register allocation pattern. - if n.Left.Type.Etype == gc.TSTRING { - return false - } - goto oindex - } - - return false - -lit: - switch as { - default: - return false - - case x86.AADDB, - x86.AADDW, - x86.AADDL, - x86.AADDQ, - x86.ASUBB, - x86.ASUBW, - x86.ASUBL, - x86.ASUBQ, - x86.AANDB, - x86.AANDW, - x86.AANDL, - x86.AANDQ, - x86.AORB, - x86.AORW, - x86.AORL, - x86.AORQ, - x86.AXORB, - x86.AXORW, - x86.AXORL, - x86.AXORQ, - x86.AINCB, - x86.AINCW, - x86.AINCL, - x86.AINCQ, - x86.ADECB, - x86.ADECW, - x86.ADECL, - x86.ADECQ, - x86.AMOVB, - x86.AMOVW, - x86.AMOVL, - x86.AMOVQ: - break - } - - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - gc.Naddr(n, a, 1) - goto yes - -odot: - o = gc.Dotoffset(n, oary[:], &nn) - if nn == nil { - goto no - } - - if nn.Addable != 0 && o == 1 && oary[0] >= 0 { - // directly addressable set of DOTs - n1 = *nn - - n1.Type = n.Type - n1.Xoffset += oary[0] - gc.Naddr(&n1, a, 1) - goto yes - } - - regalloc(reg, gc.Types[gc.Tptr], nil) - n1 = *reg - n1.Op = gc.OINDREG - if oary[0] >= 0 { - agen(nn, reg) - n1.Xoffset = oary[0] - } else { - cgen(nn, reg) - gc.Cgen_checknil(reg) - n1.Xoffset = -(oary[0] + 1) - } - - for i = 1; i < o; i++ { - if oary[i] >= 0 { - gc.Fatal("can't happen") - } - gins(movptr, &n1, reg) - gc.Cgen_checknil(reg) - n1.Xoffset = -(oary[i] + 1) - } - - a.Type = obj.TYPE_NONE - a.Index = obj.TYPE_NONE - fixlargeoffset(&n1) - gc.Naddr(&n1, a, 1) - goto yes - -oindex: - l = n.Left - r = n.Right - if l.Ullman >= gc.UINF && r.Ullman >= gc.UINF { - return false - } - - // set o to type of array - o = 0 - - if gc.Isptr[l.Type.Etype] != 0 { - gc.Fatal("ptr ary") - } - if l.Type.Etype != gc.TARRAY { - gc.Fatal("not ary") - } - if l.Type.Bound < 0 { - o |= ODynam - } - - w = n.Type.Width - if gc.Isconst(r, gc.CTINT) { - goto oindex_const - } - - switch w { - default: - return false - - case 1, - 2, - 4, - 8: - break - } - - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - - // load the array (reg) - if l.Ullman > r.Ullman { - if xgen(l, reg, o) { - o |= OAddable - } - } - - // load the index (reg1) - t = gc.Types[gc.TUINT64] - - if gc.Issigned[r.Type.Etype] != 0 { - t = gc.Types[gc.TINT64] - } - regalloc(reg1, t, nil) - regalloc(&n3, r.Type, reg1) - cgen(r, &n3) - gmove(&n3, reg1) - regfree(&n3) - - // load the array (reg) - if l.Ullman <= r.Ullman { - if xgen(l, reg, o) { - o |= OAddable - } - } - - // check bounds - if gc.Debug['B'] == 0 && !n.Bounded { - // check bounds - n4.Op = gc.OXXX - - t = gc.Types[gc.Simtype[gc.TUINT]] - if o&ODynam != 0 { - if o&OAddable != 0 { - n2 = *l - n2.Xoffset += int64(gc.Array_nel) - n2.Type = gc.Types[gc.Simtype[gc.TUINT]] - } else { - n2 = *reg - n2.Xoffset = int64(gc.Array_nel) - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.Simtype[gc.TUINT]] - } - } else { - if gc.Is64(r.Type) { - t = gc.Types[gc.TUINT64] - } - gc.Nodconst(&n2, gc.Types[gc.TUINT64], l.Type.Bound) - } - - gins(optoas(gc.OCMP, t), reg1, &n2) - p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) - if n4.Op != gc.OXXX { - regfree(&n4) - } - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - - if o&ODynam != 0 { - if o&OAddable != 0 { - n2 = *l - n2.Xoffset += int64(gc.Array_array) - n2.Type = gc.Types[gc.Tptr] - gmove(&n2, reg) - } else { - n2 = *reg - n2.Op = gc.OINDREG - n2.Xoffset = int64(gc.Array_array) - n2.Type = gc.Types[gc.Tptr] - gmove(&n2, reg) - } - } - - if o&OAddable != 0 { - gc.Naddr(reg1, a, 1) - a.Offset = 0 - a.Scale = int8(w) - a.Index = a.Reg - a.Type = obj.TYPE_MEM - a.Reg = reg.Val.U.Reg - } else { - gc.Naddr(reg1, a, 1) - a.Offset = 0 - a.Scale = int8(w) - a.Index = a.Reg - a.Type = obj.TYPE_MEM - a.Reg = reg.Val.U.Reg - } - - goto yes - - // index is constant - // can check statically and - // can multiply by width statically - -oindex_const: - v = gc.Mpgetfix(r.Val.U.Xval) - - if sudoaddable(as, l, a) { - goto oindex_const_sudo - } - - cleani += 2 - reg = &clean[cleani-1] - reg1 = &clean[cleani-2] - reg.Op = gc.OEMPTY - reg1.Op = gc.OEMPTY - - if o&ODynam != 0 { - regalloc(reg, gc.Types[gc.Tptr], nil) - agen(l, reg) - - if gc.Debug['B'] == 0 && !n.Bounded { - n1 = *reg - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - gc.Nodconst(&n2, gc.Types[gc.TUINT64], v) - gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - - n1 = *reg - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, reg) - - n2 = *reg - n2.Op = gc.OINDREG - n2.Xoffset = v * w - fixlargeoffset(&n2) - a.Type = obj.TYPE_NONE - a.Index = obj.TYPE_NONE - gc.Naddr(&n2, a, 1) - goto yes - } - - igen(l, &n1, nil) - if n1.Op == gc.OINDREG { - *reg = n1 - reg.Op = gc.OREGISTER - } - - n1.Xoffset += v * w - fixlargeoffset(&n1) - a.Type = obj.TYPE_NONE - a.Index = obj.TYPE_NONE - gc.Naddr(&n1, a, 1) - goto yes - -oindex_const_sudo: - if o&ODynam == 0 { - // array indexed by a constant - a.Offset += v * w - - goto yes - } - - // slice indexed by a constant - if gc.Debug['B'] == 0 && !n.Bounded { - a.Offset += int64(gc.Array_nel) - gc.Nodconst(&n2, gc.Types[gc.TUINT64], v) - p1 = gins(optoas(gc.OCMP, gc.Types[gc.Simtype[gc.TUINT]]), nil, &n2) - p1.From = *a - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.Simtype[gc.TUINT]]), nil, +1) - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - a.Offset -= int64(gc.Array_nel) - } - - a.Offset += int64(gc.Array_array) - reg = &clean[cleani-1] - if reg.Op == gc.OEMPTY { - regalloc(reg, gc.Types[gc.Tptr], nil) - } - - p1 = gins(movptr, nil, reg) - p1.From = *a - - n2 = *reg - n2.Op = gc.OINDREG - n2.Xoffset = v * w - fixlargeoffset(&n2) - a.Type = obj.TYPE_NONE - a.Index = obj.TYPE_NONE - gc.Naddr(&n2, a, 1) - goto yes - -yes: - return true - -no: - sudoclean() - return false -} diff --git a/src/cmd/new6g/peep.go b/src/cmd/new6g/peep.go deleted file mode 100644 index 9870ca5e4e..0000000000 --- a/src/cmd/new6g/peep.go +++ /dev/null @@ -1,1077 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" - "fmt" -) -import "cmd/internal/gc" - -var gactive uint32 - -const ( - exregoffset = x86.REG_R15 -) - -// do we need the carry bit -func needc(p *obj.Prog) bool { - var info gc.ProgInfo - - for p != nil { - proginfo(&info, p) - if info.Flags&gc.UseCarry != 0 { - return true - } - if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 { - return false - } - p = p.Link - } - - return false -} - -func rnops(r *gc.Flow) *gc.Flow { - var p *obj.Prog - var r1 *gc.Flow - - if r != nil { - for { - p = r.Prog - if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE { - break - } - r1 = gc.Uniqs(r) - if r1 == nil { - break - } - r = r1 - } - } - - return r -} - -func peep(firstp *obj.Prog) { - var r *gc.Flow - var r1 *gc.Flow - var g *gc.Graph - var p *obj.Prog - var p1 *obj.Prog - var t int - - g = gc.Flowstart(firstp, nil) - if g == nil { - return - } - gactive = 0 - - // byte, word arithmetic elimination. - elimshortmov(g) - - // constant propagation - // find MOV $con,R followed by - // another MOV $con,R without - // setting R in the interim - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case x86.ALEAL, - x86.ALEAQ: - if regtyp(&p.To) { - if p.From.Sym != nil { - if p.From.Index == x86.REG_NONE { - conprop(r) - } - } - } - - case x86.AMOVB, - x86.AMOVW, - x86.AMOVL, - x86.AMOVQ, - x86.AMOVSS, - x86.AMOVSD: - if regtyp(&p.To) { - if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST { - conprop(r) - } - } - } - } - -loop1: - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - gc.Dumpit("loop1", g.Start, 0) - } - - t = 0 - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case x86.AMOVL, - x86.AMOVQ, - x86.AMOVSS, - x86.AMOVSD: - if regtyp(&p.To) { - if regtyp(&p.From) { - if copyprop(g, r) { - excise(r) - t++ - } else if subprop(r) && copyprop(g, r) { - excise(r) - t++ - } - } - } - - case x86.AMOVBLZX, - x86.AMOVWLZX, - x86.AMOVBLSX, - x86.AMOVWLSX: - if regtyp(&p.To) { - r1 = rnops(gc.Uniqs(r)) - if r1 != nil { - p1 = r1.Prog - if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { - p1.As = x86.AMOVL - t++ - } - } - } - - case x86.AMOVBQSX, - x86.AMOVBQZX, - x86.AMOVWQSX, - x86.AMOVWQZX, - x86.AMOVLQSX, - x86.AMOVLQZX, - x86.AMOVQL: - if regtyp(&p.To) { - r1 = rnops(gc.Uniqs(r)) - if r1 != nil { - p1 = r1.Prog - if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { - p1.As = x86.AMOVQ - t++ - } - } - } - - case x86.AADDL, - x86.AADDQ, - x86.AADDW: - if p.From.Type != obj.TYPE_CONST || needc(p.Link) { - break - } - if p.From.Offset == -1 { - if p.As == x86.AADDQ { - p.As = x86.ADECQ - } else if p.As == x86.AADDL { - p.As = x86.ADECL - } else { - p.As = x86.ADECW - } - p.From = obj.Addr{} - break - } - - if p.From.Offset == 1 { - if p.As == x86.AADDQ { - p.As = x86.AINCQ - } else if p.As == x86.AADDL { - p.As = x86.AINCL - } else { - p.As = x86.AINCW - } - p.From = obj.Addr{} - break - } - - case x86.ASUBL, - x86.ASUBQ, - x86.ASUBW: - if p.From.Type != obj.TYPE_CONST || needc(p.Link) { - break - } - if p.From.Offset == -1 { - if p.As == x86.ASUBQ { - p.As = x86.AINCQ - } else if p.As == x86.ASUBL { - p.As = x86.AINCL - } else { - p.As = x86.AINCW - } - p.From = obj.Addr{} - break - } - - if p.From.Offset == 1 { - if p.As == x86.ASUBQ { - p.As = x86.ADECQ - } else if p.As == x86.ASUBL { - p.As = x86.ADECL - } else { - p.As = x86.ADECW - } - p.From = obj.Addr{} - break - } - } - } - - if t != 0 { - goto loop1 - } - - // MOVLQZX removal. - // The MOVLQZX exists to avoid being confused for a - // MOVL that is just copying 32-bit data around during - // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 - // if it is dominated by an earlier ADDL/MOVL/etc into R1 that - // will have already cleared the high bits. - // - // MOVSD removal. - // We never use packed registers, so a MOVSD between registers - // can be replaced by MOVAPD, which moves the pair of float64s - // instead of just the lower one. We only use the lower one, but - // the processor can do better if we do moves using both. - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - if p.As == x86.AMOVLQZX { - if regtyp(&p.From) { - if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg { - if prevl(r, int(p.From.Reg)) { - excise(r) - } - } - } - } - - if p.As == x86.AMOVSD { - if regtyp(&p.From) { - if regtyp(&p.To) { - p.As = x86.AMOVAPD - } - } - } - } - - // load pipelining - // push any load from memory as early as possible - // to give it time to complete before use. - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case x86.AMOVB, - x86.AMOVW, - x86.AMOVL, - x86.AMOVQ, - x86.AMOVLQZX: - if regtyp(&p.To) && !regconsttyp(&p.From) { - pushback(r) - } - } - } - - gc.Flowend(g) -} - -func pushback(r0 *gc.Flow) { - var r *gc.Flow - var b *gc.Flow - var p0 *obj.Prog - var p *obj.Prog - var t obj.Prog - - b = nil - p0 = r0.Prog - for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) { - p = r.Prog - if p.As != obj.ANOP { - if !regconsttyp(&p.From) || !regtyp(&p.To) { - break - } - if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 { - break - } - } - - if p.As == obj.ACALL { - break - } - b = r - } - - if b == nil { - if gc.Debug['v'] != 0 { - fmt.Printf("no pushback: %v\n", r0.Prog) - if r != nil { - fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil) - } - } - - return - } - - if gc.Debug['v'] != 0 { - fmt.Printf("pushback\n") - for r = b; ; r = r.Link { - fmt.Printf("\t%v\n", r.Prog) - if r == r0 { - break - } - } - } - - t = *r0.Prog - for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) { - p0 = r.Link.Prog - p = r.Prog - p0.As = p.As - p0.Lineno = p.Lineno - p0.From = p.From - p0.To = p.To - - if r == b { - break - } - } - - p0 = r.Prog - p0.As = t.As - p0.Lineno = t.Lineno - p0.From = t.From - p0.To = t.To - - if gc.Debug['v'] != 0 { - fmt.Printf("\tafter\n") - for r = b; ; r = r.Link { - fmt.Printf("\t%v\n", r.Prog) - if r == r0 { - break - } - } - } -} - -func excise(r *gc.Flow) { - var p *obj.Prog - - p = r.Prog - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("%v ===delete===\n", p) - } - - obj.Nopout(p) - - gc.Ostats.Ndelmov++ -} - -func regtyp(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_R15 || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X15) -} - -// movb elimination. -// movb is simulated by the linker -// when a register other than ax, bx, cx, dx -// is used, so rewrite to other instructions -// when possible. a movb into a register -// can smash the entire 32-bit register without -// causing any trouble. -// -// TODO: Using the Q forms here instead of the L forms -// seems unnecessary, and it makes the instructions longer. -func elimshortmov(g *gc.Graph) { - var p *obj.Prog - var r *gc.Flow - - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - if regtyp(&p.To) { - switch p.As { - case x86.AINCB, - x86.AINCW: - p.As = x86.AINCQ - - case x86.ADECB, - x86.ADECW: - p.As = x86.ADECQ - - case x86.ANEGB, - x86.ANEGW: - p.As = x86.ANEGQ - - case x86.ANOTB, - x86.ANOTW: - p.As = x86.ANOTQ - } - - if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST { - // move or artihmetic into partial register. - // from another register or constant can be movl. - // we don't switch to 64-bit arithmetic if it can - // change how the carry bit is set (and the carry bit is needed). - switch p.As { - case x86.AMOVB, - x86.AMOVW: - p.As = x86.AMOVQ - - case x86.AADDB, - x86.AADDW: - if !needc(p.Link) { - p.As = x86.AADDQ - } - - case x86.ASUBB, - x86.ASUBW: - if !needc(p.Link) { - p.As = x86.ASUBQ - } - - case x86.AMULB, - x86.AMULW: - p.As = x86.AMULQ - - case x86.AIMULB, - x86.AIMULW: - p.As = x86.AIMULQ - - case x86.AANDB, - x86.AANDW: - p.As = x86.AANDQ - - case x86.AORB, - x86.AORW: - p.As = x86.AORQ - - case x86.AXORB, - x86.AXORW: - p.As = x86.AXORQ - - case x86.ASHLB, - x86.ASHLW: - p.As = x86.ASHLQ - } - } else if p.From.Type != obj.TYPE_REG { - // explicit zero extension, but don't - // do that if source is a byte register - // (only AH can occur and it's forbidden). - switch p.As { - case x86.AMOVB: - p.As = x86.AMOVBQZX - - case x86.AMOVW: - p.As = x86.AMOVWQZX - } - } - } - } -} - -// is 'a' a register or constant? -func regconsttyp(a *obj.Addr) bool { - if regtyp(a) { - return true - } - switch a.Type { - case obj.TYPE_CONST, - obj.TYPE_FCONST, - obj.TYPE_SCONST, - obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants. - return true - } - - return false -} - -// is reg guaranteed to be truncated by a previous L instruction? -func prevl(r0 *gc.Flow, reg int) bool { - var p *obj.Prog - var r *gc.Flow - var info gc.ProgInfo - - for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { - p = r.Prog - if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg { - proginfo(&info, p) - if info.Flags&gc.RightWrite != 0 { - if info.Flags&gc.SizeL != 0 { - return true - } - return false - } - } - } - - return false -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -func subprop(r0 *gc.Flow) bool { - var p *obj.Prog - var info gc.ProgInfo - var v1 *obj.Addr - var v2 *obj.Addr - var r *gc.Flow - var t int - - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("subprop %v\n", r0.Prog) - } - p = r0.Prog - v1 = &p.From - if !regtyp(v1) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1)) - } - return false - } - - v2 = &p.To - if !regtyp(v2) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2)) - } - return false - } - - for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\t? %v\n", r.Prog) - } - if gc.Uniqs(r) == nil { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tno unique successor\n") - } - break - } - - p = r.Prog - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - continue - } - proginfo(&info, p) - if info.Flags&gc.Call != 0 { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tfound %v; return 0\n", p) - } - return false - } - - if info.Reguse|info.Regset != 0 { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tfound %v; return 0\n", p) - } - return false - } - - if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg { - goto gotit - } - - if copyau(&p.From, v2) || copyau(&p.To, v2) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2)) - } - break - } - - if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tcopysub failed\n") - } - break - } - } - - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tran off end; return 0\n") - } - return false - -gotit: - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) - if p.From.Type == v2.Type && p.From.Reg == v2.Reg { - fmt.Printf(" excise") - } - fmt.Printf("\n") - } - - for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { - p = r.Prog - copysub(&p.From, v1, v2, 1) - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("%v\n", r.Prog) - } - } - - t = int(v1.Reg) - v1.Reg = v2.Reg - v2.Reg = int16(t) - if gc.Debug['P'] != 0 { - fmt.Printf("%v last\n", r.Prog) - } - return true -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -func copyprop(g *gc.Graph, r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("copyprop %v\n", r0.Prog) - } - p = r0.Prog - v1 = &p.From - v2 = &p.To - if copyas(v1, v2) { - return true - } - gactive++ - return copy1(v1, v2, r0.S1, 0) -} - -func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { - var t int - var p *obj.Prog - - if uint32(r.Active) == gactive { - if gc.Debug['P'] != 0 { - fmt.Printf("act set; return 1\n") - } - return true - } - - r.Active = int32(gactive) - if gc.Debug['P'] != 0 { - fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) - } - for ; r != nil; r = r.S1 { - p = r.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("%v", p) - } - if f == 0 && gc.Uniqp(r) == nil { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; merge; f=%d", f) - } - } - - t = copyu(p, v2, nil) - switch t { - case 2: /* rar, can't split */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) - } - return false - - case 3: /* set */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - - case 1, /* used, substitute */ - 4: /* use and set */ - if f != 0 { - if gc.Debug['P'] == 0 { - return false - } - if t == 4 { - fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } else { - fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } - return false - } - - if copyu(p, v2, v1) != 0 { - if gc.Debug['P'] != 0 { - fmt.Printf("; sub fail; return 0\n") - } - return false - } - - if gc.Debug['P'] != 0 { - fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) - } - if t == 4 { - if gc.Debug['P'] != 0 { - fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - } - } - - if f == 0 { - t = copyu(p, v1, nil) - if f == 0 && (t == 2 || t == 3 || t == 4) { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) - } - } - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\n") - } - if r.S2 != nil { - if !copy1(v1, v2, r.S2, f) { - return false - } - } - } - - return true -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { - var info gc.ProgInfo - - switch p.As { - case obj.AJMP: - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 1 - } - return 0 - - case obj.ARET: - if s != nil { - return 1 - } - return 3 - - case obj.ACALL: - if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset { - return 2 - } - if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { - return 2 - } - if v.Type == p.From.Type && v.Reg == p.From.Reg { - return 2 - } - - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 4 - } - return 3 - - case obj.ATEXT: - if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG { - return 3 - } - return 0 - } - - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - return 0 - } - proginfo(&info, p) - - if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 { - return 2 - } - - if info.Flags&gc.LeftAddr != 0 { - if copyas(&p.From, v) { - return 2 - } - } - - if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite { - if copyas(&p.To, v) { - return 2 - } - } - - if info.Flags&gc.RightWrite != 0 { - if copyas(&p.To, v) { - if s != nil { - return copysub(&p.From, v, s, 1) - } - if copyau(&p.From, v) { - return 4 - } - return 3 - } - } - - if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 { - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - return copysub(&p.To, v, s, 1) - } - - if copyau(&p.From, v) { - return 1 - } - if copyau(&p.To, v) { - return 1 - } - } - - return 0 -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -func copyas(a *obj.Addr, v *obj.Addr) bool { - if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B { - gc.Fatal("use of byte register") - } - if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B { - gc.Fatal("use of byte register") - } - - if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { - return false - } - if regtyp(v) { - return true - } - if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { - if v.Offset == a.Offset { - return true - } - } - return false -} - -func sameaddr(a *obj.Addr, v *obj.Addr) bool { - if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { - return false - } - if regtyp(v) { - return true - } - if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { - if v.Offset == a.Offset { - return true - } - } - return false -} - -/* - * either direct or indirect - */ -func copyau(a *obj.Addr, v *obj.Addr) bool { - if copyas(a, v) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tcopyau: copyas returned 1\n") - } - return true - } - - if regtyp(v) { - if a.Type == obj.TYPE_MEM && a.Reg == v.Reg { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tcopyau: found indir use - return 1\n") - } - return true - } - - if a.Index == v.Reg { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\tcopyau: found index use - return 1\n") - } - return true - } - } - - return false -} - -/* - * substitute s for v in a - * return failure to substitute - */ -func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { - var reg int - - if copyas(a, v) { - reg = int(s.Reg) - if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 { - if f != 0 { - a.Reg = int16(reg) - } - } - - return 0 - } - - if regtyp(v) { - reg = int(v.Reg) - if a.Type == obj.TYPE_MEM && int(a.Reg) == reg { - if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE { - return 1 /* can't use BP-base with index */ - } - if f != 0 { - a.Reg = s.Reg - } - } - - // return 0; - if int(a.Index) == reg { - if f != 0 { - a.Index = s.Reg - } - return 0 - } - - return 0 - } - - return 0 -} - -func conprop(r0 *gc.Flow) { - var r *gc.Flow - var p *obj.Prog - var p0 *obj.Prog - var t int - var v0 *obj.Addr - - p0 = r0.Prog - v0 = &p0.To - r = r0 - -loop: - r = gc.Uniqs(r) - if r == nil || r == r0 { - return - } - if gc.Uniqp(r) == nil { - return - } - - p = r.Prog - t = copyu(p, v0, nil) - switch t { - case 0, // miss - 1: // use - goto loop - - case 2, // rar - 4: // use and set - break - - case 3: // set - if p.As == p0.As { - if p.From.Type == p0.From.Type { - if p.From.Reg == p0.From.Reg { - if p.From.Node == p0.From.Node { - if p.From.Offset == p0.From.Offset { - if p.From.Scale == p0.From.Scale { - if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval { - if p.From.Index == p0.From.Index { - excise(r) - goto loop - } - } - } - } - } - } - } - } - } -} - -func smallindir(a *obj.Addr, reg *obj.Addr) bool { - return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096 -} - -func stackaddr(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP -} diff --git a/src/cmd/new6g/prog.go b/src/cmd/new6g/prog.go deleted file mode 100644 index 3f4c19567c..0000000000 --- a/src/cmd/new6g/prog.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" -) -import "cmd/internal/gc" - -var ( - AX = RtoB(x86.REG_AX) - BX = RtoB(x86.REG_BX) - CX = RtoB(x86.REG_CX) - DX = RtoB(x86.REG_DX) - DI = RtoB(x86.REG_DI) - SI = RtoB(x86.REG_SI) - LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite - RightRdwr uint32 = gc.RightRead | gc.RightWrite -) - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -var progtable = [x86.ALAST]gc.ProgInfo{ - obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, - obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, - obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, - obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, - obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, - x86.AADCL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.AADCQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.AADCW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.AADDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AADDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AADDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AADDQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AADDSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.AADDSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.AANDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AANDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AANDQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AANDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - obj.ACALL: gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0}, - x86.ACDQ: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, - x86.ACQO: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, - x86.ACWD: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, - x86.ACLD: gc.ProgInfo{gc.OK, 0, 0, 0}, - x86.ASTD: gc.ProgInfo{gc.OK, 0, 0, 0}, - x86.ACMPB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACMPL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACMPQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACMPW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ACVTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSD2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSD2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSL2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSL2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSQ2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSQ2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSS2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTSS2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTTSD2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ACVTTSS2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.ADECB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - x86.ADECL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - x86.ADECQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, - x86.ADECW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - x86.ADIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - x86.ADIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.ADIVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.ADIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.ADIVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.ADIVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.AIDIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - x86.AIDIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.AIDIVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.AIDIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - x86.AIMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - x86.AIMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, - x86.AIMULQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, - x86.AIMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, - x86.AINCB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - x86.AINCL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - x86.AINCQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, - x86.AINCW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - x86.AJCC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJCS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJEQ: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJGE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJGT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJHI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJLE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJLS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJLT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJMI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJNE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJOC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJOS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJPC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJPL: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - x86.AJPS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - obj.AJMP: gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0}, - x86.ALEAL: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - x86.ALEAQ: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - x86.AMOVBLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVBLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVBQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVBQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVBWSX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVBWZX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVLQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVLQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVWLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVWLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVWQSX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVWQZX: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVQL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - x86.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMOVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMOVQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMOVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMOVSB: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - x86.AMOVSL: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - x86.AMOVSQ: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - x86.AMOVSW: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - obj.ADUFFCOPY: gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0}, - x86.AMOVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMOVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - - // We use MOVAPD as a faster synonym for MOVSD. - x86.AMOVAPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - x86.AMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - x86.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, - x86.AMULQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, - x86.AMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, - x86.AMULSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.AMULSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.ANEGB: gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ANEGL: gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ANEGQ: gc.ProgInfo{gc.SizeQ | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ANEGW: gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ANOTB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - x86.ANOTL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - x86.ANOTQ: gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0}, - x86.ANOTW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - x86.AORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.APOPQ: gc.ProgInfo{gc.SizeQ | gc.RightWrite, 0, 0, 0}, - x86.APUSHQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead, 0, 0, 0}, - x86.ARCLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCRQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ARCRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.AREP: gc.ProgInfo{gc.OK, CX, CX, 0}, - x86.AREPN: gc.ProgInfo{gc.OK, CX, CX, 0}, - obj.ARET: gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0}, - x86.AROLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.AROLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.AROLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.AROLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ARORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ARORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ARORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ARORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASALB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASALL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASALQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASALW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASARB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASARL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASARQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASARW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASBBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ASBBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ASBBQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ASBBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - x86.ASHLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHLQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHRQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASHRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - x86.ASTOSB: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - x86.ASTOSL: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - x86.ASTOSQ: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - x86.ASTOSW: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - x86.ASUBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ASUBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ASUBQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ASUBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.ASUBSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.ASUBSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - x86.ATESTB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ATESTL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ATESTQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.ATESTW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - x86.AUCOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, - x86.AUCOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, - x86.AXCHGB: gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0}, - x86.AXCHGL: gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0}, - x86.AXCHGQ: gc.ProgInfo{gc.SizeQ | LeftRdwr | RightRdwr, 0, 0, 0}, - x86.AXCHGW: gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0}, - x86.AXORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AXORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AXORQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - x86.AXORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, -} - -func proginfo(info *gc.ProgInfo, p *obj.Prog) { - *info = progtable[p.As] - if info.Flags == 0 { - gc.Fatal("unknown instruction %v", p) - } - - if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST { - info.Reguse |= CX - } - - if info.Flags&gc.ImulAXDX != 0 { - if p.To.Type == obj.TYPE_NONE { - info.Reguse |= AX - info.Regset |= AX | DX - } else { - info.Flags |= RightRdwr - } - } - - // Addressing makes some registers used. - if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE { - info.Regindex |= RtoB(int(p.From.Reg)) - } - if p.From.Index != x86.REG_NONE { - info.Regindex |= RtoB(int(p.From.Index)) - } - if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE { - info.Regindex |= RtoB(int(p.To.Reg)) - } - if p.To.Index != x86.REG_NONE { - info.Regindex |= RtoB(int(p.To.Index)) - } -} diff --git a/src/cmd/new6g/reg.go b/src/cmd/new6g/reg.go deleted file mode 100644 index 0629a6248d..0000000000 --- a/src/cmd/new6g/reg.go +++ /dev/null @@ -1,144 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/x86" -) -import "cmd/internal/gc" - -const ( - NREGVAR = 32 -) - -var regname = []string{ - ".AX", - ".CX", - ".DX", - ".BX", - ".SP", - ".BP", - ".SI", - ".DI", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".X0", - ".X1", - ".X2", - ".X3", - ".X4", - ".X5", - ".X6", - ".X7", - ".X8", - ".X9", - ".X10", - ".X11", - ".X12", - ".X13", - ".X14", - ".X15", -} - -func regnames(n *int) []string { - *n = NREGVAR - return regname -} - -func excludedregs() uint64 { - return RtoB(x86.REG_SP) -} - -func doregbits(r int) uint64 { - var b uint64 - - b = 0 - if r >= x86.REG_AX && r <= x86.REG_R15 { - b |= RtoB(r) - } else if r >= x86.REG_AL && r <= x86.REG_R15B { - b |= RtoB(r - x86.REG_AL + x86.REG_AX) - } else if r >= x86.REG_AH && r <= x86.REG_BH { - b |= RtoB(r - x86.REG_AH + x86.REG_AX) - } else if r >= x86.REG_X0 && r <= x86.REG_X0+15 { - b |= FtoB(r) - } - return b -} - -func RtoB(r int) uint64 { - if r < x86.REG_AX || r > x86.REG_R15 { - return 0 - } - return 1 << uint(r-x86.REG_AX) -} - -func BtoR(b uint64) int { - b &= 0xffff - if gc.Nacl { - b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX)) - } else if obj.Framepointer_enabled != 0 { - // BP is part of the calling convention if framepointer_enabled. - b &^= (1 << (x86.REG_BP - x86.REG_AX)) - } - - if b == 0 { - return 0 - } - return gc.Bitno(b) + x86.REG_AX -} - -/* - * bit reg - * 16 X0 - * ... - * 31 X15 - */ -func FtoB(f int) uint64 { - if f < x86.REG_X0 || f > x86.REG_X15 { - return 0 - } - return 1 << uint(f-x86.REG_X0+16) -} - -func BtoF(b uint64) int { - b &= 0xFFFF0000 - if b == 0 { - return 0 - } - return gc.Bitno(b) - 16 + x86.REG_X0 -} diff --git a/src/cmd/new6g/util.go b/src/cmd/new6g/util.go deleted file mode 100644 index bb5eedb15a..0000000000 --- a/src/cmd/new6g/util.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func bool2int(b bool) int { - if b { - return 1 - } - return 0 -} diff --git a/src/cmd/new8a/a.y b/src/cmd/new8a/a.y deleted file mode 100644 index 906ad331df..0000000000 --- a/src/cmd/new8a/a.y +++ /dev/null @@ -1,713 +0,0 @@ -// Inferno utils/8a/a.y -// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -%{ -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/i386" -) -%} - -%union { - sym *asm.Sym - lval int64 - con2 struct { - v1 int32 - v2 int32 - } - dval float64 - sval string - addr obj.Addr - addr2 Addr2 -} - -%left '|' -%left '^' -%left '&' -%left '<' '>' -%left '+' '-' -%left '*' '/' '%' -%token LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4 -%token LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC -%token LTYPEX LTYPEPC LTYPEF LCONST LFP LPC LSB -%token LBREG LLREG LSREG LFREG LXREG -%token LFCONST -%token LSCONST LSP -%token LNAME LLAB LVAR -%type con expr pointer offset -%type mem imm reg nam rel rem rim rom omem nmem textsize -%type nonnon nonrel nonrem rimnon rimrem remrim -%type spec3 spec4 spec5 spec6 spec7 spec9 spec10 spec11 spec12 -%% -prog: -| prog - { - stmtline = asm.Lineno; - } - line - -line: - LNAME ':' - { - $1 = asm.LabelLookup($1); - if $1.Type == LLAB && $1.Value != int64(asm.PC) { - yyerror("redeclaration of %s", $1.Labelname) - } - $1.Type = LLAB; - $1.Value = int64(asm.PC) - } - line -| ';' -| inst ';' -| error ';' - -inst: - LNAME '=' expr - { - $1.Type = LVAR; - $1.Value = $3; - } -| LVAR '=' expr - { - if $1.Value != int64($3) { - yyerror("redeclaration of %s", $1.Name); - } - $1.Value = $3; - } -| LTYPE0 nonnon { outcode(int($1), &$2); } -| LTYPE1 nonrem { outcode(int($1), &$2); } -| LTYPE2 rimnon { outcode(int($1), &$2); } -| LTYPE3 rimrem { outcode(int($1), &$2); } -| LTYPE4 remrim { outcode(int($1), &$2); } -| LTYPER nonrel { outcode(int($1), &$2); } -| spec1 -| spec2 -| LTYPEC spec3 { outcode(int($1), &$2); } -| LTYPEN spec4 { outcode(int($1), &$2); } -| LTYPES spec5 { outcode(int($1), &$2); } -| LTYPEM spec6 { outcode(int($1), &$2); } -| LTYPEI spec7 { outcode(int($1), &$2); } -| spec8 -| LTYPEXC spec9 { outcode(int($1), &$2); } -| LTYPEX spec10 { outcode(int($1), &$2); } -| LTYPEPC spec11 { outcode(int($1), &$2); } -| LTYPEF spec12 { outcode(int($1), &$2); } - -nonnon: - { - $$.from = nullgen; - $$.to = nullgen; - } -| ',' - { - $$.from = nullgen; - $$.to = nullgen; - } - -rimrem: - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } - -remrim: - rem ',' rim - { - $$.from = $1; - $$.to = $3; - } - -rimnon: - rim ',' - { - $$.from = $1; - $$.to = nullgen; - } -| rim - { - $$.from = $1; - $$.to = nullgen; - } - -nonrem: - ',' rem - { - $$.from = nullgen; - $$.to = $2; - } -| rem - { - $$.from = nullgen; - $$.to = $1; - } - -nonrel: - ',' rel - { - $$.from = nullgen; - $$.to = $2; - } -| rel - { - $$.from = nullgen; - $$.to = $1; - } -| imm ',' rel - { - $$.from = $1; - $$.to = $3; - } - -spec1: /* DATA */ - LTYPED nam '/' con ',' imm - { - outcode(obj.ADATA, &Addr2{$2, $6}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -spec2: /* TEXT */ - LTYPET mem ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(obj.ATEXT, &Addr2{$2, $5}) - } -| LTYPET mem ',' con ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(obj.ATEXT, &Addr2{$2, $7}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -spec8: /* GLOBL */ - LTYPEG mem ',' imm - { - asm.Settext($2.Sym); - outcode(obj.AGLOBL, &Addr2{$2, $4}) - } -| LTYPEG mem ',' con ',' imm - { - asm.Settext($2.Sym); - outcode(obj.AGLOBL, &Addr2{$2, $6}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - - -spec3: /* JMP/CALL */ - ',' rom - { - $$.from = nullgen; - $$.to = $2; - } -| rom - { - $$.from = nullgen; - $$.to = $1; - } -| '*' nam - { - $$.from = nullgen; - $$.to = $2; - $$.to.Type = obj.TYPE_INDIR - } - -spec4: /* NOP */ - nonnon -| nonrem - -spec5: /* SHL/SHR */ - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } -| rim ',' rem ':' LLREG - { - $$.from = $1; - $$.to = $3; - if $$.from.Index != obj.TYPE_NONE { - yyerror("dp shift with lhs index"); - } - $$.from.Index = int16($5); - } - -spec6: /* MOVW/MOVL */ - rim ',' rem - { - $$.from = $1; - $$.to = $3; - } -| rim ',' rem ':' LSREG - { - $$.from = $1; - $$.to = $3; - if $$.to.Index != obj.TYPE_NONE { - yyerror("dp move with lhs index"); - } - $$.to.Index = int16($5); - } - -spec7: - rim ',' - { - $$.from = $1; - $$.to = nullgen; - } -| rim - { - $$.from = $1; - $$.to = nullgen; - } -| rim ',' rem - { - $$.from = $1; - $$.to = $3; - } - -spec9: /* CMPPS/CMPPD */ - reg ',' rem ',' con - { - $$.from = $1; - $$.to = $3; - $$.to.Offset = $5; - } - -spec10: /* PINSRD */ - imm ',' rem ',' reg - { - $$.from = $3; - $$.to = $5; - if $1.Type != obj.TYPE_CONST { - yyerror("illegal constant") - } - $$.to.Offset = $1.Offset; - } - -spec11: /* PCDATA */ - rim ',' rim - { - if $1.Type != obj.TYPE_CONST || $3.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants"); - } - $$.from = $1; - $$.to = $3; - } - -spec12: /* FUNCDATA */ - rim ',' rim - { - if $1.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant"); - } - if $3.Type != obj.TYPE_MEM || ($3.Name != obj.NAME_EXTERN && $3.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference"); - } - $$.from = $1; - $$.to = $3; - } - -rem: - reg -| mem - -rom: - rel -| nmem -| '*' reg - { - $$ = $2; - } -| '*' omem - { - $$ = $2; - } -| reg -| omem -| imm - -rim: - rem -| imm - -rel: - con '(' LPC ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1 + int64(asm.PC); - } -| LNAME offset - { - $1 = asm.LabelLookup($1); - $$ = nullgen; - if asm.Pass == 2 && $1.Type != LLAB { - yyerror("undefined label: %s", $1.Labelname); - } - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1.Value + $2; - } - -reg: - LBREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LFREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LLREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LXREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } -| LSP - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = REG_SP; - } -| LSREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1); - } - -imm: - '$' con - { - $$ = nullgen; - $$.Type = obj.TYPE_CONST; - $$.Offset = $2; - } -| '$' nam - { - $$ = $2; - $$.Type = obj.TYPE_ADDR - /* - if($2.Type == D_AUTO || $2.Type == D_PARAM) - yyerror("constant cannot be automatic: %s", - $2.Sym.name); - */ - } -| '$' LSCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_SCONST; - $$.U.Sval = $2 - } -| '$' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = $2; - } -| '$' '(' LFCONST ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = $3; - } -| '$' '(' '-' LFCONST ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = -$4; - } -| '$' '-' LFCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_FCONST; - $$.U.Dval = -$3; - } - -textsize: - LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = $1; - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -$2; - $$.U.Argsize = obj.ArgsSizeUnknown; - } -| LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = $1; - $$.U.Argsize = int32($3); - } -| '-' LCONST '-' LCONST - { - $$ = nullgen; - $$.Type = obj.TYPE_TEXTSIZE; - $$.Offset = -$2; - $$.U.Argsize = int32($4); - } - - -mem: - omem -| nmem - -omem: - con - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Offset = $1; - } -| con '(' LLREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - } -| con '(' LSP ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = REG_SP - $$.Offset = $1; - } -| con '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Offset = $1; - $$.Index = int16($3); - $$.Scale = int8($5); - checkscale($$.Scale); - } -| con '(' LLREG ')' '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - $$.Index = int16($6); - $$.Scale = int8($8); - checkscale($$.Scale); - } -| con '(' LLREG ')' '(' LSREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - $$.Index = int16($6); - $$.Scale = int8($8); - checkscale($$.Scale); - } -| '(' LLREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($2); - } -| '(' LSP ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = REG_SP - } -| con '(' LSREG ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($3) - $$.Offset = $1; - } -| '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Index = int16($2); - $$.Scale = int8($4); - checkscale($$.Scale); - } -| '(' LLREG ')' '(' LLREG '*' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Reg = int16($2) - $$.Index = int16($5); - $$.Scale = int8($7); - checkscale($$.Scale); - } - -nmem: - nam - { - $$ = $1; - } -| nam '(' LLREG '*' con ')' - { - $$ = $1; - $$.Index = int16($3); - $$.Scale = int8($5); - checkscale($$.Scale); - } - -nam: - LNAME offset '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Name = int8($4); - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); - $$.Offset = $2; - } -| LNAME '<' '>' offset '(' LSB ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM - $$.Name = obj.NAME_STATIC - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); - $$.Offset = $4; - } - -offset: - { - $$ = 0; - } -| '+' con - { - $$ = $2; - } -| '-' con - { - $$ = -$2; - } - -pointer: - LSB -| LSP - { - $$ = obj.NAME_AUTO; - } -| LFP - -con: - LCONST -| LVAR - { - $$ = $1.Value; - } -| '-' con - { - $$ = -$2; - } -| '+' con - { - $$ = $2; - } -| '~' con - { - $$ = ^$2; - } -| '(' expr ')' - { - $$ = $2; - } - -expr: - con -| expr '+' expr - { - $$ = $1 + $3; - } -| expr '-' expr - { - $$ = $1 - $3; - } -| expr '*' expr - { - $$ = $1 * $3; - } -| expr '/' expr - { - $$ = $1 / $3; - } -| expr '%' expr - { - $$ = $1 % $3; - } -| expr '<' '<' expr - { - $$ = $1 << uint($4); - } -| expr '>' '>' expr - { - $$ = $1 >> uint($4); - } -| expr '&' expr - { - $$ = $1 & $3; - } -| expr '^' expr - { - $$ = $1 ^ $3; - } -| expr '|' expr - { - $$ = $1 | $3; - } diff --git a/src/cmd/new8a/lex.go b/src/cmd/new8a/lex.go deleted file mode 100644 index bbd8610ec4..0000000000 --- a/src/cmd/new8a/lex.go +++ /dev/null @@ -1,771 +0,0 @@ -// Inferno utils/8a/lex.c -// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -//go:generate go tool yacc a.y - -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/i386" -) - -var ( - yyerror = asm.Yyerror - nullgen obj.Addr - stmtline int32 -) - -func main() { - cinit() - - asm.LSCONST = LSCONST - asm.LCONST = LCONST - asm.LFCONST = LFCONST - asm.LNAME = LNAME - asm.LVAR = LVAR - asm.LLAB = LLAB - - asm.Lexinit = lexinit - asm.Cclean = cclean - asm.Yyparse = yyparse - - asm.Thechar = '8' - asm.Thestring = "386" - asm.Thelinkarch = &i386.Link386 - - asm.Main() -} - -type yy struct{} - -func (yy) Lex(v *yySymType) int { - var av asm.Yylval - tok := asm.Yylex(&av) - v.sym = av.Sym - v.lval = av.Lval - v.sval = av.Sval - v.dval = av.Dval - return tok -} - -func (yy) Error(msg string) { - asm.Yyerror("%s", msg) -} - -func yyparse() { - yyParse(yy{}) -} - -var lexinit = []asm.Lextab{ - {"SP", LSP, obj.NAME_AUTO}, - {"SB", LSB, obj.NAME_EXTERN}, - {"FP", LFP, obj.NAME_PARAM}, - {"PC", LPC, obj.TYPE_BRANCH}, - {"AL", LBREG, i386.REG_AL}, - {"CL", LBREG, i386.REG_CL}, - {"DL", LBREG, i386.REG_DL}, - {"BL", LBREG, i386.REG_BL}, - {"AH", LBREG, i386.REG_AH}, - {"CH", LBREG, i386.REG_CH}, - {"DH", LBREG, i386.REG_DH}, - {"BH", LBREG, i386.REG_BH}, - {"AX", LLREG, i386.REG_AX}, - {"CX", LLREG, i386.REG_CX}, - {"DX", LLREG, i386.REG_DX}, - {"BX", LLREG, i386.REG_BX}, - /* "SP", LLREG, REG_SP, */ - {"BP", LLREG, i386.REG_BP}, - {"SI", LLREG, i386.REG_SI}, - {"DI", LLREG, i386.REG_DI}, - {"F0", LFREG, i386.REG_F0 + 0}, - {"F1", LFREG, i386.REG_F0 + 1}, - {"F2", LFREG, i386.REG_F0 + 2}, - {"F3", LFREG, i386.REG_F0 + 3}, - {"F4", LFREG, i386.REG_F0 + 4}, - {"F5", LFREG, i386.REG_F0 + 5}, - {"F6", LFREG, i386.REG_F0 + 6}, - {"F7", LFREG, i386.REG_F0 + 7}, - {"X0", LXREG, i386.REG_X0 + 0}, - {"X1", LXREG, i386.REG_X0 + 1}, - {"X2", LXREG, i386.REG_X0 + 2}, - {"X3", LXREG, i386.REG_X0 + 3}, - {"X4", LXREG, i386.REG_X0 + 4}, - {"X5", LXREG, i386.REG_X0 + 5}, - {"X6", LXREG, i386.REG_X0 + 6}, - {"X7", LXREG, i386.REG_X0 + 7}, - {"CS", LSREG, i386.REG_CS}, - {"SS", LSREG, i386.REG_SS}, - {"DS", LSREG, i386.REG_DS}, - {"ES", LSREG, i386.REG_ES}, - {"FS", LSREG, i386.REG_FS}, - {"GS", LSREG, i386.REG_GS}, - {"TLS", LSREG, i386.REG_TLS}, - {"GDTR", LBREG, i386.REG_GDTR}, - {"IDTR", LBREG, i386.REG_IDTR}, - {"LDTR", LBREG, i386.REG_LDTR}, - {"MSW", LBREG, i386.REG_MSW}, - {"TASK", LBREG, i386.REG_TASK}, - {"CR0", LBREG, i386.REG_CR + 0}, - {"CR1", LBREG, i386.REG_CR + 1}, - {"CR2", LBREG, i386.REG_CR + 2}, - {"CR3", LBREG, i386.REG_CR + 3}, - {"CR4", LBREG, i386.REG_CR + 4}, - {"CR5", LBREG, i386.REG_CR + 5}, - {"CR6", LBREG, i386.REG_CR + 6}, - {"CR7", LBREG, i386.REG_CR + 7}, - {"DR0", LBREG, i386.REG_DR + 0}, - {"DR1", LBREG, i386.REG_DR + 1}, - {"DR2", LBREG, i386.REG_DR + 2}, - {"DR3", LBREG, i386.REG_DR + 3}, - {"DR4", LBREG, i386.REG_DR + 4}, - {"DR5", LBREG, i386.REG_DR + 5}, - {"DR6", LBREG, i386.REG_DR + 6}, - {"DR7", LBREG, i386.REG_DR + 7}, - {"TR0", LBREG, i386.REG_TR + 0}, - {"TR1", LBREG, i386.REG_TR + 1}, - {"TR2", LBREG, i386.REG_TR + 2}, - {"TR3", LBREG, i386.REG_TR + 3}, - {"TR4", LBREG, i386.REG_TR + 4}, - {"TR5", LBREG, i386.REG_TR + 5}, - {"TR6", LBREG, i386.REG_TR + 6}, - {"TR7", LBREG, i386.REG_TR + 7}, - {"AAA", LTYPE0, i386.AAAA}, - {"AAD", LTYPE0, i386.AAAD}, - {"AAM", LTYPE0, i386.AAAM}, - {"AAS", LTYPE0, i386.AAAS}, - {"ADCB", LTYPE3, i386.AADCB}, - {"ADCL", LTYPE3, i386.AADCL}, - {"ADCW", LTYPE3, i386.AADCW}, - {"ADDB", LTYPE3, i386.AADDB}, - {"ADDL", LTYPE3, i386.AADDL}, - {"ADDW", LTYPE3, i386.AADDW}, - {"ADJSP", LTYPE2, i386.AADJSP}, - {"ANDB", LTYPE3, i386.AANDB}, - {"ANDL", LTYPE3, i386.AANDL}, - {"ANDW", LTYPE3, i386.AANDW}, - {"ARPL", LTYPE3, i386.AARPL}, - {"BOUNDL", LTYPE3, i386.ABOUNDL}, - {"BOUNDW", LTYPE3, i386.ABOUNDW}, - {"BSFL", LTYPE3, i386.ABSFL}, - {"BSFW", LTYPE3, i386.ABSFW}, - {"BSRL", LTYPE3, i386.ABSRL}, - {"BSRW", LTYPE3, i386.ABSRW}, - {"BSWAPL", LTYPE1, i386.ABSWAPL}, - {"BTCL", LTYPE3, i386.ABTCL}, - {"BTCW", LTYPE3, i386.ABTCW}, - {"BTL", LTYPE3, i386.ABTL}, - {"BTRL", LTYPE3, i386.ABTRL}, - {"BTRW", LTYPE3, i386.ABTRW}, - {"BTSL", LTYPE3, i386.ABTSL}, - {"BTSW", LTYPE3, i386.ABTSW}, - {"BTW", LTYPE3, i386.ABTW}, - {"BYTE", LTYPE2, i386.ABYTE}, - {"CALL", LTYPEC, obj.ACALL}, - {"CLC", LTYPE0, i386.ACLC}, - {"CLD", LTYPE0, i386.ACLD}, - {"CLI", LTYPE0, i386.ACLI}, - {"CLTS", LTYPE0, i386.ACLTS}, - {"CMC", LTYPE0, i386.ACMC}, - {"CMPB", LTYPE4, i386.ACMPB}, - {"CMPL", LTYPE4, i386.ACMPL}, - {"CMPW", LTYPE4, i386.ACMPW}, - {"CMPSB", LTYPE0, i386.ACMPSB}, - {"CMPSL", LTYPE0, i386.ACMPSL}, - {"CMPSW", LTYPE0, i386.ACMPSW}, - {"CMPXCHG8B", LTYPE1, i386.ACMPXCHG8B}, - {"CMPXCHGB", LTYPE3, i386.ACMPXCHGB}, - {"CMPXCHGL", LTYPE3, i386.ACMPXCHGL}, - {"CMPXCHGW", LTYPE3, i386.ACMPXCHGW}, - {"CPUID", LTYPE0, i386.ACPUID}, - {"DAA", LTYPE0, i386.ADAA}, - {"DAS", LTYPE0, i386.ADAS}, - {"DATA", LTYPED, obj.ADATA}, - {"DECB", LTYPE1, i386.ADECB}, - {"DECL", LTYPE1, i386.ADECL}, - {"DECW", LTYPE1, i386.ADECW}, - {"DIVB", LTYPE2, i386.ADIVB}, - {"DIVL", LTYPE2, i386.ADIVL}, - {"DIVW", LTYPE2, i386.ADIVW}, - {"END", LTYPE0, obj.AEND}, - {"ENTER", LTYPE2, i386.AENTER}, - {"GLOBL", LTYPEG, obj.AGLOBL}, - {"HLT", LTYPE0, i386.AHLT}, - {"IDIVB", LTYPE2, i386.AIDIVB}, - {"IDIVL", LTYPE2, i386.AIDIVL}, - {"IDIVW", LTYPE2, i386.AIDIVW}, - {"IMULB", LTYPE2, i386.AIMULB}, - {"IMULL", LTYPEI, i386.AIMULL}, - {"IMULW", LTYPEI, i386.AIMULW}, - {"INB", LTYPE0, i386.AINB}, - {"INL", LTYPE0, i386.AINL}, - {"INW", LTYPE0, i386.AINW}, - {"INCB", LTYPE1, i386.AINCB}, - {"INCL", LTYPE1, i386.AINCL}, - {"INCW", LTYPE1, i386.AINCW}, - {"INSB", LTYPE0, i386.AINSB}, - {"INSL", LTYPE0, i386.AINSL}, - {"INSW", LTYPE0, i386.AINSW}, - {"INT", LTYPE2, i386.AINT}, - {"INTO", LTYPE0, i386.AINTO}, - {"IRETL", LTYPE0, i386.AIRETL}, - {"IRETW", LTYPE0, i386.AIRETW}, - {"JOS", LTYPER, i386.AJOS}, /* overflow set (OF = 1) */ - {"JO", LTYPER, i386.AJOS}, /* alternate */ - {"JOC", LTYPER, i386.AJOC}, /* overflow clear (OF = 0) */ - {"JNO", LTYPER, i386.AJOC}, /* alternate */ - {"JCS", LTYPER, i386.AJCS}, /* carry set (CF = 1) */ - {"JB", LTYPER, i386.AJCS}, /* alternate */ - {"JC", LTYPER, i386.AJCS}, /* alternate */ - {"JNAE", LTYPER, i386.AJCS}, /* alternate */ - {"JLO", LTYPER, i386.AJCS}, /* alternate */ - {"JCC", LTYPER, i386.AJCC}, /* carry clear (CF = 0) */ - {"JAE", LTYPER, i386.AJCC}, /* alternate */ - {"JNB", LTYPER, i386.AJCC}, /* alternate */ - {"JNC", LTYPER, i386.AJCC}, /* alternate */ - {"JHS", LTYPER, i386.AJCC}, /* alternate */ - {"JEQ", LTYPER, i386.AJEQ}, /* equal (ZF = 1) */ - {"JE", LTYPER, i386.AJEQ}, /* alternate */ - {"JZ", LTYPER, i386.AJEQ}, /* alternate */ - {"JNE", LTYPER, i386.AJNE}, /* not equal (ZF = 0) */ - {"JNZ", LTYPER, i386.AJNE}, /* alternate */ - {"JLS", LTYPER, i386.AJLS}, /* lower or same (unsigned) (CF = 1 || ZF = 1) */ - {"JBE", LTYPER, i386.AJLS}, /* alternate */ - {"JNA", LTYPER, i386.AJLS}, /* alternate */ - {"JHI", LTYPER, i386.AJHI}, /* higher (unsigned) (CF = 0 && ZF = 0) */ - {"JA", LTYPER, i386.AJHI}, /* alternate */ - {"JNBE", LTYPER, i386.AJHI}, /* alternate */ - {"JMI", LTYPER, i386.AJMI}, /* negative (minus) (SF = 1) */ - {"JS", LTYPER, i386.AJMI}, /* alternate */ - {"JPL", LTYPER, i386.AJPL}, /* non-negative (plus) (SF = 0) */ - {"JNS", LTYPER, i386.AJPL}, /* alternate */ - {"JPS", LTYPER, i386.AJPS}, /* parity set (PF = 1) */ - {"JP", LTYPER, i386.AJPS}, /* alternate */ - {"JPE", LTYPER, i386.AJPS}, /* alternate */ - {"JPC", LTYPER, i386.AJPC}, /* parity clear (PF = 0) */ - {"JNP", LTYPER, i386.AJPC}, /* alternate */ - {"JPO", LTYPER, i386.AJPC}, /* alternate */ - {"JLT", LTYPER, i386.AJLT}, /* less than (signed) (SF != OF) */ - {"JL", LTYPER, i386.AJLT}, /* alternate */ - {"JNGE", LTYPER, i386.AJLT}, /* alternate */ - {"JGE", LTYPER, i386.AJGE}, /* greater than or equal (signed) (SF = OF) */ - {"JNL", LTYPER, i386.AJGE}, /* alternate */ - {"JLE", LTYPER, i386.AJLE}, /* less than or equal (signed) (ZF = 1 || SF != OF) */ - {"JNG", LTYPER, i386.AJLE}, /* alternate */ - {"JGT", LTYPER, i386.AJGT}, /* greater than (signed) (ZF = 0 && SF = OF) */ - {"JG", LTYPER, i386.AJGT}, /* alternate */ - {"JNLE", LTYPER, i386.AJGT}, /* alternate */ - {"JCXZL", LTYPER, i386.AJCXZL}, - {"JCXZW", LTYPER, i386.AJCXZW}, - {"JMP", LTYPEC, obj.AJMP}, - {"LAHF", LTYPE0, i386.ALAHF}, - {"LARL", LTYPE3, i386.ALARL}, - {"LARW", LTYPE3, i386.ALARW}, - {"LEAL", LTYPE3, i386.ALEAL}, - {"LEAW", LTYPE3, i386.ALEAW}, - {"LEAVEL", LTYPE0, i386.ALEAVEL}, - {"LEAVEW", LTYPE0, i386.ALEAVEW}, - {"LOCK", LTYPE0, i386.ALOCK}, - {"LODSB", LTYPE0, i386.ALODSB}, - {"LODSL", LTYPE0, i386.ALODSL}, - {"LODSW", LTYPE0, i386.ALODSW}, - {"LONG", LTYPE2, i386.ALONG}, - {"LOOP", LTYPER, i386.ALOOP}, - {"LOOPEQ", LTYPER, i386.ALOOPEQ}, - {"LOOPNE", LTYPER, i386.ALOOPNE}, - {"LSLL", LTYPE3, i386.ALSLL}, - {"LSLW", LTYPE3, i386.ALSLW}, - {"MOVB", LTYPE3, i386.AMOVB}, - {"MOVL", LTYPEM, i386.AMOVL}, - {"MOVW", LTYPEM, i386.AMOVW}, - {"MOVQ", LTYPEM, i386.AMOVQ}, - {"MOVBLSX", LTYPE3, i386.AMOVBLSX}, - {"MOVBLZX", LTYPE3, i386.AMOVBLZX}, - {"MOVBWSX", LTYPE3, i386.AMOVBWSX}, - {"MOVBWZX", LTYPE3, i386.AMOVBWZX}, - {"MOVWLSX", LTYPE3, i386.AMOVWLSX}, - {"MOVWLZX", LTYPE3, i386.AMOVWLZX}, - {"MOVSB", LTYPE0, i386.AMOVSB}, - {"MOVSL", LTYPE0, i386.AMOVSL}, - {"MOVSW", LTYPE0, i386.AMOVSW}, - {"MULB", LTYPE2, i386.AMULB}, - {"MULL", LTYPE2, i386.AMULL}, - {"MULW", LTYPE2, i386.AMULW}, - {"NEGB", LTYPE1, i386.ANEGB}, - {"NEGL", LTYPE1, i386.ANEGL}, - {"NEGW", LTYPE1, i386.ANEGW}, - {"NOP", LTYPEN, obj.ANOP}, - {"NOTB", LTYPE1, i386.ANOTB}, - {"NOTL", LTYPE1, i386.ANOTL}, - {"NOTW", LTYPE1, i386.ANOTW}, - {"ORB", LTYPE3, i386.AORB}, - {"ORL", LTYPE3, i386.AORL}, - {"ORW", LTYPE3, i386.AORW}, - {"OUTB", LTYPE0, i386.AOUTB}, - {"OUTL", LTYPE0, i386.AOUTL}, - {"OUTW", LTYPE0, i386.AOUTW}, - {"OUTSB", LTYPE0, i386.AOUTSB}, - {"OUTSL", LTYPE0, i386.AOUTSL}, - {"OUTSW", LTYPE0, i386.AOUTSW}, - {"PAUSE", LTYPEN, i386.APAUSE}, - {"PINSRD", LTYPEX, i386.APINSRD}, - {"POPAL", LTYPE0, i386.APOPAL}, - {"POPAW", LTYPE0, i386.APOPAW}, - {"POPFL", LTYPE0, i386.APOPFL}, - {"POPFW", LTYPE0, i386.APOPFW}, - {"POPL", LTYPE1, i386.APOPL}, - {"POPW", LTYPE1, i386.APOPW}, - {"PUSHAL", LTYPE0, i386.APUSHAL}, - {"PUSHAW", LTYPE0, i386.APUSHAW}, - {"PUSHFL", LTYPE0, i386.APUSHFL}, - {"PUSHFW", LTYPE0, i386.APUSHFW}, - {"PUSHL", LTYPE2, i386.APUSHL}, - {"PUSHW", LTYPE2, i386.APUSHW}, - {"RCLB", LTYPE3, i386.ARCLB}, - {"RCLL", LTYPE3, i386.ARCLL}, - {"RCLW", LTYPE3, i386.ARCLW}, - {"RCRB", LTYPE3, i386.ARCRB}, - {"RCRL", LTYPE3, i386.ARCRL}, - {"RCRW", LTYPE3, i386.ARCRW}, - {"RDTSC", LTYPE0, i386.ARDTSC}, - {"REP", LTYPE0, i386.AREP}, - {"REPN", LTYPE0, i386.AREPN}, - {"RET", LTYPE0, obj.ARET}, - {"ROLB", LTYPE3, i386.AROLB}, - {"ROLL", LTYPE3, i386.AROLL}, - {"ROLW", LTYPE3, i386.AROLW}, - {"RORB", LTYPE3, i386.ARORB}, - {"RORL", LTYPE3, i386.ARORL}, - {"RORW", LTYPE3, i386.ARORW}, - {"SAHF", LTYPE0, i386.ASAHF}, - {"SALB", LTYPE3, i386.ASALB}, - {"SALL", LTYPE3, i386.ASALL}, - {"SALW", LTYPE3, i386.ASALW}, - {"SARB", LTYPE3, i386.ASARB}, - {"SARL", LTYPE3, i386.ASARL}, - {"SARW", LTYPE3, i386.ASARW}, - {"SBBB", LTYPE3, i386.ASBBB}, - {"SBBL", LTYPE3, i386.ASBBL}, - {"SBBW", LTYPE3, i386.ASBBW}, - {"SCASB", LTYPE0, i386.ASCASB}, - {"SCASL", LTYPE0, i386.ASCASL}, - {"SCASW", LTYPE0, i386.ASCASW}, - {"SETCC", LTYPE1, i386.ASETCC}, /* see JCC etc above for condition codes */ - {"SETCS", LTYPE1, i386.ASETCS}, - {"SETEQ", LTYPE1, i386.ASETEQ}, - {"SETGE", LTYPE1, i386.ASETGE}, - {"SETGT", LTYPE1, i386.ASETGT}, - {"SETHI", LTYPE1, i386.ASETHI}, - {"SETLE", LTYPE1, i386.ASETLE}, - {"SETLS", LTYPE1, i386.ASETLS}, - {"SETLT", LTYPE1, i386.ASETLT}, - {"SETMI", LTYPE1, i386.ASETMI}, - {"SETNE", LTYPE1, i386.ASETNE}, - {"SETOC", LTYPE1, i386.ASETOC}, - {"SETOS", LTYPE1, i386.ASETOS}, - {"SETPC", LTYPE1, i386.ASETPC}, - {"SETPL", LTYPE1, i386.ASETPL}, - {"SETPS", LTYPE1, i386.ASETPS}, - {"CDQ", LTYPE0, i386.ACDQ}, - {"CWD", LTYPE0, i386.ACWD}, - {"SHLB", LTYPE3, i386.ASHLB}, - {"SHLL", LTYPES, i386.ASHLL}, - {"SHLW", LTYPES, i386.ASHLW}, - {"SHRB", LTYPE3, i386.ASHRB}, - {"SHRL", LTYPES, i386.ASHRL}, - {"SHRW", LTYPES, i386.ASHRW}, - {"STC", LTYPE0, i386.ASTC}, - {"STD", LTYPE0, i386.ASTD}, - {"STI", LTYPE0, i386.ASTI}, - {"STOSB", LTYPE0, i386.ASTOSB}, - {"STOSL", LTYPE0, i386.ASTOSL}, - {"STOSW", LTYPE0, i386.ASTOSW}, - {"SUBB", LTYPE3, i386.ASUBB}, - {"SUBL", LTYPE3, i386.ASUBL}, - {"SUBW", LTYPE3, i386.ASUBW}, - {"SYSCALL", LTYPE0, i386.ASYSCALL}, - {"TESTB", LTYPE3, i386.ATESTB}, - {"TESTL", LTYPE3, i386.ATESTL}, - {"TESTW", LTYPE3, i386.ATESTW}, - {"TEXT", LTYPET, obj.ATEXT}, - {"VERR", LTYPE2, i386.AVERR}, - {"VERW", LTYPE2, i386.AVERW}, - {"WAIT", LTYPE0, i386.AWAIT}, - {"WORD", LTYPE2, i386.AWORD}, - {"XADDB", LTYPE3, i386.AXADDB}, - {"XADDL", LTYPE3, i386.AXADDL}, - {"XADDW", LTYPE3, i386.AXADDW}, - {"XCHGB", LTYPE3, i386.AXCHGB}, - {"XCHGL", LTYPE3, i386.AXCHGL}, - {"XCHGW", LTYPE3, i386.AXCHGW}, - {"XLAT", LTYPE2, i386.AXLAT}, - {"XORB", LTYPE3, i386.AXORB}, - {"XORL", LTYPE3, i386.AXORL}, - {"XORW", LTYPE3, i386.AXORW}, - {"CMOVLCC", LTYPE3, i386.ACMOVLCC}, - {"CMOVLCS", LTYPE3, i386.ACMOVLCS}, - {"CMOVLEQ", LTYPE3, i386.ACMOVLEQ}, - {"CMOVLGE", LTYPE3, i386.ACMOVLGE}, - {"CMOVLGT", LTYPE3, i386.ACMOVLGT}, - {"CMOVLHI", LTYPE3, i386.ACMOVLHI}, - {"CMOVLLE", LTYPE3, i386.ACMOVLLE}, - {"CMOVLLS", LTYPE3, i386.ACMOVLLS}, - {"CMOVLLT", LTYPE3, i386.ACMOVLLT}, - {"CMOVLMI", LTYPE3, i386.ACMOVLMI}, - {"CMOVLNE", LTYPE3, i386.ACMOVLNE}, - {"CMOVLOC", LTYPE3, i386.ACMOVLOC}, - {"CMOVLOS", LTYPE3, i386.ACMOVLOS}, - {"CMOVLPC", LTYPE3, i386.ACMOVLPC}, - {"CMOVLPL", LTYPE3, i386.ACMOVLPL}, - {"CMOVLPS", LTYPE3, i386.ACMOVLPS}, - {"CMOVWCC", LTYPE3, i386.ACMOVWCC}, - {"CMOVWCS", LTYPE3, i386.ACMOVWCS}, - {"CMOVWEQ", LTYPE3, i386.ACMOVWEQ}, - {"CMOVWGE", LTYPE3, i386.ACMOVWGE}, - {"CMOVWGT", LTYPE3, i386.ACMOVWGT}, - {"CMOVWHI", LTYPE3, i386.ACMOVWHI}, - {"CMOVWLE", LTYPE3, i386.ACMOVWLE}, - {"CMOVWLS", LTYPE3, i386.ACMOVWLS}, - {"CMOVWLT", LTYPE3, i386.ACMOVWLT}, - {"CMOVWMI", LTYPE3, i386.ACMOVWMI}, - {"CMOVWNE", LTYPE3, i386.ACMOVWNE}, - {"CMOVWOC", LTYPE3, i386.ACMOVWOC}, - {"CMOVWOS", LTYPE3, i386.ACMOVWOS}, - {"CMOVWPC", LTYPE3, i386.ACMOVWPC}, - {"CMOVWPL", LTYPE3, i386.ACMOVWPL}, - {"CMOVWPS", LTYPE3, i386.ACMOVWPS}, - {"FMOVB", LTYPE3, i386.AFMOVB}, - {"FMOVBP", LTYPE3, i386.AFMOVBP}, - {"FMOVD", LTYPE3, i386.AFMOVD}, - {"FMOVDP", LTYPE3, i386.AFMOVDP}, - {"FMOVF", LTYPE3, i386.AFMOVF}, - {"FMOVFP", LTYPE3, i386.AFMOVFP}, - {"FMOVL", LTYPE3, i386.AFMOVL}, - {"FMOVLP", LTYPE3, i386.AFMOVLP}, - {"FMOVV", LTYPE3, i386.AFMOVV}, - {"FMOVVP", LTYPE3, i386.AFMOVVP}, - {"FMOVW", LTYPE3, i386.AFMOVW}, - {"FMOVWP", LTYPE3, i386.AFMOVWP}, - {"FMOVX", LTYPE3, i386.AFMOVX}, - {"FMOVXP", LTYPE3, i386.AFMOVXP}, - {"FCMOVCC", LTYPE3, i386.AFCMOVCC}, - {"FCMOVCS", LTYPE3, i386.AFCMOVCS}, - {"FCMOVEQ", LTYPE3, i386.AFCMOVEQ}, - {"FCMOVHI", LTYPE3, i386.AFCMOVHI}, - {"FCMOVLS", LTYPE3, i386.AFCMOVLS}, - {"FCMOVNE", LTYPE3, i386.AFCMOVNE}, - {"FCMOVNU", LTYPE3, i386.AFCMOVNU}, - {"FCMOVUN", LTYPE3, i386.AFCMOVUN}, - {"FCOMB", LTYPE3, i386.AFCOMB}, - {"FCOMBP", LTYPE3, i386.AFCOMBP}, - {"FCOMD", LTYPE3, i386.AFCOMD}, - {"FCOMDP", LTYPE3, i386.AFCOMDP}, - {"FCOMDPP", LTYPE3, i386.AFCOMDPP}, - {"FCOMF", LTYPE3, i386.AFCOMF}, - {"FCOMFP", LTYPE3, i386.AFCOMFP}, - {"FCOMI", LTYPE3, i386.AFCOMI}, - {"FCOMIP", LTYPE3, i386.AFCOMIP}, - {"FCOML", LTYPE3, i386.AFCOML}, - {"FCOMLP", LTYPE3, i386.AFCOMLP}, - {"FCOMW", LTYPE3, i386.AFCOMW}, - {"FCOMWP", LTYPE3, i386.AFCOMWP}, - {"FUCOM", LTYPE3, i386.AFUCOM}, - {"FUCOMI", LTYPE3, i386.AFUCOMI}, - {"FUCOMIP", LTYPE3, i386.AFUCOMIP}, - {"FUCOMP", LTYPE3, i386.AFUCOMP}, - {"FUCOMPP", LTYPE3, i386.AFUCOMPP}, - {"FADDW", LTYPE3, i386.AFADDW}, - {"FADDL", LTYPE3, i386.AFADDL}, - {"FADDF", LTYPE3, i386.AFADDF}, - {"FADDD", LTYPE3, i386.AFADDD}, - {"FADDDP", LTYPE3, i386.AFADDDP}, - {"FSUBDP", LTYPE3, i386.AFSUBDP}, - {"FSUBW", LTYPE3, i386.AFSUBW}, - {"FSUBL", LTYPE3, i386.AFSUBL}, - {"FSUBF", LTYPE3, i386.AFSUBF}, - {"FSUBD", LTYPE3, i386.AFSUBD}, - {"FSUBRDP", LTYPE3, i386.AFSUBRDP}, - {"FSUBRW", LTYPE3, i386.AFSUBRW}, - {"FSUBRL", LTYPE3, i386.AFSUBRL}, - {"FSUBRF", LTYPE3, i386.AFSUBRF}, - {"FSUBRD", LTYPE3, i386.AFSUBRD}, - {"FMULDP", LTYPE3, i386.AFMULDP}, - {"FMULW", LTYPE3, i386.AFMULW}, - {"FMULL", LTYPE3, i386.AFMULL}, - {"FMULF", LTYPE3, i386.AFMULF}, - {"FMULD", LTYPE3, i386.AFMULD}, - {"FDIVDP", LTYPE3, i386.AFDIVDP}, - {"FDIVW", LTYPE3, i386.AFDIVW}, - {"FDIVL", LTYPE3, i386.AFDIVL}, - {"FDIVF", LTYPE3, i386.AFDIVF}, - {"FDIVD", LTYPE3, i386.AFDIVD}, - {"FDIVRDP", LTYPE3, i386.AFDIVRDP}, - {"FDIVRW", LTYPE3, i386.AFDIVRW}, - {"FDIVRL", LTYPE3, i386.AFDIVRL}, - {"FDIVRF", LTYPE3, i386.AFDIVRF}, - {"FDIVRD", LTYPE3, i386.AFDIVRD}, - {"FXCHD", LTYPE3, i386.AFXCHD}, - {"FFREE", LTYPE1, i386.AFFREE}, - {"FLDCW", LTYPE2, i386.AFLDCW}, - {"FLDENV", LTYPE1, i386.AFLDENV}, - {"FRSTOR", LTYPE2, i386.AFRSTOR}, - {"FSAVE", LTYPE1, i386.AFSAVE}, - {"FSTCW", LTYPE1, i386.AFSTCW}, - {"FSTENV", LTYPE1, i386.AFSTENV}, - {"FSTSW", LTYPE1, i386.AFSTSW}, - {"F2XM1", LTYPE0, i386.AF2XM1}, - {"FABS", LTYPE0, i386.AFABS}, - {"FCHS", LTYPE0, i386.AFCHS}, - {"FCLEX", LTYPE0, i386.AFCLEX}, - {"FCOS", LTYPE0, i386.AFCOS}, - {"FDECSTP", LTYPE0, i386.AFDECSTP}, - {"FINCSTP", LTYPE0, i386.AFINCSTP}, - {"FINIT", LTYPE0, i386.AFINIT}, - {"FLD1", LTYPE0, i386.AFLD1}, - {"FLDL2E", LTYPE0, i386.AFLDL2E}, - {"FLDL2T", LTYPE0, i386.AFLDL2T}, - {"FLDLG2", LTYPE0, i386.AFLDLG2}, - {"FLDLN2", LTYPE0, i386.AFLDLN2}, - {"FLDPI", LTYPE0, i386.AFLDPI}, - {"FLDZ", LTYPE0, i386.AFLDZ}, - {"FNOP", LTYPE0, i386.AFNOP}, - {"FPATAN", LTYPE0, i386.AFPATAN}, - {"FPREM", LTYPE0, i386.AFPREM}, - {"FPREM1", LTYPE0, i386.AFPREM1}, - {"FPTAN", LTYPE0, i386.AFPTAN}, - {"FRNDINT", LTYPE0, i386.AFRNDINT}, - {"FSCALE", LTYPE0, i386.AFSCALE}, - {"FSIN", LTYPE0, i386.AFSIN}, - {"FSINCOS", LTYPE0, i386.AFSINCOS}, - {"FSQRT", LTYPE0, i386.AFSQRT}, - {"FTST", LTYPE0, i386.AFTST}, - {"FXAM", LTYPE0, i386.AFXAM}, - {"FXTRACT", LTYPE0, i386.AFXTRACT}, - {"FYL2X", LTYPE0, i386.AFYL2X}, - {"FYL2XP1", LTYPE0, i386.AFYL2XP1}, - {"LFENCE", LTYPE0, i386.ALFENCE}, - {"MFENCE", LTYPE0, i386.AMFENCE}, - {"SFENCE", LTYPE0, i386.ASFENCE}, - {"EMMS", LTYPE0, i386.AEMMS}, - {"PREFETCHT0", LTYPE2, i386.APREFETCHT0}, - {"PREFETCHT1", LTYPE2, i386.APREFETCHT1}, - {"PREFETCHT2", LTYPE2, i386.APREFETCHT2}, - {"PREFETCHNTA", LTYPE2, i386.APREFETCHNTA}, - {"UNDEF", LTYPE0, obj.AUNDEF}, - {"ADDPD", LTYPE3, i386.AADDPD}, - {"ADDPS", LTYPE3, i386.AADDPS}, - {"ADDSD", LTYPE3, i386.AADDSD}, - {"ADDSS", LTYPE3, i386.AADDSS}, - {"AESENC", LTYPE3, i386.AAESENC}, - {"ANDNPD", LTYPE3, i386.AANDNPD}, - {"ANDNPS", LTYPE3, i386.AANDNPS}, - {"ANDPD", LTYPE3, i386.AANDPD}, - {"ANDPS", LTYPE3, i386.AANDPS}, - {"CMPPD", LTYPEXC, i386.ACMPPD}, - {"CMPPS", LTYPEXC, i386.ACMPPS}, - {"CMPSD", LTYPEXC, i386.ACMPSD}, - {"CMPSS", LTYPEXC, i386.ACMPSS}, - {"COMISD", LTYPE3, i386.ACOMISD}, - {"COMISS", LTYPE3, i386.ACOMISS}, - {"CVTPL2PD", LTYPE3, i386.ACVTPL2PD}, - {"CVTPL2PS", LTYPE3, i386.ACVTPL2PS}, - {"CVTPD2PL", LTYPE3, i386.ACVTPD2PL}, - {"CVTPD2PS", LTYPE3, i386.ACVTPD2PS}, - {"CVTPS2PL", LTYPE3, i386.ACVTPS2PL}, - {"CVTPS2PD", LTYPE3, i386.ACVTPS2PD}, - {"CVTSD2SL", LTYPE3, i386.ACVTSD2SL}, - {"CVTSD2SS", LTYPE3, i386.ACVTSD2SS}, - {"CVTSL2SD", LTYPE3, i386.ACVTSL2SD}, - {"CVTSL2SS", LTYPE3, i386.ACVTSL2SS}, - {"CVTSS2SD", LTYPE3, i386.ACVTSS2SD}, - {"CVTSS2SL", LTYPE3, i386.ACVTSS2SL}, - {"CVTTPD2PL", LTYPE3, i386.ACVTTPD2PL}, - {"CVTTPS2PL", LTYPE3, i386.ACVTTPS2PL}, - {"CVTTSD2SL", LTYPE3, i386.ACVTTSD2SL}, - {"CVTTSS2SL", LTYPE3, i386.ACVTTSS2SL}, - {"DIVPD", LTYPE3, i386.ADIVPD}, - {"DIVPS", LTYPE3, i386.ADIVPS}, - {"DIVSD", LTYPE3, i386.ADIVSD}, - {"DIVSS", LTYPE3, i386.ADIVSS}, - {"MASKMOVOU", LTYPE3, i386.AMASKMOVOU}, - {"MASKMOVDQU", LTYPE3, i386.AMASKMOVOU}, /* syn */ - {"MAXPD", LTYPE3, i386.AMAXPD}, - {"MAXPS", LTYPE3, i386.AMAXPS}, - {"MAXSD", LTYPE3, i386.AMAXSD}, - {"MAXSS", LTYPE3, i386.AMAXSS}, - {"MINPD", LTYPE3, i386.AMINPD}, - {"MINPS", LTYPE3, i386.AMINPS}, - {"MINSD", LTYPE3, i386.AMINSD}, - {"MINSS", LTYPE3, i386.AMINSS}, - {"MOVAPD", LTYPE3, i386.AMOVAPD}, - {"MOVAPS", LTYPE3, i386.AMOVAPS}, - {"MOVO", LTYPE3, i386.AMOVO}, - {"MOVOA", LTYPE3, i386.AMOVO}, /* syn */ - {"MOVOU", LTYPE3, i386.AMOVOU}, - {"MOVHLPS", LTYPE3, i386.AMOVHLPS}, - {"MOVHPD", LTYPE3, i386.AMOVHPD}, - {"MOVHPS", LTYPE3, i386.AMOVHPS}, - {"MOVLHPS", LTYPE3, i386.AMOVLHPS}, - {"MOVLPD", LTYPE3, i386.AMOVLPD}, - {"MOVLPS", LTYPE3, i386.AMOVLPS}, - {"MOVMSKPD", LTYPE3, i386.AMOVMSKPD}, - {"MOVMSKPS", LTYPE3, i386.AMOVMSKPS}, - {"MOVNTO", LTYPE3, i386.AMOVNTO}, - {"MOVNTDQ", LTYPE3, i386.AMOVNTO}, /* syn */ - {"MOVNTPD", LTYPE3, i386.AMOVNTPD}, - {"MOVNTPS", LTYPE3, i386.AMOVNTPS}, - {"MOVSD", LTYPE3, i386.AMOVSD}, - {"MOVSS", LTYPE3, i386.AMOVSS}, - {"MOVUPD", LTYPE3, i386.AMOVUPD}, - {"MOVUPS", LTYPE3, i386.AMOVUPS}, - {"MULPD", LTYPE3, i386.AMULPD}, - {"MULPS", LTYPE3, i386.AMULPS}, - {"MULSD", LTYPE3, i386.AMULSD}, - {"MULSS", LTYPE3, i386.AMULSS}, - {"ORPD", LTYPE3, i386.AORPD}, - {"ORPS", LTYPE3, i386.AORPS}, - {"PADDQ", LTYPE3, i386.APADDQ}, - {"PAND", LTYPE3, i386.APAND}, - {"PCMPEQB", LTYPE3, i386.APCMPEQB}, - {"PMAXSW", LTYPE3, i386.APMAXSW}, - {"PMAXUB", LTYPE3, i386.APMAXUB}, - {"PMINSW", LTYPE3, i386.APMINSW}, - {"PMINUB", LTYPE3, i386.APMINUB}, - {"PMOVMSKB", LTYPE3, i386.APMOVMSKB}, - {"PSADBW", LTYPE3, i386.APSADBW}, - {"PSHUFB", LTYPE3, i386.APSHUFB}, - {"PSHUFHW", LTYPEX, i386.APSHUFHW}, - {"PSHUFL", LTYPEX, i386.APSHUFL}, - {"PSHUFLW", LTYPEX, i386.APSHUFLW}, - {"PSUBB", LTYPE3, i386.APSUBB}, - {"PSUBL", LTYPE3, i386.APSUBL}, - {"PSUBQ", LTYPE3, i386.APSUBQ}, - {"PSUBSB", LTYPE3, i386.APSUBSB}, - {"PSUBSW", LTYPE3, i386.APSUBSW}, - {"PSUBUSB", LTYPE3, i386.APSUBUSB}, - {"PSUBUSW", LTYPE3, i386.APSUBUSW}, - {"PSUBW", LTYPE3, i386.APSUBW}, - {"PUNPCKHQDQ", LTYPE3, i386.APUNPCKHQDQ}, - {"PUNPCKLQDQ", LTYPE3, i386.APUNPCKLQDQ}, - {"PXOR", LTYPE3, i386.APXOR}, - {"RCPPS", LTYPE3, i386.ARCPPS}, - {"RCPSS", LTYPE3, i386.ARCPSS}, - {"RSQRTPS", LTYPE3, i386.ARSQRTPS}, - {"RSQRTSS", LTYPE3, i386.ARSQRTSS}, - {"SQRTPD", LTYPE3, i386.ASQRTPD}, - {"SQRTPS", LTYPE3, i386.ASQRTPS}, - {"SQRTSD", LTYPE3, i386.ASQRTSD}, - {"SQRTSS", LTYPE3, i386.ASQRTSS}, - {"SUBPD", LTYPE3, i386.ASUBPD}, - {"SUBPS", LTYPE3, i386.ASUBPS}, - {"SUBSD", LTYPE3, i386.ASUBSD}, - {"SUBSS", LTYPE3, i386.ASUBSS}, - {"UCOMISD", LTYPE3, i386.AUCOMISD}, - {"UCOMISS", LTYPE3, i386.AUCOMISS}, - {"UNPCKHPD", LTYPE3, i386.AUNPCKHPD}, - {"UNPCKHPS", LTYPE3, i386.AUNPCKHPS}, - {"UNPCKLPD", LTYPE3, i386.AUNPCKLPD}, - {"UNPCKLPS", LTYPE3, i386.AUNPCKLPS}, - {"XORPD", LTYPE3, i386.AXORPD}, - {"XORPS", LTYPE3, i386.AXORPS}, - {"USEFIELD", LTYPEN, obj.AUSEFIELD}, - {"PCDATA", LTYPEPC, obj.APCDATA}, - {"FUNCDATA", LTYPEF, obj.AFUNCDATA}, -} - -func cinit() { - nullgen.Type = i386.REG_NONE - nullgen.Index = i386.REG_NONE -} - -func checkscale(scale int8) { - switch scale { - case 1, - 2, - 4, - 8: - return - } - - yyerror("scale must be 1248: %d", scale) -} - -func syminit(s *asm.Sym) { - s.Type = LNAME - s.Value = 0 -} - -func cclean() { - var g2 Addr2 - - g2.from = nullgen - g2.to = nullgen - outcode(obj.AEND, &g2) -} - -var lastpc *obj.Prog - -type Addr2 struct { - from obj.Addr - to obj.Addr -} - -func outcode(a int, g2 *Addr2) { - var p *obj.Prog - var pl *obj.Plist - - if asm.Pass == 1 { - goto out - } - - p = new(obj.Prog) - *p = obj.Prog{} - p.Ctxt = asm.Ctxt - p.As = int16(a) - p.Lineno = stmtline - p.From = g2.from - p.To = g2.to - p.Pc = int64(asm.PC) - - if lastpc == nil { - pl = obj.Linknewplist(asm.Ctxt) - pl.Firstpc = p - } else { - - lastpc.Link = p - } - lastpc = p - -out: - if a != obj.AGLOBL && a != obj.ADATA { - asm.PC++ - } -} diff --git a/src/cmd/new8a/y.go b/src/cmd/new8a/y.go deleted file mode 100644 index 82c8a5fb2e..0000000000 --- a/src/cmd/new8a/y.go +++ /dev/null @@ -1,1308 +0,0 @@ -//line a.y:32 -package main - -import __yyfmt__ "fmt" - -//line a.y:32 -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/i386" -) - -//line a.y:41 -type yySymType struct { - yys int - sym *asm.Sym - lval int64 - con2 struct { - v1 int32 - v2 int32 - } - dval float64 - sval string - addr obj.Addr - addr2 Addr2 -} - -const LTYPE0 = 57346 -const LTYPE1 = 57347 -const LTYPE2 = 57348 -const LTYPE3 = 57349 -const LTYPE4 = 57350 -const LTYPEC = 57351 -const LTYPED = 57352 -const LTYPEN = 57353 -const LTYPER = 57354 -const LTYPET = 57355 -const LTYPES = 57356 -const LTYPEM = 57357 -const LTYPEI = 57358 -const LTYPEG = 57359 -const LTYPEXC = 57360 -const LTYPEX = 57361 -const LTYPEPC = 57362 -const LTYPEF = 57363 -const LCONST = 57364 -const LFP = 57365 -const LPC = 57366 -const LSB = 57367 -const LBREG = 57368 -const LLREG = 57369 -const LSREG = 57370 -const LFREG = 57371 -const LXREG = 57372 -const LFCONST = 57373 -const LSCONST = 57374 -const LSP = 57375 -const LNAME = 57376 -const LLAB = 57377 -const LVAR = 57378 - -var yyToknames = []string{ - "'|'", - "'^'", - "'&'", - "'<'", - "'>'", - "'+'", - "'-'", - "'*'", - "'/'", - "'%'", - "LTYPE0", - "LTYPE1", - "LTYPE2", - "LTYPE3", - "LTYPE4", - "LTYPEC", - "LTYPED", - "LTYPEN", - "LTYPER", - "LTYPET", - "LTYPES", - "LTYPEM", - "LTYPEI", - "LTYPEG", - "LTYPEXC", - "LTYPEX", - "LTYPEPC", - "LTYPEF", - "LCONST", - "LFP", - "LPC", - "LSB", - "LBREG", - "LLREG", - "LSREG", - "LFREG", - "LXREG", - "LFCONST", - "LSCONST", - "LSP", - "LNAME", - "LLAB", - "LVAR", -} -var yyStatenames = []string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyMaxDepth = 200 - -//line yacctab:1 -var yyExca = []int{ - -1, 1, - 1, -1, - -2, 2, -} - -const yyNprod = 131 -const yyPrivate = 57344 - -var yyTokenNames []string -var yyStates []string - -const yyLast = 556 - -var yyAct = []int{ - - 50, 226, 120, 40, 48, 3, 268, 207, 62, 79, - 77, 169, 49, 267, 266, 72, 60, 262, 84, 254, - 52, 81, 82, 71, 70, 252, 83, 97, 115, 65, - 80, 240, 109, 99, 238, 109, 91, 93, 95, 236, - 220, 218, 101, 103, 209, 208, 170, 239, 104, 206, - 233, 210, 109, 168, 173, 142, 117, 118, 119, 135, - 108, 116, 112, 110, 125, 63, 248, 56, 55, 78, - 72, 230, 229, 225, 224, 109, 136, 84, 223, 133, - 81, 82, 140, 141, 126, 83, 153, 137, 143, 80, - 53, 152, 150, 149, 42, 44, 47, 43, 45, 139, - 61, 46, 85, 148, 54, 147, 146, 145, 76, 63, - 51, 39, 57, 154, 67, 144, 134, 132, 131, 39, - 124, 36, 34, 175, 176, 30, 222, 31, 33, 32, - 109, 117, 221, 58, 242, 72, 241, 183, 235, 111, - 165, 167, 140, 141, 182, 216, 166, 214, 172, 181, - 250, 251, 191, 193, 195, 215, 109, 109, 109, 109, - 109, 255, 194, 109, 109, 109, 189, 190, 165, 167, - 211, 183, 56, 130, 166, 56, 55, 217, 263, 117, - 256, 247, 37, 151, 196, 197, 198, 199, 200, 228, - 111, 203, 204, 205, 260, 53, 41, 35, 53, 56, - 55, 88, 109, 109, 128, 127, 259, 58, 234, 54, - 73, 227, 54, 237, 253, 129, 87, 57, 74, 212, - 57, 257, 53, 246, 243, 105, 106, 113, 244, 202, - 231, 232, 180, 114, 245, 121, 54, 122, 123, 249, - 122, 123, 74, 174, 57, 184, 185, 186, 187, 188, - 258, 7, 201, 22, 261, 42, 44, 47, 43, 45, - 264, 265, 46, 9, 10, 11, 12, 13, 17, 27, - 18, 14, 28, 19, 20, 21, 29, 23, 24, 25, - 26, 56, 55, 138, 163, 162, 160, 161, 155, 156, - 157, 158, 159, 4, 16, 8, 15, 5, 56, 55, - 6, 107, 56, 55, 53, 157, 158, 159, 42, 44, - 47, 43, 45, 2, 1, 46, 85, 102, 54, 100, - 98, 53, 96, 63, 51, 53, 57, 56, 55, 42, - 44, 47, 43, 45, 94, 54, 46, 58, 92, 54, - 63, 74, 90, 57, 63, 51, 86, 57, 56, 55, - 53, 75, 66, 64, 42, 44, 47, 43, 45, 59, - 68, 46, 58, 213, 54, 0, 0, 0, 89, 0, - 51, 53, 57, 56, 55, 42, 44, 47, 43, 45, - 0, 0, 46, 58, 0, 54, 0, 0, 0, 38, - 0, 51, 0, 57, 56, 55, 53, 0, 0, 0, - 42, 44, 47, 43, 45, 0, 0, 46, 58, 0, - 54, 155, 156, 157, 158, 159, 51, 53, 57, 0, - 0, 42, 44, 47, 43, 45, 0, 0, 46, 56, - 55, 54, 0, 0, 0, 0, 0, 51, 0, 57, - 164, 163, 162, 160, 161, 155, 156, 157, 158, 159, - 56, 55, 53, 0, 56, 55, 0, 56, 55, 0, - 0, 0, 0, 0, 73, 0, 54, 0, 0, 0, - 69, 63, 74, 53, 57, 56, 55, 53, 56, 178, - 53, 0, 219, 0, 0, 56, 55, 54, 0, 171, - 0, 54, 58, 74, 54, 57, 192, 74, 53, 57, - 51, 53, 57, 0, 0, 0, 0, 179, 53, 0, - 177, 0, 54, 0, 0, 54, 0, 0, 74, 0, - 57, 74, 54, 57, 0, 0, 0, 0, 74, 0, - 57, 164, 163, 162, 160, 161, 155, 156, 157, 158, - 159, 162, 160, 161, 155, 156, 157, 158, 159, 160, - 161, 155, 156, 157, 158, 159, -} -var yyPact = []int{ - - -1000, -1000, 249, -1000, 78, -1000, 81, 80, 73, 71, - 339, 293, 293, 364, 420, -1000, -1000, 58, 318, 293, - 293, 293, -1000, 219, 14, 293, 293, 89, 448, 448, - -1000, 476, -1000, -1000, 476, -1000, -1000, -1000, 364, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 10, 190, 9, -1000, -1000, 476, 476, 476, 228, -1000, - 70, -1000, -1000, 163, -1000, 68, -1000, 67, -1000, 166, - -1000, 66, 7, 231, 476, -1000, 272, -1000, 364, -1000, - -1000, -1000, -1000, -1000, 3, 228, -1000, -1000, -1000, 364, - -1000, 65, -1000, 57, -1000, 56, -1000, 55, -1000, 53, - -1000, 43, -1000, 42, 171, 41, 36, 249, 527, -1000, - 527, -1000, 131, 0, -7, 436, 111, -1000, -1000, -1000, - 2, 235, 476, 476, -1000, -1000, -1000, -1000, -1000, 469, - 466, 364, 293, -1000, 166, 137, -1000, -1000, 385, -1000, - -1000, -1000, 103, 2, 364, 364, 364, 364, 364, 293, - 293, 476, 445, 289, -1000, 476, 476, 476, 476, 476, - 245, 221, 476, 476, 476, -4, -8, -9, -1, 476, - -1000, -1000, 208, 112, 231, -1000, -1000, -12, 441, -1000, - -1000, -1000, -1000, -13, 85, 79, -1000, 28, 24, -1000, - -1000, 23, 179, 22, -1000, 21, 294, 294, -1000, -1000, - -1000, 476, 476, 542, 535, 279, -2, 476, -1000, -1000, - 101, -14, 476, -19, -1000, -1000, -1000, -5, -1000, -22, - -1000, 99, 96, 476, 219, 14, -1000, 213, 149, 15, - 14, 402, 402, 113, -28, 203, -1000, -34, -1000, 126, - -1000, -1000, -1000, -1000, -1000, -1000, 148, 211, 179, -1000, - 195, 183, -1000, 476, -1000, -36, -1000, 146, -1000, 476, - 476, -39, -1000, -1000, -40, -47, -1000, -1000, -1000, -} -var yyPgo = []int{ - - 0, 0, 28, 363, 2, 196, 8, 3, 20, 9, - 100, 16, 10, 4, 12, 1, 197, 360, 182, 359, - 353, 352, 351, 346, 342, 338, 334, 322, 320, 319, - 317, 314, 313, 5, 301, 300, 296, 294, 253, -} -var yyR1 = []int{ - - 0, 31, 32, 31, 34, 33, 33, 33, 33, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 35, 35, 16, - 16, 20, 21, 19, 19, 18, 18, 17, 17, 17, - 36, 37, 37, 38, 38, 22, 22, 22, 23, 23, - 24, 24, 25, 25, 26, 26, 26, 27, 28, 29, - 30, 10, 10, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 9, 9, 7, 7, 7, 7, 7, 7, - 6, 6, 6, 6, 6, 6, 6, 15, 15, 15, - 15, 5, 5, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 14, 14, 8, 8, 4, 4, - 4, 3, 3, 3, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, -} -var yyR2 = []int{ - - 0, 0, 0, 3, 0, 4, 1, 2, 2, 3, - 3, 2, 2, 2, 2, 2, 2, 1, 1, 2, - 2, 2, 2, 2, 1, 2, 2, 2, 2, 0, - 1, 3, 3, 2, 1, 2, 1, 2, 1, 3, - 6, 5, 7, 4, 6, 2, 1, 2, 1, 1, - 3, 5, 3, 5, 2, 1, 3, 5, 5, 3, - 3, 1, 1, 1, 1, 2, 2, 1, 1, 1, - 1, 1, 4, 2, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 4, 5, 3, 1, 2, 3, - 4, 1, 1, 1, 4, 4, 6, 9, 9, 3, - 3, 4, 5, 8, 1, 6, 5, 7, 0, 2, - 2, 1, 1, 1, 1, 1, 2, 2, 2, 3, - 1, 3, 3, 3, 3, 3, 4, 4, 3, 3, - 3, -} -var yyChk = []int{ - - -1000, -31, -32, -33, 44, 48, -35, 2, 46, 14, - 15, 16, 17, 18, 22, -36, -37, 19, 21, 24, - 25, 26, -38, 28, 29, 30, 31, 20, 23, 27, - 47, 49, 48, 48, 49, -16, 50, -18, 50, -10, - -7, -5, 36, 39, 37, 40, 43, 38, -13, -14, - -1, 52, -8, 32, 46, 10, 9, 54, 44, -19, - -11, -10, -6, 51, -20, -11, -21, -10, -17, 50, - -9, -6, -1, 44, 52, -22, 50, -12, 11, -9, - -14, -7, -13, -6, -1, 44, -23, -16, -18, 50, - -24, -11, -25, -11, -26, -11, -27, -7, -28, -6, - -29, -11, -30, -11, -8, -5, -5, -34, -2, -1, - -2, -10, 52, 37, 43, -2, 52, -1, -1, -1, - -4, 7, 9, 10, 50, -1, -8, 42, 41, 52, - 10, 50, 50, -9, 50, 52, -4, -12, 11, -8, - -7, -13, 52, -4, 50, 50, 50, 50, 50, 50, - 50, 12, 50, 50, -33, 9, 10, 11, 12, 13, - 7, 8, 6, 5, 4, 37, 43, 38, 53, 11, - 53, 53, 37, 52, 8, -1, -1, 41, 10, 41, - -10, -11, -9, 34, -10, -10, -10, -10, -10, -11, - -11, -1, 51, -1, -6, -1, -2, -2, -2, -2, - -2, 7, 8, -2, -2, -2, 53, 11, 53, 53, - 52, -1, 11, -3, 35, 43, 33, -4, 53, 41, - 53, 47, 47, 50, 50, 50, -15, 32, 10, 50, - 50, -2, -2, 52, -1, 37, 53, -1, 53, 52, - 53, 37, 38, -1, -7, -6, 10, 32, 51, -6, - 37, 38, 53, 11, 53, 35, 32, 10, -15, 11, - 11, -1, 53, 32, -1, -1, 53, 53, 53, -} -var yyDef = []int{ - - 1, -2, 0, 3, 0, 6, 0, 0, 0, 29, - 0, 0, 0, 0, 0, 17, 18, 0, 29, 0, - 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, - 4, 0, 7, 8, 0, 11, 30, 12, 0, 36, - 61, 62, 74, 75, 76, 77, 78, 79, 91, 92, - 93, 0, 104, 114, 115, 0, 0, 0, 108, 13, - 34, 70, 71, 0, 14, 0, 15, 0, 16, 0, - 38, 0, 0, 108, 0, 19, 0, 46, 0, 63, - 64, 67, 68, 69, 93, 108, 20, 48, 49, 30, - 21, 0, 22, 0, 23, 55, 25, 0, 26, 0, - 27, 0, 28, 0, 0, 0, 0, 0, 9, 120, - 10, 35, 0, 0, 0, 0, 0, 116, 117, 118, - 0, 0, 0, 0, 33, 80, 81, 82, 83, 0, - 0, 0, 0, 37, 0, 0, 73, 45, 0, 47, - 65, 66, 0, 73, 0, 0, 54, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, - 100, 119, 0, 0, 108, 109, 110, 0, 0, 86, - 31, 32, 39, 0, 50, 52, 56, 0, 0, 59, - 60, 0, 0, 0, 43, 0, 121, 122, 123, 124, - 125, 0, 0, 128, 129, 130, 94, 0, 95, 101, - 0, 0, 0, 0, 111, 112, 113, 0, 84, 0, - 72, 0, 0, 0, 0, 0, 41, 87, 0, 0, - 0, 126, 127, 0, 0, 0, 102, 0, 106, 0, - 85, 51, 53, 57, 58, 40, 0, 88, 0, 44, - 0, 0, 96, 0, 105, 0, 89, 0, 42, 0, - 0, 0, 107, 90, 0, 0, 103, 97, 98, -} -var yyTok1 = []int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 51, 13, 6, 3, - 52, 53, 11, 9, 50, 10, 3, 12, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 47, 48, - 7, 49, 8, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 3, 54, -} -var yyTok2 = []int{ - - 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, -} -var yyTok3 = []int{ - 0, -} - -//line yaccpar:1 - -/* parser for yacc output */ - -var yyDebug = 0 - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - // 4 is TOKSTART above - if c >= 4 && c-4 < len(yyToknames) { - if yyToknames[c-4] != "" { - return yyToknames[c-4] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yylex1(lex yyLexer, lval *yySymType) int { - c := 0 - char := lex.Lex(lval) - if char <= 0 { - c = yyTok1[0] - goto out - } - if char < len(yyTok1) { - c = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - c = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - c = yyTok3[i+0] - if c == char { - c = yyTok3[i+1] - goto out - } - } - -out: - if c == 0 { - c = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(c), uint(char)) - } - return c -} - -func yyParse(yylex yyLexer) int { - var yyn int - var yylval yySymType - var yyVAL yySymType - yyS := make([]yySymType, yyMaxDepth) - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yychar := -1 - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yychar), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - yyn += yychar - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yychar { /* valid shift */ - yychar = -1 - yyVAL = yylval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yychar < 0 { - yychar = yylex1(yylex, &yylval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yychar { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error("syntax error") - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yychar)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yychar)) - } - if yychar == yyEofCode { - goto ret1 - } - yychar = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 2: - //line a.y:74 - { - stmtline = asm.Lineno - } - case 4: - //line a.y:81 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - if yyS[yypt-1].sym.Type == LLAB && yyS[yypt-1].sym.Value != int64(asm.PC) { - yyerror("redeclaration of %s", yyS[yypt-1].sym.Labelname) - } - yyS[yypt-1].sym.Type = LLAB - yyS[yypt-1].sym.Value = int64(asm.PC) - } - case 9: - //line a.y:96 - { - yyS[yypt-2].sym.Type = LVAR - yyS[yypt-2].sym.Value = yyS[yypt-0].lval - } - case 10: - //line a.y:101 - { - if yyS[yypt-2].sym.Value != int64(yyS[yypt-0].lval) { - yyerror("redeclaration of %s", yyS[yypt-2].sym.Name) - } - yyS[yypt-2].sym.Value = yyS[yypt-0].lval - } - case 11: - //line a.y:107 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 12: - //line a.y:108 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 13: - //line a.y:109 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 14: - //line a.y:110 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 15: - //line a.y:111 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 16: - //line a.y:112 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 19: - //line a.y:115 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 20: - //line a.y:116 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 21: - //line a.y:117 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 22: - //line a.y:118 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 23: - //line a.y:119 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 25: - //line a.y:121 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 26: - //line a.y:122 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 27: - //line a.y:123 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 28: - //line a.y:124 - { - outcode(int(yyS[yypt-1].lval), &yyS[yypt-0].addr2) - } - case 29: - //line a.y:127 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = nullgen - } - case 30: - //line a.y:132 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = nullgen - } - case 31: - //line a.y:139 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 32: - //line a.y:146 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 33: - //line a.y:153 - { - yyVAL.addr2.from = yyS[yypt-1].addr - yyVAL.addr2.to = nullgen - } - case 34: - //line a.y:158 - { - yyVAL.addr2.from = yyS[yypt-0].addr - yyVAL.addr2.to = nullgen - } - case 35: - //line a.y:165 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 36: - //line a.y:170 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 37: - //line a.y:177 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 38: - //line a.y:182 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 39: - //line a.y:187 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 40: - //line a.y:194 - { - outcode(obj.ADATA, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-2].lval - } - } - case 41: - //line a.y:204 - { - asm.Settext(yyS[yypt-3].addr.Sym) - outcode(obj.ATEXT, &Addr2{yyS[yypt-3].addr, yyS[yypt-0].addr}) - } - case 42: - //line a.y:209 - { - asm.Settext(yyS[yypt-5].addr.Sym) - outcode(obj.ATEXT, &Addr2{yyS[yypt-5].addr, yyS[yypt-0].addr}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-3].lval - } - } - case 43: - //line a.y:220 - { - asm.Settext(yyS[yypt-2].addr.Sym) - outcode(obj.AGLOBL, &Addr2{yyS[yypt-2].addr, yyS[yypt-0].addr}) - } - case 44: - //line a.y:225 - { - asm.Settext(yyS[yypt-4].addr.Sym) - outcode(obj.AGLOBL, &Addr2{yyS[yypt-4].addr, yyS[yypt-0].addr}) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyS[yypt-2].lval - } - } - case 45: - //line a.y:237 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 46: - //line a.y:242 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 47: - //line a.y:247 - { - yyVAL.addr2.from = nullgen - yyVAL.addr2.to = yyS[yypt-0].addr - yyVAL.addr2.to.Type = obj.TYPE_INDIR - } - case 48: - yyVAL.addr2 = yyS[yypt-0].addr2 - case 49: - yyVAL.addr2 = yyS[yypt-0].addr2 - case 50: - //line a.y:259 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 51: - //line a.y:264 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - if yyVAL.addr2.from.Index != obj.TYPE_NONE { - yyerror("dp shift with lhs index") - } - yyVAL.addr2.from.Index = int16(yyS[yypt-0].lval) - } - case 52: - //line a.y:275 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 53: - //line a.y:280 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - if yyVAL.addr2.to.Index != obj.TYPE_NONE { - yyerror("dp move with lhs index") - } - yyVAL.addr2.to.Index = int16(yyS[yypt-0].lval) - } - case 54: - //line a.y:291 - { - yyVAL.addr2.from = yyS[yypt-1].addr - yyVAL.addr2.to = nullgen - } - case 55: - //line a.y:296 - { - yyVAL.addr2.from = yyS[yypt-0].addr - yyVAL.addr2.to = nullgen - } - case 56: - //line a.y:301 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 57: - //line a.y:308 - { - yyVAL.addr2.from = yyS[yypt-4].addr - yyVAL.addr2.to = yyS[yypt-2].addr - yyVAL.addr2.to.Offset = yyS[yypt-0].lval - } - case 58: - //line a.y:316 - { - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - if yyS[yypt-4].addr.Type != obj.TYPE_CONST { - yyerror("illegal constant") - } - yyVAL.addr2.to.Offset = yyS[yypt-4].addr.Offset - } - case 59: - //line a.y:327 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST || yyS[yypt-0].addr.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants") - } - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 60: - //line a.y:337 - { - if yyS[yypt-2].addr.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if yyS[yypt-0].addr.Type != obj.TYPE_MEM || (yyS[yypt-0].addr.Name != obj.NAME_EXTERN && yyS[yypt-0].addr.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference") - } - yyVAL.addr2.from = yyS[yypt-2].addr - yyVAL.addr2.to = yyS[yypt-0].addr - } - case 61: - yyVAL.addr = yyS[yypt-0].addr - case 62: - yyVAL.addr = yyS[yypt-0].addr - case 63: - yyVAL.addr = yyS[yypt-0].addr - case 64: - yyVAL.addr = yyS[yypt-0].addr - case 65: - //line a.y:356 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 66: - //line a.y:360 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 67: - yyVAL.addr = yyS[yypt-0].addr - case 68: - yyVAL.addr = yyS[yypt-0].addr - case 69: - yyVAL.addr = yyS[yypt-0].addr - case 70: - yyVAL.addr = yyS[yypt-0].addr - case 71: - yyVAL.addr = yyS[yypt-0].addr - case 72: - //line a.y:373 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyS[yypt-3].lval + int64(asm.PC) - } - case 73: - //line a.y:379 - { - yyS[yypt-1].sym = asm.LabelLookup(yyS[yypt-1].sym) - yyVAL.addr = nullgen - if asm.Pass == 2 && yyS[yypt-1].sym.Type != LLAB { - yyerror("undefined label: %s", yyS[yypt-1].sym.Labelname) - } - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyS[yypt-1].sym.Value + yyS[yypt-0].lval - } - case 74: - //line a.y:391 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 75: - //line a.y:397 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 76: - //line a.y:403 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 77: - //line a.y:409 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 78: - //line a.y:415 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = REG_SP - } - case 79: - //line a.y:421 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyS[yypt-0].lval) - } - case 80: - //line a.y:429 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - yyVAL.addr.Offset = yyS[yypt-0].lval - } - case 81: - //line a.y:435 - { - yyVAL.addr = yyS[yypt-0].addr - yyVAL.addr.Type = obj.TYPE_ADDR - /* - if($2.Type == D_AUTO || $2.Type == D_PARAM) - yyerror("constant cannot be automatic: %s", - $2.Sym.name); - */ - } - case 82: - //line a.y:444 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SCONST - yyVAL.addr.U.Sval = yyS[yypt-0].sval - } - case 83: - //line a.y:450 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyS[yypt-0].dval - } - case 84: - //line a.y:456 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyS[yypt-1].dval - } - case 85: - //line a.y:462 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyS[yypt-1].dval - } - case 86: - //line a.y:468 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyS[yypt-0].dval - } - case 87: - //line a.y:476 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = yyS[yypt-0].lval - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 88: - //line a.y:483 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -yyS[yypt-0].lval - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 89: - //line a.y:490 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = yyS[yypt-2].lval - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 90: - //line a.y:497 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -yyS[yypt-2].lval - yyVAL.addr.U.Argsize = int32(yyS[yypt-0].lval) - } - case 91: - yyVAL.addr = yyS[yypt-0].addr - case 92: - yyVAL.addr = yyS[yypt-0].addr - case 93: - //line a.y:511 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Offset = yyS[yypt-0].lval - } - case 94: - //line a.y:517 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 95: - //line a.y:524 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = REG_SP - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 96: - //line a.y:531 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Offset = yyS[yypt-5].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 97: - //line a.y:540 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Offset = yyS[yypt-8].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 98: - //line a.y:550 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Offset = yyS[yypt-8].lval - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 99: - //line a.y:560 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - } - case 100: - //line a.y:566 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = REG_SP - } - case 101: - //line a.y:572 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-1].lval) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 102: - //line a.y:579 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 103: - //line a.y:587 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyS[yypt-6].lval) - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 104: - //line a.y:598 - { - yyVAL.addr = yyS[yypt-0].addr - } - case 105: - //line a.y:602 - { - yyVAL.addr = yyS[yypt-5].addr - yyVAL.addr.Index = int16(yyS[yypt-3].lval) - yyVAL.addr.Scale = int8(yyS[yypt-1].lval) - checkscale(yyVAL.addr.Scale) - } - case 106: - //line a.y:611 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyS[yypt-1].lval) - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-4].sym.Name, 0) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 107: - //line a.y:619 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = obj.NAME_STATIC - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyS[yypt-6].sym.Name, 1) - yyVAL.addr.Offset = yyS[yypt-3].lval - } - case 108: - //line a.y:628 - { - yyVAL.lval = 0 - } - case 109: - //line a.y:632 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 110: - //line a.y:636 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 111: - yyVAL.lval = yyS[yypt-0].lval - case 112: - //line a.y:643 - { - yyVAL.lval = obj.NAME_AUTO - } - case 113: - yyVAL.lval = yyS[yypt-0].lval - case 114: - yyVAL.lval = yyS[yypt-0].lval - case 115: - //line a.y:651 - { - yyVAL.lval = yyS[yypt-0].sym.Value - } - case 116: - //line a.y:655 - { - yyVAL.lval = -yyS[yypt-0].lval - } - case 117: - //line a.y:659 - { - yyVAL.lval = yyS[yypt-0].lval - } - case 118: - //line a.y:663 - { - yyVAL.lval = ^yyS[yypt-0].lval - } - case 119: - //line a.y:667 - { - yyVAL.lval = yyS[yypt-1].lval - } - case 120: - yyVAL.lval = yyS[yypt-0].lval - case 121: - //line a.y:674 - { - yyVAL.lval = yyS[yypt-2].lval + yyS[yypt-0].lval - } - case 122: - //line a.y:678 - { - yyVAL.lval = yyS[yypt-2].lval - yyS[yypt-0].lval - } - case 123: - //line a.y:682 - { - yyVAL.lval = yyS[yypt-2].lval * yyS[yypt-0].lval - } - case 124: - //line a.y:686 - { - yyVAL.lval = yyS[yypt-2].lval / yyS[yypt-0].lval - } - case 125: - //line a.y:690 - { - yyVAL.lval = yyS[yypt-2].lval % yyS[yypt-0].lval - } - case 126: - //line a.y:694 - { - yyVAL.lval = yyS[yypt-3].lval << uint(yyS[yypt-0].lval) - } - case 127: - //line a.y:698 - { - yyVAL.lval = yyS[yypt-3].lval >> uint(yyS[yypt-0].lval) - } - case 128: - //line a.y:702 - { - yyVAL.lval = yyS[yypt-2].lval & yyS[yypt-0].lval - } - case 129: - //line a.y:706 - { - yyVAL.lval = yyS[yypt-2].lval ^ yyS[yypt-0].lval - } - case 130: - //line a.y:710 - { - yyVAL.lval = yyS[yypt-2].lval | yyS[yypt-0].lval - } - } - goto yystack /* stack new state and value */ -} diff --git a/src/cmd/new8g/cgen.go b/src/cmd/new8g/cgen.go deleted file mode 100644 index 9f736b1745..0000000000 --- a/src/cmd/new8g/cgen.go +++ /dev/null @@ -1,1730 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" - "fmt" -) -import "cmd/internal/gc" - -/* - * reg.c - */ - -/* - * peep.c - */ -func mgen(n *gc.Node, n1 *gc.Node, rg *gc.Node) { - var n2 gc.Node - - n1.Op = gc.OEMPTY - - if n.Addable != 0 { - *n1 = *n - if n1.Op == gc.OREGISTER || n1.Op == gc.OINDREG { - reg[n.Val.U.Reg]++ - } - return - } - - gc.Tempname(n1, n.Type) - cgen(n, n1) - if n.Type.Width <= int64(gc.Widthptr) || gc.Isfloat[n.Type.Etype] != 0 { - n2 = *n1 - regalloc(n1, n.Type, rg) - gmove(&n2, n1) - } -} - -func mfree(n *gc.Node) { - if n.Op == gc.OREGISTER { - regfree(n) - } -} - -/* - * generate: - * res = n; - * simplifies and calls gmove. - * - * TODO: - * sudoaddable - */ -func cgen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var nt gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var a int - - if gc.Debug['g'] != 0 { - gc.Dump("\ncgen-n", n) - gc.Dump("cgen-res", res) - } - - if n == nil || n.Type == nil { - gc.Fatal("cgen: n nil") - } - if res == nil || res.Type == nil { - gc.Fatal("cgen: res nil") - } - - switch n.Op { - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_slice(n, res) - } - return - - case gc.OEFACE: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_eface(n, res) - } - return - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - // function calls on both sides? introduce temporary - if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { - gc.Tempname(&n1, n.Type) - cgen(n, &n1) - cgen(&n1, res) - return - } - - // structs etc get handled specially - if gc.Isfat(n.Type) { - if n.Type.Width < 0 { - gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) - } - sgen(n, res, n.Type.Width) - return - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch n.Op { - case gc.OSPTR, - gc.OLEN: - if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { - n.Addable = n.Left.Addable - } - - case gc.OCAP: - if gc.Isslice(n.Left.Type) { - n.Addable = n.Left.Addable - } - - case gc.OITAB: - n.Addable = n.Left.Addable - } - - // if both are addressable, move - if n.Addable != 0 && res.Addable != 0 { - gmove(n, res) - return - } - - // if both are not addressable, use a temporary. - if n.Addable == 0 && res.Addable == 0 { - // could use regalloc here sometimes, - // but have to check for ullman >= UINF. - gc.Tempname(&n1, n.Type) - - cgen(n, &n1) - cgen(&n1, res) - return - } - - // if result is not addressable directly but n is, - // compute its address and then store via the address. - if res.Addable == 0 { - igen(res, &n1, nil) - cgen(n, &n1) - regfree(&n1) - return - } - - // complex types - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - return - } - - // otherwise, the result is addressable but n is not. - // let's do some computation. - - // use ullman to pick operand to eval first. - nl = n.Left - - nr = n.Right - if nl != nil && nl.Ullman >= gc.UINF { - if nr != nil && nr.Ullman >= gc.UINF { - // both are hard - gc.Tempname(&n1, nl.Type) - - cgen(nl, &n1) - n2 = *n - n2.Left = &n1 - cgen(&n2, res) - return - } - } - - // 64-bit ops are hard on 32-bit machine. - if gc.Is64(n.Type) || gc.Is64(res.Type) || n.Left != nil && gc.Is64(n.Left.Type) { - switch n.Op { - // math goes to cgen64. - case gc.OMINUS, - gc.OCOM, - gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OLROT, - gc.OLSH, - gc.ORSH, - gc.OAND, - gc.OOR, - gc.OXOR: - cgen64(n, res) - - return - } - } - - if nl != nil && gc.Isfloat[n.Type.Etype] != 0 && gc.Isfloat[nl.Type.Etype] != 0 { - cgen_float(n, res) - return - } - - switch n.Op { - default: - gc.Dump("cgen", n) - gc.Fatal("cgen %v", gc.Oconv(int(n.Op), 0)) - - case gc.OREAL, - gc.OIMAG, - gc.OCOMPLEX: - gc.Fatal("unexpected complex") - return - - // these call bgen to get a bool value - case gc.OOROR, - gc.OANDAND, - gc.OEQ, - gc.ONE, - gc.OLT, - gc.OLE, - gc.OGE, - gc.OGT, - gc.ONOT: - p1 = gc.Gbranch(obj.AJMP, nil, 0) - - p2 = gc.Pc - gmove(gc.Nodbool(true), res) - p3 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n, true, 0, p2) - gmove(gc.Nodbool(false), res) - gc.Patch(p3, gc.Pc) - return - - case gc.OPLUS: - cgen(nl, res) - return - - case gc.OMINUS, - gc.OCOM: - a = optoas(int(n.Op), nl.Type) - goto uop - - // symmetric binary - case gc.OAND, - gc.OOR, - gc.OXOR, - gc.OADD, - gc.OMUL: - a = optoas(int(n.Op), nl.Type) - - if a == i386.AIMULB { - cgen_bmul(int(n.Op), nl, nr, res) - break - } - - goto sbop - - // asymmetric binary - case gc.OSUB: - a = optoas(int(n.Op), nl.Type) - - goto abop - - case gc.OHMUL: - cgen_hmul(nl, nr, res) - - case gc.OCONV: - if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { - cgen(nl, res) - break - } - - gc.Tempname(&n2, n.Type) - mgen(nl, &n1, res) - gmove(&n1, &n2) - gmove(&n2, res) - mfree(&n1) - - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res) - - gmove(&n1, res) - regfree(&n1) - - case gc.OITAB: - igen(nl, &n1, res) - n1.Type = gc.Ptrto(gc.Types[gc.TUINTPTR]) - gmove(&n1, res) - regfree(&n1) - - // pointer is the first word of string or slice. - case gc.OSPTR: - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n1, gc.Types[gc.Tptr], res) - p1 = gins(i386.ALEAL, nil, &n1) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - gmove(&n1, res) - regfree(&n1) - break - } - - igen(nl, &n1, res) - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - case gc.OLEN: - if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { - // map has len in the first 32-bit word. - // a zero pointer means zero length - gc.Tempname(&n1, gc.Types[gc.Tptr]) - - cgen(nl, &n1) - regalloc(&n2, gc.Types[gc.Tptr], nil) - gmove(&n1, &n2) - n1 = n2 - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.TINT32] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { - // both slice and string have len one pointer into the struct. - igen(nl, &n1, res) - - n1.Type = gc.Types[gc.TUINT32] - n1.Xoffset += int64(gc.Array_nel) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OCAP: - if gc.Istype(nl.Type, gc.TCHAN) { - // chan has cap in the second 32-bit word. - // a zero pointer means zero length - gc.Tempname(&n1, gc.Types[gc.Tptr]) - - cgen(nl, &n1) - regalloc(&n2, gc.Types[gc.Tptr], nil) - gmove(&n1, &n2) - n1 = n2 - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, -1) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Xoffset = 4 - n2.Type = gc.Types[gc.TINT32] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Isslice(nl.Type) { - igen(nl, &n1, res) - n1.Type = gc.Types[gc.TUINT32] - n1.Xoffset += int64(gc.Array_cap) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OADDR: - agen(nl, res) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - cgen_callret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_callret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_callret(n, res) - - case gc.OMOD, - gc.ODIV: - cgen_div(int(n.Op), nl, nr, res) - - case gc.OLSH, - gc.ORSH, - gc.OLROT: - cgen_shift(int(n.Op), n.Bounded, nl, nr, res) - } - - return - -sbop: // symmetric binary - if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL { - r = nl - nl = nr - nr = r - } - -abop: // asymmetric binary - if gc.Smallintconst(nr) { - mgen(nl, &n1, res) - regalloc(&n2, nl.Type, &n1) - gmove(&n1, &n2) - gins(a, nr, &n2) - gmove(&n2, res) - regfree(&n2) - mfree(&n1) - } else if nl.Ullman >= nr.Ullman { - gc.Tempname(&nt, nl.Type) - cgen(nl, &nt) - mgen(nr, &n2, nil) - regalloc(&n1, nl.Type, res) - gmove(&nt, &n1) - gins(a, &n2, &n1) - gmove(&n1, res) - regfree(&n1) - mfree(&n2) - } else { - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gins(a, &n2, &n1) - regfree(&n2) - gmove(&n1, res) - regfree(&n1) - } - - return - -uop: // unary - gc.Tempname(&n1, nl.Type) - - cgen(nl, &n1) - gins(a, nil, &n1) - gmove(&n1, res) - return -} - -/* - * generate an addressable node in res, containing the value of n. - * n is an array index, and might be any size; res width is <= 32-bit. - * returns Prog* to patch to panic call. - */ -func igenindex(n *gc.Node, res *gc.Node, bounded int) *obj.Prog { - var tmp gc.Node - var lo gc.Node - var hi gc.Node - var zero gc.Node - - if !gc.Is64(n.Type) { - if n.Addable != 0 { - // nothing to do. - *res = *n - } else { - gc.Tempname(res, gc.Types[gc.TUINT32]) - cgen(n, res) - } - - return nil - } - - gc.Tempname(&tmp, gc.Types[gc.TINT64]) - cgen(n, &tmp) - split64(&tmp, &lo, &hi) - gc.Tempname(res, gc.Types[gc.TUINT32]) - gmove(&lo, res) - if bounded != 0 { - splitclean() - return nil - } - - gc.Nodconst(&zero, gc.Types[gc.TINT32], 0) - gins(i386.ACMPL, &hi, &zero) - splitclean() - return gc.Gbranch(i386.AJNE, nil, +1) -} - -/* - * address gen - * res = &n; - * The generated code checks that the result is not nil. - */ -func agen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var tmp gc.Node - var nlen gc.Node - var t *gc.Type - var w uint32 - var v uint64 - var p1 *obj.Prog - var p2 *obj.Prog - var bounded bool - - if gc.Debug['g'] != 0 { - gc.Dump("\nagen-res", res) - gc.Dump("agen-r", n) - } - - if n == nil || n.Type == nil || res == nil || res.Type == nil { - gc.Fatal("agen") - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - gc.Tempname(&n1, n.Type) - - gc.Gvardef(&n1) - clearfat(&n1) - regalloc(&n2, gc.Types[gc.Tptr], res) - gins(i386.ALEAL, &n1, &n2) - gmove(&n2, res) - regfree(&n2) - return - } - - // addressable var is easy - if n.Addable != 0 { - if n.Op == gc.OREGISTER { - gc.Fatal("agen OREGISTER") - } - regalloc(&n1, gc.Types[gc.Tptr], res) - gins(i386.ALEAL, n, &n1) - gmove(&n1, res) - regfree(&n1) - return - } - - // let's compute - nl = n.Left - - nr = n.Right - - switch n.Op { - default: - gc.Fatal("agen %v", gc.Oconv(int(n.Op), 0)) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - cgen_aret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_aret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_aret(n, res) - - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - agen(&n1, res) - - case gc.OEFACE: - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - agen(&n1, res) - - case gc.OINDEX: - p2 = nil // to be patched to panicindex. - w = uint32(n.Type.Width) - bounded = gc.Debug['B'] != 0 || n.Bounded - if nr.Addable != 0 { - // Generate &nl first, and move nr into register. - if !gc.Isconst(nl, gc.CTSTR) { - igen(nl, &n3, res) - } - if !gc.Isconst(nr, gc.CTINT) { - p2 = igenindex(nr, &tmp, bool2int(bounded)) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - } else if nl.Addable != 0 { - // Generate nr first, and move &nl into register. - if !gc.Isconst(nr, gc.CTINT) { - p2 = igenindex(nr, &tmp, bool2int(bounded)) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - - if !gc.Isconst(nl, gc.CTSTR) { - igen(nl, &n3, res) - } - } else { - p2 = igenindex(nr, &tmp, bool2int(bounded)) - nr = &tmp - if !gc.Isconst(nl, gc.CTSTR) { - igen(nl, &n3, res) - } - regalloc(&n1, tmp.Type, nil) - gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) - } - - // For fixed array we really want the pointer in n3. - if gc.Isfixedarray(nl.Type) { - regalloc(&n2, gc.Types[gc.Tptr], &n3) - agen(&n3, &n2) - regfree(&n3) - n3 = n2 - } - - // &a[0] is in n3 (allocated in res) - // i is in n1 (if not constant) - // len(a) is in nlen (if needed) - // w is width - - // constant index - if gc.Isconst(nr, gc.CTINT) { - if gc.Isconst(nl, gc.CTSTR) { - gc.Fatal("constant string constant index") // front end should handle - } - v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - if gc.Debug['B'] == 0 && !n.Bounded { - nlen = n3 - nlen.Type = gc.Types[gc.TUINT32] - nlen.Xoffset += int64(gc.Array_nel) - gc.Nodconst(&n2, gc.Types[gc.TUINT32], int64(v)) - gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &nlen, &n2) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT32]), nil, +1) - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - } - - // Load base pointer in n2 = n3. - regalloc(&n2, gc.Types[gc.Tptr], &n3) - - n3.Type = gc.Types[gc.Tptr] - n3.Xoffset += int64(gc.Array_array) - gmove(&n3, &n2) - regfree(&n3) - if v*uint64(w) != 0 { - gc.Nodconst(&n1, gc.Types[gc.Tptr], int64(v*uint64(w))) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, &n2) - } - - gmove(&n2, res) - regfree(&n2) - break - } - - // i is in register n1, extend to 32 bits. - t = gc.Types[gc.TUINT32] - - if gc.Issigned[n1.Type.Etype] != 0 { - t = gc.Types[gc.TINT32] - } - - regalloc(&n2, t, &n1) // i - gmove(&n1, &n2) - regfree(&n1) - - if gc.Debug['B'] == 0 && !n.Bounded { - // check bounds - t = gc.Types[gc.TUINT32] - - if gc.Isconst(nl, gc.CTSTR) { - gc.Nodconst(&nlen, t, int64(len(nl.Val.U.Sval.S))) - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - nlen = n3 - nlen.Type = t - nlen.Xoffset += int64(gc.Array_nel) - } else { - gc.Nodconst(&nlen, t, nl.Type.Bound) - } - - gins(optoas(gc.OCMP, t), &n2, &nlen) - p1 = gc.Gbranch(optoas(gc.OLT, t), nil, +1) - if p2 != nil { - gc.Patch(p2, gc.Pc) - } - ginscall(gc.Panicindex, -1) - gc.Patch(p1, gc.Pc) - } - - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n3, gc.Types[gc.Tptr], res) - p1 = gins(i386.ALEAL, nil, &n3) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - p1.From.Scale = 1 - p1.From.Index = n2.Val.U.Reg - goto indexdone - } - - // Load base pointer in n3. - regalloc(&tmp, gc.Types[gc.Tptr], &n3) - - if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - n3.Type = gc.Types[gc.Tptr] - n3.Xoffset += int64(gc.Array_array) - gmove(&n3, &tmp) - } - - regfree(&n3) - n3 = tmp - - if w == 0 { - } else // nothing to do - if w == 1 || w == 2 || w == 4 || w == 8 { - // LEAL (n3)(n2*w), n3 - p1 = gins(i386.ALEAL, &n2, &n3) - - p1.From.Scale = int8(w) - p1.From.Type = obj.TYPE_MEM - p1.From.Index = p1.From.Reg - p1.From.Reg = p1.To.Reg - } else { - gc.Nodconst(&tmp, gc.Types[gc.TUINT32], int64(w)) - gins(optoas(gc.OMUL, gc.Types[gc.TUINT32]), &tmp, &n2) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - } - - indexdone: - gmove(&n3, res) - regfree(&n2) - regfree(&n3) - - // should only get here with names in this func. - case gc.ONAME: - if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) - } - - // should only get here for heap vars or paramref - if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME class %#x", n.Class) - } - - cgen(n.Heapaddr, res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) - } - - case gc.OIND: - cgen(nl, res) - gc.Cgen_checknil(res) - - case gc.ODOT: - agen(nl, res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) - } - - case gc.ODOTPTR: - t = nl.Type - if gc.Isptr[t.Etype] == 0 { - gc.Fatal("agen: not ptr %v", gc.Nconv(n, 0)) - } - cgen(nl, res) - gc.Cgen_checknil(res) - if n.Xoffset != 0 { - gc.Nodconst(&n1, gc.Types[gc.Tptr], n.Xoffset) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n1, res) - } - } -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -func igen(n *gc.Node, a *gc.Node, res *gc.Node) { - var fp *gc.Type - var flist gc.Iter - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("\nigen-n", n) - } - - switch n.Op { - case gc.ONAME: - if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { - break - } - *a = *n - return - - // Increase the refcount of the register so that igen's caller - // has to call regfree. - case gc.OINDREG: - if n.Val.U.Reg != i386.REG_SP { - reg[n.Val.U.Reg]++ - } - *a = *n - return - - case gc.ODOT: - igen(n.Left, a, res) - a.Xoffset += n.Xoffset - a.Type = n.Type - return - - case gc.ODOTPTR: - switch n.Left.Op { - // igen-able nodes. - case gc.ODOT, - gc.ODOTPTR, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n.Left, &n1, res) - - regalloc(a, gc.Types[gc.Tptr], &n1) - gmove(&n1, a) - regfree(&n1) - - default: - regalloc(a, gc.Types[gc.Tptr], res) - cgen(n.Left, a) - } - - gc.Cgen_checknil(a) - a.Op = gc.OINDREG - a.Xoffset += n.Xoffset - a.Type = n.Type - return - - case gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - switch n.Op { - case gc.OCALLFUNC: - cgen_call(n, 0) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - - case gc.OCALLINTER: - cgen_callinter(n, nil, 0) - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) - *a = gc.Node{} - a.Op = gc.OINDREG - a.Val.U.Reg = i386.REG_SP - a.Addable = 1 - a.Xoffset = fp.Width - a.Type = n.Type - return - - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - case gc.OINDEX: - if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { - if gc.Isconst(n.Right, gc.CTINT) { - // Compute &a. - if gc.Isptr[n.Left.Type.Etype] == 0 { - igen(n.Left, a, res) - } else { - igen(n.Left, &n1, res) - gc.Cgen_checknil(&n1) - regalloc(a, gc.Types[gc.Tptr], res) - gmove(&n1, a) - regfree(&n1) - a.Op = gc.OINDREG - } - - // Compute &a[i] as &a + i*width. - a.Type = n.Type - - a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width - return - } - } - } - - // release register for now, to avoid - // confusing tempname. - if res != nil && res.Op == gc.OREGISTER { - reg[res.Val.U.Reg]-- - } - gc.Tempname(&n1, gc.Types[gc.Tptr]) - agen(n, &n1) - if res != nil && res.Op == gc.OREGISTER { - reg[res.Val.U.Reg]++ - } - regalloc(a, gc.Types[gc.Tptr], res) - gmove(&n1, a) - a.Op = gc.OINDREG - a.Type = n.Type -} - -/* - * branch gen - * if(n == true) goto to; - */ -func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { - var et int - var a int - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var tmp gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['g'] != 0 { - gc.Dump("\nbgen", n) - } - - if n == nil { - n = gc.Nodbool(true) - } - - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - - if n.Type == nil { - gc.Convlit(&n, gc.Types[gc.TBOOL]) - if n.Type == nil { - return - } - } - - et = int(n.Type.Etype) - if et != gc.TBOOL { - gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) - gc.Patch(gins(obj.AEND, nil, nil), to) - return - } - - for n.Op == gc.OCONVNOP { - n = n.Left - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - } - - nl = n.Left - nr = nil - - if nl != nil && gc.Isfloat[nl.Type.Etype] != 0 { - bgen_float(n, bool2int(true_), likely, to) - return - } - - switch n.Op { - default: - goto def - - // need to ask if it is bool? - case gc.OLITERAL: - if !true_ == (n.Val.U.Bval == 0) { - gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) - } - return - - case gc.ONAME: - if n.Addable == 0 { - goto def - } - gc.Nodconst(&n1, n.Type, 0) - gins(optoas(gc.OCMP, n.Type), n, &n1) - a = i386.AJNE - if !true_ { - a = i386.AJEQ - } - gc.Patch(gc.Gbranch(a, n.Type, likely), to) - return - - case gc.OANDAND, - gc.OOROR: - if (n.Op == gc.OANDAND) == true_ { - p1 = gc.Gbranch(obj.AJMP, nil, 0) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n.Left, !true_, -likely, p2) - bgen(n.Right, !true_, -likely, p2) - p1 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, to) - gc.Patch(p2, gc.Pc) - } else { - bgen(n.Left, true_, likely, to) - bgen(n.Right, true_, likely, to) - } - - return - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - nr = n.Right - if nr == nil || nr.Type == nil { - return - } - fallthrough - - case gc.ONOT: // unary - nl = n.Left - - if nl == nil || nl.Type == nil { - return - } - } - - switch n.Op { - case gc.ONOT: - bgen(nl, !true_, likely, to) - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - a = int(n.Op) - if !true_ { - a = gc.Brcom(a) - true_ = !true_ - } - - // make simplest on right - if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { - a = gc.Brrev(a) - r = nl - nl = nr - nr = r - } - - if gc.Isslice(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal slice comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Xoffset += int64(gc.Array_array) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Isinter(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal interface comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &tmp) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Iscomplex[nl.Type.Etype] != 0 { - gc.Complexbool(a, nl, nr, true_, likely, to) - break - } - - if gc.Is64(nr.Type) { - if nl.Addable == 0 || gc.Isconst(nl, gc.CTINT) { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - nl = &n1 - } - - if nr.Addable == 0 { - gc.Tempname(&n2, nr.Type) - cgen(nr, &n2) - nr = &n2 - } - - cmp64(nl, nr, a, likely, to) - break - } - - if nr.Ullman >= gc.UINF { - if nl.Addable == 0 { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - nl = &n1 - } - - if nr.Addable == 0 { - gc.Tempname(&tmp, nr.Type) - cgen(nr, &tmp) - nr = &tmp - } - - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - nr = &n2 - goto cmp - } - - if nl.Addable == 0 { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - nl = &n1 - } - - if gc.Smallintconst(nr) { - gins(optoas(gc.OCMP, nr.Type), nl, nr) - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - break - } - - if nr.Addable == 0 { - gc.Tempname(&tmp, nr.Type) - cgen(nr, &tmp) - nr = &tmp - } - - regalloc(&n2, nr.Type, nil) - gmove(nr, &n2) - nr = &n2 - - cmp: - gins(optoas(gc.OCMP, nr.Type), nl, nr) - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - - if nl.Op == gc.OREGISTER { - regfree(nl) - } - regfree(nr) - } - - return - -def: - regalloc(&n1, n.Type, nil) - cgen(n, &n1) - gc.Nodconst(&n2, n.Type, 0) - gins(optoas(gc.OCMP, n.Type), &n1, &n2) - a = i386.AJNE - if !true_ { - a = i386.AJEQ - } - gc.Patch(gc.Gbranch(a, n.Type, likely), to) - regfree(&n1) - return -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -func stkof(n *gc.Node) int32 { - var t *gc.Type - var flist gc.Iter - var off int32 - - switch n.Op { - case gc.OINDREG: - return int32(n.Xoffset) - - case gc.ODOT: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - return int32(int64(off) + n.Xoffset) - - case gc.OINDEX: - t = n.Left.Type - if !gc.Isfixedarray(t) { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - if gc.Isconst(n.Right, gc.CTINT) { - return int32(int64(off) + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval)) - } - return 1000 - - case gc.OCALLMETH, - gc.OCALLINTER, - gc.OCALLFUNC: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - t = gc.Structfirst(&flist, gc.Getoutarg(t)) - if t != nil { - return int32(t.Width) - } - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000 -} - -/* - * struct gen - * memmove(&res, &n, w); - */ -func sgen(n *gc.Node, res *gc.Node, w int64) { - var dst gc.Node - var src gc.Node - var tdst gc.Node - var tsrc gc.Node - var cx gc.Node - var c int32 - var q int32 - var odst int32 - var osrc int32 - var l *gc.NodeList - var p *obj.Prog - - if gc.Debug['g'] != 0 { - fmt.Printf("\nsgen w=%d\n", w) - gc.Dump("r", n) - gc.Dump("res", res) - } - - if n.Ullman >= gc.UINF && res.Ullman >= gc.UINF { - gc.Fatal("sgen UINF") - } - - if w < 0 || int64(int32(w)) != w { - gc.Fatal("sgen copy %d", w) - } - - if w == 0 { - // evaluate side effects only. - gc.Tempname(&tdst, gc.Types[gc.Tptr]) - - agen(res, &tdst) - agen(n, &tdst) - return - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if res.Op == gc.ONAME && res.Sym.Name == ".args" { - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - if l.N.Class == gc.PPARAMOUT { - gc.Gvardef(l.N) - } - } - } - - // Avoid taking the address for simple enough types. - if componentgen(n, res) { - return - } - - // offset on the stack - osrc = stkof(n) - - odst = stkof(res) - - if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - gc.Tempname(&tsrc, n.Type) - - sgen(n, &tsrc, w) - sgen(&tsrc, res, w) - return - } - - gc.Nodreg(&dst, gc.Types[gc.Tptr], i386.REG_DI) - gc.Nodreg(&src, gc.Types[gc.Tptr], i386.REG_SI) - - gc.Tempname(&tsrc, gc.Types[gc.Tptr]) - gc.Tempname(&tdst, gc.Types[gc.Tptr]) - if n.Addable == 0 { - agen(n, &tsrc) - } - if res.Addable == 0 { - agen(res, &tdst) - } - if n.Addable != 0 { - agen(n, &src) - } else { - gmove(&tsrc, &src) - } - - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - - if res.Addable != 0 { - agen(res, &dst) - } else { - gmove(&tdst, &dst) - } - - c = int32(w % 4) // bytes - q = int32(w / 4) // doublewords - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - if osrc < odst && int64(odst) < int64(osrc)+w { - // reverse direction - gins(i386.ASTD, nil, nil) // set direction flag - if c > 0 { - gconreg(i386.AADDL, w-1, i386.REG_SI) - gconreg(i386.AADDL, w-1, i386.REG_DI) - - gconreg(i386.AMOVL, int64(c), i386.REG_CX) - gins(i386.AREP, nil, nil) // repeat - gins(i386.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)- - } - - if q > 0 { - if c > 0 { - gconreg(i386.AADDL, -3, i386.REG_SI) - gconreg(i386.AADDL, -3, i386.REG_DI) - } else { - gconreg(i386.AADDL, w-4, i386.REG_SI) - gconreg(i386.AADDL, w-4, i386.REG_DI) - } - - gconreg(i386.AMOVL, int64(q), i386.REG_CX) - gins(i386.AREP, nil, nil) // repeat - gins(i386.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)- - } - - // we leave with the flag clear - gins(i386.ACLD, nil, nil) - } else { - gins(i386.ACLD, nil, nil) // paranoia. TODO(rsc): remove? - - // normal direction - if q > 128 || (q >= 4 && gc.Nacl) { - gconreg(i386.AMOVL, int64(q), i386.REG_CX) - gins(i386.AREP, nil, nil) // repeat - gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+ - } else if q >= 4 { - p = gins(obj.ADUFFCOPY, nil, nil) - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg)) - - // 10 and 128 = magic constants: see ../../runtime/asm_386.s - p.To.Offset = 10 * (128 - int64(q)) - } else if !gc.Nacl && c == 0 { - gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX) - - // We don't need the MOVSL side-effect of updating SI and DI, - // and issuing a sequence of MOVLs directly is faster. - src.Op = gc.OINDREG - - dst.Op = gc.OINDREG - for q > 0 { - gmove(&src, &cx) // MOVL x+(SI),CX - gmove(&cx, &dst) // MOVL CX,x+(DI) - src.Xoffset += 4 - dst.Xoffset += 4 - q-- - } - } else { - for q > 0 { - gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+ - q-- - } - } - - for c > 0 { - gins(i386.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+ - c-- - } - } -} - -func cadable(n *gc.Node) bool { - if n.Addable == 0 { - // dont know how it happens, - // but it does - return false - } - - switch n.Op { - case gc.ONAME: - return true - } - - return false -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -func componentgen(nr *gc.Node, nl *gc.Node) bool { - var nodl gc.Node - var nodr gc.Node - var tmp gc.Node - var t *gc.Type - var freel int - var freer int - var fldcount int64 - var loffset int64 - var roffset int64 - - freel = 0 - freer = 0 - - switch nl.Type.Etype { - default: - goto no - - case gc.TARRAY: - t = nl.Type - - // Slices are ok. - if gc.Isslice(t) { - break - } - - // Small arrays are ok. - if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { - break - } - - goto no - - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - case gc.TSTRUCT: - fldcount = 0 - - for t = nl.Type.Type; t != nil; t = t.Down { - if gc.Isfat(t.Type) { - goto no - } - if t.Etype != gc.TFIELD { - gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) - } - fldcount++ - } - - if fldcount == 0 || fldcount > 4 { - goto no - } - - case gc.TSTRING, - gc.TINTER: - break - } - - nodl = *nl - if !cadable(nl) { - if nr != nil && !cadable(nr) { - goto no - } - igen(nl, &nodl, nil) - freel = 1 - } - - if nr != nil { - nodr = *nr - if !cadable(nr) { - igen(nr, &nodr, nil) - freer = 1 - } - } else { - // When zeroing, prepare a register containing zero. - gc.Nodconst(&tmp, nl.Type, 0) - - regalloc(&nodr, gc.Types[gc.TUINT], nil) - gmove(&tmp, &nodr) - freer = 1 - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { - goto yes - } - - switch nl.Type.Etype { - // componentgen for arrays. - case gc.TARRAY: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - t = nl.Type - if !gc.Isslice(t) { - nodl.Type = t.Type - nodr.Type = nodl.Type - for fldcount = 0; fldcount < t.Bound; fldcount++ { - if nr == nil { - gc.Clearslim(&nodl) - } else { - gmove(&nodr, &nodl) - } - nodl.Xoffset += t.Type.Width - nodr.Xoffset += t.Type.Width - } - - goto yes - } - - // componentgen for slices. - nodl.Xoffset += int64(gc.Array_array) - - nodl.Type = gc.Ptrto(nl.Type.Type) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRING: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TINTER: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRUCT: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - loffset = nodl.Xoffset - roffset = nodr.Xoffset - - // funarg structs may not begin at offset zero. - if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { - loffset -= nl.Type.Type.Width - } - if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { - roffset -= nr.Type.Type.Width - } - - for t = nl.Type.Type; t != nil; t = t.Down { - nodl.Xoffset = loffset + t.Width - nodl.Type = t.Type - - if nr == nil { - gc.Clearslim(&nodl) - } else { - nodr.Xoffset = roffset + t.Width - nodr.Type = nodl.Type - gmove(&nodr, &nodl) - } - } - - goto yes - } - -no: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return false - -yes: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return true -} diff --git a/src/cmd/new8g/cgen64.go b/src/cmd/new8g/cgen64.go deleted file mode 100644 index 1937ae0941..0000000000 --- a/src/cmd/new8g/cgen64.go +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" -) -import "cmd/internal/gc" - -/* - * attempt to generate 64-bit - * res = n - * return 1 on success, 0 if op not handled. - */ -func cgen64(n *gc.Node, res *gc.Node) { - var t1 gc.Node - var t2 gc.Node - var ax gc.Node - var dx gc.Node - var cx gc.Node - var ex gc.Node - var fx gc.Node - var l *gc.Node - var r *gc.Node - var lo1 gc.Node - var lo2 gc.Node - var hi1 gc.Node - var hi2 gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var v uint64 - var lv uint32 - var hv uint32 - - if res.Op != gc.OINDREG && res.Op != gc.ONAME { - gc.Dump("n", n) - gc.Dump("res", res) - gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0)) - } - - switch n.Op { - default: - gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0)) - - case gc.OMINUS: - cgen(n.Left, res) - split64(res, &lo1, &hi1) - gins(i386.ANEGL, nil, &lo1) - gins(i386.AADCL, ncon(0), &hi1) - gins(i386.ANEGL, nil, &hi1) - splitclean() - return - - case gc.OCOM: - cgen(n.Left, res) - split64(res, &lo1, &hi1) - gins(i386.ANOTL, nil, &lo1) - gins(i386.ANOTL, nil, &hi1) - splitclean() - return - - // binary operators. - // common setup below. - case gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OLROT, - gc.OLSH, - gc.ORSH, - gc.OAND, - gc.OOR, - gc.OXOR: - break - } - - l = n.Left - r = n.Right - if l.Addable == 0 { - gc.Tempname(&t1, l.Type) - cgen(l, &t1) - l = &t1 - } - - if r != nil && r.Addable == 0 { - gc.Tempname(&t2, r.Type) - cgen(r, &t2) - r = &t2 - } - - gc.Nodreg(&ax, gc.Types[gc.TINT32], i386.REG_AX) - gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX) - gc.Nodreg(&dx, gc.Types[gc.TINT32], i386.REG_DX) - - // Setup for binary operation. - split64(l, &lo1, &hi1) - - if gc.Is64(r.Type) { - split64(r, &lo2, &hi2) - } - - // Do op. Leave result in DX:AX. - switch n.Op { - // TODO: Constants - case gc.OADD: - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - gins(i386.AADDL, &lo2, &ax) - gins(i386.AADCL, &hi2, &dx) - - // TODO: Constants. - case gc.OSUB: - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - gins(i386.ASUBL, &lo2, &ax) - gins(i386.ASBBL, &hi2, &dx) - - // let's call the next two EX and FX. - case gc.OMUL: - regalloc(&ex, gc.Types[gc.TPTR32], nil) - - regalloc(&fx, gc.Types[gc.TPTR32], nil) - - // load args into DX:AX and EX:CX. - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - gins(i386.AMOVL, &lo2, &cx) - gins(i386.AMOVL, &hi2, &ex) - - // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply. - gins(i386.AMOVL, &dx, &fx) - - gins(i386.AORL, &ex, &fx) - p1 = gc.Gbranch(i386.AJNE, nil, 0) - gins(i386.AMULL, &cx, nil) // implicit &ax - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - - // full 64x64 -> 64, from 32x32 -> 64. - gins(i386.AIMULL, &cx, &dx) - - gins(i386.AMOVL, &ax, &fx) - gins(i386.AIMULL, &ex, &fx) - gins(i386.AADDL, &dx, &fx) - gins(i386.AMOVL, &cx, &dx) - gins(i386.AMULL, &dx, nil) // implicit &ax - gins(i386.AADDL, &fx, &dx) - gc.Patch(p2, gc.Pc) - - regfree(&ex) - regfree(&fx) - - // We only rotate by a constant c in [0,64). - // if c >= 32: - // lo, hi = hi, lo - // c -= 32 - // if c == 0: - // no-op - // else: - // t = hi - // shld hi:lo, c - // shld lo:t, c - case gc.OLROT: - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - - if v >= 32 { - // reverse during load to do the first 32 bits of rotate - v -= 32 - - gins(i386.AMOVL, &lo1, &dx) - gins(i386.AMOVL, &hi1, &ax) - } else { - gins(i386.AMOVL, &lo1, &ax) - gins(i386.AMOVL, &hi1, &dx) - } - - if v == 0 { - } else // done - { - gins(i386.AMOVL, &dx, &cx) - p1 = gins(i386.ASHLL, ncon(uint32(v)), &dx) - p1.From.Index = i386.REG_AX // double-width shift - p1.From.Scale = 0 - p1 = gins(i386.ASHLL, ncon(uint32(v)), &ax) - p1.From.Index = i386.REG_CX // double-width shift - p1.From.Scale = 0 - } - - case gc.OLSH: - if r.Op == gc.OLITERAL { - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - if v >= 64 { - if gc.Is64(r.Type) { - splitclean() - } - splitclean() - split64(res, &lo2, &hi2) - gins(i386.AMOVL, ncon(0), &lo2) - gins(i386.AMOVL, ncon(0), &hi2) - splitclean() - goto out - } - - if v >= 32 { - if gc.Is64(r.Type) { - splitclean() - } - split64(res, &lo2, &hi2) - gmove(&lo1, &hi2) - if v > 32 { - gins(i386.ASHLL, ncon(uint32(v-32)), &hi2) - } - - gins(i386.AMOVL, ncon(0), &lo2) - splitclean() - splitclean() - goto out - } - - // general shift - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - p1 = gins(i386.ASHLL, ncon(uint32(v)), &dx) - p1.From.Index = i386.REG_AX // double-width shift - p1.From.Scale = 0 - gins(i386.ASHLL, ncon(uint32(v)), &ax) - break - } - - // load value into DX:AX. - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - - // load shift value into register. - // if high bits are set, zero value. - p1 = nil - - if gc.Is64(r.Type) { - gins(i386.ACMPL, &hi2, ncon(0)) - p1 = gc.Gbranch(i386.AJNE, nil, +1) - gins(i386.AMOVL, &lo2, &cx) - } else { - cx.Type = gc.Types[gc.TUINT32] - gmove(r, &cx) - } - - // if shift count is >=64, zero value - gins(i386.ACMPL, &cx, ncon(64)) - - p2 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - if p1 != nil { - gc.Patch(p1, gc.Pc) - } - gins(i386.AXORL, &dx, &dx) - gins(i386.AXORL, &ax, &ax) - gc.Patch(p2, gc.Pc) - - // if shift count is >= 32, zero low. - gins(i386.ACMPL, &cx, ncon(32)) - - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - gins(i386.AMOVL, &ax, &dx) - gins(i386.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count - gins(i386.AXORL, &ax, &ax) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - - // general shift - p1 = gins(i386.ASHLL, &cx, &dx) - - p1.From.Index = i386.REG_AX // double-width shift - p1.From.Scale = 0 - gins(i386.ASHLL, &cx, &ax) - gc.Patch(p2, gc.Pc) - - case gc.ORSH: - if r.Op == gc.OLITERAL { - v = uint64(gc.Mpgetfix(r.Val.U.Xval)) - if v >= 64 { - if gc.Is64(r.Type) { - splitclean() - } - splitclean() - split64(res, &lo2, &hi2) - if hi1.Type.Etype == gc.TINT32 { - gmove(&hi1, &lo2) - gins(i386.ASARL, ncon(31), &lo2) - gmove(&hi1, &hi2) - gins(i386.ASARL, ncon(31), &hi2) - } else { - gins(i386.AMOVL, ncon(0), &lo2) - gins(i386.AMOVL, ncon(0), &hi2) - } - - splitclean() - goto out - } - - if v >= 32 { - if gc.Is64(r.Type) { - splitclean() - } - split64(res, &lo2, &hi2) - gmove(&hi1, &lo2) - if v > 32 { - gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2) - } - if hi1.Type.Etype == gc.TINT32 { - gmove(&hi1, &hi2) - gins(i386.ASARL, ncon(31), &hi2) - } else { - gins(i386.AMOVL, ncon(0), &hi2) - } - splitclean() - splitclean() - goto out - } - - // general shift - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - p1 = gins(i386.ASHRL, ncon(uint32(v)), &ax) - p1.From.Index = i386.REG_DX // double-width shift - p1.From.Scale = 0 - gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx) - break - } - - // load value into DX:AX. - gins(i386.AMOVL, &lo1, &ax) - - gins(i386.AMOVL, &hi1, &dx) - - // load shift value into register. - // if high bits are set, zero value. - p1 = nil - - if gc.Is64(r.Type) { - gins(i386.ACMPL, &hi2, ncon(0)) - p1 = gc.Gbranch(i386.AJNE, nil, +1) - gins(i386.AMOVL, &lo2, &cx) - } else { - cx.Type = gc.Types[gc.TUINT32] - gmove(r, &cx) - } - - // if shift count is >=64, zero or sign-extend value - gins(i386.ACMPL, &cx, ncon(64)) - - p2 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - if p1 != nil { - gc.Patch(p1, gc.Pc) - } - if hi1.Type.Etype == gc.TINT32 { - gins(i386.ASARL, ncon(31), &dx) - gins(i386.AMOVL, &dx, &ax) - } else { - gins(i386.AXORL, &dx, &dx) - gins(i386.AXORL, &ax, &ax) - } - - gc.Patch(p2, gc.Pc) - - // if shift count is >= 32, sign-extend hi. - gins(i386.ACMPL, &cx, ncon(32)) - - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - gins(i386.AMOVL, &dx, &ax) - if hi1.Type.Etype == gc.TINT32 { - gins(i386.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count - gins(i386.ASARL, ncon(31), &dx) - } else { - gins(i386.ASHRL, &cx, &ax) - gins(i386.AXORL, &dx, &dx) - } - - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - - // general shift - p1 = gins(i386.ASHRL, &cx, &ax) - - p1.From.Index = i386.REG_DX // double-width shift - p1.From.Scale = 0 - gins(optoas(gc.ORSH, hi1.Type), &cx, &dx) - gc.Patch(p2, gc.Pc) - - // make constant the right side (it usually is anyway). - case gc.OXOR, - gc.OAND, - gc.OOR: - if lo1.Op == gc.OLITERAL { - nswap(&lo1, &lo2) - nswap(&hi1, &hi2) - } - - if lo2.Op == gc.OLITERAL { - // special cases for constants. - lv = uint32(gc.Mpgetfix(lo2.Val.U.Xval)) - - hv = uint32(gc.Mpgetfix(hi2.Val.U.Xval)) - splitclean() // right side - split64(res, &lo2, &hi2) - switch n.Op { - case gc.OXOR: - gmove(&lo1, &lo2) - gmove(&hi1, &hi2) - switch lv { - case 0: - break - - case 0xffffffff: - gins(i386.ANOTL, nil, &lo2) - - default: - gins(i386.AXORL, ncon(lv), &lo2) - } - - switch hv { - case 0: - break - - case 0xffffffff: - gins(i386.ANOTL, nil, &hi2) - - default: - gins(i386.AXORL, ncon(hv), &hi2) - } - - case gc.OAND: - switch lv { - case 0: - gins(i386.AMOVL, ncon(0), &lo2) - - default: - gmove(&lo1, &lo2) - if lv != 0xffffffff { - gins(i386.AANDL, ncon(lv), &lo2) - } - } - - switch hv { - case 0: - gins(i386.AMOVL, ncon(0), &hi2) - - default: - gmove(&hi1, &hi2) - if hv != 0xffffffff { - gins(i386.AANDL, ncon(hv), &hi2) - } - } - - case gc.OOR: - switch lv { - case 0: - gmove(&lo1, &lo2) - - case 0xffffffff: - gins(i386.AMOVL, ncon(0xffffffff), &lo2) - - default: - gmove(&lo1, &lo2) - gins(i386.AORL, ncon(lv), &lo2) - } - - switch hv { - case 0: - gmove(&hi1, &hi2) - - case 0xffffffff: - gins(i386.AMOVL, ncon(0xffffffff), &hi2) - - default: - gmove(&hi1, &hi2) - gins(i386.AORL, ncon(hv), &hi2) - } - } - - splitclean() - splitclean() - goto out - } - - gins(i386.AMOVL, &lo1, &ax) - gins(i386.AMOVL, &hi1, &dx) - gins(optoas(int(n.Op), lo1.Type), &lo2, &ax) - gins(optoas(int(n.Op), lo1.Type), &hi2, &dx) - } - - if gc.Is64(r.Type) { - splitclean() - } - splitclean() - - split64(res, &lo1, &hi1) - gins(i386.AMOVL, &ax, &lo1) - gins(i386.AMOVL, &dx, &hi1) - splitclean() - -out: -} - -/* - * generate comparison of nl, nr, both 64-bit. - * nl is memory; nr is constant or memory. - */ -func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) { - var lo1 gc.Node - var hi1 gc.Node - var lo2 gc.Node - var hi2 gc.Node - var rr gc.Node - var br *obj.Prog - var t *gc.Type - - split64(nl, &lo1, &hi1) - split64(nr, &lo2, &hi2) - - // compare most significant word; - // if they differ, we're done. - t = hi1.Type - - if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { - gins(i386.ACMPL, &hi1, &hi2) - } else { - regalloc(&rr, gc.Types[gc.TINT32], nil) - gins(i386.AMOVL, &hi1, &rr) - gins(i386.ACMPL, &rr, &hi2) - regfree(&rr) - } - - br = nil - switch op { - default: - gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - // cmp hi - // jne L - // cmp lo - // jeq to - // L: - case gc.OEQ: - br = gc.Gbranch(i386.AJNE, nil, -likely) - - // cmp hi - // jne to - // cmp lo - // jne to - case gc.ONE: - gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to) - - // cmp hi - // jgt to - // jlt L - // cmp lo - // jge to (or jgt to) - // L: - case gc.OGE, - gc.OGT: - gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to) - - br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely) - - // cmp hi - // jlt to - // jgt L - // cmp lo - // jle to (or jlt to) - // L: - case gc.OLE, - gc.OLT: - gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to) - - br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely) - } - - // compare least significant word - t = lo1.Type - - if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL { - gins(i386.ACMPL, &lo1, &lo2) - } else { - regalloc(&rr, gc.Types[gc.TINT32], nil) - gins(i386.AMOVL, &lo1, &rr) - gins(i386.ACMPL, &rr, &lo2) - regfree(&rr) - } - - // jump again - gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to) - - // point first branch down here if appropriate - if br != nil { - gc.Patch(br, gc.Pc) - } - - splitclean() - splitclean() -} diff --git a/src/cmd/new8g/galign.go b/src/cmd/new8g/galign.go deleted file mode 100644 index 45ef1302f3..0000000000 --- a/src/cmd/new8g/galign.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" -) -import "cmd/internal/gc" - -var thechar int = '8' - -var thestring string = "386" - -var thelinkarch *obj.LinkArch = &i386.Link386 - -func linkarchinit() { -} - -var MAXWIDTH int64 = (1 << 32) - 1 - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -var typedefs = []gc.Typedef{ - gc.Typedef{"int", gc.TINT, gc.TINT32}, - gc.Typedef{"uint", gc.TUINT, gc.TUINT32}, - gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32}, -} - -func betypeinit() { - gc.Widthptr = 4 - gc.Widthint = 4 - gc.Widthreg = 4 - -} - -func main() { - gc.Thearch.Thechar = thechar - gc.Thearch.Thestring = thestring - gc.Thearch.Thelinkarch = thelinkarch - gc.Thearch.Typedefs = typedefs - gc.Thearch.REGSP = i386.REGSP - gc.Thearch.REGCTXT = i386.REGCTXT - gc.Thearch.MAXWIDTH = MAXWIDTH - gc.Thearch.Anyregalloc = anyregalloc - gc.Thearch.Betypeinit = betypeinit - gc.Thearch.Bgen = bgen - gc.Thearch.Cgen = cgen - gc.Thearch.Cgen_call = cgen_call - gc.Thearch.Cgen_callinter = cgen_callinter - gc.Thearch.Cgen_ret = cgen_ret - gc.Thearch.Clearfat = clearfat - gc.Thearch.Defframe = defframe - gc.Thearch.Excise = excise - gc.Thearch.Expandchecks = expandchecks - gc.Thearch.Gclean = gclean - gc.Thearch.Ginit = ginit - gc.Thearch.Gins = gins - gc.Thearch.Ginscall = ginscall - gc.Thearch.Igen = igen - gc.Thearch.Linkarchinit = linkarchinit - gc.Thearch.Peep = peep - gc.Thearch.Proginfo = proginfo - gc.Thearch.Regalloc = regalloc - gc.Thearch.Regfree = regfree - gc.Thearch.Regtyp = regtyp - gc.Thearch.Sameaddr = sameaddr - gc.Thearch.Smallindir = smallindir - gc.Thearch.Stackaddr = stackaddr - gc.Thearch.Excludedregs = excludedregs - gc.Thearch.RtoB = RtoB - gc.Thearch.FtoB = FtoB - gc.Thearch.BtoR = BtoR - gc.Thearch.BtoF = BtoF - gc.Thearch.Optoas = optoas - gc.Thearch.Doregbits = doregbits - gc.Thearch.Regnames = regnames - - gc.Main() - gc.Exit(0) -} diff --git a/src/cmd/new8g/gg.go b/src/cmd/new8g/gg.go deleted file mode 100644 index 4aeff92952..0000000000 --- a/src/cmd/new8g/gg.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "cmd/internal/obj/i386" -import "cmd/internal/gc" - -// TODO(rsc): -// assume CLD? - -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// foptoas flags -const ( - Frev = 1 << 0 - Fpop = 1 << 1 - Fpop2 = 1 << 2 -) - -var reg [i386.MAXREG]uint8 - -var panicdiv *gc.Node - -/* - * cgen.c - */ - -/* - * list.c - */ diff --git a/src/cmd/new8g/ggen.go b/src/cmd/new8g/ggen.go deleted file mode 100644 index f72beda21a..0000000000 --- a/src/cmd/new8g/ggen.go +++ /dev/null @@ -1,1297 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" -) -import "cmd/internal/gc" - -func defframe(ptxt *obj.Prog) { - var frame uint32 - var ax uint32 - var p *obj.Prog - var lo int64 - var hi int64 - var l *gc.NodeList - var n *gc.Node - - // fill in argument size, stack size - ptxt.To.Type = obj.TYPE_TEXTSIZE - - ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) - frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) - ptxt.To.Offset = int64(frame) - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt - - hi = 0 - lo = hi - ax = 0 - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - n = l.N - if n.Needzero == 0 { - continue - } - if n.Class != gc.PAUTO { - gc.Fatal("needzero class %d", n.Class) - } - if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { - gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) - } - if lo != hi && n.Xoffset+n.Type.Width == lo-int64(2*gc.Widthptr) { - // merge with range we already have - lo = n.Xoffset - - continue - } - - // zero old range - p = zerorange(p, int64(frame), lo, hi, &ax) - - // set new range - hi = n.Xoffset + n.Type.Width - - lo = n.Xoffset - } - - // zero final range - zerorange(p, int64(frame), lo, hi, &ax) -} - -func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog { - var cnt int64 - var i int64 - - cnt = hi - lo - if cnt == 0 { - return p - } - if *ax == 0 { - p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, i386.REG_AX, 0) - *ax = 1 - } - - if cnt <= int64(4*gc.Widthreg) { - for i = 0; i < cnt; i += int64(gc.Widthreg) { - p = appendpp(p, i386.AMOVL, obj.TYPE_REG, i386.REG_AX, 0, obj.TYPE_MEM, i386.REG_SP, frame+lo+i) - } - } else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) { - p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0) - p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg))) - p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) - } else { - p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, i386.REG_CX, 0) - p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0) - p = appendpp(p, i386.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) - p = appendpp(p, i386.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0) - } - - return p -} - -func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { - var q *obj.Prog - q = gc.Ctxt.NewProg() - gc.Clearp(q) - q.As = int16(as) - q.Lineno = p.Lineno - q.From.Type = int16(ftype) - q.From.Reg = int16(freg) - q.From.Offset = foffset - q.To.Type = int16(ttype) - q.To.Reg = int16(treg) - q.To.Offset = toffset - q.Link = p.Link - p.Link = q - return q -} - -func clearfat(nl *gc.Node) { - var w uint32 - var c uint32 - var q uint32 - var n1 gc.Node - var z gc.Node - var p *obj.Prog - - /* clear a fat object */ - if gc.Debug['g'] != 0 { - gc.Dump("\nclearfat", nl) - } - - w = uint32(nl.Type.Width) - - // Avoid taking the address for simple enough types. - if componentgen(nil, nl) { - return - } - - c = w % 4 // bytes - q = w / 4 // quads - - if q < 4 { - // Write sequence of MOV 0, off(base) instead of using STOSL. - // The hope is that although the code will be slightly longer, - // the MOVs will have no dependencies and pipeline better - // than the unrolled STOSL loop. - // NOTE: Must use agen, not igen, so that optimizer sees address - // being taken. We are not writing on field boundaries. - regalloc(&n1, gc.Types[gc.Tptr], nil) - - agen(nl, &n1) - n1.Op = gc.OINDREG - gc.Nodconst(&z, gc.Types[gc.TUINT64], 0) - for { - tmp14 := q - q-- - if tmp14 <= 0 { - break - } - n1.Type = z.Type - gins(i386.AMOVL, &z, &n1) - n1.Xoffset += 4 - } - - gc.Nodconst(&z, gc.Types[gc.TUINT8], 0) - for { - tmp15 := c - c-- - if tmp15 <= 0 { - break - } - n1.Type = z.Type - gins(i386.AMOVB, &z, &n1) - n1.Xoffset++ - } - - regfree(&n1) - return - } - - gc.Nodreg(&n1, gc.Types[gc.Tptr], i386.REG_DI) - agen(nl, &n1) - gconreg(i386.AMOVL, 0, i386.REG_AX) - - if q > 128 || (q >= 4 && gc.Nacl) { - gconreg(i386.AMOVL, int64(q), i386.REG_CX) - gins(i386.AREP, nil, nil) // repeat - gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+ - } else if q >= 4 { - p = gins(obj.ADUFFZERO, nil, nil) - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg)) - - // 1 and 128 = magic constants: see ../../runtime/asm_386.s - p.To.Offset = 1 * (128 - int64(q)) - } else { - for q > 0 { - gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+ - q-- - } - } - - for c > 0 { - gins(i386.ASTOSB, nil, nil) // STOB AL,*(DI)+ - c-- - } -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) -*/ -func ginscall(f *gc.Node, proc int) { - var p *obj.Prog - var reg gc.Node - var r1 gc.Node - var con gc.Node - var stk gc.Node - var extra int32 - - if f.Type != nil { - extra = 0 - if proc == 1 || proc == 2 { - extra = 2 * int32(gc.Widthptr) - } - gc.Setmaxarg(f.Type, extra) - } - - switch proc { - default: - gc.Fatal("ginscall: bad proc %d", proc) - - case 0, // normal call - -1: // normal call but no return - if f.Op == gc.ONAME && f.Class == gc.PFUNC { - if f == gc.Deferreturn { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert an x86 NOP that we will have the right line number. - // x86 NOP 0x90 is really XCHG AX, AX; use that description - // because the NOP pseudo-instruction will be removed by - // the linker. - gc.Nodreg(®, gc.Types[gc.TINT], i386.REG_AX) - - gins(i386.AXCHGL, ®, ®) - } - - p = gins(obj.ACALL, nil, f) - gc.Afunclit(&p.To, f) - if proc == -1 || gc.Noreturn(p) { - gins(obj.AUNDEF, nil, nil) - } - break - } - - gc.Nodreg(®, gc.Types[gc.Tptr], i386.REG_DX) - gc.Nodreg(&r1, gc.Types[gc.Tptr], i386.REG_BX) - gmove(f, ®) - reg.Op = gc.OINDREG - gmove(®, &r1) - reg.Op = gc.OREGISTER - gins(obj.ACALL, ®, &r1) - - case 3: // normal call of c function pointer - gins(obj.ACALL, nil, f) - - case 1, // call in new proc (go) - 2: // deferred call (defer) - stk = gc.Node{} - - stk.Op = gc.OINDREG - stk.Val.U.Reg = i386.REG_SP - stk.Xoffset = 0 - - // size of arguments at 0(SP) - gc.Nodconst(&con, gc.Types[gc.TINT32], int64(gc.Argsize(f.Type))) - - gins(i386.AMOVL, &con, &stk) - - // FuncVal* at 4(SP) - stk.Xoffset = int64(gc.Widthptr) - - gins(i386.AMOVL, f, &stk) - - if proc == 1 { - ginscall(gc.Newproc, 0) - } else { - ginscall(gc.Deferproc, 0) - } - if proc == 2 { - gc.Nodreg(®, gc.Types[gc.TINT32], i386.REG_AX) - gins(i386.ATESTL, ®, ®) - p = gc.Gbranch(i386.AJEQ, nil, +1) - cgen_ret(nil) - gc.Patch(p, gc.Pc) - } - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { - var i *gc.Node - var f *gc.Node - var tmpi gc.Node - var nodi gc.Node - var nodo gc.Node - var nodr gc.Node - var nodsp gc.Node - - i = n.Left - if i.Op != gc.ODOTINTER { - gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) - } - - f = i.Right // field - if f.Op != gc.ONAME { - gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) - } - - i = i.Left // interface - - if i.Addable == 0 { - gc.Tempname(&tmpi, i.Type) - cgen(i, &tmpi) - i = &tmpi - } - - gc.Genlist(n.List) // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res) // REG = &inter - - gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], i386.REG_SP) - - nodsp.Xoffset = 0 - if proc != 0 { - nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn - } - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset += int64(gc.Widthptr) - cgen(&nodi, &nodsp) // {0 or 8}(SP) = 4(REG) -- i.data - - regalloc(&nodo, gc.Types[gc.Tptr], res) - - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset -= int64(gc.Widthptr) - cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab - regfree(&nodi) - - regalloc(&nodr, gc.Types[gc.Tptr], &nodo) - if n.Left.Xoffset == gc.BADWIDTH { - gc.Fatal("cgen_callinter: badwidth") - } - gc.Cgen_checknil(&nodo) - nodo.Op = gc.OINDREG - nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 - - if proc == 0 { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr) // REG = 20+offset(REG) -- i.tab->fun[f] - proc = 3 - } else { - // go/defer. generate go func value. - gins(i386.ALEAL, &nodo, &nodr) // REG = &(20+offset(REG)) -- i.tab->fun[f] - } - - nodr.Type = n.Left.Type - ginscall(&nodr, proc) - - regfree(&nodr) - regfree(&nodo) -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -func cgen_call(n *gc.Node, proc int) { - var t *gc.Type - var nod gc.Node - var afun gc.Node - - if n == nil { - return - } - - if n.Left.Ullman >= gc.UINF { - // if name involves a fn call - // precompute the address of the fn - gc.Tempname(&afun, gc.Types[gc.Tptr]) - - cgen(n.Left, &afun) - } - - gc.Genlist(n.List) // assign the args - t = n.Left.Type - - // call tempname pointer - if n.Left.Ullman >= gc.UINF { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, &afun) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call pointer - if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, n.Left) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call direct - n.Left.Method = 1 - - ginscall(n.Left, proc) -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -func cgen_callret(n *gc.Node, res *gc.Node) { - var nod gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_callret: nil") - } - - nod = gc.Node{} - nod.Op = gc.OINDREG - nod.Val.U.Reg = i386.REG_SP - nod.Addable = 1 - - nod.Xoffset = fp.Width - nod.Type = fp.Type - gc.Cgen_as(res, &nod) -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -func cgen_aret(n *gc.Node, res *gc.Node) { - var nod1 gc.Node - var nod2 gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_aret: nil") - } - - nod1 = gc.Node{} - nod1.Op = gc.OINDREG - nod1.Val.U.Reg = i386.REG_SP - nod1.Addable = 1 - - nod1.Xoffset = fp.Width - nod1.Type = fp.Type - - if res.Op != gc.OREGISTER { - regalloc(&nod2, gc.Types[gc.Tptr], res) - gins(i386.ALEAL, &nod1, &nod2) - gins(i386.AMOVL, &nod2, res) - regfree(&nod2) - } else { - gins(i386.ALEAL, &nod1, res) - } -} - -/* - * generate return. - * n->left is assignments to return values. - */ -func cgen_ret(n *gc.Node) { - var p *obj.Prog - - if n != nil { - gc.Genlist(n.List) // copy out args - } - if gc.Hasdefer != 0 { - ginscall(gc.Deferreturn, 0) - } - gc.Genlist(gc.Curfn.Exit) - p = gins(obj.ARET, nil, nil) - if n != nil && n.Op == gc.ORETJMP { - p.To.Type = obj.TYPE_MEM - p.To.Name = obj.NAME_EXTERN - p.To.Sym = gc.Linksym(n.Left.Sym) - } -} - -/* - * generate division. - * caller must set: - * ax = allocated AX register - * dx = allocated DX register - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node, ax *gc.Node, dx *gc.Node) { - var check int - var n1 gc.Node - var t1 gc.Node - var t2 gc.Node - var t3 gc.Node - var t4 gc.Node - var n4 gc.Node - var nz gc.Node - var t *gc.Type - var t0 *gc.Type - var p1 *obj.Prog - var p2 *obj.Prog - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will trap. - // Also the byte divide instruction needs AH, - // which we otherwise don't have to deal with. - // Easiest way to avoid for int8, int16: use int32. - // For int32 and int64, use explicit test. - // Could use int64 hw for int32. - t = nl.Type - - t0 = t - check = 0 - if gc.Issigned[t.Etype] != 0 { - check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1< 0 && !gc.Samereg(x, res) { - gc.Tempname(oldx, gc.Types[gc.TINT32]) - gmove(x, oldx) - } - - regalloc(x, t, x) -} - -func restx(x *gc.Node, oldx *gc.Node) { - regfree(x) - - if oldx.Op != 0 { - x.Type = gc.Types[gc.TINT32] - gmove(oldx, x) - } -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var ax gc.Node - var dx gc.Node - var oldax gc.Node - var olddx gc.Node - var t *gc.Type - - if gc.Is64(nl.Type) { - gc.Fatal("cgen_div %v", gc.Tconv(nl.Type, 0)) - } - - if gc.Issigned[nl.Type.Etype] != 0 { - t = gc.Types[gc.TINT32] - } else { - t = gc.Types[gc.TUINT32] - } - savex(i386.REG_AX, &ax, &oldax, res, t) - savex(i386.REG_DX, &dx, &olddx, res, t) - dodiv(op, nl, nr, res, &ax, &dx) - restx(&dx, &olddx) - restx(&ax, &oldax) -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var nt gc.Node - var cx gc.Node - var oldcx gc.Node - var hi gc.Node - var lo gc.Node - var a int - var w int - var p1 *obj.Prog - var p2 *obj.Prog - var sc uint64 - - if nl.Type.Width > 4 { - gc.Fatal("cgen_shift %v", gc.Tconv(nl.Type, 0)) - } - - w = int(nl.Type.Width * 8) - - a = optoas(op, nl.Type) - - if nr.Op == gc.OLITERAL { - gc.Tempname(&n2, nl.Type) - cgen(nl, &n2) - regalloc(&n1, nl.Type, res) - gmove(&n2, &n1) - sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if sc >= uint64(nl.Type.Width*8) { - // large shift gets 2 shifts by width-1 - gins(a, ncon(uint32(w)-1), &n1) - - gins(a, ncon(uint32(w)-1), &n1) - } else { - gins(a, nr, &n1) - } - gmove(&n1, res) - regfree(&n1) - return - } - - oldcx = gc.Node{} - gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX) - if reg[i386.REG_CX] > 1 && !gc.Samereg(&cx, res) { - gc.Tempname(&oldcx, gc.Types[gc.TUINT32]) - gmove(&cx, &oldcx) - } - - if nr.Type.Width > 4 { - gc.Tempname(&nt, nr.Type) - n1 = nt - } else { - gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) - regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX - } - - if gc.Samereg(&cx, res) { - regalloc(&n2, nl.Type, nil) - } else { - regalloc(&n2, nl.Type, res) - } - if nl.Ullman >= nr.Ullman { - cgen(nl, &n2) - cgen(nr, &n1) - } else { - cgen(nr, &n1) - cgen(nl, &n2) - } - - // test and fix up large shifts - if bounded { - if nr.Type.Width > 4 { - // delayed reg alloc - gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) - - regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX - split64(&nt, &lo, &hi) - gmove(&lo, &n1) - splitclean() - } - } else { - if nr.Type.Width > 4 { - // delayed reg alloc - gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX) - - regalloc(&n1, gc.Types[gc.TUINT32], &n1) // to hold the shift type in CX - split64(&nt, &lo, &hi) - gmove(&lo, &n1) - gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &hi, ncon(0)) - p2 = gc.Gbranch(optoas(gc.ONE, gc.Types[gc.TUINT32]), nil, +1) - gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n1, ncon(uint32(w))) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - splitclean() - gc.Patch(p2, gc.Pc) - } else { - gins(optoas(gc.OCMP, nr.Type), &n1, ncon(uint32(w))) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1) - } - - if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { - gins(a, ncon(uint32(w)-1), &n2) - } else { - gmove(ncon(0), &n2) - } - - gc.Patch(p1, gc.Pc) - } - - gins(a, &n1, &n2) - - if oldcx.Op != 0 { - gmove(&oldcx, &cx) - } - - gmove(&n2, res) - - regfree(&n1) - regfree(&n2) -} - -/* - * generate byte multiply: - * res = nl * nr - * there is no 2-operand byte multiply instruction so - * we do a full-width multiplication and truncate afterwards. - */ -func cgen_bmul(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var nt gc.Node - var tmp *gc.Node - var t *gc.Type - var a int - - // copy from byte to full registers - t = gc.Types[gc.TUINT32] - - if gc.Issigned[nl.Type.Etype] != 0 { - t = gc.Types[gc.TINT32] - } - - // largest ullman on left. - if nl.Ullman < nr.Ullman { - tmp = nl - nl = nr - nr = tmp - } - - gc.Tempname(&nt, nl.Type) - cgen(nl, &nt) - regalloc(&n1, t, res) - cgen(nr, &n1) - regalloc(&n2, t, nil) - gmove(&nt, &n2) - a = optoas(op, t) - gins(a, &n2, &n1) - regfree(&n2) - gmove(&n1, res) - regfree(&n1) -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { - var t *gc.Type - var a int - var n1 gc.Node - var n2 gc.Node - var ax gc.Node - var dx gc.Node - - t = nl.Type - a = optoas(gc.OHMUL, t) - - // gen nl in n1. - gc.Tempname(&n1, t) - - cgen(nl, &n1) - - // gen nr in n2. - regalloc(&n2, t, res) - - cgen(nr, &n2) - - // multiply. - gc.Nodreg(&ax, t, i386.REG_AX) - - gmove(&n2, &ax) - gins(a, &n1, nil) - regfree(&n2) - - if t.Width == 1 { - // byte multiply behaves differently. - gc.Nodreg(&ax, t, i386.REG_AH) - - gc.Nodreg(&dx, t, i386.REG_DX) - gmove(&ax, &dx) - } - - gc.Nodreg(&dx, t, i386.REG_DX) - gmove(&dx, res) -} - -/* - * generate floating-point operation. - */ -func cgen_float(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var n1 gc.Node - var n2 gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - - nl = n.Left - switch n.Op { - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OLE, - gc.OGE: - p1 = gc.Gbranch(obj.AJMP, nil, 0) - p2 = gc.Pc - gmove(gc.Nodbool(true), res) - p3 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n, true, 0, p2) - gmove(gc.Nodbool(false), res) - gc.Patch(p3, gc.Pc) - return - - case gc.OPLUS: - cgen(nl, res) - return - - case gc.OCONV: - if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) { - cgen(nl, res) - return - } - - gc.Tempname(&n2, n.Type) - mgen(nl, &n1, res) - gmove(&n1, &n2) - gmove(&n2, res) - mfree(&n1) - return - } - - if gc.Use_sse != 0 { - cgen_floatsse(n, res) - } else { - cgen_float387(n, res) - } -} - -// floating-point. 387 (not SSE2) -func cgen_float387(n *gc.Node, res *gc.Node) { - var f0 gc.Node - var f1 gc.Node - var nl *gc.Node - var nr *gc.Node - - nl = n.Left - nr = n.Right - gc.Nodreg(&f0, nl.Type, i386.REG_F0) - gc.Nodreg(&f1, n.Type, i386.REG_F0+1) - if nr != nil { - goto flt2 - } - - // unary - cgen(nl, &f0) - - if n.Op != gc.OCONV && n.Op != gc.OPLUS { - gins(foptoas(int(n.Op), n.Type, 0), nil, nil) - } - gmove(&f0, res) - return - -flt2: // binary - if nl.Ullman >= nr.Ullman { - cgen(nl, &f0) - if nr.Addable != 0 { - gins(foptoas(int(n.Op), n.Type, 0), nr, &f0) - } else { - cgen(nr, &f0) - gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1) - } - } else { - cgen(nr, &f0) - if nl.Addable != 0 { - gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0) - } else { - cgen(nl, &f0) - gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1) - } - } - - gmove(&f0, res) - return -} - -func cgen_floatsse(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var nt gc.Node - var a int - - nl = n.Left - nr = n.Right - switch n.Op { - default: - gc.Dump("cgen_floatsse", n) - gc.Fatal("cgen_floatsse %v", gc.Oconv(int(n.Op), 0)) - return - - case gc.OMINUS, - gc.OCOM: - nr = gc.Nodintconst(-1) - gc.Convlit(&nr, n.Type) - a = foptoas(gc.OMUL, nl.Type, 0) - goto sbop - - // symmetric binary - case gc.OADD, - gc.OMUL: - a = foptoas(int(n.Op), nl.Type, 0) - - goto sbop - - // asymmetric binary - case gc.OSUB, - gc.OMOD, - gc.ODIV: - a = foptoas(int(n.Op), nl.Type, 0) - - goto abop - } - -sbop: // symmetric binary - if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL { - r = nl - nl = nr - nr = r - } - -abop: // asymmetric binary - if nl.Ullman >= nr.Ullman { - gc.Tempname(&nt, nl.Type) - cgen(nl, &nt) - mgen(nr, &n2, nil) - regalloc(&n1, nl.Type, res) - gmove(&nt, &n1) - gins(a, &n2, &n1) - gmove(&n1, res) - regfree(&n1) - mfree(&n2) - } else { - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gins(a, &n2, &n1) - regfree(&n2) - gmove(&n1, res) - regfree(&n1) - } - - return -} - -func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) { - var et int - var a int - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var tmp gc.Node - var t1 gc.Node - var t2 gc.Node - var ax gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - nl = n.Left - nr = n.Right - a = int(n.Op) - if true_ == 0 { - // brcom is not valid on floats when NaN is involved. - p1 = gc.Gbranch(obj.AJMP, nil, 0) - - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - - // No need to avoid re-genning ninit. - bgen_float(n, 1, -likely, p2) - - gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) - gc.Patch(p2, gc.Pc) - return - } - - if gc.Use_sse != 0 { - goto sse - } else { - goto x87 - } - -x87: - a = gc.Brrev(a) // because the args are stacked - if a == gc.OGE || a == gc.OGT { - // only < and <= work right with NaN; reverse if needed - r = nr - - nr = nl - nl = r - a = gc.Brrev(a) - } - - gc.Nodreg(&tmp, nr.Type, i386.REG_F0) - gc.Nodreg(&n2, nr.Type, i386.REG_F0+1) - gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX) - et = gc.Simsimtype(nr.Type) - if et == gc.TFLOAT64 { - if nl.Ullman > nr.Ullman { - cgen(nl, &tmp) - cgen(nr, &tmp) - gins(i386.AFXCHD, &tmp, &n2) - } else { - cgen(nr, &tmp) - cgen(nl, &tmp) - } - - gins(i386.AFUCOMIP, &tmp, &n2) - gins(i386.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF - } else { - // TODO(rsc): The moves back and forth to memory - // here are for truncating the value to 32 bits. - // This handles 32-bit comparison but presumably - // all the other ops have the same problem. - // We need to figure out what the right general - // solution is, besides telling people to use float64. - gc.Tempname(&t1, gc.Types[gc.TFLOAT32]) - - gc.Tempname(&t2, gc.Types[gc.TFLOAT32]) - cgen(nr, &t1) - cgen(nl, &t2) - gmove(&t2, &tmp) - gins(i386.AFCOMFP, &t1, &tmp) - gins(i386.AFSTSW, nil, &ax) - gins(i386.ASAHF, nil, nil) - } - - goto ret - -sse: - if nl.Addable == 0 { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - nl = &n1 - } - - if nr.Addable == 0 { - gc.Tempname(&tmp, nr.Type) - cgen(nr, &tmp) - nr = &tmp - } - - regalloc(&n2, nr.Type, nil) - gmove(nr, &n2) - nr = &n2 - - if nl.Op != gc.OREGISTER { - regalloc(&n3, nl.Type, nil) - gmove(nl, &n3) - nl = &n3 - } - - if a == gc.OGE || a == gc.OGT { - // only < and <= work right with NaN; reverse if needed - r = nr - - nr = nl - nl = r - a = gc.Brrev(a) - } - - gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr) - if nl.Op == gc.OREGISTER { - regfree(nl) - } - regfree(nr) - -ret: - if a == gc.OEQ { - // neither NE nor P - p1 = gc.Gbranch(i386.AJNE, nil, -likely) - - p2 = gc.Gbranch(i386.AJPS, nil, -likely) - gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) - gc.Patch(p1, gc.Pc) - gc.Patch(p2, gc.Pc) - } else if a == gc.ONE { - // either NE or P - gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to) - - gc.Patch(gc.Gbranch(i386.AJPS, nil, likely), to) - } else { - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to) - } -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -func expandchecks(firstp *obj.Prog) { - var p *obj.Prog - var p1 *obj.Prog - var p2 *obj.Prog - - for p = firstp; p != nil; p = p.Link { - if p.As != obj.ACHECKNIL { - continue - } - if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers - gc.Warnl(int(p.Lineno), "generated nil check") - } - - // check is - // CMP arg, $0 - // JNE 2(PC) (likely) - // MOV AX, 0 - p1 = gc.Ctxt.NewProg() - - p2 = gc.Ctxt.NewProg() - gc.Clearp(p1) - gc.Clearp(p2) - p1.Link = p2 - p2.Link = p.Link - p.Link = p1 - p1.Lineno = p.Lineno - p2.Lineno = p.Lineno - p1.Pc = 9999 - p2.Pc = 9999 - p.As = i386.ACMPL - p.To.Type = obj.TYPE_CONST - p.To.Offset = 0 - p1.As = i386.AJNE - p1.From.Type = obj.TYPE_CONST - p1.From.Offset = 1 // likely - p1.To.Type = obj.TYPE_BRANCH - p1.To.U.Branch = p2.Link - - // crash by write to memory address 0. - // if possible, since we know arg is 0, use 0(arg), - // which will be shorter to encode than plain 0. - p2.As = i386.AMOVL - - p2.From.Type = obj.TYPE_REG - p2.From.Reg = i386.REG_AX - if regtyp(&p.From) { - p2.To.Type = obj.TYPE_MEM - p2.To.Reg = p.From.Reg - } else { - p2.To.Type = obj.TYPE_MEM - } - p2.To.Offset = 0 - } -} diff --git a/src/cmd/new8g/gsubr.go b/src/cmd/new8g/gsubr.go deleted file mode 100644 index 2728c2a276..0000000000 --- a/src/cmd/new8g/gsubr.go +++ /dev/null @@ -1,1931 +0,0 @@ -// Derived from Inferno utils/8c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" - "fmt" -) -import "cmd/internal/gc" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 8l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -var unmappedzero uint32 = 4096 - -/* - * return Axxx for Oxxx on type t. - */ -func optoas(op int, t *gc.Type) int { - var a int - - if t == nil { - gc.Fatal("optoas: t is nil") - } - - a = obj.AXXX - switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { - default: - gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - case gc.OADDR<<16 | gc.TPTR32: - a = i386.ALEAL - - case gc.OEQ<<16 | gc.TBOOL, - gc.OEQ<<16 | gc.TINT8, - gc.OEQ<<16 | gc.TUINT8, - gc.OEQ<<16 | gc.TINT16, - gc.OEQ<<16 | gc.TUINT16, - gc.OEQ<<16 | gc.TINT32, - gc.OEQ<<16 | gc.TUINT32, - gc.OEQ<<16 | gc.TINT64, - gc.OEQ<<16 | gc.TUINT64, - gc.OEQ<<16 | gc.TPTR32, - gc.OEQ<<16 | gc.TPTR64, - gc.OEQ<<16 | gc.TFLOAT32, - gc.OEQ<<16 | gc.TFLOAT64: - a = i386.AJEQ - - case gc.ONE<<16 | gc.TBOOL, - gc.ONE<<16 | gc.TINT8, - gc.ONE<<16 | gc.TUINT8, - gc.ONE<<16 | gc.TINT16, - gc.ONE<<16 | gc.TUINT16, - gc.ONE<<16 | gc.TINT32, - gc.ONE<<16 | gc.TUINT32, - gc.ONE<<16 | gc.TINT64, - gc.ONE<<16 | gc.TUINT64, - gc.ONE<<16 | gc.TPTR32, - gc.ONE<<16 | gc.TPTR64, - gc.ONE<<16 | gc.TFLOAT32, - gc.ONE<<16 | gc.TFLOAT64: - a = i386.AJNE - - case gc.OLT<<16 | gc.TINT8, - gc.OLT<<16 | gc.TINT16, - gc.OLT<<16 | gc.TINT32, - gc.OLT<<16 | gc.TINT64: - a = i386.AJLT - - case gc.OLT<<16 | gc.TUINT8, - gc.OLT<<16 | gc.TUINT16, - gc.OLT<<16 | gc.TUINT32, - gc.OLT<<16 | gc.TUINT64: - a = i386.AJCS - - case gc.OLE<<16 | gc.TINT8, - gc.OLE<<16 | gc.TINT16, - gc.OLE<<16 | gc.TINT32, - gc.OLE<<16 | gc.TINT64: - a = i386.AJLE - - case gc.OLE<<16 | gc.TUINT8, - gc.OLE<<16 | gc.TUINT16, - gc.OLE<<16 | gc.TUINT32, - gc.OLE<<16 | gc.TUINT64: - a = i386.AJLS - - case gc.OGT<<16 | gc.TINT8, - gc.OGT<<16 | gc.TINT16, - gc.OGT<<16 | gc.TINT32, - gc.OGT<<16 | gc.TINT64: - a = i386.AJGT - - case gc.OGT<<16 | gc.TUINT8, - gc.OGT<<16 | gc.TUINT16, - gc.OGT<<16 | gc.TUINT32, - gc.OGT<<16 | gc.TUINT64, - gc.OLT<<16 | gc.TFLOAT32, - gc.OLT<<16 | gc.TFLOAT64: - a = i386.AJHI - - case gc.OGE<<16 | gc.TINT8, - gc.OGE<<16 | gc.TINT16, - gc.OGE<<16 | gc.TINT32, - gc.OGE<<16 | gc.TINT64: - a = i386.AJGE - - case gc.OGE<<16 | gc.TUINT8, - gc.OGE<<16 | gc.TUINT16, - gc.OGE<<16 | gc.TUINT32, - gc.OGE<<16 | gc.TUINT64, - gc.OLE<<16 | gc.TFLOAT32, - gc.OLE<<16 | gc.TFLOAT64: - a = i386.AJCC - - case gc.OCMP<<16 | gc.TBOOL, - gc.OCMP<<16 | gc.TINT8, - gc.OCMP<<16 | gc.TUINT8: - a = i386.ACMPB - - case gc.OCMP<<16 | gc.TINT16, - gc.OCMP<<16 | gc.TUINT16: - a = i386.ACMPW - - case gc.OCMP<<16 | gc.TINT32, - gc.OCMP<<16 | gc.TUINT32, - gc.OCMP<<16 | gc.TPTR32: - a = i386.ACMPL - - case gc.OAS<<16 | gc.TBOOL, - gc.OAS<<16 | gc.TINT8, - gc.OAS<<16 | gc.TUINT8: - a = i386.AMOVB - - case gc.OAS<<16 | gc.TINT16, - gc.OAS<<16 | gc.TUINT16: - a = i386.AMOVW - - case gc.OAS<<16 | gc.TINT32, - gc.OAS<<16 | gc.TUINT32, - gc.OAS<<16 | gc.TPTR32: - a = i386.AMOVL - - case gc.OAS<<16 | gc.TFLOAT32: - a = i386.AMOVSS - - case gc.OAS<<16 | gc.TFLOAT64: - a = i386.AMOVSD - - case gc.OADD<<16 | gc.TINT8, - gc.OADD<<16 | gc.TUINT8: - a = i386.AADDB - - case gc.OADD<<16 | gc.TINT16, - gc.OADD<<16 | gc.TUINT16: - a = i386.AADDW - - case gc.OADD<<16 | gc.TINT32, - gc.OADD<<16 | gc.TUINT32, - gc.OADD<<16 | gc.TPTR32: - a = i386.AADDL - - case gc.OSUB<<16 | gc.TINT8, - gc.OSUB<<16 | gc.TUINT8: - a = i386.ASUBB - - case gc.OSUB<<16 | gc.TINT16, - gc.OSUB<<16 | gc.TUINT16: - a = i386.ASUBW - - case gc.OSUB<<16 | gc.TINT32, - gc.OSUB<<16 | gc.TUINT32, - gc.OSUB<<16 | gc.TPTR32: - a = i386.ASUBL - - case gc.OINC<<16 | gc.TINT8, - gc.OINC<<16 | gc.TUINT8: - a = i386.AINCB - - case gc.OINC<<16 | gc.TINT16, - gc.OINC<<16 | gc.TUINT16: - a = i386.AINCW - - case gc.OINC<<16 | gc.TINT32, - gc.OINC<<16 | gc.TUINT32, - gc.OINC<<16 | gc.TPTR32: - a = i386.AINCL - - case gc.ODEC<<16 | gc.TINT8, - gc.ODEC<<16 | gc.TUINT8: - a = i386.ADECB - - case gc.ODEC<<16 | gc.TINT16, - gc.ODEC<<16 | gc.TUINT16: - a = i386.ADECW - - case gc.ODEC<<16 | gc.TINT32, - gc.ODEC<<16 | gc.TUINT32, - gc.ODEC<<16 | gc.TPTR32: - a = i386.ADECL - - case gc.OCOM<<16 | gc.TINT8, - gc.OCOM<<16 | gc.TUINT8: - a = i386.ANOTB - - case gc.OCOM<<16 | gc.TINT16, - gc.OCOM<<16 | gc.TUINT16: - a = i386.ANOTW - - case gc.OCOM<<16 | gc.TINT32, - gc.OCOM<<16 | gc.TUINT32, - gc.OCOM<<16 | gc.TPTR32: - a = i386.ANOTL - - case gc.OMINUS<<16 | gc.TINT8, - gc.OMINUS<<16 | gc.TUINT8: - a = i386.ANEGB - - case gc.OMINUS<<16 | gc.TINT16, - gc.OMINUS<<16 | gc.TUINT16: - a = i386.ANEGW - - case gc.OMINUS<<16 | gc.TINT32, - gc.OMINUS<<16 | gc.TUINT32, - gc.OMINUS<<16 | gc.TPTR32: - a = i386.ANEGL - - case gc.OAND<<16 | gc.TINT8, - gc.OAND<<16 | gc.TUINT8: - a = i386.AANDB - - case gc.OAND<<16 | gc.TINT16, - gc.OAND<<16 | gc.TUINT16: - a = i386.AANDW - - case gc.OAND<<16 | gc.TINT32, - gc.OAND<<16 | gc.TUINT32, - gc.OAND<<16 | gc.TPTR32: - a = i386.AANDL - - case gc.OOR<<16 | gc.TINT8, - gc.OOR<<16 | gc.TUINT8: - a = i386.AORB - - case gc.OOR<<16 | gc.TINT16, - gc.OOR<<16 | gc.TUINT16: - a = i386.AORW - - case gc.OOR<<16 | gc.TINT32, - gc.OOR<<16 | gc.TUINT32, - gc.OOR<<16 | gc.TPTR32: - a = i386.AORL - - case gc.OXOR<<16 | gc.TINT8, - gc.OXOR<<16 | gc.TUINT8: - a = i386.AXORB - - case gc.OXOR<<16 | gc.TINT16, - gc.OXOR<<16 | gc.TUINT16: - a = i386.AXORW - - case gc.OXOR<<16 | gc.TINT32, - gc.OXOR<<16 | gc.TUINT32, - gc.OXOR<<16 | gc.TPTR32: - a = i386.AXORL - - case gc.OLROT<<16 | gc.TINT8, - gc.OLROT<<16 | gc.TUINT8: - a = i386.AROLB - - case gc.OLROT<<16 | gc.TINT16, - gc.OLROT<<16 | gc.TUINT16: - a = i386.AROLW - - case gc.OLROT<<16 | gc.TINT32, - gc.OLROT<<16 | gc.TUINT32, - gc.OLROT<<16 | gc.TPTR32: - a = i386.AROLL - - case gc.OLSH<<16 | gc.TINT8, - gc.OLSH<<16 | gc.TUINT8: - a = i386.ASHLB - - case gc.OLSH<<16 | gc.TINT16, - gc.OLSH<<16 | gc.TUINT16: - a = i386.ASHLW - - case gc.OLSH<<16 | gc.TINT32, - gc.OLSH<<16 | gc.TUINT32, - gc.OLSH<<16 | gc.TPTR32: - a = i386.ASHLL - - case gc.ORSH<<16 | gc.TUINT8: - a = i386.ASHRB - - case gc.ORSH<<16 | gc.TUINT16: - a = i386.ASHRW - - case gc.ORSH<<16 | gc.TUINT32, - gc.ORSH<<16 | gc.TPTR32: - a = i386.ASHRL - - case gc.ORSH<<16 | gc.TINT8: - a = i386.ASARB - - case gc.ORSH<<16 | gc.TINT16: - a = i386.ASARW - - case gc.ORSH<<16 | gc.TINT32: - a = i386.ASARL - - case gc.OHMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TUINT8: - a = i386.AIMULB - - case gc.OHMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TUINT16: - a = i386.AIMULW - - case gc.OHMUL<<16 | gc.TINT32, - gc.OMUL<<16 | gc.TINT32, - gc.OMUL<<16 | gc.TUINT32, - gc.OMUL<<16 | gc.TPTR32: - a = i386.AIMULL - - case gc.OHMUL<<16 | gc.TUINT8: - a = i386.AMULB - - case gc.OHMUL<<16 | gc.TUINT16: - a = i386.AMULW - - case gc.OHMUL<<16 | gc.TUINT32, - gc.OHMUL<<16 | gc.TPTR32: - a = i386.AMULL - - case gc.ODIV<<16 | gc.TINT8, - gc.OMOD<<16 | gc.TINT8: - a = i386.AIDIVB - - case gc.ODIV<<16 | gc.TUINT8, - gc.OMOD<<16 | gc.TUINT8: - a = i386.ADIVB - - case gc.ODIV<<16 | gc.TINT16, - gc.OMOD<<16 | gc.TINT16: - a = i386.AIDIVW - - case gc.ODIV<<16 | gc.TUINT16, - gc.OMOD<<16 | gc.TUINT16: - a = i386.ADIVW - - case gc.ODIV<<16 | gc.TINT32, - gc.OMOD<<16 | gc.TINT32: - a = i386.AIDIVL - - case gc.ODIV<<16 | gc.TUINT32, - gc.ODIV<<16 | gc.TPTR32, - gc.OMOD<<16 | gc.TUINT32, - gc.OMOD<<16 | gc.TPTR32: - a = i386.ADIVL - - case gc.OEXTEND<<16 | gc.TINT16: - a = i386.ACWD - - case gc.OEXTEND<<16 | gc.TINT32: - a = i386.ACDQ - } - - return a -} - -func foptoas(op int, t *gc.Type, flg int) int { - var et int - var a int - - a = obj.AXXX - et = int(gc.Simtype[t.Etype]) - - if gc.Use_sse != 0 { - goto sse - } - - // If we need Fpop, it means we're working on - // two different floating-point registers, not memory. - // There the instruction only has a float64 form. - if flg&Fpop != 0 { - et = gc.TFLOAT64 - } - - // clear Frev if unneeded - switch op { - case gc.OADD, - gc.OMUL: - flg &^= Frev - } - - switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) { - case gc.OADD<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFADDF - - case gc.OADD<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFADDD - - case gc.OADD<<16 | (gc.TFLOAT64<<8 | Fpop): - return i386.AFADDDP - - case gc.OSUB<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFSUBF - - case gc.OSUB<<16 | (gc.TFLOAT32<<8 | Frev): - return i386.AFSUBRF - - case gc.OSUB<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFSUBD - - case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Frev): - return i386.AFSUBRD - - case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Fpop): - return i386.AFSUBDP - - case gc.OSUB<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)): - return i386.AFSUBRDP - - case gc.OMUL<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFMULF - - case gc.OMUL<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFMULD - - case gc.OMUL<<16 | (gc.TFLOAT64<<8 | Fpop): - return i386.AFMULDP - - case gc.ODIV<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFDIVF - - case gc.ODIV<<16 | (gc.TFLOAT32<<8 | Frev): - return i386.AFDIVRF - - case gc.ODIV<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFDIVD - - case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Frev): - return i386.AFDIVRD - - case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Fpop): - return i386.AFDIVDP - - case gc.ODIV<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)): - return i386.AFDIVRDP - - case gc.OCMP<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFCOMF - - case gc.OCMP<<16 | (gc.TFLOAT32<<8 | Fpop): - return i386.AFCOMFP - - case gc.OCMP<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFCOMD - - case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop): - return i386.AFCOMDP - - case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop2): - return i386.AFCOMDPP - - case gc.OMINUS<<16 | (gc.TFLOAT32<<8 | 0): - return i386.AFCHS - - case gc.OMINUS<<16 | (gc.TFLOAT64<<8 | 0): - return i386.AFCHS - } - - gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), gc.Tconv(t, 0), flg) - return 0 - -sse: - switch uint32(op)<<16 | uint32(et) { - default: - gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - case gc.OCMP<<16 | gc.TFLOAT32: - a = i386.AUCOMISS - - case gc.OCMP<<16 | gc.TFLOAT64: - a = i386.AUCOMISD - - case gc.OAS<<16 | gc.TFLOAT32: - a = i386.AMOVSS - - case gc.OAS<<16 | gc.TFLOAT64: - a = i386.AMOVSD - - case gc.OADD<<16 | gc.TFLOAT32: - a = i386.AADDSS - - case gc.OADD<<16 | gc.TFLOAT64: - a = i386.AADDSD - - case gc.OSUB<<16 | gc.TFLOAT32: - a = i386.ASUBSS - - case gc.OSUB<<16 | gc.TFLOAT64: - a = i386.ASUBSD - - case gc.OMUL<<16 | gc.TFLOAT32: - a = i386.AMULSS - - case gc.OMUL<<16 | gc.TFLOAT64: - a = i386.AMULSD - - case gc.ODIV<<16 | gc.TFLOAT32: - a = i386.ADIVSS - - case gc.ODIV<<16 | gc.TFLOAT64: - a = i386.ADIVSD - } - - return a -} - -var resvd = []int{ - // REG_DI, // for movstring - // REG_SI, // for movstring - - i386.REG_AX, // for divide - i386.REG_CX, // for shift - i386.REG_DX, // for divide - i386.REG_SP, // for stack - - i386.REG_BL, // because REG_BX can be allocated - i386.REG_BH, -} - -func ginit() { - var i int - - for i = 0; i < len(reg); i++ { - reg[i] = 1 - } - for i = i386.REG_AX; i <= i386.REG_DI; i++ { - reg[i] = 0 - } - for i = i386.REG_X0; i <= i386.REG_X7; i++ { - reg[i] = 0 - } - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]++ - } -} - -var regpc [i386.MAXREG]uint32 - -func gclean() { - var i int - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]]-- - } - - for i = i386.REG_AX; i <= i386.REG_DI; i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated at %x", gc.Ctxt.Rconv(i), regpc[i]) - } - } - for i = i386.REG_X0; i <= i386.REG_X7; i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated\n", gc.Ctxt.Rconv(i)) - } - } -} - -func anyregalloc() bool { - var i int - var j int - - for i = i386.REG_AX; i <= i386.REG_DI; i++ { - if reg[i] == 0 { - goto ok - } - for j = 0; j < len(resvd); j++ { - if resvd[j] == i { - goto ok - } - } - return true - ok: - } - - for i = i386.REG_X0; i <= i386.REG_X7; i++ { - if reg[i] != 0 { - return true - } - } - return false -} - -/* - * allocate register of type t, leave in n. - * if o != N, o is desired fixed register. - * caller must regfree(n). - */ -func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { - var i int - var et int - - if t == nil { - gc.Fatal("regalloc: t nil") - } - et = int(gc.Simtype[t.Etype]) - - switch et { - case gc.TINT64, - gc.TUINT64: - gc.Fatal("regalloc64") - - case gc.TINT8, - gc.TUINT8, - gc.TINT16, - gc.TUINT16, - gc.TINT32, - gc.TUINT32, - gc.TPTR32, - gc.TPTR64, - gc.TBOOL: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= i386.REG_AX && i <= i386.REG_DI { - goto out - } - } - - for i = i386.REG_AX; i <= i386.REG_DI; i++ { - if reg[i] == 0 { - goto out - } - } - - fmt.Printf("registers allocated at\n") - for i = i386.REG_AX; i <= i386.REG_DI; i++ { - fmt.Printf("\t%v\t%#x\n", gc.Ctxt.Rconv(i), regpc[i]) - } - gc.Fatal("out of fixed registers") - goto err - - case gc.TFLOAT32, - gc.TFLOAT64: - if gc.Use_sse == 0 { - i = i386.REG_F0 - goto out - } - - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= i386.REG_X0 && i <= i386.REG_X7 { - goto out - } - } - - for i = i386.REG_X0; i <= i386.REG_X7; i++ { - if reg[i] == 0 { - goto out - } - } - fmt.Printf("registers allocated at\n") - for i = i386.REG_X0; i <= i386.REG_X7; i++ { - fmt.Printf("\t%v\t%#x\n", gc.Ctxt.Rconv(i), regpc[i]) - } - gc.Fatal("out of floating registers") - } - - gc.Yyerror("regalloc: unknown type %v", gc.Tconv(t, 0)) - -err: - gc.Nodreg(n, t, 0) - return - -out: - if i == i386.REG_SP { - fmt.Printf("alloc SP\n") - } - if reg[i] == 0 { - regpc[i] = uint32(obj.Getcallerpc(&n)) - if i == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.REG_SP { - gc.Dump("regalloc-o", o) - gc.Fatal("regalloc %v", gc.Ctxt.Rconv(i)) - } - } - - reg[i]++ - gc.Nodreg(n, t, i) -} - -func regfree(n *gc.Node) { - var i int - - if n.Op == gc.ONAME { - return - } - if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { - gc.Fatal("regfree: not a register") - } - i = int(n.Val.U.Reg) - if i == i386.REG_SP { - return - } - if i < 0 || i >= len(reg) { - gc.Fatal("regfree: reg out of range") - } - if reg[i] <= 0 { - gc.Fatal("regfree: reg not allocated") - } - reg[i]-- - if reg[i] == 0 && (i == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.REG_SP) { - gc.Fatal("regfree %v", gc.Ctxt.Rconv(i)) - } -} - -/* - * generate - * as $c, reg - */ -func gconreg(as int, c int64, reg int) { - var n1 gc.Node - var n2 gc.Node - - gc.Nodconst(&n1, gc.Types[gc.TINT64], c) - gc.Nodreg(&n2, gc.Types[gc.TINT64], reg) - gins(as, &n1, &n2) -} - -/* - * swap node contents - */ -func nswap(a *gc.Node, b *gc.Node) { - var t gc.Node - - t = *a - *a = *b - *b = t -} - -/* - * return constant i node. - * overwritten by next call, but useful in calls to gins. - */ - -var ncon_n gc.Node - -func ncon(i uint32) *gc.Node { - if ncon_n.Type == nil { - gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0) - } - gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i)) - return &ncon_n -} - -var sclean [10]gc.Node - -var nsclean int - -/* - * n is a 64-bit value. fill in lo and hi to refer to its 32-bit halves. - */ -func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) { - var n1 gc.Node - var i int64 - - if !gc.Is64(n.Type) { - gc.Fatal("split64 %v", gc.Tconv(n.Type, 0)) - } - - if nsclean >= len(sclean) { - gc.Fatal("split64 clean") - } - sclean[nsclean].Op = gc.OEMPTY - nsclean++ - switch n.Op { - default: - switch n.Op { - default: - if !dotaddable(n, &n1) { - igen(n, &n1, nil) - sclean[nsclean-1] = n1 - } - - n = &n1 - - case gc.ONAME: - if n.Class == gc.PPARAMREF { - cgen(n.Heapaddr, &n1) - sclean[nsclean-1] = n1 - n = &n1 - } - - // nothing - case gc.OINDREG: - break - } - - *lo = *n - *hi = *n - lo.Type = gc.Types[gc.TUINT32] - if n.Type.Etype == gc.TINT64 { - hi.Type = gc.Types[gc.TINT32] - } else { - hi.Type = gc.Types[gc.TUINT32] - } - hi.Xoffset += 4 - - case gc.OLITERAL: - gc.Convconst(&n1, n.Type, &n.Val) - i = gc.Mpgetfix(n1.Val.U.Xval) - gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i))) - i >>= 32 - if n.Type.Etype == gc.TINT64 { - gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i))) - } else { - gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i))) - } - } -} - -func splitclean() { - if nsclean <= 0 { - gc.Fatal("splitclean") - } - nsclean-- - if sclean[nsclean].Op != gc.OEMPTY { - regfree(&sclean[nsclean]) - } -} - -/* - * set up nodes representing fp constants - */ -var zerof gc.Node - -var two64f gc.Node - -var two63f gc.Node - -var bignodes_did int - -func bignodes() { - if bignodes_did != 0 { - return - } - bignodes_did = 1 - - two64f = *ncon(0) - two64f.Type = gc.Types[gc.TFLOAT64] - two64f.Val.Ctype = gc.CTFLT - two64f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two64f.Val.U.Fval, 18446744073709551616.) - - two63f = two64f - two63f.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(two63f.Val.U.Fval, 9223372036854775808.) - - zerof = two64f - zerof.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovecflt(zerof.Val.U.Fval, 0) -} - -func memname(n *gc.Node, t *gc.Type) { - gc.Tempname(n, t) - n.Sym = gc.Lookup("." + n.Sym.Name[1:]) // keep optimizer from registerizing - n.Orig.Sym = n.Sym -} - -func gmove(f *gc.Node, t *gc.Node) { - var a int - var ft int - var tt int - var cvt *gc.Type - var r1 gc.Node - var r2 gc.Node - var flo gc.Node - var fhi gc.Node - var tlo gc.Node - var thi gc.Node - var con gc.Node - - if gc.Debug['M'] != 0 { - fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, 0), gc.Nconv(t, 0)) - } - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { - gc.Complexmove(f, t) - return - } - - if gc.Isfloat[ft] != 0 || gc.Isfloat[tt] != 0 { - floatmove(f, t) - return - } - - // cannot have two integer memory operands; - // except 64-bit, which always copies via registers anyway. - if gc.Isint[ft] != 0 && gc.Isint[tt] != 0 && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - - // convert constant to desired type - if f.Op == gc.OLITERAL { - gc.Convconst(&con, t.Type, &f.Val) - f = &con - ft = gc.Simsimtype(con.Type) - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch uint32(ft)<<16 | uint32(tt) { - default: - goto fatal - - /* - * integer copy and truncate - */ - case gc.TINT8<<16 | gc.TINT8, // same size - gc.TINT8<<16 | gc.TUINT8, - gc.TUINT8<<16 | gc.TINT8, - gc.TUINT8<<16 | gc.TUINT8: - a = i386.AMOVB - - case gc.TINT16<<16 | gc.TINT8, // truncate - gc.TUINT16<<16 | gc.TINT8, - gc.TINT32<<16 | gc.TINT8, - gc.TUINT32<<16 | gc.TINT8, - gc.TINT16<<16 | gc.TUINT8, - gc.TUINT16<<16 | gc.TUINT8, - gc.TINT32<<16 | gc.TUINT8, - gc.TUINT32<<16 | gc.TUINT8: - a = i386.AMOVB - - goto rsrc - - case gc.TINT64<<16 | gc.TINT8, // truncate low word - gc.TUINT64<<16 | gc.TINT8, - gc.TINT64<<16 | gc.TUINT8, - gc.TUINT64<<16 | gc.TUINT8: - split64(f, &flo, &fhi) - - gc.Nodreg(&r1, t.Type, i386.REG_AX) - gmove(&flo, &r1) - gins(i386.AMOVB, &r1, t) - splitclean() - return - - case gc.TINT16<<16 | gc.TINT16, // same size - gc.TINT16<<16 | gc.TUINT16, - gc.TUINT16<<16 | gc.TINT16, - gc.TUINT16<<16 | gc.TUINT16: - a = i386.AMOVW - - case gc.TINT32<<16 | gc.TINT16, // truncate - gc.TUINT32<<16 | gc.TINT16, - gc.TINT32<<16 | gc.TUINT16, - gc.TUINT32<<16 | gc.TUINT16: - a = i386.AMOVW - - goto rsrc - - case gc.TINT64<<16 | gc.TINT16, // truncate low word - gc.TUINT64<<16 | gc.TINT16, - gc.TINT64<<16 | gc.TUINT16, - gc.TUINT64<<16 | gc.TUINT16: - split64(f, &flo, &fhi) - - gc.Nodreg(&r1, t.Type, i386.REG_AX) - gmove(&flo, &r1) - gins(i386.AMOVW, &r1, t) - splitclean() - return - - case gc.TINT32<<16 | gc.TINT32, // same size - gc.TINT32<<16 | gc.TUINT32, - gc.TUINT32<<16 | gc.TINT32, - gc.TUINT32<<16 | gc.TUINT32: - a = i386.AMOVL - - case gc.TINT64<<16 | gc.TINT32, // truncate - gc.TUINT64<<16 | gc.TINT32, - gc.TINT64<<16 | gc.TUINT32, - gc.TUINT64<<16 | gc.TUINT32: - split64(f, &flo, &fhi) - - gc.Nodreg(&r1, t.Type, i386.REG_AX) - gmove(&flo, &r1) - gins(i386.AMOVL, &r1, t) - splitclean() - return - - case gc.TINT64<<16 | gc.TINT64, // same size - gc.TINT64<<16 | gc.TUINT64, - gc.TUINT64<<16 | gc.TINT64, - gc.TUINT64<<16 | gc.TUINT64: - split64(f, &flo, &fhi) - - split64(t, &tlo, &thi) - if f.Op == gc.OLITERAL { - gins(i386.AMOVL, &flo, &tlo) - gins(i386.AMOVL, &fhi, &thi) - } else { - gc.Nodreg(&r1, gc.Types[gc.TUINT32], i386.REG_AX) - gc.Nodreg(&r2, gc.Types[gc.TUINT32], i386.REG_DX) - gins(i386.AMOVL, &flo, &r1) - gins(i386.AMOVL, &fhi, &r2) - gins(i386.AMOVL, &r1, &tlo) - gins(i386.AMOVL, &r2, &thi) - } - - splitclean() - splitclean() - return - - /* - * integer up-conversions - */ - case gc.TINT8<<16 | gc.TINT16, // sign extend int8 - gc.TINT8<<16 | gc.TUINT16: - a = i386.AMOVBWSX - - goto rdst - - case gc.TINT8<<16 | gc.TINT32, - gc.TINT8<<16 | gc.TUINT32: - a = i386.AMOVBLSX - goto rdst - - case gc.TINT8<<16 | gc.TINT64, // convert via int32 - gc.TINT8<<16 | gc.TUINT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 - gc.TUINT8<<16 | gc.TUINT16: - a = i386.AMOVBWZX - - goto rdst - - case gc.TUINT8<<16 | gc.TINT32, - gc.TUINT8<<16 | gc.TUINT32: - a = i386.AMOVBLZX - goto rdst - - case gc.TUINT8<<16 | gc.TINT64, // convert via uint32 - gc.TUINT8<<16 | gc.TUINT64: - cvt = gc.Types[gc.TUINT32] - - goto hard - - case gc.TINT16<<16 | gc.TINT32, // sign extend int16 - gc.TINT16<<16 | gc.TUINT32: - a = i386.AMOVWLSX - - goto rdst - - case gc.TINT16<<16 | gc.TINT64, // convert via int32 - gc.TINT16<<16 | gc.TUINT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 - gc.TUINT16<<16 | gc.TUINT32: - a = i386.AMOVWLZX - - goto rdst - - case gc.TUINT16<<16 | gc.TINT64, // convert via uint32 - gc.TUINT16<<16 | gc.TUINT64: - cvt = gc.Types[gc.TUINT32] - - goto hard - - case gc.TINT32<<16 | gc.TINT64, // sign extend int32 - gc.TINT32<<16 | gc.TUINT64: - split64(t, &tlo, &thi) - - gc.Nodreg(&flo, tlo.Type, i386.REG_AX) - gc.Nodreg(&fhi, thi.Type, i386.REG_DX) - gmove(f, &flo) - gins(i386.ACDQ, nil, nil) - gins(i386.AMOVL, &flo, &tlo) - gins(i386.AMOVL, &fhi, &thi) - splitclean() - return - - case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 - gc.TUINT32<<16 | gc.TUINT64: - split64(t, &tlo, &thi) - - gmove(f, &tlo) - gins(i386.AMOVL, ncon(0), &thi) - splitclean() - return - } - - gins(a, f, t) - return - - // requires register source -rsrc: - regalloc(&r1, f.Type, t) - - gmove(f, &r1) - gins(a, &r1, t) - regfree(&r1) - return - - // requires register destination -rdst: - regalloc(&r1, t.Type, t) - - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // should not happen -fatal: - gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) -} - -func floatmove(f *gc.Node, t *gc.Node) { - var r1 gc.Node - var r2 gc.Node - var t1 gc.Node - var t2 gc.Node - var tlo gc.Node - var thi gc.Node - var con gc.Node - var f0 gc.Node - var f1 gc.Node - var ax gc.Node - var dx gc.Node - var cx gc.Node - var cvt *gc.Type - var ft int - var tt int - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - // cannot have two floating point memory operands. - if gc.Isfloat[ft] != 0 && gc.Isfloat[tt] != 0 && gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - - // convert constant to desired type - if f.Op == gc.OLITERAL { - gc.Convconst(&con, t.Type, &f.Val) - f = &con - ft = gc.Simsimtype(con.Type) - - // some constants can't move directly to memory. - if gc.Ismem(t) { - // float constants come from memory. - if gc.Isfloat[tt] != 0 { - goto hard - } - } - } - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch uint32(ft)<<16 | uint32(tt) { - default: - if gc.Use_sse != 0 { - floatmove_sse(f, t) - } else { - floatmove_387(f, t) - } - return - - // float to very long integer. - case gc.TFLOAT32<<16 | gc.TINT64, - gc.TFLOAT64<<16 | gc.TINT64: - if f.Op == gc.OREGISTER { - cvt = f.Type - goto hardmem - } - - gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0) - if ft == gc.TFLOAT32 { - gins(i386.AFMOVF, f, &r1) - } else { - gins(i386.AFMOVD, f, &r1) - } - - // set round to zero mode during conversion - memname(&t1, gc.Types[gc.TUINT16]) - - memname(&t2, gc.Types[gc.TUINT16]) - gins(i386.AFSTCW, nil, &t1) - gins(i386.AMOVW, ncon(0xf7f), &t2) - gins(i386.AFLDCW, &t2, nil) - if tt == gc.TINT16 { - gins(i386.AFMOVWP, &r1, t) - } else if tt == gc.TINT32 { - gins(i386.AFMOVLP, &r1, t) - } else { - gins(i386.AFMOVVP, &r1, t) - } - gins(i386.AFLDCW, &t1, nil) - return - - case gc.TFLOAT32<<16 | gc.TUINT64, - gc.TFLOAT64<<16 | gc.TUINT64: - if !gc.Ismem(f) { - cvt = f.Type - goto hardmem - } - - bignodes() - gc.Nodreg(&f0, gc.Types[ft], i386.REG_F0) - gc.Nodreg(&f1, gc.Types[ft], i386.REG_F0+1) - gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX) - - if ft == gc.TFLOAT32 { - gins(i386.AFMOVF, f, &f0) - } else { - gins(i386.AFMOVD, f, &f0) - } - - // if 0 > v { answer = 0 } - gins(i386.AFMOVD, &zerof, &f0) - - gins(i386.AFUCOMIP, &f0, &f1) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0) - - // if 1<<64 <= v { answer = 0 too } - gins(i386.AFMOVD, &two64f, &f0) - - gins(i386.AFUCOMIP, &f0, &f1) - p2 = gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0) - gc.Patch(p1, gc.Pc) - gins(i386.AFMOVVP, &f0, t) // don't care about t, but will pop the stack - split64(t, &tlo, &thi) - gins(i386.AMOVL, ncon(0), &tlo) - gins(i386.AMOVL, ncon(0), &thi) - splitclean() - p1 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p2, gc.Pc) - - // in range; algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - - // set round to zero mode during conversion - memname(&t1, gc.Types[gc.TUINT16]) - - memname(&t2, gc.Types[gc.TUINT16]) - gins(i386.AFSTCW, nil, &t1) - gins(i386.AMOVW, ncon(0xf7f), &t2) - gins(i386.AFLDCW, &t2, nil) - - // actual work - gins(i386.AFMOVD, &two63f, &f0) - - gins(i386.AFUCOMIP, &f0, &f1) - p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0) - gins(i386.AFMOVVP, &f0, t) - p3 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p2, gc.Pc) - gins(i386.AFMOVD, &two63f, &f0) - gins(i386.AFSUBDP, &f0, &f1) - gins(i386.AFMOVVP, &f0, t) - split64(t, &tlo, &thi) - gins(i386.AXORL, ncon(0x80000000), &thi) // + 2^63 - gc.Patch(p3, gc.Pc) - splitclean() - - // restore rounding mode - gins(i386.AFLDCW, &t1, nil) - - gc.Patch(p1, gc.Pc) - return - - /* - * integer to float - */ - case gc.TINT64<<16 | gc.TFLOAT32, - gc.TINT64<<16 | gc.TFLOAT64: - if t.Op == gc.OREGISTER { - goto hardmem - } - gc.Nodreg(&f0, t.Type, i386.REG_F0) - gins(i386.AFMOVV, f, &f0) - if tt == gc.TFLOAT32 { - gins(i386.AFMOVFP, &f0, t) - } else { - gins(i386.AFMOVDP, &f0, t) - } - return - - // algorithm is: - // if small enough, use native int64 -> float64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - case gc.TUINT64<<16 | gc.TFLOAT32, - gc.TUINT64<<16 | gc.TFLOAT64: - gc.Nodreg(&ax, gc.Types[gc.TUINT32], i386.REG_AX) - - gc.Nodreg(&dx, gc.Types[gc.TUINT32], i386.REG_DX) - gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX) - gc.Tempname(&t1, f.Type) - split64(&t1, &tlo, &thi) - gmove(f, &t1) - gins(i386.ACMPL, &thi, ncon(0)) - p1 = gc.Gbranch(i386.AJLT, nil, 0) - - // native - gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0) - - gins(i386.AFMOVV, &t1, &r1) - if tt == gc.TFLOAT32 { - gins(i386.AFMOVFP, &r1, t) - } else { - gins(i386.AFMOVDP, &r1, t) - } - p2 = gc.Gbranch(obj.AJMP, nil, 0) - - // simulated - gc.Patch(p1, gc.Pc) - - gmove(&tlo, &ax) - gmove(&thi, &dx) - p1 = gins(i386.ASHRL, ncon(1), &ax) - p1.From.Index = i386.REG_DX // double-width shift DX -> AX - p1.From.Scale = 0 - gins(i386.AMOVL, ncon(0), &cx) - gins(i386.ASETCC, nil, &cx) - gins(i386.AORL, &cx, &ax) - gins(i386.ASHRL, ncon(1), &dx) - gmove(&dx, &thi) - gmove(&ax, &tlo) - gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0) - gc.Nodreg(&r2, gc.Types[tt], i386.REG_F0+1) - gins(i386.AFMOVV, &t1, &r1) - gins(i386.AFMOVD, &r1, &r1) - gins(i386.AFADDDP, &r1, &r2) - if tt == gc.TFLOAT32 { - gins(i386.AFMOVFP, &r1, t) - } else { - gins(i386.AFMOVDP, &r1, t) - } - gc.Patch(p2, gc.Pc) - splitclean() - return - } - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires memory intermediate -hardmem: - gc.Tempname(&r1, cvt) - - gmove(f, &r1) - gmove(&r1, t) - return -} - -func floatmove_387(f *gc.Node, t *gc.Node) { - var r1 gc.Node - var t1 gc.Node - var t2 gc.Node - var cvt *gc.Type - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var a int - var ft int - var tt int - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - switch uint32(ft)<<16 | uint32(tt) { - default: - goto fatal - - /* - * float to integer - */ - case gc.TFLOAT32<<16 | gc.TINT16, - gc.TFLOAT32<<16 | gc.TINT32, - gc.TFLOAT32<<16 | gc.TINT64, - gc.TFLOAT64<<16 | gc.TINT16, - gc.TFLOAT64<<16 | gc.TINT32, - gc.TFLOAT64<<16 | gc.TINT64: - if t.Op == gc.OREGISTER { - goto hardmem - } - gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0) - if f.Op != gc.OREGISTER { - if ft == gc.TFLOAT32 { - gins(i386.AFMOVF, f, &r1) - } else { - gins(i386.AFMOVD, f, &r1) - } - } - - // set round to zero mode during conversion - memname(&t1, gc.Types[gc.TUINT16]) - - memname(&t2, gc.Types[gc.TUINT16]) - gins(i386.AFSTCW, nil, &t1) - gins(i386.AMOVW, ncon(0xf7f), &t2) - gins(i386.AFLDCW, &t2, nil) - if tt == gc.TINT16 { - gins(i386.AFMOVWP, &r1, t) - } else if tt == gc.TINT32 { - gins(i386.AFMOVLP, &r1, t) - } else { - gins(i386.AFMOVVP, &r1, t) - } - gins(i386.AFLDCW, &t1, nil) - return - - // convert via int32. - case gc.TFLOAT32<<16 | gc.TINT8, - gc.TFLOAT32<<16 | gc.TUINT16, - gc.TFLOAT32<<16 | gc.TUINT8, - gc.TFLOAT64<<16 | gc.TINT8, - gc.TFLOAT64<<16 | gc.TUINT16, - gc.TFLOAT64<<16 | gc.TUINT8: - gc.Tempname(&t1, gc.Types[gc.TINT32]) - - gmove(f, &t1) - switch tt { - default: - gc.Fatal("gmove %v", gc.Nconv(t, 0)) - - case gc.TINT8: - gins(i386.ACMPL, &t1, ncon(-0x80&(1<<32-1))) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1) - gins(i386.ACMPL, &t1, ncon(0x7f)) - p2 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TINT32]), nil, -1) - p3 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - gc.Patch(p2, gc.Pc) - gmove(ncon(-0x80&(1<<32-1)), &t1) - gc.Patch(p3, gc.Pc) - gmove(&t1, t) - - case gc.TUINT8: - gins(i386.ATESTL, ncon(0xffffff00), &t1) - p1 = gc.Gbranch(i386.AJEQ, nil, +1) - gins(i386.AMOVL, ncon(0), &t1) - gc.Patch(p1, gc.Pc) - gmove(&t1, t) - - case gc.TUINT16: - gins(i386.ATESTL, ncon(0xffff0000), &t1) - p1 = gc.Gbranch(i386.AJEQ, nil, +1) - gins(i386.AMOVL, ncon(0), &t1) - gc.Patch(p1, gc.Pc) - gmove(&t1, t) - } - - return - - // convert via int64. - case gc.TFLOAT32<<16 | gc.TUINT32, - gc.TFLOAT64<<16 | gc.TUINT32: - cvt = gc.Types[gc.TINT64] - - goto hardmem - - /* - * integer to float - */ - case gc.TINT16<<16 | gc.TFLOAT32, - gc.TINT16<<16 | gc.TFLOAT64, - gc.TINT32<<16 | gc.TFLOAT32, - gc.TINT32<<16 | gc.TFLOAT64, - gc.TINT64<<16 | gc.TFLOAT32, - gc.TINT64<<16 | gc.TFLOAT64: - if t.Op != gc.OREGISTER { - goto hard - } - if f.Op == gc.OREGISTER { - cvt = f.Type - goto hardmem - } - - switch ft { - case gc.TINT16: - a = i386.AFMOVW - - case gc.TINT32: - a = i386.AFMOVL - - default: - a = i386.AFMOVV - } - - // convert via int32 memory - case gc.TINT8<<16 | gc.TFLOAT32, - gc.TINT8<<16 | gc.TFLOAT64, - gc.TUINT16<<16 | gc.TFLOAT32, - gc.TUINT16<<16 | gc.TFLOAT64, - gc.TUINT8<<16 | gc.TFLOAT32, - gc.TUINT8<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT32] - - goto hardmem - - // convert via int64 memory - case gc.TUINT32<<16 | gc.TFLOAT32, - gc.TUINT32<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT64] - - goto hardmem - - // The way the code generator uses floating-point - // registers, a move from F0 to F0 is intended as a no-op. - // On the x86, it's not: it pushes a second copy of F0 - // on the floating point stack. So toss it away here. - // Also, F0 is the *only* register we ever evaluate - // into, so we should only see register/register as F0/F0. - /* - * float to float - */ - case gc.TFLOAT32<<16 | gc.TFLOAT32, - gc.TFLOAT64<<16 | gc.TFLOAT64: - if gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { - if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 { - goto fatal - } - return - } - - a = i386.AFMOVF - if ft == gc.TFLOAT64 { - a = i386.AFMOVD - } - if gc.Ismem(t) { - if f.Op != gc.OREGISTER || f.Val.U.Reg != i386.REG_F0 { - gc.Fatal("gmove %v", gc.Nconv(f, 0)) - } - a = i386.AFMOVFP - if ft == gc.TFLOAT64 { - a = i386.AFMOVDP - } - } - - case gc.TFLOAT32<<16 | gc.TFLOAT64: - if gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { - if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 { - goto fatal - } - return - } - - if f.Op == gc.OREGISTER { - gins(i386.AFMOVDP, f, t) - } else { - gins(i386.AFMOVF, f, t) - } - return - - case gc.TFLOAT64<<16 | gc.TFLOAT32: - if gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER { - gc.Tempname(&r1, gc.Types[gc.TFLOAT32]) - gins(i386.AFMOVFP, f, &r1) - gins(i386.AFMOVF, &r1, t) - return - } - - if f.Op == gc.OREGISTER { - gins(i386.AFMOVFP, f, t) - } else { - gins(i386.AFMOVD, f, t) - } - return - } - - gins(a, f, t) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires memory intermediate -hardmem: - gc.Tempname(&r1, cvt) - - gmove(f, &r1) - gmove(&r1, t) - return - - // should not happen -fatal: - gc.Fatal("gmove %v -> %v", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) - - return -} - -func floatmove_sse(f *gc.Node, t *gc.Node) { - var r1 gc.Node - var cvt *gc.Type - var a int - var ft int - var tt int - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - - switch uint32(ft)<<16 | uint32(tt) { - // should not happen - default: - gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0)) - - return - - // convert via int32. - /* - * float to integer - */ - case gc.TFLOAT32<<16 | gc.TINT16, - gc.TFLOAT32<<16 | gc.TINT8, - gc.TFLOAT32<<16 | gc.TUINT16, - gc.TFLOAT32<<16 | gc.TUINT8, - gc.TFLOAT64<<16 | gc.TINT16, - gc.TFLOAT64<<16 | gc.TINT8, - gc.TFLOAT64<<16 | gc.TUINT16, - gc.TFLOAT64<<16 | gc.TUINT8: - cvt = gc.Types[gc.TINT32] - - goto hard - - // convert via int64. - case gc.TFLOAT32<<16 | gc.TUINT32, - gc.TFLOAT64<<16 | gc.TUINT32: - cvt = gc.Types[gc.TINT64] - - goto hardmem - - case gc.TFLOAT32<<16 | gc.TINT32: - a = i386.ACVTTSS2SL - goto rdst - - case gc.TFLOAT64<<16 | gc.TINT32: - a = i386.ACVTTSD2SL - goto rdst - - // convert via int32 memory - /* - * integer to float - */ - case gc.TINT8<<16 | gc.TFLOAT32, - gc.TINT8<<16 | gc.TFLOAT64, - gc.TINT16<<16 | gc.TFLOAT32, - gc.TINT16<<16 | gc.TFLOAT64, - gc.TUINT16<<16 | gc.TFLOAT32, - gc.TUINT16<<16 | gc.TFLOAT64, - gc.TUINT8<<16 | gc.TFLOAT32, - gc.TUINT8<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT32] - - goto hard - - // convert via int64 memory - case gc.TUINT32<<16 | gc.TFLOAT32, - gc.TUINT32<<16 | gc.TFLOAT64: - cvt = gc.Types[gc.TINT64] - - goto hardmem - - case gc.TINT32<<16 | gc.TFLOAT32: - a = i386.ACVTSL2SS - goto rdst - - case gc.TINT32<<16 | gc.TFLOAT64: - a = i386.ACVTSL2SD - goto rdst - - /* - * float to float - */ - case gc.TFLOAT32<<16 | gc.TFLOAT32: - a = i386.AMOVSS - - case gc.TFLOAT64<<16 | gc.TFLOAT64: - a = i386.AMOVSD - - case gc.TFLOAT32<<16 | gc.TFLOAT64: - a = i386.ACVTSS2SD - goto rdst - - case gc.TFLOAT64<<16 | gc.TFLOAT32: - a = i386.ACVTSD2SS - goto rdst - } - - gins(a, f, t) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires memory intermediate -hardmem: - gc.Tempname(&r1, cvt) - - gmove(f, &r1) - gmove(&r1, t) - return - - // requires register destination -rdst: - regalloc(&r1, t.Type, t) - - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return -} - -func samaddr(f *gc.Node, t *gc.Node) bool { - if f.Op != t.Op { - return false - } - - switch f.Op { - case gc.OREGISTER: - if f.Val.U.Reg != t.Val.U.Reg { - break - } - return true - } - - return false -} - -/* - * generate one instruction: - * as f, t - */ -func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { - var p *obj.Prog - var af obj.Addr - var at obj.Addr - var w int - - if as == i386.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER { - gc.Fatal("gins MOVF reg, reg") - } - if as == i386.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL { - gc.Fatal("gins CVTSD2SS const") - } - if as == i386.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Val.U.Reg == i386.REG_F0 { - gc.Fatal("gins MOVSD into F0") - } - - switch as { - case i386.AMOVB, - i386.AMOVW, - i386.AMOVL: - if f != nil && t != nil && samaddr(f, t) { - return nil - } - - case i386.ALEAL: - if f != nil && gc.Isconst(f, gc.CTNIL) { - gc.Fatal("gins LEAL nil %v", gc.Tconv(f.Type, 0)) - } - } - - af = obj.Addr{} - at = obj.Addr{} - if f != nil { - gc.Naddr(f, &af, 1) - } - if t != nil { - gc.Naddr(t, &at, 1) - } - p = gc.Prog(as) - if f != nil { - p.From = af - } - if t != nil { - p.To = at - } - if gc.Debug['g'] != 0 { - fmt.Printf("%v\n", p) - } - - w = 0 - switch as { - case i386.AMOVB: - w = 1 - - case i386.AMOVW: - w = 2 - - case i386.AMOVL: - w = 4 - } - - if true && w != 0 && f != nil && (af.Width > int64(w) || at.Width > int64(w)) { - gc.Dump("bad width from:", f) - gc.Dump("bad width to:", t) - gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) - } - - if p.To.Type == obj.TYPE_ADDR && w > 0 { - gc.Fatal("bad use of addr: %v", p) - } - - return p -} - -func dotaddable(n *gc.Node, n1 *gc.Node) bool { - var o int - var oary [10]int64 - var nn *gc.Node - - if n.Op != gc.ODOT { - return false - } - - o = gc.Dotoffset(n, oary[:], &nn) - if nn != nil && nn.Addable != 0 && o == 1 && oary[0] >= 0 { - *n1 = *nn - n1.Type = n.Type - n1.Xoffset += oary[0] - return true - } - - return false -} - -func sudoclean() { -} - -func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { - *a = obj.Addr{} - return false -} diff --git a/src/cmd/new8g/peep.go b/src/cmd/new8g/peep.go deleted file mode 100644 index 0838882e38..0000000000 --- a/src/cmd/new8g/peep.go +++ /dev/null @@ -1,847 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" - "fmt" -) -import "cmd/internal/gc" - -const ( - REGEXT = 0 - exregoffset = i386.REG_DI -) - -var gactive uint32 - -// do we need the carry bit -func needc(p *obj.Prog) bool { - var info gc.ProgInfo - - for p != nil { - proginfo(&info, p) - if info.Flags&gc.UseCarry != 0 { - return true - } - if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 { - return false - } - p = p.Link - } - - return false -} - -func rnops(r *gc.Flow) *gc.Flow { - var p *obj.Prog - var r1 *gc.Flow - - if r != nil { - for { - p = r.Prog - if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE { - break - } - r1 = gc.Uniqs(r) - if r1 == nil { - break - } - r = r1 - } - } - - return r -} - -func peep(firstp *obj.Prog) { - var r *gc.Flow - var r1 *gc.Flow - var g *gc.Graph - var p *obj.Prog - var p1 *obj.Prog - var t int - - g = gc.Flowstart(firstp, nil) - if g == nil { - return - } - gactive = 0 - - // byte, word arithmetic elimination. - elimshortmov(g) - - // constant propagation - // find MOV $con,R followed by - // another MOV $con,R without - // setting R in the interim - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case i386.ALEAL: - if regtyp(&p.To) { - if p.From.Sym != nil { - if p.From.Index == i386.REG_NONE { - conprop(r) - } - } - } - - case i386.AMOVB, - i386.AMOVW, - i386.AMOVL, - i386.AMOVSS, - i386.AMOVSD: - if regtyp(&p.To) { - if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST { - conprop(r) - } - } - } - } - -loop1: - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - gc.Dumpit("loop1", g.Start, 0) - } - - t = 0 - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case i386.AMOVL, - i386.AMOVSS, - i386.AMOVSD: - if regtyp(&p.To) { - if regtyp(&p.From) { - if copyprop(g, r) { - excise(r) - t++ - } else if subprop(r) && copyprop(g, r) { - excise(r) - t++ - } - } - } - - case i386.AMOVBLZX, - i386.AMOVWLZX, - i386.AMOVBLSX, - i386.AMOVWLSX: - if regtyp(&p.To) { - r1 = rnops(gc.Uniqs(r)) - if r1 != nil { - p1 = r1.Prog - if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg { - p1.As = i386.AMOVL - t++ - } - } - } - - case i386.AADDL, - i386.AADDW: - if p.From.Type != obj.TYPE_CONST || needc(p.Link) { - break - } - if p.From.Offset == -1 { - if p.As == i386.AADDL { - p.As = i386.ADECL - } else { - p.As = i386.ADECW - } - p.From = obj.Addr{} - break - } - - if p.From.Offset == 1 { - if p.As == i386.AADDL { - p.As = i386.AINCL - } else { - p.As = i386.AINCW - } - p.From = obj.Addr{} - break - } - - case i386.ASUBL, - i386.ASUBW: - if p.From.Type != obj.TYPE_CONST || needc(p.Link) { - break - } - if p.From.Offset == -1 { - if p.As == i386.ASUBL { - p.As = i386.AINCL - } else { - p.As = i386.AINCW - } - p.From = obj.Addr{} - break - } - - if p.From.Offset == 1 { - if p.As == i386.ASUBL { - p.As = i386.ADECL - } else { - p.As = i386.ADECW - } - p.From = obj.Addr{} - break - } - } - } - - if t != 0 { - goto loop1 - } - - // MOVSD removal. - // We never use packed registers, so a MOVSD between registers - // can be replaced by MOVAPD, which moves the pair of float64s - // instead of just the lower one. We only use the lower one, but - // the processor can do better if we do moves using both. - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - if p.As == i386.AMOVSD { - if regtyp(&p.From) { - if regtyp(&p.To) { - p.As = i386.AMOVAPD - } - } - } - } - - gc.Flowend(g) -} - -func excise(r *gc.Flow) { - var p *obj.Prog - - p = r.Prog - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("%v ===delete===\n", p) - } - - obj.Nopout(p) - - gc.Ostats.Ndelmov++ -} - -func regtyp(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && (i386.REG_AX <= a.Reg && a.Reg <= i386.REG_DI || i386.REG_X0 <= a.Reg && a.Reg <= i386.REG_X7) -} - -// movb elimination. -// movb is simulated by the linker -// when a register other than ax, bx, cx, dx -// is used, so rewrite to other instructions -// when possible. a movb into a register -// can smash the entire 64-bit register without -// causing any trouble. -func elimshortmov(g *gc.Graph) { - var p *obj.Prog - var r *gc.Flow - - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - if regtyp(&p.To) { - switch p.As { - case i386.AINCB, - i386.AINCW: - p.As = i386.AINCL - - case i386.ADECB, - i386.ADECW: - p.As = i386.ADECL - - case i386.ANEGB, - i386.ANEGW: - p.As = i386.ANEGL - - case i386.ANOTB, - i386.ANOTW: - p.As = i386.ANOTL - } - - if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST { - // move or artihmetic into partial register. - // from another register or constant can be movl. - // we don't switch to 32-bit arithmetic if it can - // change how the carry bit is set (and the carry bit is needed). - switch p.As { - case i386.AMOVB, - i386.AMOVW: - p.As = i386.AMOVL - - case i386.AADDB, - i386.AADDW: - if !needc(p.Link) { - p.As = i386.AADDL - } - - case i386.ASUBB, - i386.ASUBW: - if !needc(p.Link) { - p.As = i386.ASUBL - } - - case i386.AMULB, - i386.AMULW: - p.As = i386.AMULL - - case i386.AIMULB, - i386.AIMULW: - p.As = i386.AIMULL - - case i386.AANDB, - i386.AANDW: - p.As = i386.AANDL - - case i386.AORB, - i386.AORW: - p.As = i386.AORL - - case i386.AXORB, - i386.AXORW: - p.As = i386.AXORL - - case i386.ASHLB, - i386.ASHLW: - p.As = i386.ASHLL - } - } else { - // explicit zero extension - switch p.As { - case i386.AMOVB: - p.As = i386.AMOVBLZX - - case i386.AMOVW: - p.As = i386.AMOVWLZX - } - } - } - } -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R0 - * ADD b, R0 / no use of R1 - * MOV R0, R1 - * would be converted to - * MOV a, R1 - * ADD b, R1 - * MOV R1, R0 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - */ -func subprop(r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - var r *gc.Flow - var t int - var info gc.ProgInfo - - p = r0.Prog - v1 = &p.From - if !regtyp(v1) { - return false - } - v2 = &p.To - if !regtyp(v2) { - return false - } - for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("\t? %v\n", r.Prog) - } - if gc.Uniqs(r) == nil { - break - } - p = r.Prog - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - continue - } - proginfo(&info, p) - if info.Flags&gc.Call != 0 { - return false - } - - if info.Reguse|info.Regset != 0 { - return false - } - - if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg { - goto gotit - } - - if copyau(&p.From, v2) || copyau(&p.To, v2) { - break - } - if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { - break - } - } - - return false - -gotit: - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) - if p.From.Type == v2.Type && p.From.Reg == v2.Reg { - fmt.Printf(" excise") - } - fmt.Printf("\n") - } - - for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { - p = r.Prog - copysub(&p.From, v1, v2, 1) - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("%v\n", r.Prog) - } - } - - t = int(v1.Reg) - v1.Reg = v2.Reg - v2.Reg = int16(t) - if gc.Debug['P'] != 0 { - fmt.Printf("%v last\n", r.Prog) - } - return true -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success - */ -func copyprop(g *gc.Graph, r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - - p = r0.Prog - v1 = &p.From - v2 = &p.To - if copyas(v1, v2) { - return true - } - gactive++ - return copy1(v1, v2, r0.S1, 0) -} - -func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { - var t int - var p *obj.Prog - - if uint32(r.Active) == gactive { - if gc.Debug['P'] != 0 { - fmt.Printf("act set; return 1\n") - } - return true - } - - r.Active = int32(gactive) - if gc.Debug['P'] != 0 { - fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f) - } - for ; r != nil; r = r.S1 { - p = r.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("%v", p) - } - if f == 0 && gc.Uniqp(r) == nil { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; merge; f=%d", f) - } - } - - t = copyu(p, v2, nil) - switch t { - case 2: /* rar, can't split */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) - } - return false - - case 3: /* set */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - - case 1, /* used, substitute */ - 4: /* use and set */ - if f != 0 { - if gc.Debug['P'] == 0 { - return false - } - if t == 4 { - fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } else { - fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } - return false - } - - if copyu(p, v2, v1) != 0 { - if gc.Debug['P'] != 0 { - fmt.Printf("; sub fail; return 0\n") - } - return false - } - - if gc.Debug['P'] != 0 { - fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1)) - } - if t == 4 { - if gc.Debug['P'] != 0 { - fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - } - } - - if f == 0 { - t = copyu(p, v1, nil) - if f == 0 && (t == 2 || t == 3 || t == 4) { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) - } - } - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\n") - } - if r.S2 != nil { - if !copy1(v1, v2, r.S2, f) { - return false - } - } - } - - return true -} - -/* - * return - * 1 if v only used (and substitute), - * 2 if read-alter-rewrite - * 3 if set - * 4 if set and used - * 0 otherwise (not touched) - */ -func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { - var info gc.ProgInfo - - switch p.As { - case obj.AJMP: - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 1 - } - return 0 - - case obj.ARET: - if s != nil { - return 1 - } - return 3 - - case obj.ACALL: - if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset { - return 2 - } - if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG { - return 2 - } - if v.Type == p.From.Type && v.Reg == p.From.Reg { - return 2 - } - - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 4 - } - return 3 - - case obj.ATEXT: - if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG { - return 3 - } - return 0 - } - - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - return 0 - } - proginfo(&info, p) - - if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 { - return 2 - } - - if info.Flags&gc.LeftAddr != 0 { - if copyas(&p.From, v) { - return 2 - } - } - - if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite { - if copyas(&p.To, v) { - return 2 - } - } - - if info.Flags&gc.RightWrite != 0 { - if copyas(&p.To, v) { - if s != nil { - return copysub(&p.From, v, s, 1) - } - if copyau(&p.From, v) { - return 4 - } - return 3 - } - } - - if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 { - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - return copysub(&p.To, v, s, 1) - } - - if copyau(&p.From, v) { - return 1 - } - if copyau(&p.To, v) { - return 1 - } - } - - return 0 -} - -/* - * direct reference, - * could be set/use depending on - * semantics - */ -func copyas(a *obj.Addr, v *obj.Addr) bool { - if i386.REG_AL <= a.Reg && a.Reg <= i386.REG_BL { - gc.Fatal("use of byte register") - } - if i386.REG_AL <= v.Reg && v.Reg <= i386.REG_BL { - gc.Fatal("use of byte register") - } - - if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { - return false - } - if regtyp(v) { - return true - } - if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { - if v.Offset == a.Offset { - return true - } - } - return false -} - -func sameaddr(a *obj.Addr, v *obj.Addr) bool { - if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg { - return false - } - if regtyp(v) { - return true - } - if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) { - if v.Offset == a.Offset { - return true - } - } - return false -} - -/* - * either direct or indirect - */ -func copyau(a *obj.Addr, v *obj.Addr) bool { - if copyas(a, v) { - return true - } - if regtyp(v) { - if a.Type == obj.TYPE_MEM && a.Reg == v.Reg { - return true - } - if a.Index == v.Reg { - return true - } - } - - return false -} - -/* - * substitute s for v in a - * return failure to substitute - */ -func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { - var reg int - - if copyas(a, v) { - reg = int(s.Reg) - if reg >= i386.REG_AX && reg <= i386.REG_DI || reg >= i386.REG_X0 && reg <= i386.REG_X7 { - if f != 0 { - a.Reg = int16(reg) - } - } - - return 0 - } - - if regtyp(v) { - reg = int(v.Reg) - if a.Type == obj.TYPE_MEM && int(a.Reg) == reg { - if (s.Reg == i386.REG_BP) && a.Index != obj.TYPE_NONE { - return 1 /* can't use BP-base with index */ - } - if f != 0 { - a.Reg = s.Reg - } - } - - // return 0; - if int(a.Index) == reg { - if f != 0 { - a.Index = s.Reg - } - return 0 - } - - return 0 - } - - return 0 -} - -func conprop(r0 *gc.Flow) { - var r *gc.Flow - var p *obj.Prog - var p0 *obj.Prog - var t int - var v0 *obj.Addr - - p0 = r0.Prog - v0 = &p0.To - r = r0 - -loop: - r = gc.Uniqs(r) - if r == nil || r == r0 { - return - } - if gc.Uniqp(r) == nil { - return - } - - p = r.Prog - t = copyu(p, v0, nil) - switch t { - case 0, // miss - 1: // use - goto loop - - case 2, // rar - 4: // use and set - break - - case 3: // set - if p.As == p0.As { - if p.From.Type == p0.From.Type { - if p.From.Reg == p0.From.Reg { - if p.From.Node == p0.From.Node { - if p.From.Offset == p0.From.Offset { - if p.From.Scale == p0.From.Scale { - if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval { - if p.From.Index == p0.From.Index { - excise(r) - goto loop - } - } - } - } - } - } - } - } - } -} - -func smallindir(a *obj.Addr, reg *obj.Addr) bool { - return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == i386.REG_NONE && 0 <= a.Offset && a.Offset < 4096 -} - -func stackaddr(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && a.Reg == i386.REG_SP -} diff --git a/src/cmd/new8g/prog.go b/src/cmd/new8g/prog.go deleted file mode 100644 index d8e46e5108..0000000000 --- a/src/cmd/new8g/prog.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/i386" -) -import "cmd/internal/gc" - -var ( - AX = RtoB(i386.REG_AX) - BX = RtoB(i386.REG_BX) - CX = RtoB(i386.REG_CX) - DX = RtoB(i386.REG_DX) - DI = RtoB(i386.REG_DI) - SI = RtoB(i386.REG_SI) - LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite - RightRdwr uint32 = gc.RightRead | gc.RightWrite -) - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -var progtable = [i386.ALAST]gc.ProgInfo{ - obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, - obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, - obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, - obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, - obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Intel opcode. - obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, - i386.AADCL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.AADCW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.AADDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AADDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AADDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AADDSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.AADDSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.AANDB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AANDL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AANDW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - obj.ACALL: gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0}, - i386.ACDQ: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, - i386.ACWD: gc.ProgInfo{gc.OK, AX, AX | DX, 0}, - i386.ACLD: gc.ProgInfo{gc.OK, 0, 0, 0}, - i386.ASTD: gc.ProgInfo{gc.OK, 0, 0, 0}, - i386.ACMPB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ACMPL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ACMPW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ACOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ACOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ACVTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTSD2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTSL2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTSL2SS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTSS2SD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.ADECB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - i386.ADECL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - i386.ADECW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - i386.ADIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - i386.ADIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - i386.ADIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - i386.ADIVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.ADIVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.AFLDCW: gc.ProgInfo{gc.SizeW | gc.LeftAddr, 0, 0, 0}, - i386.AFSTCW: gc.ProgInfo{gc.SizeW | gc.RightAddr, 0, 0, 0}, - i386.AFSTSW: gc.ProgInfo{gc.SizeW | gc.RightAddr | gc.RightWrite, 0, 0, 0}, - i386.AFADDD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFADDDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFADDF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFCOMD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFCOMDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFCOMDPP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFCOMF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFCOMFP: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFUCOMIP: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0}, - i386.AFCHS: gc.ProgInfo{gc.SizeD | RightRdwr, 0, 0, 0}, // also SizeF - - i386.AFDIVDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFDIVF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFDIVD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFDIVRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFDIVRF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFDIVRD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFXCHD: gc.ProgInfo{gc.SizeD | LeftRdwr | RightRdwr, 0, 0, 0}, - i386.AFSUBD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFSUBDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFSUBF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFSUBRD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFSUBRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFSUBRF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFMOVD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - i386.AFMOVF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - i386.AFMOVL: gc.ProgInfo{gc.SizeL | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - i386.AFMOVW: gc.ProgInfo{gc.SizeW | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - i386.AFMOVV: gc.ProgInfo{gc.SizeQ | gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - - // These instructions are marked as RightAddr - // so that the register optimizer does not try to replace the - // memory references with integer register references. - // But they do not use the previous value at the address, so - // we also mark them RightWrite. - i386.AFMOVDP: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, - i386.AFMOVFP: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, - i386.AFMOVLP: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, - i386.AFMOVWP: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, - i386.AFMOVVP: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0}, - i386.AFMULD: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFMULDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AFMULF: gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0}, - i386.AIDIVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - i386.AIDIVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - i386.AIDIVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0}, - i386.AIMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - i386.AIMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, - i386.AIMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0}, - i386.AINCB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - i386.AINCL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - i386.AINCW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - i386.AJCC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJCS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJEQ: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJGE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJGT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJHI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJLE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJLS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJLT: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJMI: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJNE: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJOC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJOS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJPC: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJPL: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - i386.AJPS: gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0}, - obj.AJMP: gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0}, - i386.ALEAL: gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0}, - i386.AMOVBLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVBLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVBWSX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVBWZX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVWLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVWLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - i386.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - i386.AMOVL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - i386.AMOVW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - i386.AMOVSB: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - i386.AMOVSL: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - i386.AMOVSW: gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0}, - obj.ADUFFCOPY: gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0}, - i386.AMOVSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - i386.AMOVSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - - // We use MOVAPD as a faster synonym for MOVSD. - i386.AMOVAPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - i386.AMULB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0}, - i386.AMULL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, - i386.AMULW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0}, - i386.AMULSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.AMULSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.ANEGB: gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ANEGL: gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ANEGW: gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ANOTB: gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0}, - i386.ANOTL: gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0}, - i386.ANOTW: gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0}, - i386.AORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.APOPL: gc.ProgInfo{gc.SizeL | gc.RightWrite, 0, 0, 0}, - i386.APUSHL: gc.ProgInfo{gc.SizeL | gc.LeftRead, 0, 0, 0}, - i386.ARCLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ARCLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ARCLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ARCRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ARCRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ARCRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.AREP: gc.ProgInfo{gc.OK, CX, CX, 0}, - i386.AREPN: gc.ProgInfo{gc.OK, CX, CX, 0}, - obj.ARET: gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0}, - i386.AROLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.AROLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.AROLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ARORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ARORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ARORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASAHF: gc.ProgInfo{gc.OK, AX, AX, 0}, - i386.ASALB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASALL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASALW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASARB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASARL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASARW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASBBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ASBBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ASBBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0}, - i386.ASETCC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETCS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETEQ: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETGE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETGT: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETHI: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETLE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETLS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETLT: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETMI: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETNE: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETOC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETOS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETPC: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETPL: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASETPS: gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0}, - i386.ASHLB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASHLL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASHLW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASHRB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASHRL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASHRW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0}, - i386.ASTOSB: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - i386.ASTOSL: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - i386.ASTOSW: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0}, - i386.ASUBB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ASUBL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ASUBW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.ASUBSD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.ASUBSS: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0}, - i386.ATESTB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ATESTL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.ATESTW: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0}, - i386.AUCOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, - i386.AUCOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0}, - i386.AXCHGB: gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0}, - i386.AXCHGL: gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0}, - i386.AXCHGW: gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0}, - i386.AXORB: gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AXORL: gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, - i386.AXORW: gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0}, -} - -func proginfo(info *gc.ProgInfo, p *obj.Prog) { - *info = progtable[p.As] - if info.Flags == 0 { - gc.Fatal("unknown instruction %v", p) - } - - if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST { - info.Reguse |= CX - } - - if info.Flags&gc.ImulAXDX != 0 { - if p.To.Type == obj.TYPE_NONE { - info.Reguse |= AX - info.Regset |= AX | DX - } else { - info.Flags |= RightRdwr - } - } - - // Addressing makes some registers used. - if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE { - info.Regindex |= RtoB(int(p.From.Reg)) - } - if p.From.Index != i386.REG_NONE { - info.Regindex |= RtoB(int(p.From.Index)) - } - if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE { - info.Regindex |= RtoB(int(p.To.Reg)) - } - if p.To.Index != i386.REG_NONE { - info.Regindex |= RtoB(int(p.To.Index)) - } -} diff --git a/src/cmd/new8g/reg.go b/src/cmd/new8g/reg.go deleted file mode 100644 index 76bd260f54..0000000000 --- a/src/cmd/new8g/reg.go +++ /dev/null @@ -1,112 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import "cmd/internal/obj/i386" -import "cmd/internal/gc" - -const ( - NREGVAR = 16 -) - -var regname = []string{ - ".ax", - ".cx", - ".dx", - ".bx", - ".sp", - ".bp", - ".si", - ".di", - ".x0", - ".x1", - ".x2", - ".x3", - ".x4", - ".x5", - ".x6", - ".x7", -} - -func regnames(n *int) []string { - *n = NREGVAR - return regname -} - -func excludedregs() uint64 { - return RtoB(i386.REG_SP) -} - -func doregbits(r int) uint64 { - var b uint64 - - b = 0 - if r >= i386.REG_AX && r <= i386.REG_DI { - b |= RtoB(r) - } else if r >= i386.REG_AL && r <= i386.REG_BL { - b |= RtoB(r - i386.REG_AL + i386.REG_AX) - } else if r >= i386.REG_AH && r <= i386.REG_BH { - b |= RtoB(r - i386.REG_AH + i386.REG_AX) - } else if r >= i386.REG_X0 && r <= i386.REG_X0+7 { - b |= FtoB(r) - } - return b -} - -func RtoB(r int) uint64 { - if r < i386.REG_AX || r > i386.REG_DI { - return 0 - } - return 1 << uint(r-i386.REG_AX) -} - -func BtoR(b uint64) int { - b &= 0xff - if b == 0 { - return 0 - } - return gc.Bitno(b) + i386.REG_AX -} - -func FtoB(f int) uint64 { - if f < i386.REG_X0 || f > i386.REG_X7 { - return 0 - } - return 1 << uint(f-i386.REG_X0+8) -} - -func BtoF(b uint64) int { - b &= 0xFF00 - if b == 0 { - return 0 - } - return gc.Bitno(b) - 8 + i386.REG_X0 -} diff --git a/src/cmd/new8g/util.go b/src/cmd/new8g/util.go deleted file mode 100644 index bb5eedb15a..0000000000 --- a/src/cmd/new8g/util.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func bool2int(b bool) int { - if b { - return 1 - } - return 0 -} diff --git a/src/cmd/new9a/a.y b/src/cmd/new9a/a.y deleted file mode 100644 index db733c5987..0000000000 --- a/src/cmd/new9a/a.y +++ /dev/null @@ -1,1055 +0,0 @@ -// cmd/9a/a.y from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -%{ -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/ppc64" -) -%} - -%union -{ - sym *asm.Sym - lval int64 - dval float64 - sval string - addr obj.Addr -} - -%left '|' -%left '^' -%left '&' -%left '<' '>' -%left '+' '-' -%left '*' '/' '%' -%token LMOVW LMOVB LABS LLOGW LSHW LADDW LCMP LCROP -%token LBRA LFMOV LFCONV LFCMP LFADD LFMA LTRAP LXORW -%token LNOP LEND LRETT LWORD LTEXT LDATA LGLOBL LRETRN -%token LCONST LSP LSB LFP LPC LCREG LFLUSH -%token LREG LFREG LR LCR LF LFPSCR -%token LLR LCTR LSPR LSPREG LSEG LMSR -%token LPCDAT LFUNCDAT LSCHED LXLD LXST LXOP LXMV -%token LRLWM LMOVMW LMOVEM LMOVFL LMTFSB LMA -%token LFCONST -%token LSCONST -%token LNAME LLAB LVAR -%type con expr pointer offset sreg -%type addr rreg regaddr name creg freg xlreg lr ctr textsize -%type imm ximm fimm rel psr lcr cbit fpscr msr mask -%% -prog: -| prog - { - stmtline = asm.Lineno - } - line - -line: - LNAME ':' - { - $1 = asm.LabelLookup($1); - if $1.Type == LLAB && $1.Value != int64(asm.PC) { - yyerror("redeclaration of %s", $1.Labelname) - } - $1.Type = LLAB; - $1.Value = int64(asm.PC); - } - line -| LNAME '=' expr ';' - { - $1.Type = LVAR; - $1.Value = $3; - } -| LVAR '=' expr ';' - { - if $1.Value != $3 { - yyerror("redeclaration of %s", $1.Name) - } - $1.Value = $3; - } -| LSCHED ';' - { - nosched = int($1); - } -| ';' -| inst ';' -| error ';' - -inst: -/* - * load ints and bytes - */ - LMOVW rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW addr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW regaddr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVB rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVB addr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVB regaddr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -/* - * load floats - */ -| LFMOV addr ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFMOV regaddr ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFMOV fimm ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFMOV freg ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFMOV freg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -| LFMOV freg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * store ints and bytes - */ -| LMOVW rreg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW rreg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVB rreg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVB rreg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * store floats - */ -| LMOVW freg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW freg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * floating point status - */ -| LMOVW fpscr ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW freg ',' fpscr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW freg ',' imm ',' fpscr - { - outgcode(int($1), &$2, 0, &$4, &$6); - } -| LMOVW fpscr ',' creg - { - outcode(int($1), &$2, 0, &$4); - } -| LMTFSB imm ',' con - { - outcode(int($1), &$2, int($4), &nullgen); - } -/* - * field moves (mtcrf) - */ -| LMOVW rreg ',' imm ',' lcr - { - outgcode(int($1), &$2, 0, &$4, &$6); - } -| LMOVW rreg ',' creg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW rreg ',' lcr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * integer operations - * logical instructions - * shift instructions - * unary instructions - */ -| LADDW rreg ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -| LADDW imm ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -| LADDW rreg ',' imm ',' rreg - { - outgcode(int($1), &$2, 0, &$4, &$6); - } -| LADDW rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LADDW imm ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LLOGW rreg ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -| LLOGW rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LSHW rreg ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -| LSHW rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LSHW imm ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -| LSHW imm ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LABS rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LABS rreg - { - outcode(int($1), &$2, 0, &$2); - } -/* - * multiply-accumulate - */ -| LMA rreg ',' sreg ',' rreg - { - outcode(int($1), &$2, int($4), &$6); - } -/* - * move immediate: macro for cau+or, addi, addis, and other combinations - */ -| LMOVW imm ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW ximm ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -/* - * condition register operations - */ -| LCROP cbit ',' cbit - { - outcode(int($1), &$2, int($4.Reg), &$4); - } -| LCROP cbit ',' con ',' cbit - { - outcode(int($1), &$2, int($4), &$6); - } -/* - * condition register moves - * move from machine state register - */ -| LMOVW creg ',' creg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW psr ',' creg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW lcr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW psr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW xlreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW rreg ',' xlreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW creg ',' psr - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVW rreg ',' psr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * branch, branch conditional - * branch conditional register - * branch conditional to count register - */ -| LBRA rel - { - outcode(int($1), &nullgen, 0, &$2); - } -| LBRA addr - { - outcode(int($1), &nullgen, 0, &$2); - } -| LBRA '(' xlreg ')' - { - outcode(int($1), &nullgen, 0, &$3); - } -| LBRA ',' rel - { - outcode(int($1), &nullgen, 0, &$3); - } -| LBRA ',' addr - { - outcode(int($1), &nullgen, 0, &$3); - } -| LBRA ',' '(' xlreg ')' - { - outcode(int($1), &nullgen, 0, &$4); - } -| LBRA creg ',' rel - { - outcode(int($1), &$2, 0, &$4); - } -| LBRA creg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -| LBRA creg ',' '(' xlreg ')' - { - outcode(int($1), &$2, 0, &$5); - } -| LBRA con ',' rel - { - outcode(int($1), &nullgen, int($2), &$4); - } -| LBRA con ',' addr - { - outcode(int($1), &nullgen, int($2), &$4); - } -| LBRA con ',' '(' xlreg ')' - { - outcode(int($1), &nullgen, int($2), &$5); - } -| LBRA con ',' con ',' rel - { - var g obj.Addr - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = $2; - outcode(int($1), &g, int(REG_R0+$4), &$6); - } -| LBRA con ',' con ',' addr - { - var g obj.Addr - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = $2; - outcode(int($1), &g, int(REG_R0+$4), &$6); - } -| LBRA con ',' con ',' '(' xlreg ')' - { - var g obj.Addr - g = nullgen; - g.Type = obj.TYPE_CONST; - g.Offset = $2; - outcode(int($1), &g, int(REG_R0+$4), &$7); - } -/* - * conditional trap - */ -| LTRAP rreg ',' sreg - { - outcode(int($1), &$2, int($4), &nullgen); - } -| LTRAP imm ',' sreg - { - outcode(int($1), &$2, int($4), &nullgen); - } -| LTRAP rreg comma - { - outcode(int($1), &$2, 0, &nullgen); - } -| LTRAP comma - { - outcode(int($1), &nullgen, 0, &nullgen); - } -/* - * floating point operate - */ -| LFCONV freg ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFADD freg ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFADD freg ',' freg ',' freg - { - outcode(int($1), &$2, int($4.Reg), &$6); - } -| LFMA freg ',' freg ',' freg ',' freg - { - outgcode(int($1), &$2, int($4.Reg), &$6, &$8); - } -| LFCMP freg ',' freg - { - outcode(int($1), &$2, 0, &$4); - } -| LFCMP freg ',' freg ',' creg - { - outcode(int($1), &$2, int($6.Reg), &$4); - } -/* - * CMP - */ -| LCMP rreg ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LCMP rreg ',' imm - { - outcode(int($1), &$2, 0, &$4); - } -| LCMP rreg ',' rreg ',' creg - { - outcode(int($1), &$2, int($6.Reg), &$4); - } -| LCMP rreg ',' imm ',' creg - { - outcode(int($1), &$2, int($6.Reg), &$4); - } -/* - * rotate and mask - */ -| LRLWM imm ',' rreg ',' imm ',' rreg - { - outgcode(int($1), &$2, int($4.Reg), &$6, &$8); - } -| LRLWM imm ',' rreg ',' mask ',' rreg - { - outgcode(int($1), &$2, int($4.Reg), &$6, &$8); - } -| LRLWM rreg ',' rreg ',' imm ',' rreg - { - outgcode(int($1), &$2, int($4.Reg), &$6, &$8); - } -| LRLWM rreg ',' rreg ',' mask ',' rreg - { - outgcode(int($1), &$2, int($4.Reg), &$6, &$8); - } -/* - * load/store multiple - */ -| LMOVMW addr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LMOVMW rreg ',' addr - { - outcode(int($1), &$2, 0, &$4); - } -/* - * various indexed load/store - * indexed unary (eg, cache clear) - */ -| LXLD regaddr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LXLD regaddr ',' imm ',' rreg - { - outgcode(int($1), &$2, 0, &$4, &$6); - } -| LXST rreg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -| LXST rreg ',' imm ',' regaddr - { - outgcode(int($1), &$2, 0, &$4, &$6); - } -| LXMV regaddr ',' rreg - { - outcode(int($1), &$2, 0, &$4); - } -| LXMV rreg ',' regaddr - { - outcode(int($1), &$2, 0, &$4); - } -| LXOP regaddr - { - outcode(int($1), &$2, 0, &nullgen); - } -/* - * NOP - */ -| LNOP comma - { - outcode(int($1), &nullgen, 0, &nullgen); - } -| LNOP rreg comma - { - outcode(int($1), &$2, 0, &nullgen); - } -| LNOP freg comma - { - outcode(int($1), &$2, 0, &nullgen); - } -| LNOP ',' rreg - { - outcode(int($1), &nullgen, 0, &$3); - } -| LNOP ',' freg - { - outcode(int($1), &nullgen, 0, &$3); - } -| LNOP imm /* SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards. */ - { - outcode(int($1), &$2, 0, &nullgen); - } -/* - * word - */ -| LWORD imm comma - { - outcode(int($1), &$2, 0, &nullgen); - } -| LWORD ximm comma - { - outcode(int($1), &$2, 0, &nullgen); - } -/* - * PCDATA - */ -| LPCDAT imm ',' imm - { - if $2.Type != obj.TYPE_CONST || $4.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants") - } - outcode(int($1), &$2, 0, &$4); - } -/* - * FUNCDATA - */ -| LFUNCDAT imm ',' addr - { - if $2.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if $4.Type != obj.TYPE_MEM || ($4.Name != obj.NAME_EXTERN && $4.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference") - } - outcode(int($1), &$2, 0, &$4); - } -/* - * END - */ -| LEND comma - { - outcode(int($1), &nullgen, 0, &nullgen); - } -/* - * TEXT - */ -| LTEXT name ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(int($1), &$2, 0, &$5); - } -| LTEXT name ',' con ',' '$' textsize - { - asm.Settext($2.Sym); - outcode(int($1), &$2, int($4), &$7); - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } -/* - * GLOBL - */ -| LGLOBL name ',' imm - { - asm.Settext($2.Sym) - outcode(int($1), &$2, 0, &$4) - } -| LGLOBL name ',' con ',' imm - { - asm.Settext($2.Sym) - outcode(int($1), &$2, 0, &$6) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } - -/* - * DATA - */ -| LDATA name '/' con ',' imm - { - outcode(int($1), &$2, 0, &$6); - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } -| LDATA name '/' con ',' ximm - { - outcode(int($1), &$2, 0, &$6); - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } -| LDATA name '/' con ',' fimm - { - outcode(int($1), &$2, 0, &$6); - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = $4 - } - } -/* - * RETURN - */ -| LRETRN comma - { - outcode(int($1), &nullgen, 0, &nullgen); - } - -rel: - con '(' LPC ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1 + int64(asm.PC); - } -| LNAME offset - { - $1 = asm.LabelLookup($1); - $$ = nullgen; - if asm.Pass == 2 && $1.Type != LLAB { - yyerror("undefined label: %s", $1.Labelname) - } - $$.Type = obj.TYPE_BRANCH; - $$.Offset = $1.Value + $2; - } - -rreg: - sreg - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } - -xlreg: - lr -| ctr - -lr: - LLR - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } - -lcr: - LCR - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); /* whole register */ - } - -ctr: - LCTR - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } - -msr: - LMSR - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1) - } - -psr: - LSPREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } -| LSPR '(' con ')' - { - if $3 < 0 || $3 >= 1024 { - yyerror("SPR/DCR out of range") - } - $$ = nullgen; - $$.Type = obj.TYPE_REG - $$.Reg = int16($1 + $3); - } -| msr - -fpscr: - LFPSCR - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } - -freg: - LFREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } -| LF '(' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16(REG_F0 + $3); - } - -creg: - LCREG - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } -| LCR '(' con ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16(REG_C0 + $3); - } - - -cbit: con - { - $$ = nullgen; - $$.Type = obj.TYPE_REG; - $$.Reg = int16($1); - } - -mask: - con ',' con - { - var mb, me int - var v uint32 - - $$ = nullgen; - $$.Type = obj.TYPE_CONST; - mb = int($1); - me = int($3); - if(mb < 0 || mb > 31 || me < 0 || me > 31){ - yyerror("illegal mask start/end value(s)"); - mb = 0 - me = 0; - } - if mb <= me { - v = (^uint32(0)>>uint(mb)) & (^uint32(0)<>uint(me+1)) & (^uint32(0)<= NREG { - print("register value out of range\n") - } - $$ = REG_R0 + $3; - } - -regaddr: - '(' sreg ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Reg = int16($2); - $$.Offset = 0; - } -| '(' sreg '+' sreg ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Reg = int16($2); - $$.Scale = int8($4); - $$.Offset = 0; - } - -addr: - name -| con '(' sreg ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Reg = int16($3); - $$.Offset = $1; - } - -name: - con '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = int8($3); - $$.Sym = nil; - $$.Offset = $1; - } -| LNAME offset '(' pointer ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = int8($4); - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 0); - $$.Offset = $2; - } -| LNAME '<' '>' offset '(' LSB ')' - { - $$ = nullgen; - $$.Type = obj.TYPE_MEM; - $$.Name = obj.NAME_STATIC; - $$.Sym = obj.Linklookup(asm.Ctxt, $1.Name, 1); - $$.Offset = $4; - } - -comma: -| ',' - -offset: - { - $$ = 0; - } -| '+' con - { - $$ = $2; - } -| '-' con - { - $$ = -$2; - } - -pointer: - LSB -| LSP -| LFP - -con: - LCONST -| LVAR - { - $$ = $1.Value; - } -| '-' con - { - $$ = -$2; - } -| '+' con - { - $$ = $2; - } -| '~' con - { - $$ = ^$2; - } -| '(' expr ')' - { - $$ = $2; - } - -expr: - con -| expr '+' expr - { - $$ = $1 + $3; - } -| expr '-' expr - { - $$ = $1 - $3; - } -| expr '*' expr - { - $$ = $1 * $3; - } -| expr '/' expr - { - $$ = $1 / $3; - } -| expr '%' expr - { - $$ = $1 % $3; - } -| expr '<' '<' expr - { - $$ = $1 << uint($4); - } -| expr '>' '>' expr - { - $$ = $1 >> uint($4); - } -| expr '&' expr - { - $$ = $1 & $3; - } -| expr '^' expr - { - $$ = $1 ^ $3; - } -| expr '|' expr - { - $$ = $1 | $3; - } diff --git a/src/cmd/new9a/lex.go b/src/cmd/new9a/lex.go deleted file mode 100644 index d480e4540e..0000000000 --- a/src/cmd/new9a/lex.go +++ /dev/null @@ -1,555 +0,0 @@ -// cmd/9a/lex.c from Vita Nuova. -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -//go:generate go tool yacc a.y - -package main - -import ( - "cmd/internal/asm" - "cmd/internal/obj" - "cmd/internal/obj/ppc64" -) - -var ( - yyerror = asm.Yyerror - nullgen obj.Addr - stmtline int32 -) - -func main() { - cinit() - - asm.LSCONST = LSCONST - asm.LCONST = LCONST - asm.LFCONST = LFCONST - asm.LNAME = LNAME - asm.LVAR = LVAR - asm.LLAB = LLAB - - asm.Lexinit = lexinit - asm.Cclean = cclean - asm.Yyparse = yyparse - - asm.Thechar = '9' - asm.Thestring = "ppc64" - asm.Thelinkarch = &ppc64.Linkppc64 - asm.Arches = map[string]*obj.LinkArch{ - "ppc64le": &ppc64.Linkppc64le, - } - - asm.Main() -} - -type yy struct{} - -func (yy) Lex(v *yySymType) int { - var av asm.Yylval - tok := asm.Yylex(&av) - v.sym = av.Sym - v.lval = av.Lval - v.sval = av.Sval - v.dval = av.Dval - return tok -} - -func (yy) Error(msg string) { - asm.Yyerror("%s", msg) -} - -func yyparse() { - nosched = 0 - yyParse(yy{}) -} - -var lexinit = []asm.Lextab{ - {"SP", LSP, obj.NAME_AUTO}, - {"SB", LSB, obj.NAME_EXTERN}, - {"FP", LFP, obj.NAME_PARAM}, - {"PC", LPC, obj.TYPE_BRANCH}, - {"LR", LLR, ppc64.REG_LR}, - {"CTR", LCTR, ppc64.REG_CTR}, - {"XER", LSPREG, ppc64.REG_XER}, - {"MSR", LMSR, ppc64.REG_MSR}, - {"FPSCR", LFPSCR, ppc64.REG_FPSCR}, - {"SPR", LSPR, ppc64.REG_SPR0}, - {"DCR", LSPR, ppc64.REG_DCR0}, - {"CR", LCR, ppc64.REG_CR}, - {"CR0", LCREG, ppc64.REG_C0}, - {"CR1", LCREG, ppc64.REG_C1}, - {"CR2", LCREG, ppc64.REG_C2}, - {"CR3", LCREG, ppc64.REG_C3}, - {"CR4", LCREG, ppc64.REG_C4}, - {"CR5", LCREG, ppc64.REG_C5}, - {"CR6", LCREG, ppc64.REG_C6}, - {"CR7", LCREG, ppc64.REG_C7}, - {"R", LR, 0}, - {"R0", LREG, ppc64.REG_R0}, - {"R1", LREG, ppc64.REG_R1}, - {"R2", LREG, ppc64.REG_R2}, - {"R3", LREG, ppc64.REG_R3}, - {"R4", LREG, ppc64.REG_R4}, - {"R5", LREG, ppc64.REG_R5}, - {"R6", LREG, ppc64.REG_R6}, - {"R7", LREG, ppc64.REG_R7}, - {"R8", LREG, ppc64.REG_R8}, - {"R9", LREG, ppc64.REG_R9}, - {"R10", LREG, ppc64.REG_R10}, - {"R11", LREG, ppc64.REG_R11}, - {"R12", LREG, ppc64.REG_R12}, - {"R13", LREG, ppc64.REG_R13}, - {"R14", LREG, ppc64.REG_R14}, - {"R15", LREG, ppc64.REG_R15}, - {"R16", LREG, ppc64.REG_R16}, - {"R17", LREG, ppc64.REG_R17}, - {"R18", LREG, ppc64.REG_R18}, - {"R19", LREG, ppc64.REG_R19}, - {"R20", LREG, ppc64.REG_R20}, - {"R21", LREG, ppc64.REG_R21}, - {"R22", LREG, ppc64.REG_R22}, - {"R23", LREG, ppc64.REG_R23}, - {"R24", LREG, ppc64.REG_R24}, - {"R25", LREG, ppc64.REG_R25}, - {"R26", LREG, ppc64.REG_R26}, - {"R27", LREG, ppc64.REG_R27}, - {"R28", LREG, ppc64.REG_R28}, - {"R29", LREG, ppc64.REG_R29}, - {"g", LREG, ppc64.REG_R30}, // avoid unintentionally clobbering g using R30 - {"R31", LREG, ppc64.REG_R31}, - {"F", LF, 0}, - {"F0", LFREG, ppc64.REG_F0}, - {"F1", LFREG, ppc64.REG_F1}, - {"F2", LFREG, ppc64.REG_F2}, - {"F3", LFREG, ppc64.REG_F3}, - {"F4", LFREG, ppc64.REG_F4}, - {"F5", LFREG, ppc64.REG_F5}, - {"F6", LFREG, ppc64.REG_F6}, - {"F7", LFREG, ppc64.REG_F7}, - {"F8", LFREG, ppc64.REG_F8}, - {"F9", LFREG, ppc64.REG_F9}, - {"F10", LFREG, ppc64.REG_F10}, - {"F11", LFREG, ppc64.REG_F11}, - {"F12", LFREG, ppc64.REG_F12}, - {"F13", LFREG, ppc64.REG_F13}, - {"F14", LFREG, ppc64.REG_F14}, - {"F15", LFREG, ppc64.REG_F15}, - {"F16", LFREG, ppc64.REG_F16}, - {"F17", LFREG, ppc64.REG_F17}, - {"F18", LFREG, ppc64.REG_F18}, - {"F19", LFREG, ppc64.REG_F19}, - {"F20", LFREG, ppc64.REG_F20}, - {"F21", LFREG, ppc64.REG_F21}, - {"F22", LFREG, ppc64.REG_F22}, - {"F23", LFREG, ppc64.REG_F23}, - {"F24", LFREG, ppc64.REG_F24}, - {"F25", LFREG, ppc64.REG_F25}, - {"F26", LFREG, ppc64.REG_F26}, - {"F27", LFREG, ppc64.REG_F27}, - {"F28", LFREG, ppc64.REG_F28}, - {"F29", LFREG, ppc64.REG_F29}, - {"F30", LFREG, ppc64.REG_F30}, - {"F31", LFREG, ppc64.REG_F31}, - {"CREQV", LCROP, ppc64.ACREQV}, - {"CRXOR", LCROP, ppc64.ACRXOR}, - {"CRAND", LCROP, ppc64.ACRAND}, - {"CROR", LCROP, ppc64.ACROR}, - {"CRANDN", LCROP, ppc64.ACRANDN}, - {"CRORN", LCROP, ppc64.ACRORN}, - {"CRNAND", LCROP, ppc64.ACRNAND}, - {"CRNOR", LCROP, ppc64.ACRNOR}, - {"ADD", LADDW, ppc64.AADD}, - {"ADDV", LADDW, ppc64.AADDV}, - {"ADDCC", LADDW, ppc64.AADDCC}, - {"ADDVCC", LADDW, ppc64.AADDVCC}, - {"ADDC", LADDW, ppc64.AADDC}, - {"ADDCV", LADDW, ppc64.AADDCV}, - {"ADDCCC", LADDW, ppc64.AADDCCC}, - {"ADDCVCC", LADDW, ppc64.AADDCVCC}, - {"ADDE", LLOGW, ppc64.AADDE}, - {"ADDEV", LLOGW, ppc64.AADDEV}, - {"ADDECC", LLOGW, ppc64.AADDECC}, - {"ADDEVCC", LLOGW, ppc64.AADDEVCC}, - {"ADDME", LABS, ppc64.AADDME}, - {"ADDMEV", LABS, ppc64.AADDMEV}, - {"ADDMECC", LABS, ppc64.AADDMECC}, - {"ADDMEVCC", LABS, ppc64.AADDMEVCC}, - {"ADDZE", LABS, ppc64.AADDZE}, - {"ADDZEV", LABS, ppc64.AADDZEV}, - {"ADDZECC", LABS, ppc64.AADDZECC}, - {"ADDZEVCC", LABS, ppc64.AADDZEVCC}, - {"SUB", LADDW, ppc64.ASUB}, - {"SUBV", LADDW, ppc64.ASUBV}, - {"SUBCC", LADDW, ppc64.ASUBCC}, - {"SUBVCC", LADDW, ppc64.ASUBVCC}, - {"SUBE", LLOGW, ppc64.ASUBE}, - {"SUBECC", LLOGW, ppc64.ASUBECC}, - {"SUBEV", LLOGW, ppc64.ASUBEV}, - {"SUBEVCC", LLOGW, ppc64.ASUBEVCC}, - {"SUBC", LADDW, ppc64.ASUBC}, - {"SUBCCC", LADDW, ppc64.ASUBCCC}, - {"SUBCV", LADDW, ppc64.ASUBCV}, - {"SUBCVCC", LADDW, ppc64.ASUBCVCC}, - {"SUBME", LABS, ppc64.ASUBME}, - {"SUBMEV", LABS, ppc64.ASUBMEV}, - {"SUBMECC", LABS, ppc64.ASUBMECC}, - {"SUBMEVCC", LABS, ppc64.ASUBMEVCC}, - {"SUBZE", LABS, ppc64.ASUBZE}, - {"SUBZEV", LABS, ppc64.ASUBZEV}, - {"SUBZECC", LABS, ppc64.ASUBZECC}, - {"SUBZEVCC", LABS, ppc64.ASUBZEVCC}, - {"AND", LADDW, ppc64.AAND}, - {"ANDCC", LADDW, ppc64.AANDCC}, /* includes andil & andiu */ - {"ANDN", LLOGW, ppc64.AANDN}, - {"ANDNCC", LLOGW, ppc64.AANDNCC}, - {"EQV", LLOGW, ppc64.AEQV}, - {"EQVCC", LLOGW, ppc64.AEQVCC}, - {"NAND", LLOGW, ppc64.ANAND}, - {"NANDCC", LLOGW, ppc64.ANANDCC}, - {"NOR", LLOGW, ppc64.ANOR}, - {"NORCC", LLOGW, ppc64.ANORCC}, - {"OR", LADDW, ppc64.AOR}, /* includes oril & oriu */ - {"ORCC", LADDW, ppc64.AORCC}, - {"ORN", LLOGW, ppc64.AORN}, - {"ORNCC", LLOGW, ppc64.AORNCC}, - {"XOR", LADDW, ppc64.AXOR}, /* includes xoril & xoriu */ - {"XORCC", LLOGW, ppc64.AXORCC}, - {"EXTSB", LABS, ppc64.AEXTSB}, - {"EXTSBCC", LABS, ppc64.AEXTSBCC}, - {"EXTSH", LABS, ppc64.AEXTSH}, - {"EXTSHCC", LABS, ppc64.AEXTSHCC}, - {"CNTLZW", LABS, ppc64.ACNTLZW}, - {"CNTLZWCC", LABS, ppc64.ACNTLZWCC}, - {"RLWMI", LRLWM, ppc64.ARLWMI}, - {"RLWMICC", LRLWM, ppc64.ARLWMICC}, - {"RLWNM", LRLWM, ppc64.ARLWNM}, - {"RLWNMCC", LRLWM, ppc64.ARLWNMCC}, - {"SLW", LSHW, ppc64.ASLW}, - {"SLWCC", LSHW, ppc64.ASLWCC}, - {"SRW", LSHW, ppc64.ASRW}, - {"SRWCC", LSHW, ppc64.ASRWCC}, - {"SRAW", LSHW, ppc64.ASRAW}, - {"SRAWCC", LSHW, ppc64.ASRAWCC}, - {"BR", LBRA, ppc64.ABR}, - {"BC", LBRA, ppc64.ABC}, - {"BCL", LBRA, ppc64.ABC}, - {"BL", LBRA, ppc64.ABL}, - {"BEQ", LBRA, ppc64.ABEQ}, - {"BNE", LBRA, ppc64.ABNE}, - {"BGT", LBRA, ppc64.ABGT}, - {"BGE", LBRA, ppc64.ABGE}, - {"BLT", LBRA, ppc64.ABLT}, - {"BLE", LBRA, ppc64.ABLE}, - {"BVC", LBRA, ppc64.ABVC}, - {"BVS", LBRA, ppc64.ABVS}, - {"CMP", LCMP, ppc64.ACMP}, - {"CMPU", LCMP, ppc64.ACMPU}, - {"CMPW", LCMP, ppc64.ACMPW}, - {"CMPWU", LCMP, ppc64.ACMPWU}, - {"DIVW", LLOGW, ppc64.ADIVW}, - {"DIVWV", LLOGW, ppc64.ADIVWV}, - {"DIVWCC", LLOGW, ppc64.ADIVWCC}, - {"DIVWVCC", LLOGW, ppc64.ADIVWVCC}, - {"DIVWU", LLOGW, ppc64.ADIVWU}, - {"DIVWUV", LLOGW, ppc64.ADIVWUV}, - {"DIVWUCC", LLOGW, ppc64.ADIVWUCC}, - {"DIVWUVCC", LLOGW, ppc64.ADIVWUVCC}, - {"FABS", LFCONV, ppc64.AFABS}, - {"FABSCC", LFCONV, ppc64.AFABSCC}, - {"FNEG", LFCONV, ppc64.AFNEG}, - {"FNEGCC", LFCONV, ppc64.AFNEGCC}, - {"FNABS", LFCONV, ppc64.AFNABS}, - {"FNABSCC", LFCONV, ppc64.AFNABSCC}, - {"FADD", LFADD, ppc64.AFADD}, - {"FADDCC", LFADD, ppc64.AFADDCC}, - {"FSUB", LFADD, ppc64.AFSUB}, - {"FSUBCC", LFADD, ppc64.AFSUBCC}, - {"FMUL", LFADD, ppc64.AFMUL}, - {"FMULCC", LFADD, ppc64.AFMULCC}, - {"FDIV", LFADD, ppc64.AFDIV}, - {"FDIVCC", LFADD, ppc64.AFDIVCC}, - {"FRSP", LFCONV, ppc64.AFRSP}, - {"FRSPCC", LFCONV, ppc64.AFRSPCC}, - {"FCTIW", LFCONV, ppc64.AFCTIW}, - {"FCTIWCC", LFCONV, ppc64.AFCTIWCC}, - {"FCTIWZ", LFCONV, ppc64.AFCTIWZ}, - {"FCTIWZCC", LFCONV, ppc64.AFCTIWZCC}, - {"FMADD", LFMA, ppc64.AFMADD}, - {"FMADDCC", LFMA, ppc64.AFMADDCC}, - {"FMSUB", LFMA, ppc64.AFMSUB}, - {"FMSUBCC", LFMA, ppc64.AFMSUBCC}, - {"FNMADD", LFMA, ppc64.AFNMADD}, - {"FNMADDCC", LFMA, ppc64.AFNMADDCC}, - {"FNMSUB", LFMA, ppc64.AFNMSUB}, - {"FNMSUBCC", LFMA, ppc64.AFNMSUBCC}, - {"FMADDS", LFMA, ppc64.AFMADDS}, - {"FMADDSCC", LFMA, ppc64.AFMADDSCC}, - {"FMSUBS", LFMA, ppc64.AFMSUBS}, - {"FMSUBSCC", LFMA, ppc64.AFMSUBSCC}, - {"FNMADDS", LFMA, ppc64.AFNMADDS}, - {"FNMADDSCC", LFMA, ppc64.AFNMADDSCC}, - {"FNMSUBS", LFMA, ppc64.AFNMSUBS}, - {"FNMSUBSCC", LFMA, ppc64.AFNMSUBSCC}, - {"FCMPU", LFCMP, ppc64.AFCMPU}, - {"FCMPO", LFCMP, ppc64.AFCMPO}, - {"MTFSB0", LMTFSB, ppc64.AMTFSB0}, - {"MTFSB1", LMTFSB, ppc64.AMTFSB1}, - {"FMOVD", LFMOV, ppc64.AFMOVD}, - {"FMOVS", LFMOV, ppc64.AFMOVS}, - {"FMOVDCC", LFCONV, ppc64.AFMOVDCC}, /* fmr. */ - {"GLOBL", LGLOBL, obj.AGLOBL}, - {"MOVB", LMOVB, ppc64.AMOVB}, - {"MOVBZ", LMOVB, ppc64.AMOVBZ}, - {"MOVBU", LMOVB, ppc64.AMOVBU}, - {"MOVBZU", LMOVB, ppc64.AMOVBZU}, - {"MOVH", LMOVB, ppc64.AMOVH}, - {"MOVHZ", LMOVB, ppc64.AMOVHZ}, - {"MOVHU", LMOVB, ppc64.AMOVHU}, - {"MOVHZU", LMOVB, ppc64.AMOVHZU}, - {"MOVHBR", LXMV, ppc64.AMOVHBR}, - {"MOVWBR", LXMV, ppc64.AMOVWBR}, - {"MOVW", LMOVW, ppc64.AMOVW}, - {"MOVWU", LMOVW, ppc64.AMOVWU}, - {"MOVMW", LMOVMW, ppc64.AMOVMW}, - {"MOVFL", LMOVW, ppc64.AMOVFL}, - {"MULLW", LADDW, ppc64.AMULLW}, /* includes multiply immediate 10-139 */ - {"MULLWV", LLOGW, ppc64.AMULLWV}, - {"MULLWCC", LLOGW, ppc64.AMULLWCC}, - {"MULLWVCC", LLOGW, ppc64.AMULLWVCC}, - {"MULHW", LLOGW, ppc64.AMULHW}, - {"MULHWCC", LLOGW, ppc64.AMULHWCC}, - {"MULHWU", LLOGW, ppc64.AMULHWU}, - {"MULHWUCC", LLOGW, ppc64.AMULHWUCC}, - {"NEG", LABS, ppc64.ANEG}, - {"NEGV", LABS, ppc64.ANEGV}, - {"NEGCC", LABS, ppc64.ANEGCC}, - {"NEGVCC", LABS, ppc64.ANEGVCC}, - {"NOP", LNOP, obj.ANOP}, /* ori 0,0,0 */ - {"SYSCALL", LNOP, ppc64.ASYSCALL}, - {"UNDEF", LNOP, obj.AUNDEF}, - {"RET", LRETRN, obj.ARET}, - {"RETURN", LRETRN, obj.ARET}, - {"RFI", LRETRN, ppc64.ARFI}, - {"RFCI", LRETRN, ppc64.ARFCI}, - {"DATA", LDATA, obj.ADATA}, - {"END", LEND, obj.AEND}, - {"TEXT", LTEXT, obj.ATEXT}, - - /* 64-bit instructions */ - {"CNTLZD", LABS, ppc64.ACNTLZD}, - {"CNTLZDCC", LABS, ppc64.ACNTLZDCC}, - {"DIVD", LLOGW, ppc64.ADIVD}, - {"DIVDCC", LLOGW, ppc64.ADIVDCC}, - {"DIVDVCC", LLOGW, ppc64.ADIVDVCC}, - {"DIVDV", LLOGW, ppc64.ADIVDV}, - {"DIVDU", LLOGW, ppc64.ADIVDU}, - {"DIVDUCC", LLOGW, ppc64.ADIVDUCC}, - {"DIVDUVCC", LLOGW, ppc64.ADIVDUVCC}, - {"DIVDUV", LLOGW, ppc64.ADIVDUV}, - {"EXTSW", LABS, ppc64.AEXTSW}, - {"EXTSWCC", LABS, ppc64.AEXTSWCC}, - {"FCTID", LFCONV, ppc64.AFCTID}, - {"FCTIDCC", LFCONV, ppc64.AFCTIDCC}, - {"FCTIDZ", LFCONV, ppc64.AFCTIDZ}, - {"FCTIDZCC", LFCONV, ppc64.AFCTIDZCC}, - {"FCFID", LFCONV, ppc64.AFCFID}, - {"FCFIDCC", LFCONV, ppc64.AFCFIDCC}, - {"LDAR", LXLD, ppc64.ALDAR}, - {"MOVD", LMOVW, ppc64.AMOVD}, - {"MOVDU", LMOVW, ppc64.AMOVDU}, - {"MOVWZ", LMOVW, ppc64.AMOVWZ}, - {"MOVWZU", LMOVW, ppc64.AMOVWZU}, - {"MULHD", LLOGW, ppc64.AMULHD}, - {"MULHDCC", LLOGW, ppc64.AMULHDCC}, - {"MULHDU", LLOGW, ppc64.AMULHDU}, - {"MULHDUCC", LLOGW, ppc64.AMULHDUCC}, - {"MULLD", LADDW, ppc64.AMULLD}, /* includes multiply immediate? */ - {"MULLDCC", LLOGW, ppc64.AMULLDCC}, - {"MULLDVCC", LLOGW, ppc64.AMULLDVCC}, - {"MULLDV", LLOGW, ppc64.AMULLDV}, - {"RFID", LRETRN, ppc64.ARFID}, - {"HRFID", LRETRN, ppc64.AHRFID}, - {"RLDMI", LRLWM, ppc64.ARLDMI}, - {"RLDMICC", LRLWM, ppc64.ARLDMICC}, - {"RLDC", LRLWM, ppc64.ARLDC}, - {"RLDCCC", LRLWM, ppc64.ARLDCCC}, - {"RLDCR", LRLWM, ppc64.ARLDCR}, - {"RLDCRCC", LRLWM, ppc64.ARLDCRCC}, - {"RLDCL", LRLWM, ppc64.ARLDCL}, - {"RLDCLCC", LRLWM, ppc64.ARLDCLCC}, - {"SLBIA", LNOP, ppc64.ASLBIA}, - {"SLBIE", LNOP, ppc64.ASLBIE}, - {"SLBMFEE", LABS, ppc64.ASLBMFEE}, - {"SLBMFEV", LABS, ppc64.ASLBMFEV}, - {"SLBMTE", LABS, ppc64.ASLBMTE}, - {"SLD", LSHW, ppc64.ASLD}, - {"SLDCC", LSHW, ppc64.ASLDCC}, - {"SRD", LSHW, ppc64.ASRD}, - {"SRAD", LSHW, ppc64.ASRAD}, - {"SRADCC", LSHW, ppc64.ASRADCC}, - {"SRDCC", LSHW, ppc64.ASRDCC}, - {"STDCCC", LXST, ppc64.ASTDCCC}, - {"TD", LADDW, ppc64.ATD}, - - /* pseudo instructions */ - {"REM", LLOGW, ppc64.AREM}, - {"REMCC", LLOGW, ppc64.AREMCC}, - {"REMV", LLOGW, ppc64.AREMV}, - {"REMVCC", LLOGW, ppc64.AREMVCC}, - {"REMU", LLOGW, ppc64.AREMU}, - {"REMUCC", LLOGW, ppc64.AREMUCC}, - {"REMUV", LLOGW, ppc64.AREMUV}, - {"REMUVCC", LLOGW, ppc64.AREMUVCC}, - {"REMD", LLOGW, ppc64.AREMD}, - {"REMDCC", LLOGW, ppc64.AREMDCC}, - {"REMDV", LLOGW, ppc64.AREMDV}, - {"REMDVCC", LLOGW, ppc64.AREMDVCC}, - {"REMDU", LLOGW, ppc64.AREMDU}, - {"REMDUCC", LLOGW, ppc64.AREMDUCC}, - {"REMDUV", LLOGW, ppc64.AREMDUV}, - {"REMDUVCC", LLOGW, ppc64.AREMDUVCC}, - - /* special instructions */ - {"DCBF", LXOP, ppc64.ADCBF}, - {"DCBI", LXOP, ppc64.ADCBI}, - {"DCBST", LXOP, ppc64.ADCBST}, - {"DCBT", LXOP, ppc64.ADCBT}, - {"DCBTST", LXOP, ppc64.ADCBTST}, - {"DCBZ", LXOP, ppc64.ADCBZ}, - {"ICBI", LXOP, ppc64.AICBI}, - {"ECIWX", LXLD, ppc64.AECIWX}, - {"ECOWX", LXST, ppc64.AECOWX}, - {"LWAR", LXLD, ppc64.ALWAR}, - {"STWCCC", LXST, ppc64.ASTWCCC}, - {"EIEIO", LRETRN, ppc64.AEIEIO}, - {"TLBIE", LNOP, ppc64.ATLBIE}, - {"TLBIEL", LNOP, ppc64.ATLBIEL}, - {"LSW", LXLD, ppc64.ALSW}, - {"STSW", LXST, ppc64.ASTSW}, - {"ISYNC", LRETRN, ppc64.AISYNC}, - {"SYNC", LRETRN, ppc64.ASYNC}, - {"TLBSYNC", LRETRN, ppc64.ATLBSYNC}, - {"PTESYNC", LRETRN, ppc64.APTESYNC}, - - /* "TW", LADDW, ATW,*/ - {"WORD", LWORD, ppc64.AWORD}, - {"DWORD", LWORD, ppc64.ADWORD}, - {"SCHED", LSCHED, 0}, - {"NOSCHED", LSCHED, 0x80}, - {"PCDATA", LPCDAT, obj.APCDATA}, - {"FUNCDATA", LFUNCDAT, obj.AFUNCDATA}, -} - -func cinit() { -} - -func cclean() { - outcode(obj.AEND, &nullgen, 0, &nullgen) -} - -var lastpc *obj.Prog -var nosched int - -func outcode(a int, g1 *obj.Addr, reg int, g2 *obj.Addr) { - var p *obj.Prog - var pl *obj.Plist - - if asm.Pass == 1 { - goto out - } - - if g1.Scale != 0 { - if reg != 0 || g2.Scale != 0 { - yyerror("bad addressing modes") - } - reg = int(g1.Scale) - } else if g2.Scale != 0 { - if reg != 0 { - yyerror("bad addressing modes") - } - reg = int(g2.Scale) - } - - p = asm.Ctxt.NewProg() - p.As = int16(a) - p.Lineno = stmtline - if nosched != 0 { - p.Mark |= ppc64.NOSCHED - } - p.From = *g1 - p.Reg = int16(reg) - p.To = *g2 - p.Pc = int64(asm.PC) - - if lastpc == nil { - pl = obj.Linknewplist(asm.Ctxt) - pl.Firstpc = p - } else { - lastpc.Link = p - } - lastpc = p - -out: - if a != obj.AGLOBL && a != obj.ADATA { - asm.PC++ - } -} - -func outgcode(a int, g1 *obj.Addr, reg int, g2, g3 *obj.Addr) { - var p *obj.Prog - var pl *obj.Plist - - if asm.Pass == 1 { - goto out - } - - p = asm.Ctxt.NewProg() - p.As = int16(a) - p.Lineno = stmtline - if nosched != 0 { - p.Mark |= ppc64.NOSCHED - } - p.From = *g1 - p.Reg = int16(reg) - p.From3 = *g2 - p.To = *g3 - p.Pc = int64(asm.PC) - - if lastpc == nil { - pl = obj.Linknewplist(asm.Ctxt) - pl.Firstpc = p - } else { - lastpc.Link = p - } - lastpc = p - -out: - if a != obj.AGLOBL && a != obj.ADATA { - asm.PC++ - } -} diff --git a/src/cmd/new9a/y.go b/src/cmd/new9a/y.go deleted file mode 100644 index 2e42378059..0000000000 --- a/src/cmd/new9a/y.go +++ /dev/null @@ -1,1953 +0,0 @@ -//line a.y:31 -package main - -import __yyfmt__ "fmt" - -//line a.y:31 -import ( - "cmd/internal/asm" - "cmd/internal/obj" - . "cmd/internal/obj/ppc64" -) - -//line a.y:40 -type yySymType struct { - yys int - sym *asm.Sym - lval int64 - dval float64 - sval string - addr obj.Addr -} - -const LMOVW = 57346 -const LMOVB = 57347 -const LABS = 57348 -const LLOGW = 57349 -const LSHW = 57350 -const LADDW = 57351 -const LCMP = 57352 -const LCROP = 57353 -const LBRA = 57354 -const LFMOV = 57355 -const LFCONV = 57356 -const LFCMP = 57357 -const LFADD = 57358 -const LFMA = 57359 -const LTRAP = 57360 -const LXORW = 57361 -const LNOP = 57362 -const LEND = 57363 -const LRETT = 57364 -const LWORD = 57365 -const LTEXT = 57366 -const LDATA = 57367 -const LGLOBL = 57368 -const LRETRN = 57369 -const LCONST = 57370 -const LSP = 57371 -const LSB = 57372 -const LFP = 57373 -const LPC = 57374 -const LCREG = 57375 -const LFLUSH = 57376 -const LREG = 57377 -const LFREG = 57378 -const LR = 57379 -const LCR = 57380 -const LF = 57381 -const LFPSCR = 57382 -const LLR = 57383 -const LCTR = 57384 -const LSPR = 57385 -const LSPREG = 57386 -const LSEG = 57387 -const LMSR = 57388 -const LPCDAT = 57389 -const LFUNCDAT = 57390 -const LSCHED = 57391 -const LXLD = 57392 -const LXST = 57393 -const LXOP = 57394 -const LXMV = 57395 -const LRLWM = 57396 -const LMOVMW = 57397 -const LMOVEM = 57398 -const LMOVFL = 57399 -const LMTFSB = 57400 -const LMA = 57401 -const LFCONST = 57402 -const LSCONST = 57403 -const LNAME = 57404 -const LLAB = 57405 -const LVAR = 57406 - -var yyToknames = []string{ - "'|'", - "'^'", - "'&'", - "'<'", - "'>'", - "'+'", - "'-'", - "'*'", - "'/'", - "'%'", - "LMOVW", - "LMOVB", - "LABS", - "LLOGW", - "LSHW", - "LADDW", - "LCMP", - "LCROP", - "LBRA", - "LFMOV", - "LFCONV", - "LFCMP", - "LFADD", - "LFMA", - "LTRAP", - "LXORW", - "LNOP", - "LEND", - "LRETT", - "LWORD", - "LTEXT", - "LDATA", - "LGLOBL", - "LRETRN", - "LCONST", - "LSP", - "LSB", - "LFP", - "LPC", - "LCREG", - "LFLUSH", - "LREG", - "LFREG", - "LR", - "LCR", - "LF", - "LFPSCR", - "LLR", - "LCTR", - "LSPR", - "LSPREG", - "LSEG", - "LMSR", - "LPCDAT", - "LFUNCDAT", - "LSCHED", - "LXLD", - "LXST", - "LXOP", - "LXMV", - "LRLWM", - "LMOVMW", - "LMOVEM", - "LMOVFL", - "LMTFSB", - "LMA", - "LFCONST", - "LSCONST", - "LNAME", - "LLAB", - "LVAR", -} -var yyStatenames = []string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyMaxDepth = 200 - -//line yacctab:1 -var yyExca = []int{ - -1, 1, - 1, -1, - -2, 2, -} - -const yyNprod = 187 -const yyPrivate = 57344 - -var yyTokenNames []string -var yyStates []string - -const yyLast = 900 - -var yyAct = []int{ - - 48, 394, 54, 90, 427, 273, 440, 58, 52, 102, - 80, 79, 85, 172, 94, 95, 97, 98, 100, 101, - 51, 57, 113, 3, 80, 79, 56, 121, 123, 125, - 435, 128, 130, 91, 133, 53, 278, 138, 74, 77, - 75, 66, 164, 117, 118, 119, 120, 454, 453, 93, - 96, 65, 99, 77, 134, 417, 127, 114, 94, 74, - 416, 75, 74, 122, 75, 406, 83, 84, 105, 136, - 137, 139, 140, 76, 94, 78, 80, 79, 405, 384, - 62, 127, 94, 81, 383, 205, 148, 150, 149, 78, - 50, 380, 116, 369, 104, 94, 127, 81, 368, 61, - 61, 61, 87, 89, 367, 77, 366, 277, 103, 110, - 364, 363, 316, 63, 407, 198, 64, 61, 284, 55, - 126, 205, 129, 131, 162, 206, 232, 143, 143, 143, - 169, 74, 63, 75, 171, 64, 225, 204, 205, 76, - 109, 78, 170, 165, 448, 47, 62, 447, 92, 81, - 446, 445, 248, 256, 257, 168, 226, 264, 265, 254, - 269, 270, 271, 260, 135, 444, 443, 94, 176, 177, - 178, 235, 399, 253, 398, 397, 262, 199, 255, 393, - 288, 291, 292, 189, 392, 267, 391, 251, 390, 389, - 261, 303, 305, 307, 309, 311, 312, 202, 388, 387, - 166, 386, 385, 293, 294, 295, 296, 314, 379, 317, - 115, 49, 86, 88, 378, 332, 334, 335, 336, 377, - 338, 106, 342, 376, 375, 374, 302, 373, 372, 124, - 362, 328, 329, 330, 331, 361, 233, 231, 230, 229, - 61, 116, 250, 61, 132, 259, 222, 221, 141, 220, - 333, 219, 146, 218, 280, 339, 341, 217, 281, 282, - 283, 216, 215, 286, 287, 344, 214, 213, 61, 348, - 290, 252, 318, 321, 61, 263, 298, 300, 266, 268, - 351, 352, 353, 354, 355, 212, 315, 358, 359, 360, - 370, 211, 202, 324, 59, 210, 80, 79, 209, 371, - 207, 203, 197, 196, 195, 194, 193, 61, 192, 200, - 191, 340, 190, 343, 188, 185, 184, 80, 79, 61, - 347, 183, 349, 350, 208, 77, 182, 181, 381, 180, - 67, 382, 74, 63, 75, 68, 64, 65, 83, 84, - 70, 69, 179, 82, 223, 224, 77, 161, 227, 228, - 160, 159, 249, 158, 157, 258, 156, 163, 155, 76, - 154, 78, 153, 152, 151, 46, 62, 45, 66, 81, - 44, 404, 187, 408, 409, 410, 411, 412, 413, 414, - 289, 299, 78, 402, 42, 43, 297, 104, 63, 415, - 81, 64, 67, 431, 65, 63, 430, 112, 64, 400, - 401, 403, 438, 439, 319, 322, 421, 422, 246, 245, - 244, 242, 243, 237, 238, 239, 240, 241, 67, 337, - 441, 461, 163, 112, 449, 434, 426, 429, 442, 234, - 450, 345, 186, 433, 436, 437, 357, 451, 74, 63, - 75, 74, 64, 75, 285, 456, 457, 356, 459, 460, - 67, 8, 418, 60, 67, 112, 74, 272, 75, 112, - 70, 69, 396, 82, 455, 275, 274, 276, 103, 174, - 175, 74, 202, 75, 275, 274, 276, 80, 452, 428, - 428, 247, 147, 2, 432, 301, 304, 306, 308, 310, - 395, 313, 142, 144, 145, 275, 274, 276, 325, 9, - 272, 74, 326, 75, 327, 1, 77, 423, 424, 425, - 71, 10, 11, 17, 15, 16, 14, 26, 19, 20, - 12, 22, 25, 23, 24, 21, 73, 33, 37, 168, - 34, 38, 40, 39, 41, 458, 72, 0, 186, 167, - 76, 176, 78, 80, 79, 0, 173, 104, 174, 175, - 81, 239, 240, 241, 35, 36, 6, 29, 30, 32, - 31, 27, 28, 80, 79, 13, 18, 0, 0, 4, - 0, 5, 77, 365, 7, 0, 0, 67, 0, 74, - 0, 75, 68, 0, 419, 83, 84, 70, 69, 0, - 82, 0, 77, 0, 80, 79, 0, 67, 0, 0, - 80, 79, 112, 0, 0, 0, 76, 0, 78, 80, - 79, 0, 0, 62, 0, 94, 81, 237, 238, 239, - 240, 241, 0, 77, 0, 0, 111, 0, 78, 77, - 0, 63, 108, 107, 64, 0, 81, 0, 77, 80, - 79, 0, 0, 0, 0, 74, 0, 75, 245, 244, - 242, 243, 237, 238, 239, 240, 241, 76, 0, 78, - 0, 0, 167, 76, 62, 78, 0, 81, 77, 0, - 104, 0, 76, 81, 78, 74, 0, 75, 0, 62, - 0, 0, 81, 246, 245, 244, 242, 243, 237, 238, - 239, 240, 241, 80, 79, 80, 79, 80, 79, 0, - 0, 0, 76, 0, 78, 0, 80, 79, 0, 104, - 80, 79, 81, 0, 0, 0, 0, 0, 0, 80, - 79, 0, 77, 0, 77, 0, 77, 0, 0, 74, - 0, 75, 80, 79, 0, 77, 0, 0, 0, 77, - 0, 0, 0, 80, 79, 0, 0, 0, 77, 0, - 0, 0, 80, 79, 0, 0, 299, 0, 78, 279, - 78, 77, 78, 104, 0, 104, 81, 104, 81, 94, - 81, 78, 77, 111, 0, 78, 104, 0, 346, 81, - 420, 77, 76, 81, 78, 0, 0, 0, 0, 104, - 0, 0, 81, 0, 0, 111, 0, 78, 0, 0, - 0, 0, 323, 0, 0, 81, 111, 0, 78, 0, - 0, 0, 0, 320, 0, 111, 81, 78, 0, 0, - 0, 0, 201, 0, 0, 81, 246, 245, 244, 242, - 243, 237, 238, 239, 240, 241, 244, 242, 243, 237, - 238, 239, 240, 241, 242, 243, 237, 238, 239, 240, - 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, -} -var yyPact = []int{ - - -1000, -1000, 497, -1000, 309, 294, 290, -1000, 288, 68, - 287, 600, 67, -67, -7, 396, -7, 396, 396, 308, - 554, 14, 342, 342, 342, 342, 396, -7, 630, 2, - 396, 17, 2, 86, -40, -67, -67, 163, 710, 710, - 710, 163, -1000, 308, 308, -1000, -1000, -1000, 286, 285, - 284, 282, 280, 278, 276, 275, 273, 272, 269, -1000, - -1000, 45, 684, -1000, 64, -1000, 591, -1000, 51, -1000, - 63, -1000, -1000, -1000, -1000, 55, 539, -1000, -1000, 308, - 308, 308, -1000, -1000, -1000, 264, 251, 249, 248, 243, - 238, 237, 362, 236, 308, 234, 232, 230, 228, 227, - 226, 225, 224, -1000, 308, -1000, -1000, 15, 743, 223, - 59, 539, 51, 222, 220, -1000, -1000, 217, 213, 207, - 189, 188, 184, 183, 179, 175, 173, 396, 171, 169, - 168, -1000, -1000, 163, 163, 393, -1000, 163, 163, 161, - 160, -1000, 159, 47, 158, 417, -1000, 497, 822, -1000, - 404, 534, 396, 396, 1, 349, 396, 396, 407, 411, - 396, 396, 426, 27, 679, 308, -1000, -1000, 45, 308, - 308, 308, 39, 436, 308, 308, -1000, -1000, -1000, 600, - 396, 396, 342, 342, 342, 585, -1000, 311, 308, -1000, - -7, 396, 396, 396, 396, 396, 396, 308, 32, -1000, - -1000, 15, 42, 734, 723, 456, 39, 396, -1000, 396, - 342, 342, 342, 342, -7, 396, 396, 396, 710, -7, - -23, 396, 2, -1000, -1000, -1000, -1000, -1000, -1000, -67, - 710, 697, 435, 688, 308, -1000, -1000, 308, 308, 308, - 308, 308, 440, 428, 308, 308, 308, -1000, -1000, -1000, - -1000, 157, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 152, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 31, 30, -1000, -1000, -1000, -1000, 396, -1000, - 26, 24, 18, 13, 435, 460, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 150, 149, -1000, 147, -1000, 146, -1000, 145, -1000, - 141, -1000, -1000, 136, -1000, 130, -1000, 11, -1000, -1000, - 15, -1000, -1000, 15, 6, -1, -1000, -1000, -1000, 124, - 123, 121, 120, 111, 110, 108, -1000, -1000, -1000, 106, - -1000, 101, -1000, -1000, -1000, -1000, 452, 97, -1000, 96, - 94, 540, 540, -1000, -1000, -1000, 308, 308, 837, 830, - 643, 353, 344, -1000, -1000, -2, -1000, -1000, -1000, -1000, - -15, 35, 396, 396, 396, 396, 396, 396, 396, 308, - -1000, -20, -25, 701, -1000, 342, 342, 375, 375, 375, - 688, 688, 396, 2, -1000, 423, 387, -51, -67, -75, - 608, 608, -1000, -1000, -1000, -1000, -1000, 380, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 15, -1000, 88, -1000, -1000, -1000, 87, 73, 72, 69, - 66, -1000, -1000, 386, 420, 452, -1000, -1000, -1000, -1000, - 468, -32, -33, 342, 396, 396, 308, 396, 396, -1000, - 383, -1000, 686, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -} -var yyPgo = []int{ - - 0, 88, 42, 5, 13, 294, 200, 0, 90, 453, - 119, 20, 7, 536, 526, 1, 35, 2, 3, 68, - 26, 21, 9, 8, 510, 4, 505, 483, 23, 482, - 451, 210, -} -var yyR1 = []int{ - - 0, 26, 27, 26, 29, 28, 28, 28, 28, 28, - 28, 28, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 19, 19, 7, 12, 12, - 13, 21, 14, 24, 20, 20, 20, 23, 11, 11, - 10, 10, 22, 25, 15, 15, 15, 15, 17, 17, - 18, 18, 16, 5, 5, 8, 8, 6, 6, 9, - 9, 9, 31, 31, 4, 4, 4, 3, 3, 3, - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, -} -var yyR2 = []int{ - - 0, 0, 0, 3, 0, 4, 4, 4, 2, 1, - 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 6, 4, 4, 6, 4, 4, 6, 6, - 6, 4, 4, 6, 4, 6, 4, 6, 4, 4, - 2, 6, 4, 4, 4, 6, 4, 4, 4, 4, - 4, 4, 4, 4, 2, 2, 4, 3, 3, 5, - 4, 4, 6, 4, 4, 6, 6, 6, 8, 4, - 4, 3, 2, 4, 4, 6, 8, 4, 6, 4, - 4, 6, 6, 8, 8, 8, 8, 4, 4, 4, - 6, 4, 6, 4, 4, 2, 2, 3, 3, 3, - 3, 2, 3, 3, 4, 4, 2, 5, 7, 4, - 6, 6, 6, 6, 2, 4, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 1, 1, 1, 4, - 1, 4, 1, 3, 1, 2, 3, 4, 2, 2, - 2, 3, 2, 1, 4, 3, 5, 1, 4, 4, - 5, 7, 0, 1, 0, 2, 2, 1, 1, 1, - 1, 1, 2, 2, 2, 3, 1, 3, 3, 3, - 3, 3, 4, 4, 3, 3, 3, -} -var yyChk = []int{ - - -1000, -26, -27, -28, 72, 74, 59, 77, -30, 2, - 14, 15, 23, 68, 19, 17, 18, 16, 69, 21, - 22, 28, 24, 26, 27, 25, 20, 64, 65, 60, - 61, 63, 62, 30, 33, 57, 58, 31, 34, 36, - 35, 37, 75, 76, 76, 77, 77, 77, -7, -6, - -8, -11, -23, -16, -17, -10, -20, -21, -12, -5, - -9, -1, 79, 46, 49, 50, 81, 43, 48, 54, - 53, -24, -13, -14, 45, 47, 72, 38, 74, 10, - 9, 82, 56, 51, 52, -7, -6, -8, -6, -8, - -18, -11, 81, -16, 81, -7, -16, -7, -7, -16, - -7, -7, -22, -1, 79, -19, -6, 79, 78, -10, - -1, 72, 48, -7, -16, -31, 78, -11, -11, -11, - -11, -7, -16, -7, -6, -7, -8, 79, -7, -8, - -7, -8, -31, -7, -11, 78, -16, -16, -17, -16, - -16, -31, -9, -1, -9, -9, -31, -29, -2, -1, - -2, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 79, -5, -2, 79, -6, 71, -1, 79, - 79, 79, -4, 7, 9, 10, -1, -1, -1, 78, - 78, 78, 78, 78, 78, 78, 70, 10, 78, -1, - 78, 78, 78, 78, 78, 78, 78, 78, -12, -19, - -6, 79, -1, 78, 78, 79, -4, 78, -31, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, -31, -31, -7, -11, -31, -31, 78, - 78, 78, 79, 78, 12, -28, 77, 9, 10, 11, - 12, 13, 7, 8, 6, 5, 4, 77, -7, -6, - -8, -16, -10, -21, -12, -20, -7, -7, -6, -8, - -23, -16, -11, -10, -7, -7, -10, -20, -10, -7, - -7, -7, -5, -3, 40, 39, 41, 80, 9, 80, - -1, -1, -1, -1, 79, 8, -1, -1, -7, -6, - -8, -7, -7, -11, -11, -11, -11, -6, -8, 70, - -1, -5, -16, -7, -5, -7, -5, -7, -5, -7, - -5, -7, -7, -5, -22, -1, 80, -12, -19, -6, - 79, -19, -6, 79, -1, 42, -5, -5, -11, -11, - -11, -11, -7, -16, -7, -7, -7, -6, -7, -16, - -8, -16, -7, -8, -16, -6, 81, -1, -16, -1, - -1, -2, -2, -2, -2, -2, 7, 8, -2, -2, - -2, 78, 78, 80, 80, -5, 80, 80, 80, 80, - -3, -4, 78, 78, 78, 78, 78, 78, 78, 78, - 80, -12, -12, 78, 80, 78, 78, 78, 78, 78, - 78, 78, 78, 78, -15, 38, 10, 78, 78, 78, - -2, -2, -21, 48, -23, 80, 80, 79, -7, -7, - -7, -7, -7, -7, -7, -22, 80, 80, -19, -6, - 79, -11, -11, -10, -10, -10, -16, -25, -1, -16, - -25, -7, -8, 10, 38, 81, -16, -16, -17, -18, - 81, 40, -12, 78, 78, 78, 78, 78, 78, 38, - 10, -15, 10, 80, 80, -11, -7, -7, -1, -7, - -7, 38, -} -var yyDef = []int{ - - 1, -2, 0, 3, 0, 0, 0, 9, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 162, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 162, 0, 0, 0, 162, 0, 0, - 0, 162, 4, 0, 0, 8, 10, 11, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, - 157, 0, 0, 138, 0, 137, 0, 140, 131, 134, - 0, 136, 128, 129, 153, 0, 164, 170, 171, 0, - 0, 0, 133, 130, 132, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 50, 0, 0, 142, 0, 64, 65, 0, 0, 0, - 0, 164, 0, 162, 0, 82, 163, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 105, 106, 162, 162, 163, 111, 162, 162, 0, - 0, 116, 0, 0, 0, 0, 124, 0, 0, 176, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 148, 149, 152, 0, - 0, 0, 0, 0, 0, 0, 172, 173, 174, 0, - 0, 0, 0, 0, 0, 0, 150, 0, 0, 152, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, - 68, 0, 0, 0, 0, 0, 126, 163, 81, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 107, 108, 109, 110, 112, 113, 0, - 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 7, 12, 24, - 25, 0, 36, 37, 61, 63, 13, 14, 28, 29, - 31, 0, 30, 33, 52, 53, 56, 62, 57, 59, - 58, 60, 0, 0, 167, 168, 169, 155, 0, 175, - 0, 0, 0, 0, 0, 164, 165, 166, 15, 26, - 27, 16, 17, 18, 19, 20, 21, 22, 23, 151, - 34, 127, 0, 41, 127, 42, 127, 44, 127, 46, - 127, 48, 49, 0, 54, 142, 66, 0, 70, 71, - 0, 73, 74, 0, 0, 0, 79, 80, 83, 84, - 0, 87, 89, 90, 0, 0, 97, 98, 99, 0, - 101, 0, 103, 104, 114, 115, 0, 0, 119, 0, - 0, 177, 178, 179, 180, 181, 0, 0, 184, 185, - 186, 0, 0, 158, 159, 0, 139, 141, 135, 154, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 69, 0, 0, 0, 125, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 117, 144, 0, 0, 0, 0, - 182, 183, 35, 131, 32, 156, 160, 0, 38, 40, - 39, 43, 45, 47, 51, 55, 72, 75, 76, 77, - 0, 85, 0, 88, 91, 92, 0, 0, 0, 0, - 0, 100, 102, 0, 145, 0, 120, 121, 122, 123, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 146, - 0, 118, 0, 161, 78, 86, 93, 94, 143, 95, - 96, 147, -} -var yyTok1 = []int{ - - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 81, 13, 6, 3, - 79, 80, 11, 9, 78, 10, 3, 12, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 75, 77, - 7, 76, 8, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 4, 3, 82, -} -var yyTok2 = []int{ - - 2, 3, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, -} -var yyTok3 = []int{ - 0, -} - -//line yaccpar:1 - -/* parser for yacc output */ - -var yyDebug = 0 - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -type yyParser interface { - Parse(yyLexer) int - Lookahead() int -} - -type yyParserImpl struct { - lookahead func() int -} - -func (p *yyParserImpl) Lookahead() int { - return p.lookahead() -} - -func yyNewParser() yyParser { - p := &yyParserImpl{ - lookahead: func() int { return -1 }, - } - return p -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - // 4 is TOKSTART above - if c >= 4 && c-4 < len(yyToknames) { - if yyToknames[c-4] != "" { - return yyToknames[c-4] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yylex1(lex yyLexer, lval *yySymType) (char, token int) { - token = 0 - char = lex.Lex(lval) - if char <= 0 { - token = yyTok1[0] - goto out - } - if char < len(yyTok1) { - token = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - token = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - token = yyTok3[i+0] - if token == char { - token = yyTok3[i+1] - goto out - } - } - -out: - if token == 0 { - token = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) - } - return char, token -} - -func yyParse(yylex yyLexer) int { - return yyNewParser().Parse(yylex) -} - -func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { - var yyn int - var yylval yySymType - var yyVAL yySymType - var yyDollar []yySymType - yyS := make([]yySymType, yyMaxDepth) - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yychar := -1 - yytoken := -1 // yychar translated into internal numbering - yyrcvr.lookahead = func() int { return yychar } - defer func() { - // Make sure we report no lookahead when not parsing. - yychar = -1 - yytoken = -1 - }() - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yychar < 0 { - yychar, yytoken = yylex1(yylex, &yylval) - } - yyn += yytoken - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yytoken { /* valid shift */ - yychar = -1 - yytoken = -1 - yyVAL = yylval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yychar < 0 { - yychar, yytoken = yylex1(yylex, &yylval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yytoken { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error("syntax error") - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) - } - if yytoken == yyEofCode { - goto ret1 - } - yychar = -1 - yytoken = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 2: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:72 - { - stmtline = asm.Lineno - } - case 4: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:79 - { - yyDollar[1].sym = asm.LabelLookup(yyDollar[1].sym) - if yyDollar[1].sym.Type == LLAB && yyDollar[1].sym.Value != int64(asm.PC) { - yyerror("redeclaration of %s", yyDollar[1].sym.Labelname) - } - yyDollar[1].sym.Type = LLAB - yyDollar[1].sym.Value = int64(asm.PC) - } - case 6: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:89 - { - yyDollar[1].sym.Type = LVAR - yyDollar[1].sym.Value = yyDollar[3].lval - } - case 7: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:94 - { - if yyDollar[1].sym.Value != yyDollar[3].lval { - yyerror("redeclaration of %s", yyDollar[1].sym.Name) - } - yyDollar[1].sym.Value = yyDollar[3].lval - } - case 8: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:101 - { - nosched = int(yyDollar[1].lval) - } - case 12: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:113 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 13: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:117 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 14: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:121 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 15: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:125 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 16: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:129 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 17: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:133 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 18: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:140 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 19: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:144 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 20: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:148 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 21: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:152 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 22: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:156 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 23: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:160 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 24: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:167 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 25: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:171 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 26: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:175 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 27: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:179 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 28: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:186 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 29: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:190 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 30: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:197 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 31: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:201 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 32: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:205 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) - } - case 33: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:209 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 34: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:213 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) - } - case 35: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:220 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) - } - case 36: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:224 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 37: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:228 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 38: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:238 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 39: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:242 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 40: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:246 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) - } - case 41: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:250 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 42: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:254 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 43: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:258 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 44: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:262 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 45: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:266 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 46: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:270 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 47: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:274 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 48: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:278 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 49: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:282 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 50: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:286 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[2].addr) - } - case 51: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:293 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 52: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:300 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 53: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:304 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 54: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:311 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[4].addr) - } - case 55: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:315 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[6].addr) - } - case 56: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:323 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 57: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:327 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 58: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:331 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 59: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:335 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 60: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:339 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 61: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:343 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 62: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:347 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 63: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:351 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 64: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:360 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[2].addr) - } - case 65: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:364 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[2].addr) - } - case 66: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:368 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) - } - case 67: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:372 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) - } - case 68: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:376 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) - } - case 69: - yyDollar = yyS[yypt-5 : yypt+1] - //line a.y:380 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[4].addr) - } - case 70: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:384 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 71: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:388 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 72: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:392 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[5].addr) - } - case 73: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:396 - { - outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[4].addr) - } - case 74: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:400 - { - outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[4].addr) - } - case 75: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:404 - { - outcode(int(yyDollar[1].lval), &nullgen, int(yyDollar[2].lval), &yyDollar[5].addr) - } - case 76: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:408 - { - var g obj.Addr - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = yyDollar[2].lval - outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[6].addr) - } - case 77: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:416 - { - var g obj.Addr - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = yyDollar[2].lval - outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[6].addr) - } - case 78: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:424 - { - var g obj.Addr - g = nullgen - g.Type = obj.TYPE_CONST - g.Offset = yyDollar[2].lval - outcode(int(yyDollar[1].lval), &g, int(REG_R0+yyDollar[4].lval), &yyDollar[7].addr) - } - case 79: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:435 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) - } - case 80: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:439 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &nullgen) - } - case 81: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:443 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 82: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:447 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) - } - case 83: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:454 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 84: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:458 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 85: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:462 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr) - } - case 86: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:466 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) - } - case 87: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:470 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 88: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:474 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) - } - case 89: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:481 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 90: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:485 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 91: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:489 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) - } - case 92: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:493 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[6].addr.Reg), &yyDollar[4].addr) - } - case 93: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:500 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) - } - case 94: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:504 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) - } - case 95: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:508 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) - } - case 96: - yyDollar = yyS[yypt-8 : yypt+1] - //line a.y:512 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].addr.Reg), &yyDollar[6].addr, &yyDollar[8].addr) - } - case 97: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:519 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 98: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:523 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 99: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:531 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 100: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:535 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) - } - case 101: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:539 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 102: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:543 - { - outgcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr, &yyDollar[6].addr) - } - case 103: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:547 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 104: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:551 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 105: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:555 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 106: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:562 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) - } - case 107: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:566 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 108: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:570 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 109: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:574 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) - } - case 110: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:578 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &yyDollar[3].addr) - } - case 111: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:582 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 112: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:589 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 113: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:593 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &nullgen) - } - case 114: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:600 - { - if yyDollar[2].addr.Type != obj.TYPE_CONST || yyDollar[4].addr.Type != obj.TYPE_CONST { - yyerror("arguments to PCDATA must be integer constants") - } - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 115: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:610 - { - if yyDollar[2].addr.Type != obj.TYPE_CONST { - yyerror("index for FUNCDATA must be integer constant") - } - if yyDollar[4].addr.Type != obj.TYPE_MEM || (yyDollar[4].addr.Name != obj.NAME_EXTERN && yyDollar[4].addr.Name != obj.NAME_STATIC) { - yyerror("value for FUNCDATA must be symbol reference") - } - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 116: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:623 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) - } - case 117: - yyDollar = yyS[yypt-5 : yypt+1] - //line a.y:630 - { - asm.Settext(yyDollar[2].addr.Sym) - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[5].addr) - } - case 118: - yyDollar = yyS[yypt-7 : yypt+1] - //line a.y:635 - { - asm.Settext(yyDollar[2].addr.Sym) - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, int(yyDollar[4].lval), &yyDollar[7].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyDollar[4].lval - } - } - case 119: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:647 - { - asm.Settext(yyDollar[2].addr.Sym) - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[4].addr) - } - case 120: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:652 - { - asm.Settext(yyDollar[2].addr.Sym) - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyDollar[4].lval - } - } - case 121: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:665 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyDollar[4].lval - } - } - case 122: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:673 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyDollar[4].lval - } - } - case 123: - yyDollar = yyS[yypt-6 : yypt+1] - //line a.y:681 - { - outcode(int(yyDollar[1].lval), &yyDollar[2].addr, 0, &yyDollar[6].addr) - if asm.Pass > 1 { - lastpc.From3.Type = obj.TYPE_CONST - lastpc.From3.Offset = yyDollar[4].lval - } - } - case 124: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:692 - { - outcode(int(yyDollar[1].lval), &nullgen, 0, &nullgen) - } - case 125: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:698 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyDollar[1].lval + int64(asm.PC) - } - case 126: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:704 - { - yyDollar[1].sym = asm.LabelLookup(yyDollar[1].sym) - yyVAL.addr = nullgen - if asm.Pass == 2 && yyDollar[1].sym.Type != LLAB { - yyerror("undefined label: %s", yyDollar[1].sym.Labelname) - } - yyVAL.addr.Type = obj.TYPE_BRANCH - yyVAL.addr.Offset = yyDollar[1].sym.Value + yyDollar[2].lval - } - case 127: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:716 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 128: - yyVAL.addr = yyS[yypt-0].addr - case 129: - yyVAL.addr = yyS[yypt-0].addr - case 130: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:728 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 131: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:736 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) /* whole register */ - } - case 132: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:743 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 133: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:751 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 134: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:759 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 135: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:765 - { - if yyDollar[3].lval < 0 || yyDollar[3].lval >= 1024 { - yyerror("SPR/DCR out of range") - } - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval + yyDollar[3].lval) - } - case 136: - yyVAL.addr = yyS[yypt-0].addr - case 137: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:777 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 138: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:785 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 139: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:791 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(REG_F0 + yyDollar[3].lval) - } - case 140: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:799 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 141: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:805 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(REG_C0 + yyDollar[3].lval) - } - case 142: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:813 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_REG - yyVAL.addr.Reg = int16(yyDollar[1].lval) - } - case 143: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:821 - { - var mb, me int - var v uint32 - - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - mb = int(yyDollar[1].lval) - me = int(yyDollar[3].lval) - if mb < 0 || mb > 31 || me < 0 || me > 31 { - yyerror("illegal mask start/end value(s)") - mb = 0 - me = 0 - } - if mb <= me { - v = (^uint32(0) >> uint(mb)) & (^uint32(0) << uint(31-me)) - } else { - v = (^uint32(0) >> uint(me+1)) & (^uint32(0) << uint(31-(mb-1))) - } - yyVAL.addr.Offset = int64(v) - } - case 144: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:844 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = int64(yyDollar[1].lval) - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 145: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:851 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -int64(yyDollar[2].lval) - yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown - } - case 146: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:858 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = int64(yyDollar[1].lval) - yyVAL.addr.U.Argsize = int32(yyDollar[3].lval) - } - case 147: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:865 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_TEXTSIZE - yyVAL.addr.Offset = -int64(yyDollar[2].lval) - yyVAL.addr.U.Argsize = int32(yyDollar[4].lval) - } - case 148: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:874 - { - yyVAL.addr = yyDollar[2].addr - yyVAL.addr.Type = obj.TYPE_ADDR - } - case 149: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:879 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_SCONST - yyVAL.addr.U.Sval = yyDollar[2].sval - } - case 150: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:887 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = yyDollar[2].dval - } - case 151: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:893 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_FCONST - yyVAL.addr.U.Dval = -yyDollar[3].dval - } - case 152: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:900 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_CONST - yyVAL.addr.Offset = yyDollar[2].lval - } - case 153: - yyVAL.lval = yyS[yypt-0].lval - case 154: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:909 - { - if yyVAL.lval < 0 || yyVAL.lval >= NREG { - print("register value out of range\n") - } - yyVAL.lval = REG_R0 + yyDollar[3].lval - } - case 155: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:918 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyDollar[2].lval) - yyVAL.addr.Offset = 0 - } - case 156: - yyDollar = yyS[yypt-5 : yypt+1] - //line a.y:925 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyDollar[2].lval) - yyVAL.addr.Scale = int8(yyDollar[4].lval) - yyVAL.addr.Offset = 0 - } - case 157: - yyVAL.addr = yyS[yypt-0].addr - case 158: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:936 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Reg = int16(yyDollar[3].lval) - yyVAL.addr.Offset = yyDollar[1].lval - } - case 159: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:945 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyDollar[3].lval) - yyVAL.addr.Sym = nil - yyVAL.addr.Offset = yyDollar[1].lval - } - case 160: - yyDollar = yyS[yypt-5 : yypt+1] - //line a.y:953 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = int8(yyDollar[4].lval) - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyDollar[1].sym.Name, 0) - yyVAL.addr.Offset = yyDollar[2].lval - } - case 161: - yyDollar = yyS[yypt-7 : yypt+1] - //line a.y:961 - { - yyVAL.addr = nullgen - yyVAL.addr.Type = obj.TYPE_MEM - yyVAL.addr.Name = obj.NAME_STATIC - yyVAL.addr.Sym = obj.Linklookup(asm.Ctxt, yyDollar[1].sym.Name, 1) - yyVAL.addr.Offset = yyDollar[4].lval - } - case 164: - yyDollar = yyS[yypt-0 : yypt+1] - //line a.y:973 - { - yyVAL.lval = 0 - } - case 165: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:977 - { - yyVAL.lval = yyDollar[2].lval - } - case 166: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:981 - { - yyVAL.lval = -yyDollar[2].lval - } - case 167: - yyVAL.lval = yyS[yypt-0].lval - case 168: - yyVAL.lval = yyS[yypt-0].lval - case 169: - yyVAL.lval = yyS[yypt-0].lval - case 170: - yyVAL.lval = yyS[yypt-0].lval - case 171: - yyDollar = yyS[yypt-1 : yypt+1] - //line a.y:993 - { - yyVAL.lval = yyDollar[1].sym.Value - } - case 172: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:997 - { - yyVAL.lval = -yyDollar[2].lval - } - case 173: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:1001 - { - yyVAL.lval = yyDollar[2].lval - } - case 174: - yyDollar = yyS[yypt-2 : yypt+1] - //line a.y:1005 - { - yyVAL.lval = ^yyDollar[2].lval - } - case 175: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1009 - { - yyVAL.lval = yyDollar[2].lval - } - case 176: - yyVAL.lval = yyS[yypt-0].lval - case 177: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1016 - { - yyVAL.lval = yyDollar[1].lval + yyDollar[3].lval - } - case 178: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1020 - { - yyVAL.lval = yyDollar[1].lval - yyDollar[3].lval - } - case 179: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1024 - { - yyVAL.lval = yyDollar[1].lval * yyDollar[3].lval - } - case 180: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1028 - { - yyVAL.lval = yyDollar[1].lval / yyDollar[3].lval - } - case 181: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1032 - { - yyVAL.lval = yyDollar[1].lval % yyDollar[3].lval - } - case 182: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:1036 - { - yyVAL.lval = yyDollar[1].lval << uint(yyDollar[4].lval) - } - case 183: - yyDollar = yyS[yypt-4 : yypt+1] - //line a.y:1040 - { - yyVAL.lval = yyDollar[1].lval >> uint(yyDollar[4].lval) - } - case 184: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1044 - { - yyVAL.lval = yyDollar[1].lval & yyDollar[3].lval - } - case 185: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1048 - { - yyVAL.lval = yyDollar[1].lval ^ yyDollar[3].lval - } - case 186: - yyDollar = yyS[yypt-3 : yypt+1] - //line a.y:1052 - { - yyVAL.lval = yyDollar[1].lval | yyDollar[3].lval - } - } - goto yystack /* stack new state and value */ -} diff --git a/src/cmd/new9g/cgen.go b/src/cmd/new9g/cgen.go deleted file mode 100644 index 7a1e967267..0000000000 --- a/src/cmd/new9g/cgen.go +++ /dev/null @@ -1,1888 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" - "fmt" -) -import "cmd/internal/gc" - -/* - * peep.c - */ -/* - * generate: - * res = n; - * simplifies and calls gmove. - */ -func cgen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var a int - var f int - var p1 *obj.Prog - var p2 *obj.Prog - var p3 *obj.Prog - var addr obj.Addr - - //print("cgen %N(%d) -> %N(%d)\n", n, n->addable, res, res->addable); - if gc.Debug['g'] != 0 { - gc.Dump("\ncgen-n", n) - gc.Dump("cgen-res", res) - } - - if n == nil || n.Type == nil { - goto ret - } - - if res == nil || res.Type == nil { - gc.Fatal("cgen: res nil") - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - switch n.Op { - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_slice(n, res) - } - goto ret - - case gc.OEFACE: - if res.Op != gc.ONAME || res.Addable == 0 { - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - cgen(&n1, res) - } else { - gc.Cgen_eface(n, res) - } - goto ret - } - - if n.Ullman >= gc.UINF { - if n.Op == gc.OINDREG { - gc.Fatal("cgen: this is going to misscompile") - } - if res.Ullman >= gc.UINF { - gc.Tempname(&n1, n.Type) - cgen(n, &n1) - cgen(&n1, res) - goto ret - } - } - - if gc.Isfat(n.Type) { - if n.Type.Width < 0 { - gc.Fatal("forgot to compute width for %v", gc.Tconv(n.Type, 0)) - } - sgen(n, res, n.Type.Width) - goto ret - } - - if res.Addable == 0 { - if n.Ullman > res.Ullman { - regalloc(&n1, n.Type, res) - cgen(n, &n1) - if n1.Ullman > res.Ullman { - gc.Dump("n1", &n1) - gc.Dump("res", res) - gc.Fatal("loop in cgen") - } - - cgen(&n1, res) - regfree(&n1) - goto ret - } - - if res.Ullman >= gc.UINF { - goto gen - } - - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - goto ret - } - - f = 1 // gen thru register - switch n.Op { - case gc.OLITERAL: - if gc.Smallintconst(n) { - f = 0 - } - - case gc.OREGISTER: - f = 0 - } - - if gc.Iscomplex[n.Type.Etype] == 0 { - a = optoas(gc.OAS, res.Type) - if sudoaddable(a, res, &addr) { - if f != 0 { - regalloc(&n2, res.Type, nil) - cgen(n, &n2) - p1 = gins(a, &n2, nil) - regfree(&n2) - } else { - p1 = gins(a, n, nil) - } - p1.To = addr - if gc.Debug['g'] != 0 { - fmt.Printf("%v [ignore previous line]\n", p1) - } - sudoclean() - goto ret - } - } - - gen: - igen(res, &n1, nil) - cgen(n, &n1) - regfree(&n1) - goto ret - } - - // update addressability for string, slice - // can't do in walk because n->left->addable - // changes if n->left is an escaping local variable. - switch n.Op { - case gc.OSPTR, - gc.OLEN: - if gc.Isslice(n.Left.Type) || gc.Istype(n.Left.Type, gc.TSTRING) { - n.Addable = n.Left.Addable - } - - case gc.OCAP: - if gc.Isslice(n.Left.Type) { - n.Addable = n.Left.Addable - } - - case gc.OITAB: - n.Addable = n.Left.Addable - } - - if gc.Complexop(n, res) { - gc.Complexgen(n, res) - goto ret - } - - // if both are addressable, move - if n.Addable != 0 { - if n.Op == gc.OREGISTER || res.Op == gc.OREGISTER { - gmove(n, res) - } else { - regalloc(&n1, n.Type, nil) - gmove(n, &n1) - cgen(&n1, res) - regfree(&n1) - } - - goto ret - } - - nl = n.Left - nr = n.Right - - if nl != nil && nl.Ullman >= gc.UINF { - if nr != nil && nr.Ullman >= gc.UINF { - gc.Tempname(&n1, nl.Type) - cgen(nl, &n1) - n2 = *n - n2.Left = &n1 - cgen(&n2, res) - goto ret - } - } - - if gc.Iscomplex[n.Type.Etype] == 0 { - a = optoas(gc.OAS, n.Type) - if sudoaddable(a, n, &addr) { - if res.Op == gc.OREGISTER { - p1 = gins(a, nil, res) - p1.From = addr - } else { - regalloc(&n2, n.Type, nil) - p1 = gins(a, nil, &n2) - p1.From = addr - gins(a, &n2, res) - regfree(&n2) - } - - sudoclean() - goto ret - } - } - - // TODO(minux): we shouldn't reverse FP comparisons, but then we need to synthesize - // OGE, OLE, and ONE ourselves. - // if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) goto flt; - - switch n.Op { - default: - gc.Dump("cgen", n) - gc.Fatal("cgen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - // these call bgen to get a bool value - case gc.OOROR, - gc.OANDAND, - gc.OEQ, - gc.ONE, - gc.OLT, - gc.OLE, - gc.OGE, - gc.OGT, - gc.ONOT: - p1 = gc.Gbranch(ppc64.ABR, nil, 0) - - p2 = gc.Pc - gmove(gc.Nodbool(true), res) - p3 = gc.Gbranch(ppc64.ABR, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n, true, 0, p2) - gmove(gc.Nodbool(false), res) - gc.Patch(p3, gc.Pc) - goto ret - - case gc.OPLUS: - cgen(nl, res) - goto ret - - // unary - case gc.OCOM: - a = optoas(gc.OXOR, nl.Type) - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - gc.Nodconst(&n2, nl.Type, -1) - gins(a, &n2, &n1) - gmove(&n1, res) - regfree(&n1) - goto ret - - case gc.OMINUS: - if gc.Isfloat[nl.Type.Etype] != 0 { - nr = gc.Nodintconst(-1) - gc.Convlit(&nr, n.Type) - a = optoas(gc.OMUL, nl.Type) - goto sbop - } - - a = optoas(int(n.Op), nl.Type) - goto uop - - // symmetric binary - case gc.OAND, - gc.OOR, - gc.OXOR, - gc.OADD, - gc.OMUL: - a = optoas(int(n.Op), nl.Type) - - goto sbop - - // asymmetric binary - case gc.OSUB: - a = optoas(int(n.Op), nl.Type) - - goto abop - - case gc.OHMUL: - cgen_hmul(nl, nr, res) - - case gc.OCONV: - if n.Type.Width > nl.Type.Width { - // If loading from memory, do conversion during load, - // so as to avoid use of 8-bit register in, say, int(*byteptr). - switch nl.Op { - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: - igen(nl, &n1, res) - regalloc(&n2, n.Type, res) - gmove(&n1, &n2) - gmove(&n2, res) - regfree(&n2) - regfree(&n1) - goto ret - } - } - - regalloc(&n1, nl.Type, res) - regalloc(&n2, n.Type, &n1) - cgen(nl, &n1) - - // if we do the conversion n1 -> n2 here - // reusing the register, then gmove won't - // have to allocate its own register. - gmove(&n1, &n2) - - gmove(&n2, res) - regfree(&n2) - regfree(&n1) - - case gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OIND, - gc.ONAME: // PHEAP or PPARAMREF var - igen(n, &n1, res) - - gmove(&n1, res) - regfree(&n1) - - // interface table is first word of interface value - case gc.OITAB: - igen(nl, &n1, res) - - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - // pointer is the first word of string or slice. - case gc.OSPTR: - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n1, gc.Types[gc.Tptr], res) - p1 = gins(ppc64.AMOVD, nil, &n1) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - gmove(&n1, res) - regfree(&n1) - break - } - - igen(nl, &n1, res) - n1.Type = n.Type - gmove(&n1, res) - regfree(&n1) - - case gc.OLEN: - if gc.Istype(nl.Type, gc.TMAP) || gc.Istype(nl.Type, gc.TCHAN) { - // map and chan have len in the first int-sized word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Type = gc.Types[gc.Simtype[gc.TINT]] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Istype(nl.Type, gc.TSTRING) || gc.Isslice(nl.Type) { - // both slice and string have len one pointer into the struct. - // a zero pointer means zero length - igen(nl, &n1, res) - - n1.Type = gc.Types[gc.Simtype[gc.TUINT]] - n1.Xoffset += int64(gc.Array_nel) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OLEN: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OCAP: - if gc.Istype(nl.Type, gc.TCHAN) { - // chan has cap in the second int-sized word. - // a zero pointer means zero length - regalloc(&n1, gc.Types[gc.Tptr], res) - - cgen(nl, &n1) - - gc.Nodconst(&n2, gc.Types[gc.Tptr], 0) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n1, &n2) - p1 = gc.Gbranch(optoas(gc.OEQ, gc.Types[gc.Tptr]), nil, 0) - - n2 = n1 - n2.Op = gc.OINDREG - n2.Xoffset = int64(gc.Widthint) - n2.Type = gc.Types[gc.Simtype[gc.TINT]] - gmove(&n2, &n1) - - gc.Patch(p1, gc.Pc) - - gmove(&n1, res) - regfree(&n1) - break - } - - if gc.Isslice(nl.Type) { - igen(nl, &n1, res) - n1.Type = gc.Types[gc.Simtype[gc.TUINT]] - n1.Xoffset += int64(gc.Array_cap) - gmove(&n1, res) - regfree(&n1) - break - } - - gc.Fatal("cgen: OCAP: unknown type %v", gc.Tconv(nl.Type, obj.FmtLong)) - - case gc.OADDR: - if n.Bounded { // let race detector avoid nil checks - gc.Disable_checknil++ - } - agen(nl, res) - if n.Bounded { - gc.Disable_checknil-- - } - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - cgen_callret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_callret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_callret(n, res) - - case gc.OMOD, - gc.ODIV: - if gc.Isfloat[n.Type.Etype] != 0 { - a = optoas(int(n.Op), nl.Type) - goto abop - } - - if nl.Ullman >= nr.Ullman { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - cgen_div(int(n.Op), &n1, nr, res) - regfree(&n1) - } else { - if !gc.Smallintconst(nr) { - regalloc(&n2, nr.Type, res) - cgen(nr, &n2) - } else { - n2 = *nr - } - - cgen_div(int(n.Op), nl, &n2, res) - if n2.Op != gc.OLITERAL { - regfree(&n2) - } - } - - case gc.OLSH, - gc.ORSH, - gc.OLROT: - cgen_shift(int(n.Op), n.Bounded, nl, nr, res) - } - - goto ret - - /* - * put simplest on right - we'll generate into left - * and then adjust it using the computation of right. - * constants and variables have the same ullman - * count, so look for constants specially. - * - * an integer constant we can use as an immediate - * is simpler than a variable - we can use the immediate - * in the adjustment instruction directly - so it goes - * on the right. - * - * other constants, like big integers or floating point - * constants, require a mov into a register, so those - * might as well go on the left, so we can reuse that - * register for the computation. - */ -sbop: // symmetric binary - if nl.Ullman < nr.Ullman || (nl.Ullman == nr.Ullman && (gc.Smallintconst(nl) || (nr.Op == gc.OLITERAL && !gc.Smallintconst(nr)))) { - r = nl - nl = nr - nr = r - } - -abop: // asymmetric binary - if nl.Ullman >= nr.Ullman { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - - /* - * This generates smaller code - it avoids a MOV - but it's - * easily 10% slower due to not being able to - * optimize/manipulate the move. - * To see, run: go test -bench . crypto/md5 - * with and without. - * - if(sudoaddable(a, nr, &addr)) { - p1 = gins(a, N, &n1); - p1->from = addr; - gmove(&n1, res); - sudoclean(); - regfree(&n1); - goto ret; - } - * - */ - // TODO(minux): enable using constants directly in certain instructions. - //if(smallintconst(nr)) - // n2 = *nr; - //else { - regalloc(&n2, nr.Type, nil) - - cgen(nr, &n2) - } else //} - { - //if(smallintconst(nr)) - // n2 = *nr; - //else { - regalloc(&n2, nr.Type, res) - - cgen(nr, &n2) - - //} - regalloc(&n1, nl.Type, nil) - - cgen(nl, &n1) - } - - gins(a, &n2, &n1) - - // Normalize result for types smaller than word. - if n.Type.Width < int64(gc.Widthreg) { - switch n.Op { - case gc.OADD, - gc.OSUB, - gc.OMUL, - gc.OLSH: - gins(optoas(gc.OAS, n.Type), &n1, &n1) - } - } - - gmove(&n1, res) - regfree(&n1) - if n2.Op != gc.OLITERAL { - regfree(&n2) - } - goto ret - -uop: // unary - regalloc(&n1, nl.Type, res) - - cgen(nl, &n1) - gins(a, nil, &n1) - gmove(&n1, res) - regfree(&n1) - goto ret - -ret: -} - -/* - * allocate a register (reusing res if possible) and generate - * a = n - * The caller must call regfree(a). - */ -func cgenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("cgenr-n", n) - } - - if gc.Isfat(n.Type) { - gc.Fatal("cgenr on fat node") - } - - if n.Addable != 0 { - regalloc(a, n.Type, res) - gmove(n, a) - return - } - - switch n.Op { - case gc.ONAME, - gc.ODOT, - gc.ODOTPTR, - gc.OINDEX, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - gmove(&n1, a) - regfree(&n1) - - default: - regalloc(a, n.Type, res) - cgen(n, a) - } -} - -/* - * allocate a register (reusing res if possible) and generate - * a = &n - * The caller must call regfree(a). - * The generated code checks that the result is not nil. - */ -func agenr(n *gc.Node, a *gc.Node, res *gc.Node) { - var nl *gc.Node - var nr *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var tmp gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - var w uint32 - var v uint64 - - if gc.Debug['g'] != 0 { - gc.Dump("agenr-n", n) - } - - nl = n.Left - nr = n.Right - - switch n.Op { - case gc.ODOT, - gc.ODOTPTR, - gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - igen(n, &n1, res) - regalloc(a, gc.Types[gc.Tptr], &n1) - agen(&n1, a) - regfree(&n1) - - case gc.OIND: - cgenr(n.Left, a, res) - gc.Cgen_checknil(a) - - case gc.OINDEX: - p2 = nil // to be patched to panicindex. - w = uint32(n.Type.Width) - - //bounded = debug['B'] || n->bounded; - if nr.Addable != 0 { - if !gc.Isconst(nr, gc.CTINT) { - gc.Tempname(&tmp, gc.Types[gc.TINT64]) - } - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - if !gc.Isconst(nr, gc.CTINT) { - cgen(nr, &tmp) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - } else if nl.Addable != 0 { - if !gc.Isconst(nr, gc.CTINT) { - gc.Tempname(&tmp, gc.Types[gc.TINT64]) - cgen(nr, &tmp) - regalloc(&n1, tmp.Type, nil) - gmove(&tmp, &n1) - } - - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - } else { - gc.Tempname(&tmp, gc.Types[gc.TINT64]) - cgen(nr, &tmp) - nr = &tmp - if !gc.Isconst(nl, gc.CTSTR) { - agenr(nl, &n3, res) - } - regalloc(&n1, tmp.Type, nil) - gins(optoas(gc.OAS, tmp.Type), &tmp, &n1) - } - - // &a is in &n3 (allocated in res) - // i is in &n1 (if not constant) - // w is width - - // constant index - if gc.Isconst(nr, gc.CTINT) { - if gc.Isconst(nl, gc.CTSTR) { - gc.Fatal("constant string constant index") - } - v = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - if gc.Debug['B'] == 0 && !n.Bounded { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - regalloc(&n4, n1.Type, nil) - gmove(&n1, &n4) - ginscon2(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n4, int64(v)) - regfree(&n4) - p1 = gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TUINT64]), nil, +1) - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, &n3) - } - - if v*uint64(w) != 0 { - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), int64(v*uint64(w)), &n3) - } - - *a = n3 - break - } - - regalloc(&n2, gc.Types[gc.TINT64], &n1) // i - gmove(&n1, &n2) - regfree(&n1) - - if gc.Debug['B'] == 0 && !n.Bounded { - // check bounds - if gc.Isconst(nl, gc.CTSTR) { - gc.Nodconst(&n4, gc.Types[gc.TUINT64], int64(len(nl.Val.U.Sval.S))) - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_nel) - regalloc(&n4, gc.Types[gc.TUINT64], nil) - gmove(&n1, &n4) - } else { - if nl.Type.Bound < (1<<15)-1 { - gc.Nodconst(&n4, gc.Types[gc.TUINT64], nl.Type.Bound) - } else { - regalloc(&n4, gc.Types[gc.TUINT64], nil) - p1 = gins(ppc64.AMOVD, nil, &n4) - p1.From.Type = obj.TYPE_CONST - p1.From.Offset = nl.Type.Bound - } - } - - gins(optoas(gc.OCMP, gc.Types[gc.TUINT64]), &n2, &n4) - if n4.Op == gc.OREGISTER { - regfree(&n4) - } - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) - if p2 != nil { - gc.Patch(p2, gc.Pc) - } - ginscall(gc.Panicindex, 0) - gc.Patch(p1, gc.Pc) - } - - if gc.Isconst(nl, gc.CTSTR) { - regalloc(&n3, gc.Types[gc.Tptr], res) - p1 = gins(ppc64.AMOVD, nil, &n3) - gc.Datastring(nl.Val.U.Sval.S, &p1.From) - p1.From.Type = obj.TYPE_ADDR - } else if gc.Isslice(nl.Type) || nl.Type.Etype == gc.TSTRING { - n1 = n3 - n1.Op = gc.OINDREG - n1.Type = gc.Types[gc.Tptr] - n1.Xoffset = int64(gc.Array_array) - gmove(&n1, &n3) - } - - if w == 0 { - } else // nothing to do - if w == 1 { - /* w already scaled */ - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - /* else if(w == 2 || w == 4 || w == 8) { - // TODO(minux): scale using shift - } */ - } else { - regalloc(&n4, gc.Types[gc.TUINT64], nil) - gc.Nodconst(&n1, gc.Types[gc.TUINT64], int64(w)) - gmove(&n1, &n4) - gins(optoas(gc.OMUL, gc.Types[gc.TUINT64]), &n4, &n2) - gins(optoas(gc.OADD, gc.Types[gc.Tptr]), &n2, &n3) - regfree(&n4) - } - - *a = n3 - regfree(&n2) - - default: - regalloc(a, gc.Types[gc.Tptr], res) - agen(n, a) - } -} - -func ginsadd(as int, off int64, dst *gc.Node) { - var n1 gc.Node - - regalloc(&n1, gc.Types[gc.Tptr], dst) - gmove(dst, &n1) - ginscon(as, off, &n1) - gmove(&n1, dst) - regfree(&n1) -} - -/* - * generate: - * res = &n; - * The generated code checks that the result is not nil. - */ -func agen(n *gc.Node, res *gc.Node) { - var nl *gc.Node - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("\nagen-res", res) - gc.Dump("agen-r", n) - } - - if n == nil || n.Type == nil { - return - } - - for n.Op == gc.OCONVNOP { - n = n.Left - } - - if gc.Isconst(n, gc.CTNIL) && n.Type.Width > int64(gc.Widthptr) { - // Use of a nil interface or nil slice. - // Create a temporary we can take the address of and read. - // The generated code is just going to panic, so it need not - // be terribly efficient. See issue 3670. - gc.Tempname(&n1, n.Type) - - gc.Gvardef(&n1) - clearfat(&n1) - regalloc(&n2, gc.Types[gc.Tptr], res) - n3 = gc.Node{} - n3.Op = gc.OADDR - n3.Left = &n1 - gins(ppc64.AMOVD, &n3, &n2) - gmove(&n2, res) - regfree(&n2) - goto ret - } - - if n.Addable != 0 { - n1 = gc.Node{} - n1.Op = gc.OADDR - n1.Left = n - regalloc(&n2, gc.Types[gc.Tptr], res) - gins(ppc64.AMOVD, &n1, &n2) - gmove(&n2, res) - regfree(&n2) - goto ret - } - - nl = n.Left - - switch n.Op { - default: - gc.Fatal("agen: unknown op %v", gc.Nconv(n, obj.FmtShort|obj.FmtSign)) - - // TODO(minux): 5g has this: Release res so that it is available for cgen_call. - // Pick it up again after the call for OCALLMETH and OCALLFUNC. - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - - cgen_aret(n, res) - - case gc.OCALLINTER: - cgen_callinter(n, res, 0) - cgen_aret(n, res) - - case gc.OCALLFUNC: - cgen_call(n, 0) - cgen_aret(n, res) - - case gc.OSLICE, - gc.OSLICEARR, - gc.OSLICESTR, - gc.OSLICE3, - gc.OSLICE3ARR: - gc.Tempname(&n1, n.Type) - gc.Cgen_slice(n, &n1) - agen(&n1, res) - - case gc.OEFACE: - gc.Tempname(&n1, n.Type) - gc.Cgen_eface(n, &n1) - agen(&n1, res) - - case gc.OINDEX: - agenr(n, &n1, res) - gmove(&n1, res) - regfree(&n1) - - // should only get here with names in this func. - case gc.ONAME: - if n.Funcdepth > 0 && n.Funcdepth != gc.Funcdepth { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME funcdepth %d != %d", n.Funcdepth, gc.Funcdepth) - } - - // should only get here for heap vars or paramref - if n.Class&gc.PHEAP == 0 && n.Class != gc.PPARAMREF { - gc.Dump("bad agen", n) - gc.Fatal("agen: bad ONAME class %#x", n.Class) - } - - cgen(n.Heapaddr, res) - if n.Xoffset != 0 { - ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - - case gc.OIND: - cgen(nl, res) - gc.Cgen_checknil(res) - - case gc.ODOT: - agen(nl, res) - if n.Xoffset != 0 { - ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - - case gc.ODOTPTR: - cgen(nl, res) - gc.Cgen_checknil(res) - if n.Xoffset != 0 { - ginsadd(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, res) - } - } - -ret: -} - -/* - * generate: - * newreg = &n; - * res = newreg - * - * on exit, a has been changed to be *newreg. - * caller must regfree(a). - * The generated code checks that the result is not *nil. - */ -func igen(n *gc.Node, a *gc.Node, res *gc.Node) { - var fp *gc.Type - var flist gc.Iter - var n1 gc.Node - - if gc.Debug['g'] != 0 { - gc.Dump("\nigen-n", n) - } - - switch n.Op { - case gc.ONAME: - if (n.Class&gc.PHEAP != 0) || n.Class == gc.PPARAMREF { - break - } - *a = *n - return - - // Increase the refcount of the register so that igen's caller - // has to call regfree. - case gc.OINDREG: - if n.Val.U.Reg != ppc64.REGSP { - reg[n.Val.U.Reg]++ - } - *a = *n - return - - case gc.ODOT: - igen(n.Left, a, res) - a.Xoffset += n.Xoffset - a.Type = n.Type - fixlargeoffset(a) - return - - case gc.ODOTPTR: - cgenr(n.Left, a, res) - gc.Cgen_checknil(a) - a.Op = gc.OINDREG - a.Xoffset += n.Xoffset - a.Type = n.Type - fixlargeoffset(a) - return - - case gc.OCALLFUNC, - gc.OCALLMETH, - gc.OCALLINTER: - switch n.Op { - case gc.OCALLFUNC: - cgen_call(n, 0) - - case gc.OCALLMETH: - gc.Cgen_callmeth(n, 0) - - case gc.OCALLINTER: - cgen_callinter(n, nil, 0) - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(n.Left.Type)) - *a = gc.Node{} - a.Op = gc.OINDREG - a.Val.U.Reg = ppc64.REGSP - a.Addable = 1 - a.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) - a.Type = n.Type - return - - // Index of fixed-size array by constant can - // put the offset in the addressing. - // Could do the same for slice except that we need - // to use the real index for the bounds checking. - case gc.OINDEX: - if gc.Isfixedarray(n.Left.Type) || (gc.Isptr[n.Left.Type.Etype] != 0 && gc.Isfixedarray(n.Left.Left.Type)) { - if gc.Isconst(n.Right, gc.CTINT) { - // Compute &a. - if gc.Isptr[n.Left.Type.Etype] == 0 { - igen(n.Left, a, res) - } else { - igen(n.Left, &n1, res) - gc.Cgen_checknil(&n1) - regalloc(a, gc.Types[gc.Tptr], res) - gmove(&n1, a) - regfree(&n1) - a.Op = gc.OINDREG - } - - // Compute &a[i] as &a + i*width. - a.Type = n.Type - - a.Xoffset += gc.Mpgetfix(n.Right.Val.U.Xval) * n.Type.Width - fixlargeoffset(a) - return - } - } - } - - agenr(n, a, res) - a.Op = gc.OINDREG - a.Type = n.Type -} - -/* - * generate: - * if(n == true) goto to; - */ -func bgen(n *gc.Node, true_ bool, likely int, to *obj.Prog) { - var et int - var a int - var nl *gc.Node - var nr *gc.Node - var l *gc.Node - var r *gc.Node - var n1 gc.Node - var n2 gc.Node - var tmp gc.Node - var ll *gc.NodeList - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['g'] != 0 { - gc.Dump("\nbgen", n) - } - - if n == nil { - n = gc.Nodbool(true) - } - - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - - if n.Type == nil { - gc.Convlit(&n, gc.Types[gc.TBOOL]) - if n.Type == nil { - goto ret - } - } - - et = int(n.Type.Etype) - if et != gc.TBOOL { - gc.Yyerror("cgen: bad type %v for %v", gc.Tconv(n.Type, 0), gc.Oconv(int(n.Op), 0)) - gc.Patch(gins(obj.AEND, nil, nil), to) - goto ret - } - - nr = nil - - for n.Op == gc.OCONVNOP { - n = n.Left - if n.Ninit != nil { - gc.Genlist(n.Ninit) - } - } - - switch n.Op { - default: - regalloc(&n1, n.Type, nil) - cgen(n, &n1) - gc.Nodconst(&n2, n.Type, 0) - gins(optoas(gc.OCMP, n.Type), &n1, &n2) - a = ppc64.ABNE - if !true_ { - a = ppc64.ABEQ - } - gc.Patch(gc.Gbranch(a, n.Type, likely), to) - regfree(&n1) - goto ret - - // need to ask if it is bool? - case gc.OLITERAL: - if !true_ == (n.Val.U.Bval == 0) { - gc.Patch(gc.Gbranch(ppc64.ABR, nil, likely), to) - } - goto ret - - case gc.OANDAND, - gc.OOROR: - if (n.Op == gc.OANDAND) == true_ { - p1 = gc.Gbranch(obj.AJMP, nil, 0) - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - bgen(n.Left, !true_, -likely, p2) - bgen(n.Right, !true_, -likely, p2) - p1 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, to) - gc.Patch(p2, gc.Pc) - } else { - bgen(n.Left, true_, likely, to) - bgen(n.Right, true_, likely, to) - } - - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - nr = n.Right - if nr == nil || nr.Type == nil { - goto ret - } - fallthrough - - case gc.ONOT: // unary - nl = n.Left - - if nl == nil || nl.Type == nil { - goto ret - } - } - - switch n.Op { - case gc.ONOT: - bgen(nl, !true_, likely, to) - goto ret - - case gc.OEQ, - gc.ONE, - gc.OLT, - gc.OGT, - gc.OLE, - gc.OGE: - a = int(n.Op) - if !true_ { - if gc.Isfloat[nr.Type.Etype] != 0 { - // brcom is not valid on floats when NaN is involved. - p1 = gc.Gbranch(ppc64.ABR, nil, 0) - - p2 = gc.Gbranch(ppc64.ABR, nil, 0) - gc.Patch(p1, gc.Pc) - ll = n.Ninit // avoid re-genning ninit - n.Ninit = nil - bgen(n, true, -likely, p2) - n.Ninit = ll - gc.Patch(gc.Gbranch(ppc64.ABR, nil, 0), to) - gc.Patch(p2, gc.Pc) - goto ret - } - - a = gc.Brcom(a) - true_ = !true_ - } - - // make simplest on right - if nl.Op == gc.OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < gc.UINF) { - a = gc.Brrev(a) - r = nl - nl = nr - nr = r - } - - if gc.Isslice(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal slice comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Xoffset += int64(gc.Array_array) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - regalloc(&n2, gc.Types[gc.Tptr], &n1) - gmove(&n1, &n2) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) - regfree(&n2) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Isinter(nl.Type) { - // front end should only leave cmp to literal nil - if (a != gc.OEQ && a != gc.ONE) || nr.Op != gc.OLITERAL { - gc.Yyerror("illegal interface comparison") - break - } - - a = optoas(a, gc.Types[gc.Tptr]) - igen(nl, &n1, nil) - n1.Type = gc.Types[gc.Tptr] - gc.Nodconst(&tmp, gc.Types[gc.Tptr], 0) - regalloc(&n2, gc.Types[gc.Tptr], &n1) - gmove(&n1, &n2) - gins(optoas(gc.OCMP, gc.Types[gc.Tptr]), &n2, &tmp) - regfree(&n2) - gc.Patch(gc.Gbranch(a, gc.Types[gc.Tptr], likely), to) - regfree(&n1) - break - } - - if gc.Iscomplex[nl.Type.Etype] != 0 { - gc.Complexbool(a, nl, nr, true_, likely, to) - break - } - - if nr.Ullman >= gc.UINF { - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - - gc.Tempname(&tmp, nl.Type) - gmove(&n1, &tmp) - regfree(&n1) - - regalloc(&n2, nr.Type, nil) - cgen(nr, &n2) - - regalloc(&n1, nl.Type, nil) - cgen(&tmp, &n1) - - goto cmp - } - - regalloc(&n1, nl.Type, nil) - cgen(nl, &n1) - - // TODO(minux): cmpi does accept 16-bit signed immediate as p->to. - // and cmpli accepts 16-bit unsigned immediate. - //if(smallintconst(nr)) { - // gins(optoas(OCMP, nr->type), &n1, nr); - // patch(gbranch(optoas(a, nr->type), nr->type, likely), to); - // regfree(&n1); - // break; - //} - - regalloc(&n2, nr.Type, nil) - - cgen(nr, &n2) - - cmp: - l = &n1 - r = &n2 - gins(optoas(gc.OCMP, nr.Type), l, r) - if gc.Isfloat[nr.Type.Etype] != 0 && (a == gc.OLE || a == gc.OGE) { - // To get NaN right, must rewrite x <= y into separate x < y or x = y. - switch a { - case gc.OLE: - a = gc.OLT - - case gc.OGE: - a = gc.OGT - } - - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - gc.Patch(gc.Gbranch(optoas(gc.OEQ, nr.Type), nr.Type, likely), to) - } else { - gc.Patch(gc.Gbranch(optoas(a, nr.Type), nr.Type, likely), to) - } - - regfree(&n1) - regfree(&n2) - } - - goto ret - -ret: -} - -/* - * n is on stack, either local variable - * or return value from function call. - * return n's offset from SP. - */ -func stkof(n *gc.Node) int64 { - var t *gc.Type - var flist gc.Iter - var off int64 - - switch n.Op { - case gc.OINDREG: - return n.Xoffset - - case gc.ODOT: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - return off + n.Xoffset - - case gc.OINDEX: - t = n.Left.Type - if !gc.Isfixedarray(t) { - break - } - off = stkof(n.Left) - if off == -1000 || off == 1000 { - return off - } - if gc.Isconst(n.Right, gc.CTINT) { - return off + t.Type.Width*gc.Mpgetfix(n.Right.Val.U.Xval) - } - return 1000 - - case gc.OCALLMETH, - gc.OCALLINTER, - gc.OCALLFUNC: - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - t = gc.Structfirst(&flist, gc.Getoutarg(t)) - if t != nil { - return t.Width + int64(gc.Widthptr) // +widthptr: correct for saved LR - } - } - - // botch - probably failing to recognize address - // arithmetic on the above. eg INDEX and DOT - return -1000 -} - -/* - * block copy: - * memmove(&ns, &n, w); - */ -func sgen(n *gc.Node, ns *gc.Node, w int64) { - var dst gc.Node - var src gc.Node - var tmp gc.Node - var nend gc.Node - var c int32 - var odst int32 - var osrc int32 - var dir int - var align int - var op int - var p *obj.Prog - var ploop *obj.Prog - var l *gc.NodeList - var res *gc.Node = ns - - if gc.Debug['g'] != 0 { - fmt.Printf("\nsgen w=%d\n", w) - gc.Dump("r", n) - gc.Dump("res", ns) - } - - if n.Ullman >= gc.UINF && ns.Ullman >= gc.UINF { - gc.Fatal("sgen UINF") - } - - if w < 0 { - gc.Fatal("sgen copy %d", w) - } - - // If copying .args, that's all the results, so record definition sites - // for them for the liveness analysis. - if ns.Op == gc.ONAME && ns.Sym.Name == ".args" { - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - if l.N.Class == gc.PPARAMOUT { - gc.Gvardef(l.N) - } - } - } - - // Avoid taking the address for simple enough types. - //if(componentgen(n, ns)) - // return; - if w == 0 { - // evaluate side effects only. - regalloc(&dst, gc.Types[gc.Tptr], nil) - - agen(res, &dst) - agen(n, &dst) - regfree(&dst) - return - } - - // determine alignment. - // want to avoid unaligned access, so have to use - // smaller operations for less aligned types. - // for example moving [4]byte must use 4 MOVB not 1 MOVW. - align = int(n.Type.Align) - - switch align { - default: - gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0)) - - case 1: - op = ppc64.AMOVBU - - case 2: - op = ppc64.AMOVHU - - case 4: - op = ppc64.AMOVWZU // there is no lwau, only lwaux - - case 8: - op = ppc64.AMOVDU - } - - if w%int64(align) != 0 { - gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0)) - } - c = int32(w / int64(align)) - - // offset on the stack - osrc = int32(stkof(n)) - - odst = int32(stkof(res)) - if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) { - // osrc and odst both on stack, and at least one is in - // an unknown position. Could generate code to test - // for forward/backward copy, but instead just copy - // to a temporary location first. - gc.Tempname(&tmp, n.Type) - - sgen(n, &tmp, w) - sgen(&tmp, res, w) - return - } - - if osrc%int32(align) != 0 || odst%int32(align) != 0 { - gc.Fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align) - } - - // if we are copying forward on the stack and - // the src and dst overlap, then reverse direction - dir = align - - if osrc < odst && int64(odst) < int64(osrc)+w { - dir = -dir - } - - if n.Ullman >= res.Ullman { - agenr(n, &dst, res) // temporarily use dst - regalloc(&src, gc.Types[gc.Tptr], nil) - gins(ppc64.AMOVD, &dst, &src) - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agen(res, &dst) - } else { - if res.Op == gc.ONAME { - gc.Gvardef(res) - } - agenr(res, &dst, res) - agenr(n, &src, nil) - } - - regalloc(&tmp, gc.Types[gc.Tptr], nil) - - // set up end marker - nend = gc.Node{} - - // move src and dest to the end of block if necessary - if dir < 0 { - if c >= 4 { - regalloc(&nend, gc.Types[gc.Tptr], nil) - p = gins(ppc64.AMOVD, &src, &nend) - } - - p = gins(ppc64.AADD, nil, &src) - p.From.Type = obj.TYPE_CONST - p.From.Offset = w - - p = gins(ppc64.AADD, nil, &dst) - p.From.Type = obj.TYPE_CONST - p.From.Offset = w - } else { - p = gins(ppc64.AADD, nil, &src) - p.From.Type = obj.TYPE_CONST - p.From.Offset = int64(-dir) - - p = gins(ppc64.AADD, nil, &dst) - p.From.Type = obj.TYPE_CONST - p.From.Offset = int64(-dir) - - if c >= 4 { - regalloc(&nend, gc.Types[gc.Tptr], nil) - p = gins(ppc64.AMOVD, &src, &nend) - p.From.Type = obj.TYPE_ADDR - p.From.Offset = w - } - } - - // move - // TODO: enable duffcopy for larger copies. - if c >= 4 { - p = gins(op, &src, &tmp) - p.From.Type = obj.TYPE_MEM - p.From.Offset = int64(dir) - ploop = p - - p = gins(op, &tmp, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(dir) - - p = gins(ppc64.ACMP, &src, &nend) - - gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), ploop) - regfree(&nend) - } else { - // TODO(austin): Instead of generating ADD $-8,R8; ADD - // $-8,R7; n*(MOVDU 8(R8),R9; MOVDU R9,8(R7);) just - // generate the offsets directly and eliminate the - // ADDs. That will produce shorter, more - // pipeline-able code. - for { - tmp14 := c - c-- - if tmp14 <= 0 { - break - } - - p = gins(op, &src, &tmp) - p.From.Type = obj.TYPE_MEM - p.From.Offset = int64(dir) - - p = gins(op, &tmp, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(dir) - } - } - - regfree(&dst) - regfree(&src) - regfree(&tmp) -} - -func cadable(n *gc.Node) bool { - if n.Addable == 0 { - // dont know how it happens, - // but it does - return false - } - - switch n.Op { - case gc.ONAME: - return true - } - - return false -} - -/* - * copy a composite value by moving its individual components. - * Slices, strings and interfaces are supported. - * Small structs or arrays with elements of basic type are - * also supported. - * nr is N when assigning a zero value. - * return 1 if can do, 0 if can't. - */ -func componentgen(nr *gc.Node, nl *gc.Node) bool { - var nodl gc.Node - var nodr gc.Node - var tmp gc.Node - var t *gc.Type - var freel int - var freer int - var fldcount int64 - var loffset int64 - var roffset int64 - - freel = 0 - freer = 0 - - switch nl.Type.Etype { - default: - goto no - - case gc.TARRAY: - t = nl.Type - - // Slices are ok. - if gc.Isslice(t) { - break - } - - // Small arrays are ok. - if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) { - break - } - - goto no - - // Small structs with non-fat types are ok. - // Zero-sized structs are treated separately elsewhere. - case gc.TSTRUCT: - fldcount = 0 - - for t = nl.Type.Type; t != nil; t = t.Down { - if gc.Isfat(t.Type) { - goto no - } - if t.Etype != gc.TFIELD { - gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong)) - } - fldcount++ - } - - if fldcount == 0 || fldcount > 4 { - goto no - } - - case gc.TSTRING, - gc.TINTER: - break - } - - nodl = *nl - if !cadable(nl) { - if nr != nil && !cadable(nr) { - goto no - } - igen(nl, &nodl, nil) - freel = 1 - } - - if nr != nil { - nodr = *nr - if !cadable(nr) { - igen(nr, &nodr, nil) - freer = 1 - } - } else { - // When zeroing, prepare a register containing zero. - gc.Nodconst(&tmp, nl.Type, 0) - - regalloc(&nodr, gc.Types[gc.TUINT], nil) - gmove(&tmp, &nodr) - freer = 1 - } - - // nl and nr are 'cadable' which basically means they are names (variables) now. - // If they are the same variable, don't generate any code, because the - // VARDEF we generate will mark the old value as dead incorrectly. - // (And also the assignments are useless.) - if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr { - goto yes - } - - switch nl.Type.Etype { - // componentgen for arrays. - case gc.TARRAY: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - t = nl.Type - if !gc.Isslice(t) { - nodl.Type = t.Type - nodr.Type = nodl.Type - for fldcount = 0; fldcount < t.Bound; fldcount++ { - if nr == nil { - gc.Clearslim(&nodl) - } else { - gmove(&nodr, &nodl) - } - nodl.Xoffset += t.Type.Width - nodr.Xoffset += t.Type.Width - } - - goto yes - } - - // componentgen for slices. - nodl.Xoffset += int64(gc.Array_array) - - nodl.Type = gc.Ptrto(nl.Type.Type) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRING: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Types[gc.Simtype[gc.TUINT]] - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TINTER: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - nodl.Xoffset += int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8]) - - if nr != nil { - nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array) - nodr.Type = nodl.Type - } - - gmove(&nodr, &nodl) - - goto yes - - case gc.TSTRUCT: - if nl.Op == gc.ONAME { - gc.Gvardef(nl) - } - loffset = nodl.Xoffset - roffset = nodr.Xoffset - - // funarg structs may not begin at offset zero. - if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil { - loffset -= nl.Type.Type.Width - } - if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil { - roffset -= nr.Type.Type.Width - } - - for t = nl.Type.Type; t != nil; t = t.Down { - nodl.Xoffset = loffset + t.Width - nodl.Type = t.Type - - if nr == nil { - gc.Clearslim(&nodl) - } else { - nodr.Xoffset = roffset + t.Width - nodr.Type = nodl.Type - gmove(&nodr, &nodl) - } - } - - goto yes - } - -no: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return false - -yes: - if freer != 0 { - regfree(&nodr) - } - if freel != 0 { - regfree(&nodl) - } - return true -} diff --git a/src/cmd/new9g/galign.go b/src/cmd/new9g/galign.go deleted file mode 100644 index 99425c3929..0000000000 --- a/src/cmd/new9g/galign.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" -) -import "cmd/internal/gc" - -var thechar int = '9' - -var thestring string = "ppc64" - -var thelinkarch *obj.LinkArch - -func linkarchinit() { - thestring = obj.Getgoarch() - gc.Thearch.Thestring = thestring - if thestring == "ppc64le" { - thelinkarch = &ppc64.Linkppc64le - } else { - thelinkarch = &ppc64.Linkppc64 - } - gc.Thearch.Thelinkarch = thelinkarch -} - -var MAXWIDTH int64 = 1 << 50 - -/* - * go declares several platform-specific type aliases: - * int, uint, float, and uintptr - */ -var typedefs = []gc.Typedef{ - gc.Typedef{"int", gc.TINT, gc.TINT64}, - gc.Typedef{"uint", gc.TUINT, gc.TUINT64}, - gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64}, -} - -func betypeinit() { - gc.Widthptr = 8 - gc.Widthint = 8 - gc.Widthreg = 8 - -} - -func main() { - gc.Thearch.Thechar = thechar - gc.Thearch.Thestring = thestring - gc.Thearch.Thelinkarch = thelinkarch - gc.Thearch.Typedefs = typedefs - gc.Thearch.REGSP = ppc64.REGSP - gc.Thearch.REGCTXT = ppc64.REGCTXT - gc.Thearch.MAXWIDTH = MAXWIDTH - gc.Thearch.Anyregalloc = anyregalloc - gc.Thearch.Betypeinit = betypeinit - gc.Thearch.Bgen = bgen - gc.Thearch.Cgen = cgen - gc.Thearch.Cgen_call = cgen_call - gc.Thearch.Cgen_callinter = cgen_callinter - gc.Thearch.Cgen_ret = cgen_ret - gc.Thearch.Clearfat = clearfat - gc.Thearch.Defframe = defframe - gc.Thearch.Excise = excise - gc.Thearch.Expandchecks = expandchecks - gc.Thearch.Gclean = gclean - gc.Thearch.Ginit = ginit - gc.Thearch.Gins = gins - gc.Thearch.Ginscall = ginscall - gc.Thearch.Igen = igen - gc.Thearch.Linkarchinit = linkarchinit - gc.Thearch.Peep = peep - gc.Thearch.Proginfo = proginfo - gc.Thearch.Regalloc = regalloc - gc.Thearch.Regfree = regfree - gc.Thearch.Regtyp = regtyp - gc.Thearch.Sameaddr = sameaddr - gc.Thearch.Smallindir = smallindir - gc.Thearch.Stackaddr = stackaddr - gc.Thearch.Excludedregs = excludedregs - gc.Thearch.RtoB = RtoB - gc.Thearch.FtoB = RtoB - gc.Thearch.BtoR = BtoR - gc.Thearch.BtoF = BtoF - gc.Thearch.Optoas = optoas - gc.Thearch.Doregbits = doregbits - gc.Thearch.Regnames = regnames - - gc.Main() - gc.Exit(0) -} diff --git a/src/cmd/new9g/gg.go b/src/cmd/new9g/gg.go deleted file mode 100644 index 068d8afe53..0000000000 --- a/src/cmd/new9g/gg.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import "cmd/internal/obj/ppc64" -import "cmd/internal/gc" - -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -var reg [ppc64.NREG + ppc64.NFREG]uint8 - -var panicdiv *gc.Node - -/* - * cgen.c - */ - -/* - * list.c - */ - -/* - * reg.c - */ diff --git a/src/cmd/new9g/ggen.go b/src/cmd/new9g/ggen.go deleted file mode 100644 index 54bebdda40..0000000000 --- a/src/cmd/new9g/ggen.go +++ /dev/null @@ -1,1060 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" - "fmt" -) -import "cmd/internal/gc" - -func defframe(ptxt *obj.Prog) { - var frame uint32 - var p *obj.Prog - var hi int64 - var lo int64 - var l *gc.NodeList - var n *gc.Node - - // fill in argument size, stack size - ptxt.To.Type = obj.TYPE_TEXTSIZE - - ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr))) - frame = uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg))) - ptxt.To.Offset = int64(frame) - - // insert code to zero ambiguously live variables - // so that the garbage collector only sees initialized values - // when it looks for pointers. - p = ptxt - - hi = 0 - lo = hi - - // iterate through declarations - they are sorted in decreasing xoffset order. - for l = gc.Curfn.Dcl; l != nil; l = l.Next { - n = l.N - if n.Needzero == 0 { - continue - } - if n.Class != gc.PAUTO { - gc.Fatal("needzero class %d", n.Class) - } - if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 { - gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset)) - } - - if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) { - // merge with range we already have - lo = n.Xoffset - - continue - } - - // zero old range - p = zerorange(p, int64(frame), lo, hi) - - // set new range - hi = n.Xoffset + n.Type.Width - - lo = n.Xoffset - } - - // zero final range - zerorange(p, int64(frame), lo, hi) -} - -func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog { - var cnt int64 - var i int64 - var p1 *obj.Prog - var f *gc.Node - - cnt = hi - lo - if cnt == 0 { - return p - } - if cnt < int64(4*gc.Widthptr) { - for i = 0; i < cnt; i += int64(gc.Widthptr) { - p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i) - } - } else if cnt <= int64(128*gc.Widthptr) { - p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0) - p.Reg = ppc64.REGSP - p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) - f = gc.Sysfunc("duffzero") - gc.Naddr(f, &p.To, 1) - gc.Afunclit(&p.To, f) - p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr)) - } else { - p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0) - p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0) - p.Reg = ppc64.REGSP - p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0) - p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0) - p.Reg = ppc64.REGRT1 - p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr)) - p1 = p - p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0) - p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0) - gc.Patch(p, p1) - } - - return p -} - -func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog { - var q *obj.Prog - q = gc.Ctxt.NewProg() - gc.Clearp(q) - q.As = int16(as) - q.Lineno = p.Lineno - q.From.Type = int16(ftype) - q.From.Reg = int16(freg) - q.From.Offset = foffset - q.To.Type = int16(ttype) - q.To.Reg = int16(treg) - q.To.Offset = toffset - q.Link = p.Link - p.Link = q - return q -} - -/* - * generate: BL reg, f - * where both reg and f are registers. - * On power, f must be moved to CTR first. - */ -func ginsBL(reg *gc.Node, f *gc.Node) { - var p *obj.Prog - p = gins(ppc64.AMOVD, f, nil) - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REG_CTR - p = gins(ppc64.ABL, reg, nil) - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REG_CTR -} - -/* - * generate: - * call f - * proc=-1 normal call but no return - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - * proc=3 normal call to C pointer (not Go func value) -*/ -func ginscall(f *gc.Node, proc int) { - var p *obj.Prog - var reg gc.Node - var con gc.Node - var reg2 gc.Node - var r1 gc.Node - var extra int32 - - if f.Type != nil { - extra = 0 - if proc == 1 || proc == 2 { - extra = 2 * int32(gc.Widthptr) - } - gc.Setmaxarg(f.Type, extra) - } - - switch proc { - default: - gc.Fatal("ginscall: bad proc %d", proc) - - case 0, // normal call - -1: // normal call but no return - if f.Op == gc.ONAME && f.Class == gc.PFUNC { - if f == gc.Deferreturn { - // Deferred calls will appear to be returning to - // the CALL deferreturn(SB) that we are about to emit. - // However, the stack trace code will show the line - // of the instruction byte before the return PC. - // To avoid that being an unrelated instruction, - // insert a ppc64 NOP that we will have the right line number. - // The ppc64 NOP is really or r0, r0, r0; use that description - // because the NOP pseudo-instruction would be removed by - // the linker. - gc.Nodreg(®, gc.Types[gc.TINT], ppc64.REG_R0) - - gins(ppc64.AOR, ®, ®) - } - - p = gins(ppc64.ABL, nil, f) - gc.Afunclit(&p.To, f) - if proc == -1 || gc.Noreturn(p) { - gins(obj.AUNDEF, nil, nil) - } - break - } - - gc.Nodreg(®, gc.Types[gc.Tptr], ppc64.REGCTXT) - gc.Nodreg(&r1, gc.Types[gc.Tptr], ppc64.REG_R3) - gmove(f, ®) - reg.Op = gc.OINDREG - gmove(®, &r1) - reg.Op = gc.OREGISTER - ginsBL(®, &r1) - - case 3: // normal call of c function pointer - ginsBL(nil, f) - - case 1, // call in new proc (go) - 2: // deferred call (defer) - gc.Nodconst(&con, gc.Types[gc.TINT64], int64(gc.Argsize(f.Type))) - - gc.Nodreg(®, gc.Types[gc.TINT64], ppc64.REG_R3) - gc.Nodreg(®2, gc.Types[gc.TINT64], ppc64.REG_R4) - gmove(f, ®) - - gmove(&con, ®2) - p = gins(ppc64.AMOVW, ®2, nil) - p.To.Type = obj.TYPE_MEM - p.To.Reg = ppc64.REGSP - p.To.Offset = 8 - - p = gins(ppc64.AMOVD, ®, nil) - p.To.Type = obj.TYPE_MEM - p.To.Reg = ppc64.REGSP - p.To.Offset = 16 - - if proc == 1 { - ginscall(gc.Newproc, 0) - } else { - if gc.Hasdefer == 0 { - gc.Fatal("hasdefer=0 but has defer") - } - ginscall(gc.Deferproc, 0) - } - - if proc == 2 { - gc.Nodreg(®, gc.Types[gc.TINT64], ppc64.REG_R3) - p = gins(ppc64.ACMP, ®, nil) - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REG_R0 - p = gc.Gbranch(ppc64.ABEQ, nil, +1) - cgen_ret(nil) - gc.Patch(p, gc.Pc) - } - } -} - -/* - * n is call to interface method. - * generate res = n. - */ -func cgen_callinter(n *gc.Node, res *gc.Node, proc int) { - var i *gc.Node - var f *gc.Node - var tmpi gc.Node - var nodi gc.Node - var nodo gc.Node - var nodr gc.Node - var nodsp gc.Node - var p *obj.Prog - - i = n.Left - if i.Op != gc.ODOTINTER { - gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0)) - } - - f = i.Right // field - if f.Op != gc.ONAME { - gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0)) - } - - i = i.Left // interface - - if i.Addable == 0 { - gc.Tempname(&tmpi, i.Type) - cgen(i, &tmpi) - i = &tmpi - } - - gc.Genlist(n.List) // assign the args - - // i is now addable, prepare an indirected - // register to hold its address. - igen(i, &nodi, res) // REG = &inter - - gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], ppc64.REGSP) - - nodsp.Xoffset = int64(gc.Widthptr) - if proc != 0 { - nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn - } - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset += int64(gc.Widthptr) - cgen(&nodi, &nodsp) // {8 or 24}(SP) = 8(REG) -- i.data - - regalloc(&nodo, gc.Types[gc.Tptr], res) - - nodi.Type = gc.Types[gc.Tptr] - nodi.Xoffset -= int64(gc.Widthptr) - cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab - regfree(&nodi) - - regalloc(&nodr, gc.Types[gc.Tptr], &nodo) - if n.Left.Xoffset == gc.BADWIDTH { - gc.Fatal("cgen_callinter: badwidth") - } - gc.Cgen_checknil(&nodo) // in case offset is huge - nodo.Op = gc.OINDREG - nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8 - if proc == 0 { - // plain call: use direct c function pointer - more efficient - cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f] - proc = 3 - } else { - // go/defer. generate go func value. - p = gins(ppc64.AMOVD, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f] - p.From.Type = obj.TYPE_ADDR - } - - nodr.Type = n.Left.Type - ginscall(&nodr, proc) - - regfree(&nodr) - regfree(&nodo) -} - -/* - * generate function call; - * proc=0 normal call - * proc=1 goroutine run in new proc - * proc=2 defer call save away stack - */ -func cgen_call(n *gc.Node, proc int) { - var t *gc.Type - var nod gc.Node - var afun gc.Node - - if n == nil { - return - } - - if n.Left.Ullman >= gc.UINF { - // if name involves a fn call - // precompute the address of the fn - gc.Tempname(&afun, gc.Types[gc.Tptr]) - - cgen(n.Left, &afun) - } - - gc.Genlist(n.List) // assign the args - t = n.Left.Type - - // call tempname pointer - if n.Left.Ullman >= gc.UINF { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, &afun) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call pointer - if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC { - regalloc(&nod, gc.Types[gc.Tptr], nil) - gc.Cgen_as(&nod, n.Left) - nod.Type = t - ginscall(&nod, proc) - regfree(&nod) - return - } - - // call direct - n.Left.Method = 1 - - ginscall(n.Left, proc) -} - -/* - * call to n has already been generated. - * generate: - * res = return value from call. - */ -func cgen_callret(n *gc.Node, res *gc.Node) { - var nod gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_callret: nil") - } - - nod = gc.Node{} - nod.Op = gc.OINDREG - nod.Val.U.Reg = ppc64.REGSP - nod.Addable = 1 - - nod.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved LR at 0(R1) - nod.Type = fp.Type - gc.Cgen_as(res, &nod) -} - -/* - * call to n has already been generated. - * generate: - * res = &return value from call. - */ -func cgen_aret(n *gc.Node, res *gc.Node) { - var nod1 gc.Node - var nod2 gc.Node - var fp *gc.Type - var t *gc.Type - var flist gc.Iter - - t = n.Left.Type - if gc.Isptr[t.Etype] != 0 { - t = t.Type - } - - fp = gc.Structfirst(&flist, gc.Getoutarg(t)) - if fp == nil { - gc.Fatal("cgen_aret: nil") - } - - nod1 = gc.Node{} - nod1.Op = gc.OINDREG - nod1.Val.U.Reg = ppc64.REGSP - nod1.Addable = 1 - - nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP) - nod1.Type = fp.Type - - if res.Op != gc.OREGISTER { - regalloc(&nod2, gc.Types[gc.Tptr], res) - agen(&nod1, &nod2) - gins(ppc64.AMOVD, &nod2, res) - regfree(&nod2) - } else { - agen(&nod1, res) - } -} - -/* - * generate return. - * n->left is assignments to return values. - */ -func cgen_ret(n *gc.Node) { - var p *obj.Prog - - if n != nil { - gc.Genlist(n.List) // copy out args - } - if gc.Hasdefer != 0 { - ginscall(gc.Deferreturn, 0) - } - gc.Genlist(gc.Curfn.Exit) - p = gins(obj.ARET, nil, nil) - if n != nil && n.Op == gc.ORETJMP { - p.To.Name = obj.NAME_EXTERN - p.To.Type = obj.TYPE_ADDR - p.To.Sym = gc.Linksym(n.Left.Sym) - } -} - -/* - * generate division. - * generates one of: - * res = nl / nr - * res = nl % nr - * according to op. - */ -func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var a int - var check int - var t *gc.Type - var t0 *gc.Type - var tl gc.Node - var tr gc.Node - var tl2 gc.Node - var tr2 gc.Node - var nm1 gc.Node - var nz gc.Node - var tm gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - // Have to be careful about handling - // most negative int divided by -1 correctly. - // The hardware will generate undefined result. - // Also need to explicitly trap on division on zero, - // the hardware will silently generate undefined result. - // DIVW will leave unpredicable result in higher 32-bit, - // so always use DIVD/DIVDU. - t = nl.Type - - t0 = t - check = 0 - if gc.Issigned[t.Etype] != 0 { - check = 1 - if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<= nr.Ullman { - cgen(nl, &tl) - cgen(nr, &tr) - } else { - cgen(nr, &tr) - cgen(nl, &tl) - } - - if t != t0 { - // Convert - tl2 = tl - - tr2 = tr - tl.Type = t - tr.Type = t - gmove(&tl2, &tl) - gmove(&tr2, &tr) - } - - // Handle divide-by-zero panic. - p1 = gins(optoas(gc.OCMP, t), &tr, nil) - - p1.To.Type = obj.TYPE_REG - p1.To.Reg = ppc64.REGZERO - p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) - if panicdiv == nil { - panicdiv = gc.Sysfunc("panicdivide") - } - ginscall(panicdiv, -1) - gc.Patch(p1, gc.Pc) - - if check != 0 { - gc.Nodconst(&nm1, t, -1) - gins(optoas(gc.OCMP, t), &tr, &nm1) - p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1) - if op == gc.ODIV { - // a / (-1) is -a. - gins(optoas(gc.OMINUS, t), nil, &tl) - - gmove(&tl, res) - } else { - // a % (-1) is 0. - gc.Nodconst(&nz, t, 0) - - gmove(&nz, res) - } - - p2 = gc.Gbranch(obj.AJMP, nil, 0) - gc.Patch(p1, gc.Pc) - } - - p1 = gins(a, &tr, &tl) - if op == gc.ODIV { - regfree(&tr) - gmove(&tl, res) - } else { - // A%B = A-(A/B*B) - regalloc(&tm, t, nil) - - // patch div to use the 3 register form - // TODO(minux): add gins3? - p1.Reg = p1.To.Reg - - p1.To.Reg = tm.Val.U.Reg - gins(optoas(gc.OMUL, t), &tr, &tm) - regfree(&tr) - gins(optoas(gc.OSUB, t), &tm, &tl) - regfree(&tm) - gmove(&tl, res) - } - - regfree(&tl) - if check != 0 { - gc.Patch(p2, gc.Pc) - } -} - -/* - * generate division according to op, one of: - * res = nl / nr - * res = nl % nr - */ -func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var w int - var a int - var m gc.Magic - - // TODO(minux): enable division by magic multiply (also need to fix longmod below) - //if(nr->op != OLITERAL) - goto longdiv - - w = int(nl.Type.Width * 8) - - // Front end handled 32-bit division. We only need to handle 64-bit. - // try to do division by multiply by (2^w)/d - // see hacker's delight chapter 10 - switch gc.Simtype[nl.Type.Etype] { - default: - goto longdiv - - case gc.TUINT64: - m.W = w - m.Ud = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - gc.Umagic(&m) - if m.Bad != 0 { - break - } - if op == gc.OMOD { - goto longmod - } - - cgenr(nl, &n1, nil) - gc.Nodconst(&n2, nl.Type, int64(m.Um)) - regalloc(&n3, nl.Type, res) - cgen_hmul(&n1, &n2, &n3) - - if m.Ua != 0 { - // need to add numerator accounting for overflow - gins(optoas(gc.OADD, nl.Type), &n1, &n3) - - gc.Nodconst(&n2, nl.Type, 1) - gins(optoas(gc.ORROTC, nl.Type), &n2, &n3) - gc.Nodconst(&n2, nl.Type, int64(m.S)-1) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) - } else { - gc.Nodconst(&n2, nl.Type, int64(m.S)) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift dx - } - - gmove(&n3, res) - regfree(&n1) - regfree(&n3) - return - - case gc.TINT64: - m.W = w - m.Sd = gc.Mpgetfix(nr.Val.U.Xval) - gc.Smagic(&m) - if m.Bad != 0 { - break - } - if op == gc.OMOD { - goto longmod - } - - cgenr(nl, &n1, res) - gc.Nodconst(&n2, nl.Type, m.Sm) - regalloc(&n3, nl.Type, nil) - cgen_hmul(&n1, &n2, &n3) - - if m.Sm < 0 { - // need to add numerator - gins(optoas(gc.OADD, nl.Type), &n1, &n3) - } - - gc.Nodconst(&n2, nl.Type, int64(m.S)) - gins(optoas(gc.ORSH, nl.Type), &n2, &n3) // shift n3 - - gc.Nodconst(&n2, nl.Type, int64(w)-1) - - gins(optoas(gc.ORSH, nl.Type), &n2, &n1) // -1 iff num is neg - gins(optoas(gc.OSUB, nl.Type), &n1, &n3) // added - - if m.Sd < 0 { - // this could probably be removed - // by factoring it into the multiplier - gins(optoas(gc.OMINUS, nl.Type), nil, &n3) - } - - gmove(&n3, res) - regfree(&n1) - regfree(&n3) - return - } - - goto longdiv - - // division and mod using (slow) hardware instruction -longdiv: - dodiv(op, nl, nr, res) - - return - - // mod using formula A%B = A-(A/B*B) but - // we know that there is a fast algorithm for A/B -longmod: - regalloc(&n1, nl.Type, res) - - cgen(nl, &n1) - regalloc(&n2, nl.Type, nil) - cgen_div(gc.ODIV, &n1, nr, &n2) - a = optoas(gc.OMUL, nl.Type) - if w == 8 { - } - // use 2-operand 16-bit multiply - // because there is no 2-operand 8-bit multiply - //a = AIMULW; - if !gc.Smallintconst(nr) { - regalloc(&n3, nl.Type, nil) - cgen(nr, &n3) - gins(a, &n3, &n2) - regfree(&n3) - } else { - gins(a, nr, &n2) - } - gins(optoas(gc.OSUB, nl.Type), &n2, &n1) - gmove(&n1, res) - regfree(&n1) - regfree(&n2) -} - -/* - * generate high multiply: - * res = (nl*nr) >> width - */ -func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) { - var w int - var n1 gc.Node - var n2 gc.Node - var tmp *gc.Node - var t *gc.Type - var p *obj.Prog - - // largest ullman on left. - if nl.Ullman < nr.Ullman { - tmp = nl - nl = nr - nr = tmp - } - - t = nl.Type - w = int(t.Width * 8) - cgenr(nl, &n1, res) - cgenr(nr, &n2, nil) - switch gc.Simtype[t.Etype] { - case gc.TINT8, - gc.TINT16, - gc.TINT32: - gins(optoas(gc.OMUL, t), &n2, &n1) - p = gins(ppc64.ASRAD, nil, &n1) - p.From.Type = obj.TYPE_CONST - p.From.Offset = int64(w) - - case gc.TUINT8, - gc.TUINT16, - gc.TUINT32: - gins(optoas(gc.OMUL, t), &n2, &n1) - p = gins(ppc64.ASRD, nil, &n1) - p.From.Type = obj.TYPE_CONST - p.From.Offset = int64(w) - - case gc.TINT64, - gc.TUINT64: - if gc.Issigned[t.Etype] != 0 { - p = gins(ppc64.AMULHD, &n2, &n1) - } else { - p = gins(ppc64.AMULHDU, &n2, &n1) - } - - default: - gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0)) - } - - cgen(&n1, res) - regfree(&n1) - regfree(&n2) -} - -/* - * generate shift according to op, one of: - * res = nl << nr - * res = nl >> nr - */ -func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) { - var n1 gc.Node - var n2 gc.Node - var n3 gc.Node - var n4 gc.Node - var n5 gc.Node - var a int - var p1 *obj.Prog - var sc uint64 - var tcount *gc.Type - - a = optoas(op, nl.Type) - - if nr.Op == gc.OLITERAL { - regalloc(&n1, nl.Type, res) - cgen(nl, &n1) - sc = uint64(gc.Mpgetfix(nr.Val.U.Xval)) - if sc >= uint64(nl.Type.Width*8) { - // large shift gets 2 shifts by width-1 - gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) - - gins(a, &n3, &n1) - gins(a, &n3, &n1) - } else { - gins(a, nr, &n1) - } - gmove(&n1, res) - regfree(&n1) - goto ret - } - - if nl.Ullman >= gc.UINF { - gc.Tempname(&n4, nl.Type) - cgen(nl, &n4) - nl = &n4 - } - - if nr.Ullman >= gc.UINF { - gc.Tempname(&n5, nr.Type) - cgen(nr, &n5) - nr = &n5 - } - - // Allow either uint32 or uint64 as shift type, - // to avoid unnecessary conversion from uint32 to uint64 - // just to do the comparison. - tcount = gc.Types[gc.Simtype[nr.Type.Etype]] - - if tcount.Etype < gc.TUINT32 { - tcount = gc.Types[gc.TUINT32] - } - - regalloc(&n1, nr.Type, nil) // to hold the shift type in CX - regalloc(&n3, tcount, &n1) // to clear high bits of CX - - regalloc(&n2, nl.Type, res) - - if nl.Ullman >= nr.Ullman { - cgen(nl, &n2) - cgen(nr, &n1) - gmove(&n1, &n3) - } else { - cgen(nr, &n1) - gmove(&n1, &n3) - cgen(nl, &n2) - } - - regfree(&n3) - - // test and fix up large shifts - if !bounded { - gc.Nodconst(&n3, tcount, nl.Type.Width*8) - gins(optoas(gc.OCMP, tcount), &n1, &n3) - p1 = gc.Gbranch(optoas(gc.OLT, tcount), nil, +1) - if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 { - gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1) - gins(a, &n3, &n2) - } else { - gc.Nodconst(&n3, nl.Type, 0) - gmove(&n3, &n2) - } - - gc.Patch(p1, gc.Pc) - } - - gins(a, &n1, &n2) - - gmove(&n2, res) - - regfree(&n1) - regfree(&n2) - -ret: -} - -func clearfat(nl *gc.Node) { - var w uint64 - var c uint64 - var q uint64 - var t uint64 - var boff uint64 - var dst gc.Node - var end gc.Node - var r0 gc.Node - var f *gc.Node - var p *obj.Prog - var pl *obj.Prog - - /* clear a fat object */ - if gc.Debug['g'] != 0 { - fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width) - } - - w = uint64(nl.Type.Width) - - // Avoid taking the address for simple enough types. - //if(componentgen(N, nl)) - // return; - - c = w % 8 // bytes - q = w / 8 // dwords - - if reg[ppc64.REGRT1] > 0 { - gc.Fatal("R%d in use during clearfat", ppc64.REGRT1) - } - - gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REG_R0) // r0 is always zero - gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1) - reg[ppc64.REGRT1]++ - agen(nl, &dst) - - if q > 128 { - p = gins(ppc64.ASUB, nil, &dst) - p.From.Type = obj.TYPE_CONST - p.From.Offset = 8 - - regalloc(&end, gc.Types[gc.Tptr], nil) - p = gins(ppc64.AMOVD, &dst, &end) - p.From.Type = obj.TYPE_ADDR - p.From.Offset = int64(q * 8) - - p = gins(ppc64.AMOVDU, &r0, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = 8 - pl = p - - p = gins(ppc64.ACMP, &dst, &end) - gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl) - - regfree(&end) - - // The loop leaves R3 on the last zeroed dword - boff = 8 - } else if q >= 4 { - p = gins(ppc64.ASUB, nil, &dst) - p.From.Type = obj.TYPE_CONST - p.From.Offset = 8 - f = gc.Sysfunc("duffzero") - p = gins(obj.ADUFFZERO, nil, f) - gc.Afunclit(&p.To, f) - - // 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s - p.To.Offset = int64(4 * (128 - q)) - - // duffzero leaves R3 on the last zeroed dword - boff = 8 - } else { - for t = 0; t < q; t++ { - p = gins(ppc64.AMOVD, &r0, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(8 * t) - } - - boff = 8 * q - } - - for t = 0; t < c; t++ { - p = gins(ppc64.AMOVB, &r0, &dst) - p.To.Type = obj.TYPE_MEM - p.To.Offset = int64(t + boff) - } - - reg[ppc64.REGRT1]-- -} - -// Called after regopt and peep have run. -// Expand CHECKNIL pseudo-op into actual nil pointer check. -func expandchecks(firstp *obj.Prog) { - var p *obj.Prog - var p1 *obj.Prog - var p2 *obj.Prog - - for p = firstp; p != nil; p = p.Link { - if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 { - fmt.Printf("expandchecks: %v\n", p) - } - if p.As != obj.ACHECKNIL { - continue - } - if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers - gc.Warnl(int(p.Lineno), "generated nil check") - } - if p.From.Type != obj.TYPE_REG { - gc.Fatal("invalid nil check %v\n", p) - } - - /* - // check is - // TD $4, R0, arg (R0 is always zero) - // eqv. to: - // tdeq r0, arg - // NOTE: this needs special runtime support to make SIGTRAP recoverable. - reg = p->from.reg; - p->as = ATD; - p->from = p->to = p->from3 = zprog.from; - p->from.type = TYPE_CONST; - p->from.offset = 4; - p->from.reg = 0; - p->reg = REG_R0; - p->to.type = TYPE_REG; - p->to.reg = reg; - */ - // check is - // CMP arg, R0 - // BNE 2(PC) [likely] - // MOVD R0, 0(R0) - p1 = gc.Ctxt.NewProg() - - p2 = gc.Ctxt.NewProg() - gc.Clearp(p1) - gc.Clearp(p2) - p1.Link = p2 - p2.Link = p.Link - p.Link = p1 - p1.Lineno = p.Lineno - p2.Lineno = p.Lineno - p1.Pc = 9999 - p2.Pc = 9999 - p.As = ppc64.ACMP - p.To.Type = obj.TYPE_REG - p.To.Reg = ppc64.REGZERO - p1.As = ppc64.ABNE - - //p1->from.type = TYPE_CONST; - //p1->from.offset = 1; // likely - p1.To.Type = obj.TYPE_BRANCH - - p1.To.U.Branch = p2.Link - - // crash by write to memory address 0. - p2.As = ppc64.AMOVD - - p2.From.Type = obj.TYPE_REG - p2.From.Reg = ppc64.REG_R0 - p2.To.Type = obj.TYPE_MEM - p2.To.Reg = ppc64.REG_R0 - p2.To.Offset = 0 - } -} diff --git a/src/cmd/new9g/gsubr.go b/src/cmd/new9g/gsubr.go deleted file mode 100644 index 91e87ff015..0000000000 --- a/src/cmd/new9g/gsubr.go +++ /dev/null @@ -1,1165 +0,0 @@ -// Derived from Inferno utils/6c/txt.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" - "fmt" -) -import "cmd/internal/gc" - -// TODO(rsc): Can make this bigger if we move -// the text segment up higher in 6l for all GOOS. -// At the same time, can raise StackBig in ../../runtime/stack.h. -var unmappedzero int64 = 4096 - -var resvd = []int{ - ppc64.REGZERO, - ppc64.REGSP, // reserved for SP - // We need to preserve the C ABI TLS pointer because sigtramp - // may happen during C code and needs to access the g. C - // clobbers REGG, so if Go were to clobber REGTLS, sigtramp - // won't know which convention to use. By preserving REGTLS, - // we can just retrieve g from TLS when we aren't sure. - ppc64.REGTLS, - - // TODO(austin): Consolidate REGTLS and REGG? - ppc64.REGG, - ppc64.REGTMP, // REGTMP - ppc64.FREGCVI, - ppc64.FREGZERO, - ppc64.FREGHALF, - ppc64.FREGONE, - ppc64.FREGTWO, -} - -func ginit() { - var i int - - for i = 0; i < len(reg); i++ { - reg[i] = 1 - } - for i = 0; i < ppc64.NREG+ppc64.NFREG; i++ { - reg[i] = 0 - } - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]-ppc64.REG_R0]++ - } -} - -var regpc [len(reg)]uint32 - -func gclean() { - var i int - - for i = 0; i < len(resvd); i++ { - reg[resvd[i]-ppc64.REG_R0]-- - } - - for i = 0; i < len(reg); i++ { - if reg[i] != 0 { - gc.Yyerror("reg %v left allocated, %p\n", gc.Ctxt.Rconv(i+ppc64.REG_R0), regpc[i]) - } - } -} - -func anyregalloc() bool { - var i int - var j int - - for i = 0; i < len(reg); i++ { - if reg[i] == 0 { - goto ok - } - for j = 0; j < len(resvd); j++ { - if resvd[j] == i { - goto ok - } - } - return true - ok: - } - - return false -} - -/* - * allocate register of type t, leave in n. - * if o != N, o is desired fixed register. - * caller must regfree(n). - */ -func regalloc(n *gc.Node, t *gc.Type, o *gc.Node) { - var i int - var et int - var fixfree int - var fltfree int - - if t == nil { - gc.Fatal("regalloc: t nil") - } - et = int(gc.Simtype[t.Etype]) - - if gc.Debug['r'] != 0 { - fixfree = 0 - fltfree = 0 - for i = ppc64.REG_R0; i < ppc64.REG_F31; i++ { - if reg[i-ppc64.REG_R0] == 0 { - if i < ppc64.REG_F0 { - fixfree++ - } else { - fltfree++ - } - } - } - - fmt.Printf("regalloc fix %d flt %d free\n", fixfree, fltfree) - } - - switch et { - case gc.TINT8, - gc.TUINT8, - gc.TINT16, - gc.TUINT16, - gc.TINT32, - gc.TUINT32, - gc.TINT64, - gc.TUINT64, - gc.TPTR32, - gc.TPTR64, - gc.TBOOL: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= ppc64.REGMIN && i <= ppc64.REGMAX { - goto out - } - } - - for i = ppc64.REGMIN; i <= ppc64.REGMAX; i++ { - if reg[i-ppc64.REG_R0] == 0 { - regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n)) - goto out - } - } - - gc.Flusherrors() - for i = ppc64.REG_R0; i < ppc64.REG_R0+ppc64.NREG; i++ { - fmt.Printf("R%d %p\n", i, regpc[i-ppc64.REG_R0]) - } - gc.Fatal("out of fixed registers") - - case gc.TFLOAT32, - gc.TFLOAT64: - if o != nil && o.Op == gc.OREGISTER { - i = int(o.Val.U.Reg) - if i >= ppc64.FREGMIN && i <= ppc64.FREGMAX { - goto out - } - } - - for i = ppc64.FREGMIN; i <= ppc64.FREGMAX; i++ { - if reg[i-ppc64.REG_R0] == 0 { - regpc[i-ppc64.REG_R0] = uint32(obj.Getcallerpc(&n)) - goto out - } - } - - gc.Flusherrors() - for i = ppc64.REG_F0; i < ppc64.REG_F0+ppc64.NREG; i++ { - fmt.Printf("F%d %p\n", i, regpc[i-ppc64.REG_R0]) - } - gc.Fatal("out of floating registers") - - case gc.TCOMPLEX64, - gc.TCOMPLEX128: - gc.Tempname(n, t) - return - } - - gc.Fatal("regalloc: unknown type %v", gc.Tconv(t, 0)) - return - -out: - reg[i-ppc64.REG_R0]++ - gc.Nodreg(n, t, i) -} - -func regfree(n *gc.Node) { - var i int - - if n.Op == gc.ONAME { - return - } - if n.Op != gc.OREGISTER && n.Op != gc.OINDREG { - gc.Fatal("regfree: not a register") - } - i = int(n.Val.U.Reg) - ppc64.REG_R0 - if i == ppc64.REGSP-ppc64.REG_R0 { - return - } - if i < 0 || i >= len(reg) { - gc.Fatal("regfree: reg out of range") - } - if reg[i] <= 0 { - gc.Fatal("regfree: reg not allocated") - } - reg[i]-- - if reg[i] == 0 { - regpc[i] = 0 - } -} - -/* - * generate - * as $c, n - */ -func ginscon(as int, c int64, n2 *gc.Node) { - var n1 gc.Node - var ntmp gc.Node - - gc.Nodconst(&n1, gc.Types[gc.TINT64], c) - - if as != ppc64.AMOVD && (c < -ppc64.BIG || c > ppc64.BIG) { - // cannot have more than 16-bit of immediate in ADD, etc. - // instead, MOV into register first. - regalloc(&ntmp, gc.Types[gc.TINT64], nil) - - gins(ppc64.AMOVD, &n1, &ntmp) - gins(as, &ntmp, n2) - regfree(&ntmp) - return - } - - gins(as, &n1, n2) -} - -/* - * generate - * as n, $c (CMP/CMPU) - */ -func ginscon2(as int, n2 *gc.Node, c int64) { - var n1 gc.Node - var ntmp gc.Node - - gc.Nodconst(&n1, gc.Types[gc.TINT64], c) - - switch as { - default: - gc.Fatal("ginscon2") - - case ppc64.ACMP: - if -ppc64.BIG <= c && c <= ppc64.BIG { - gins(as, n2, &n1) - return - } - - case ppc64.ACMPU: - if 0 <= c && c <= 2*ppc64.BIG { - gins(as, n2, &n1) - return - } - } - - // MOV n1 into register first - regalloc(&ntmp, gc.Types[gc.TINT64], nil) - - gins(ppc64.AMOVD, &n1, &ntmp) - gins(as, n2, &ntmp) - regfree(&ntmp) -} - -/* - * set up nodes representing 2^63 - */ -var bigi gc.Node - -var bigf gc.Node - -var bignodes_did int - -func bignodes() { - if bignodes_did != 0 { - return - } - bignodes_did = 1 - - gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1) - gc.Mpshiftfix(bigi.Val.U.Xval, 63) - - bigf = bigi - bigf.Type = gc.Types[gc.TFLOAT64] - bigf.Val.Ctype = gc.CTFLT - bigf.Val.U.Fval = new(gc.Mpflt) - gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval) -} - -/* - * generate move: - * t = f - * hard part is conversions. - */ -func gmove(f *gc.Node, t *gc.Node) { - var a int - var ft int - var tt int - var cvt *gc.Type - var r1 gc.Node - var r2 gc.Node - var r3 gc.Node - var con gc.Node - var p1 *obj.Prog - var p2 *obj.Prog - - if gc.Debug['M'] != 0 { - fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong)) - } - - ft = gc.Simsimtype(f.Type) - tt = gc.Simsimtype(t.Type) - cvt = t.Type - - if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 { - gc.Complexmove(f, t) - return - } - - // cannot have two memory operands - if gc.Ismem(f) && gc.Ismem(t) { - goto hard - } - - // convert constant to desired type - if f.Op == gc.OLITERAL { - switch tt { - default: - gc.Convconst(&con, t.Type, &f.Val) - - case gc.TINT32, - gc.TINT16, - gc.TINT8: - gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val) - regalloc(&r1, con.Type, t) - gins(ppc64.AMOVD, &con, &r1) - gmove(&r1, t) - regfree(&r1) - return - - case gc.TUINT32, - gc.TUINT16, - gc.TUINT8: - gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val) - regalloc(&r1, con.Type, t) - gins(ppc64.AMOVD, &con, &r1) - gmove(&r1, t) - regfree(&r1) - return - } - - f = &con - ft = tt // so big switch will choose a simple mov - - // constants can't move directly to memory. - if gc.Ismem(t) { - goto hard - } - } - - // float constants come from memory. - //if(isfloat[tt]) - // goto hard; - - // 64-bit immediates are also from memory. - //if(isint[tt]) - // goto hard; - //// 64-bit immediates are really 32-bit sign-extended - //// unless moving into a register. - //if(isint[tt]) { - // if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0) - // goto hard; - // if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0) - // goto hard; - //} - - // value -> value copy, only one memory operand. - // figure out the instruction to use. - // break out of switch for one-instruction gins. - // goto rdst for "destination must be register". - // goto hard for "convert to cvt type first". - // otherwise handle and return. - - switch uint32(ft)<<16 | uint32(tt) { - default: - gc.Fatal("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong)) - - /* - * integer copy and truncate - */ - case gc.TINT8<<16 | gc.TINT8, // same size - gc.TUINT8<<16 | gc.TINT8, - gc.TINT16<<16 | gc.TINT8, - // truncate - gc.TUINT16<<16 | gc.TINT8, - gc.TINT32<<16 | gc.TINT8, - gc.TUINT32<<16 | gc.TINT8, - gc.TINT64<<16 | gc.TINT8, - gc.TUINT64<<16 | gc.TINT8: - a = ppc64.AMOVB - - case gc.TINT8<<16 | gc.TUINT8, // same size - gc.TUINT8<<16 | gc.TUINT8, - gc.TINT16<<16 | gc.TUINT8, - // truncate - gc.TUINT16<<16 | gc.TUINT8, - gc.TINT32<<16 | gc.TUINT8, - gc.TUINT32<<16 | gc.TUINT8, - gc.TINT64<<16 | gc.TUINT8, - gc.TUINT64<<16 | gc.TUINT8: - a = ppc64.AMOVBZ - - case gc.TINT16<<16 | gc.TINT16, // same size - gc.TUINT16<<16 | gc.TINT16, - gc.TINT32<<16 | gc.TINT16, - // truncate - gc.TUINT32<<16 | gc.TINT16, - gc.TINT64<<16 | gc.TINT16, - gc.TUINT64<<16 | gc.TINT16: - a = ppc64.AMOVH - - case gc.TINT16<<16 | gc.TUINT16, // same size - gc.TUINT16<<16 | gc.TUINT16, - gc.TINT32<<16 | gc.TUINT16, - // truncate - gc.TUINT32<<16 | gc.TUINT16, - gc.TINT64<<16 | gc.TUINT16, - gc.TUINT64<<16 | gc.TUINT16: - a = ppc64.AMOVHZ - - case gc.TINT32<<16 | gc.TINT32, // same size - gc.TUINT32<<16 | gc.TINT32, - gc.TINT64<<16 | gc.TINT32, - // truncate - gc.TUINT64<<16 | gc.TINT32: - a = ppc64.AMOVW - - case gc.TINT32<<16 | gc.TUINT32, // same size - gc.TUINT32<<16 | gc.TUINT32, - gc.TINT64<<16 | gc.TUINT32, - gc.TUINT64<<16 | gc.TUINT32: - a = ppc64.AMOVWZ - - case gc.TINT64<<16 | gc.TINT64, // same size - gc.TINT64<<16 | gc.TUINT64, - gc.TUINT64<<16 | gc.TINT64, - gc.TUINT64<<16 | gc.TUINT64: - a = ppc64.AMOVD - - /* - * integer up-conversions - */ - case gc.TINT8<<16 | gc.TINT16, // sign extend int8 - gc.TINT8<<16 | gc.TUINT16, - gc.TINT8<<16 | gc.TINT32, - gc.TINT8<<16 | gc.TUINT32, - gc.TINT8<<16 | gc.TINT64, - gc.TINT8<<16 | gc.TUINT64: - a = ppc64.AMOVB - - goto rdst - - case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8 - gc.TUINT8<<16 | gc.TUINT16, - gc.TUINT8<<16 | gc.TINT32, - gc.TUINT8<<16 | gc.TUINT32, - gc.TUINT8<<16 | gc.TINT64, - gc.TUINT8<<16 | gc.TUINT64: - a = ppc64.AMOVBZ - - goto rdst - - case gc.TINT16<<16 | gc.TINT32, // sign extend int16 - gc.TINT16<<16 | gc.TUINT32, - gc.TINT16<<16 | gc.TINT64, - gc.TINT16<<16 | gc.TUINT64: - a = ppc64.AMOVH - - goto rdst - - case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16 - gc.TUINT16<<16 | gc.TUINT32, - gc.TUINT16<<16 | gc.TINT64, - gc.TUINT16<<16 | gc.TUINT64: - a = ppc64.AMOVHZ - - goto rdst - - case gc.TINT32<<16 | gc.TINT64, // sign extend int32 - gc.TINT32<<16 | gc.TUINT64: - a = ppc64.AMOVW - - goto rdst - - case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32 - gc.TUINT32<<16 | gc.TUINT64: - a = ppc64.AMOVWZ - - goto rdst - - //warn("gmove: convert float to int not implemented: %N -> %N\n", f, t); - //return; - // algorithm is: - // if small enough, use native float64 -> int64 conversion. - // otherwise, subtract 2^63, convert, and add it back. - /* - * float to integer - */ - case gc.TFLOAT32<<16 | gc.TINT32, - gc.TFLOAT64<<16 | gc.TINT32, - gc.TFLOAT32<<16 | gc.TINT64, - gc.TFLOAT64<<16 | gc.TINT64, - gc.TFLOAT32<<16 | gc.TINT16, - gc.TFLOAT32<<16 | gc.TINT8, - gc.TFLOAT32<<16 | gc.TUINT16, - gc.TFLOAT32<<16 | gc.TUINT8, - gc.TFLOAT64<<16 | gc.TINT16, - gc.TFLOAT64<<16 | gc.TINT8, - gc.TFLOAT64<<16 | gc.TUINT16, - gc.TFLOAT64<<16 | gc.TUINT8, - gc.TFLOAT32<<16 | gc.TUINT32, - gc.TFLOAT64<<16 | gc.TUINT32, - gc.TFLOAT32<<16 | gc.TUINT64, - gc.TFLOAT64<<16 | gc.TUINT64: - bignodes() - - regalloc(&r1, gc.Types[ft], f) - gmove(f, &r1) - if tt == gc.TUINT64 { - regalloc(&r2, gc.Types[gc.TFLOAT64], nil) - gmove(&bigf, &r2) - gins(ppc64.AFCMPU, &r1, &r2) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) - gins(ppc64.AFSUB, &r2, &r1) - gc.Patch(p1, gc.Pc) - regfree(&r2) - } - - regalloc(&r2, gc.Types[gc.TFLOAT64], nil) - regalloc(&r3, gc.Types[gc.TINT64], t) - gins(ppc64.AFCTIDZ, &r1, &r2) - p1 = gins(ppc64.AFMOVD, &r2, nil) - p1.To.Type = obj.TYPE_MEM - p1.To.Reg = ppc64.REGSP - p1.To.Offset = -8 - p1 = gins(ppc64.AMOVD, nil, &r3) - p1.From.Type = obj.TYPE_MEM - p1.From.Reg = ppc64.REGSP - p1.From.Offset = -8 - regfree(&r2) - regfree(&r1) - if tt == gc.TUINT64 { - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TFLOAT64]), nil, +1) // use CR0 here again - gc.Nodreg(&r1, gc.Types[gc.TINT64], ppc64.REGTMP) - gins(ppc64.AMOVD, &bigi, &r1) - gins(ppc64.AADD, &r1, &r3) - gc.Patch(p1, gc.Pc) - } - - gmove(&r3, t) - regfree(&r3) - return - - //warn("gmove: convert int to float not implemented: %N -> %N\n", f, t); - //return; - // algorithm is: - // if small enough, use native int64 -> uint64 conversion. - // otherwise, halve (rounding to odd?), convert, and double. - /* - * integer to float - */ - case gc.TINT32<<16 | gc.TFLOAT32, - gc.TINT32<<16 | gc.TFLOAT64, - gc.TINT64<<16 | gc.TFLOAT32, - gc.TINT64<<16 | gc.TFLOAT64, - gc.TINT16<<16 | gc.TFLOAT32, - gc.TINT16<<16 | gc.TFLOAT64, - gc.TINT8<<16 | gc.TFLOAT32, - gc.TINT8<<16 | gc.TFLOAT64, - gc.TUINT16<<16 | gc.TFLOAT32, - gc.TUINT16<<16 | gc.TFLOAT64, - gc.TUINT8<<16 | gc.TFLOAT32, - gc.TUINT8<<16 | gc.TFLOAT64, - gc.TUINT32<<16 | gc.TFLOAT32, - gc.TUINT32<<16 | gc.TFLOAT64, - gc.TUINT64<<16 | gc.TFLOAT32, - gc.TUINT64<<16 | gc.TFLOAT64: - bignodes() - - regalloc(&r1, gc.Types[gc.TINT64], nil) - gmove(f, &r1) - if ft == gc.TUINT64 { - gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP) - gmove(&bigi, &r2) - gins(ppc64.ACMPU, &r1, &r2) - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) - p2 = gins(ppc64.ASRD, nil, &r1) - p2.From.Type = obj.TYPE_CONST - p2.From.Offset = 1 - gc.Patch(p1, gc.Pc) - } - - regalloc(&r2, gc.Types[gc.TFLOAT64], t) - p1 = gins(ppc64.AMOVD, &r1, nil) - p1.To.Type = obj.TYPE_MEM - p1.To.Reg = ppc64.REGSP - p1.To.Offset = -8 - p1 = gins(ppc64.AFMOVD, nil, &r2) - p1.From.Type = obj.TYPE_MEM - p1.From.Reg = ppc64.REGSP - p1.From.Offset = -8 - gins(ppc64.AFCFID, &r2, &r2) - regfree(&r1) - if ft == gc.TUINT64 { - p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again - gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO) - gins(ppc64.AFMUL, &r1, &r2) - gc.Patch(p1, gc.Pc) - } - - gmove(&r2, t) - regfree(&r2) - return - - /* - * float to float - */ - case gc.TFLOAT32<<16 | gc.TFLOAT32: - a = ppc64.AFMOVS - - case gc.TFLOAT64<<16 | gc.TFLOAT64: - a = ppc64.AFMOVD - - case gc.TFLOAT32<<16 | gc.TFLOAT64: - a = ppc64.AFMOVS - goto rdst - - case gc.TFLOAT64<<16 | gc.TFLOAT32: - a = ppc64.AFRSP - goto rdst - } - - gins(a, f, t) - return - - // requires register destination -rdst: - regalloc(&r1, t.Type, t) - - gins(a, f, &r1) - gmove(&r1, t) - regfree(&r1) - return - - // requires register intermediate -hard: - regalloc(&r1, cvt, t) - - gmove(f, &r1) - gmove(&r1, t) - regfree(&r1) - return -} - -/* - * generate one instruction: - * as f, t - */ -func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog { - var w int32 - var p *obj.Prog - var af obj.Addr - var at obj.Addr - - // TODO(austin): Add self-move test like in 6g (but be careful - // of truncation moves) - - af = obj.Addr{} - - at = obj.Addr{} - if f != nil { - gc.Naddr(f, &af, 1) - } - if t != nil { - gc.Naddr(t, &at, 1) - } - p = gc.Prog(as) - if f != nil { - p.From = af - } - if t != nil { - p.To = at - } - if gc.Debug['g'] != 0 { - fmt.Printf("%v\n", p) - } - - w = 0 - switch as { - case ppc64.AMOVB, - ppc64.AMOVBU, - ppc64.AMOVBZ, - ppc64.AMOVBZU: - w = 1 - - case ppc64.AMOVH, - ppc64.AMOVHU, - ppc64.AMOVHZ, - ppc64.AMOVHZU: - w = 2 - - case ppc64.AMOVW, - ppc64.AMOVWU, - ppc64.AMOVWZ, - ppc64.AMOVWZU: - w = 4 - - case ppc64.AMOVD, - ppc64.AMOVDU: - if af.Type == obj.TYPE_CONST || af.Type == obj.TYPE_ADDR { - break - } - w = 8 - } - - if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Type != obj.TYPE_REG && at.Width > int64(w))) { - gc.Dump("f", f) - gc.Dump("t", t) - gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width) - } - - return p -} - -func fixlargeoffset(n *gc.Node) { - var a gc.Node - - if n == nil { - return - } - if n.Op != gc.OINDREG { - return - } - if n.Val.U.Reg == ppc64.REGSP { // stack offset cannot be large - return - } - if n.Xoffset != int64(int32(n.Xoffset)) { - // TODO(minux): offset too large, move into R31 and add to R31 instead. - // this is used only in test/fixedbugs/issue6036.go. - gc.Fatal("offset too large: %v", gc.Nconv(n, 0)) - - a = *n - a.Op = gc.OREGISTER - a.Type = gc.Types[gc.Tptr] - a.Xoffset = 0 - gc.Cgen_checknil(&a) - ginscon(optoas(gc.OADD, gc.Types[gc.Tptr]), n.Xoffset, &a) - n.Xoffset = 0 - } -} - -/* - * return Axxx for Oxxx on type t. - */ -func optoas(op int, t *gc.Type) int { - var a int - - if t == nil { - gc.Fatal("optoas: t is nil") - } - - a = obj.AXXX - switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) { - default: - gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0)) - - case gc.OEQ<<16 | gc.TBOOL, - gc.OEQ<<16 | gc.TINT8, - gc.OEQ<<16 | gc.TUINT8, - gc.OEQ<<16 | gc.TINT16, - gc.OEQ<<16 | gc.TUINT16, - gc.OEQ<<16 | gc.TINT32, - gc.OEQ<<16 | gc.TUINT32, - gc.OEQ<<16 | gc.TINT64, - gc.OEQ<<16 | gc.TUINT64, - gc.OEQ<<16 | gc.TPTR32, - gc.OEQ<<16 | gc.TPTR64, - gc.OEQ<<16 | gc.TFLOAT32, - gc.OEQ<<16 | gc.TFLOAT64: - a = ppc64.ABEQ - - case gc.ONE<<16 | gc.TBOOL, - gc.ONE<<16 | gc.TINT8, - gc.ONE<<16 | gc.TUINT8, - gc.ONE<<16 | gc.TINT16, - gc.ONE<<16 | gc.TUINT16, - gc.ONE<<16 | gc.TINT32, - gc.ONE<<16 | gc.TUINT32, - gc.ONE<<16 | gc.TINT64, - gc.ONE<<16 | gc.TUINT64, - gc.ONE<<16 | gc.TPTR32, - gc.ONE<<16 | gc.TPTR64, - gc.ONE<<16 | gc.TFLOAT32, - gc.ONE<<16 | gc.TFLOAT64: - a = ppc64.ABNE - - case gc.OLT<<16 | gc.TINT8, // ACMP - gc.OLT<<16 | gc.TINT16, - gc.OLT<<16 | gc.TINT32, - gc.OLT<<16 | gc.TINT64, - gc.OLT<<16 | gc.TUINT8, - // ACMPU - gc.OLT<<16 | gc.TUINT16, - gc.OLT<<16 | gc.TUINT32, - gc.OLT<<16 | gc.TUINT64, - gc.OLT<<16 | gc.TFLOAT32, - // AFCMPU - gc.OLT<<16 | gc.TFLOAT64: - a = ppc64.ABLT - - case gc.OLE<<16 | gc.TINT8, // ACMP - gc.OLE<<16 | gc.TINT16, - gc.OLE<<16 | gc.TINT32, - gc.OLE<<16 | gc.TINT64, - gc.OLE<<16 | gc.TUINT8, - // ACMPU - gc.OLE<<16 | gc.TUINT16, - gc.OLE<<16 | gc.TUINT32, - gc.OLE<<16 | gc.TUINT64, - gc.OLE<<16 | gc.TFLOAT32, - // AFCMPU - gc.OLE<<16 | gc.TFLOAT64: - a = ppc64.ABLE - - case gc.OGT<<16 | gc.TINT8, - gc.OGT<<16 | gc.TINT16, - gc.OGT<<16 | gc.TINT32, - gc.OGT<<16 | gc.TINT64, - gc.OGT<<16 | gc.TUINT8, - gc.OGT<<16 | gc.TUINT16, - gc.OGT<<16 | gc.TUINT32, - gc.OGT<<16 | gc.TUINT64, - gc.OGT<<16 | gc.TFLOAT32, - gc.OGT<<16 | gc.TFLOAT64: - a = ppc64.ABGT - - case gc.OGE<<16 | gc.TINT8, - gc.OGE<<16 | gc.TINT16, - gc.OGE<<16 | gc.TINT32, - gc.OGE<<16 | gc.TINT64, - gc.OGE<<16 | gc.TUINT8, - gc.OGE<<16 | gc.TUINT16, - gc.OGE<<16 | gc.TUINT32, - gc.OGE<<16 | gc.TUINT64, - gc.OGE<<16 | gc.TFLOAT32, - gc.OGE<<16 | gc.TFLOAT64: - a = ppc64.ABGE - - case gc.OCMP<<16 | gc.TBOOL, - gc.OCMP<<16 | gc.TINT8, - gc.OCMP<<16 | gc.TINT16, - gc.OCMP<<16 | gc.TINT32, - gc.OCMP<<16 | gc.TPTR32, - gc.OCMP<<16 | gc.TINT64: - a = ppc64.ACMP - - case gc.OCMP<<16 | gc.TUINT8, - gc.OCMP<<16 | gc.TUINT16, - gc.OCMP<<16 | gc.TUINT32, - gc.OCMP<<16 | gc.TUINT64, - gc.OCMP<<16 | gc.TPTR64: - a = ppc64.ACMPU - - case gc.OCMP<<16 | gc.TFLOAT32, - gc.OCMP<<16 | gc.TFLOAT64: - a = ppc64.AFCMPU - - case gc.OAS<<16 | gc.TBOOL, - gc.OAS<<16 | gc.TINT8: - a = ppc64.AMOVB - - case gc.OAS<<16 | gc.TUINT8: - a = ppc64.AMOVBZ - - case gc.OAS<<16 | gc.TINT16: - a = ppc64.AMOVH - - case gc.OAS<<16 | gc.TUINT16: - a = ppc64.AMOVHZ - - case gc.OAS<<16 | gc.TINT32: - a = ppc64.AMOVW - - case gc.OAS<<16 | gc.TUINT32, - gc.OAS<<16 | gc.TPTR32: - a = ppc64.AMOVWZ - - case gc.OAS<<16 | gc.TINT64, - gc.OAS<<16 | gc.TUINT64, - gc.OAS<<16 | gc.TPTR64: - a = ppc64.AMOVD - - case gc.OAS<<16 | gc.TFLOAT32: - a = ppc64.AFMOVS - - case gc.OAS<<16 | gc.TFLOAT64: - a = ppc64.AFMOVD - - case gc.OADD<<16 | gc.TINT8, - gc.OADD<<16 | gc.TUINT8, - gc.OADD<<16 | gc.TINT16, - gc.OADD<<16 | gc.TUINT16, - gc.OADD<<16 | gc.TINT32, - gc.OADD<<16 | gc.TUINT32, - gc.OADD<<16 | gc.TPTR32, - gc.OADD<<16 | gc.TINT64, - gc.OADD<<16 | gc.TUINT64, - gc.OADD<<16 | gc.TPTR64: - a = ppc64.AADD - - case gc.OADD<<16 | gc.TFLOAT32: - a = ppc64.AFADDS - - case gc.OADD<<16 | gc.TFLOAT64: - a = ppc64.AFADD - - case gc.OSUB<<16 | gc.TINT8, - gc.OSUB<<16 | gc.TUINT8, - gc.OSUB<<16 | gc.TINT16, - gc.OSUB<<16 | gc.TUINT16, - gc.OSUB<<16 | gc.TINT32, - gc.OSUB<<16 | gc.TUINT32, - gc.OSUB<<16 | gc.TPTR32, - gc.OSUB<<16 | gc.TINT64, - gc.OSUB<<16 | gc.TUINT64, - gc.OSUB<<16 | gc.TPTR64: - a = ppc64.ASUB - - case gc.OSUB<<16 | gc.TFLOAT32: - a = ppc64.AFSUBS - - case gc.OSUB<<16 | gc.TFLOAT64: - a = ppc64.AFSUB - - case gc.OMINUS<<16 | gc.TINT8, - gc.OMINUS<<16 | gc.TUINT8, - gc.OMINUS<<16 | gc.TINT16, - gc.OMINUS<<16 | gc.TUINT16, - gc.OMINUS<<16 | gc.TINT32, - gc.OMINUS<<16 | gc.TUINT32, - gc.OMINUS<<16 | gc.TPTR32, - gc.OMINUS<<16 | gc.TINT64, - gc.OMINUS<<16 | gc.TUINT64, - gc.OMINUS<<16 | gc.TPTR64: - a = ppc64.ANEG - - case gc.OAND<<16 | gc.TINT8, - gc.OAND<<16 | gc.TUINT8, - gc.OAND<<16 | gc.TINT16, - gc.OAND<<16 | gc.TUINT16, - gc.OAND<<16 | gc.TINT32, - gc.OAND<<16 | gc.TUINT32, - gc.OAND<<16 | gc.TPTR32, - gc.OAND<<16 | gc.TINT64, - gc.OAND<<16 | gc.TUINT64, - gc.OAND<<16 | gc.TPTR64: - a = ppc64.AAND - - case gc.OOR<<16 | gc.TINT8, - gc.OOR<<16 | gc.TUINT8, - gc.OOR<<16 | gc.TINT16, - gc.OOR<<16 | gc.TUINT16, - gc.OOR<<16 | gc.TINT32, - gc.OOR<<16 | gc.TUINT32, - gc.OOR<<16 | gc.TPTR32, - gc.OOR<<16 | gc.TINT64, - gc.OOR<<16 | gc.TUINT64, - gc.OOR<<16 | gc.TPTR64: - a = ppc64.AOR - - case gc.OXOR<<16 | gc.TINT8, - gc.OXOR<<16 | gc.TUINT8, - gc.OXOR<<16 | gc.TINT16, - gc.OXOR<<16 | gc.TUINT16, - gc.OXOR<<16 | gc.TINT32, - gc.OXOR<<16 | gc.TUINT32, - gc.OXOR<<16 | gc.TPTR32, - gc.OXOR<<16 | gc.TINT64, - gc.OXOR<<16 | gc.TUINT64, - gc.OXOR<<16 | gc.TPTR64: - a = ppc64.AXOR - - // TODO(minux): handle rotates - //case CASE(OLROT, TINT8): - //case CASE(OLROT, TUINT8): - //case CASE(OLROT, TINT16): - //case CASE(OLROT, TUINT16): - //case CASE(OLROT, TINT32): - //case CASE(OLROT, TUINT32): - //case CASE(OLROT, TPTR32): - //case CASE(OLROT, TINT64): - //case CASE(OLROT, TUINT64): - //case CASE(OLROT, TPTR64): - // a = 0//???; RLDC? - // break; - - case gc.OLSH<<16 | gc.TINT8, - gc.OLSH<<16 | gc.TUINT8, - gc.OLSH<<16 | gc.TINT16, - gc.OLSH<<16 | gc.TUINT16, - gc.OLSH<<16 | gc.TINT32, - gc.OLSH<<16 | gc.TUINT32, - gc.OLSH<<16 | gc.TPTR32, - gc.OLSH<<16 | gc.TINT64, - gc.OLSH<<16 | gc.TUINT64, - gc.OLSH<<16 | gc.TPTR64: - a = ppc64.ASLD - - case gc.ORSH<<16 | gc.TUINT8, - gc.ORSH<<16 | gc.TUINT16, - gc.ORSH<<16 | gc.TUINT32, - gc.ORSH<<16 | gc.TPTR32, - gc.ORSH<<16 | gc.TUINT64, - gc.ORSH<<16 | gc.TPTR64: - a = ppc64.ASRD - - case gc.ORSH<<16 | gc.TINT8, - gc.ORSH<<16 | gc.TINT16, - gc.ORSH<<16 | gc.TINT32, - gc.ORSH<<16 | gc.TINT64: - a = ppc64.ASRAD - - // TODO(minux): handle rotates - //case CASE(ORROTC, TINT8): - //case CASE(ORROTC, TUINT8): - //case CASE(ORROTC, TINT16): - //case CASE(ORROTC, TUINT16): - //case CASE(ORROTC, TINT32): - //case CASE(ORROTC, TUINT32): - //case CASE(ORROTC, TINT64): - //case CASE(ORROTC, TUINT64): - // a = 0//??? RLDC?? - // break; - - case gc.OHMUL<<16 | gc.TINT64: - a = ppc64.AMULHD - - case gc.OHMUL<<16 | gc.TUINT64, - gc.OHMUL<<16 | gc.TPTR64: - a = ppc64.AMULHDU - - case gc.OMUL<<16 | gc.TINT8, - gc.OMUL<<16 | gc.TINT16, - gc.OMUL<<16 | gc.TINT32, - gc.OMUL<<16 | gc.TINT64: - a = ppc64.AMULLD - - case gc.OMUL<<16 | gc.TUINT8, - gc.OMUL<<16 | gc.TUINT16, - gc.OMUL<<16 | gc.TUINT32, - gc.OMUL<<16 | gc.TPTR32, - // don't use word multiply, the high 32-bit are undefined. - // fallthrough - gc.OMUL<<16 | gc.TUINT64, - gc.OMUL<<16 | gc.TPTR64: - a = ppc64.AMULLD - // for 64-bit multiplies, signedness doesn't matter. - - case gc.OMUL<<16 | gc.TFLOAT32: - a = ppc64.AFMULS - - case gc.OMUL<<16 | gc.TFLOAT64: - a = ppc64.AFMUL - - case gc.ODIV<<16 | gc.TINT8, - gc.ODIV<<16 | gc.TINT16, - gc.ODIV<<16 | gc.TINT32, - gc.ODIV<<16 | gc.TINT64: - a = ppc64.ADIVD - - case gc.ODIV<<16 | gc.TUINT8, - gc.ODIV<<16 | gc.TUINT16, - gc.ODIV<<16 | gc.TUINT32, - gc.ODIV<<16 | gc.TPTR32, - gc.ODIV<<16 | gc.TUINT64, - gc.ODIV<<16 | gc.TPTR64: - a = ppc64.ADIVDU - - case gc.ODIV<<16 | gc.TFLOAT32: - a = ppc64.AFDIVS - - case gc.ODIV<<16 | gc.TFLOAT64: - a = ppc64.AFDIV - } - - return a -} - -const ( - ODynam = 1 << 0 - OAddable = 1 << 1 -) - -func xgen(n *gc.Node, a *gc.Node, o int) bool { - // TODO(minux) - - return -1 != 0 /*TypeKind(100016)*/ -} - -func sudoclean() { - return -} - -/* - * generate code to compute address of n, - * a reference to a (perhaps nested) field inside - * an array or struct. - * return 0 on failure, 1 on success. - * on success, leaves usable address in a. - * - * caller is responsible for calling sudoclean - * after successful sudoaddable, - * to release the register used for a. - */ -func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool { - // TODO(minux) - - *a = obj.Addr{} - return false -} diff --git a/src/cmd/new9g/opt.go b/src/cmd/new9g/opt.go deleted file mode 100644 index a0294209aa..0000000000 --- a/src/cmd/new9g/opt.go +++ /dev/null @@ -1,42 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Many Power ISA arithmetic and logical instructions come in four -// standard variants. These bits let us map between variants. -const ( - V_CC = 1 << 0 - V_V = 1 << 1 -) diff --git a/src/cmd/new9g/peep.go b/src/cmd/new9g/peep.go deleted file mode 100644 index 486b316dcf..0000000000 --- a/src/cmd/new9g/peep.go +++ /dev/null @@ -1,1071 +0,0 @@ -// Derived from Inferno utils/6c/peep.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" - "fmt" -) -import "cmd/internal/gc" - -var gactive uint32 - -func peep(firstp *obj.Prog) { - var g *gc.Graph - var r *gc.Flow - var r1 *gc.Flow - var p *obj.Prog - var p1 *obj.Prog - var t int - - g = gc.Flowstart(firstp, nil) - if g == nil { - return - } - gactive = 0 - -loop1: - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - gc.Dumpit("loop1", g.Start, 0) - } - - t = 0 - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - - // TODO(austin) Handle smaller moves. arm and amd64 - // distinguish between moves that moves that *must* - // sign/zero extend and moves that don't care so they - // can eliminate moves that don't care without - // breaking moves that do care. This might let us - // simplify or remove the next peep loop, too. - if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD { - if regtyp(&p.To) { - // Try to eliminate reg->reg moves - if regtyp(&p.From) { - if p.From.Type == p.To.Type { - if copyprop(r) { - excise(r) - t++ - } else if subprop(r) && copyprop(r) { - excise(r) - t++ - } - } - } - - // Convert uses to $0 to uses of R0 and - // propagate R0 - if regzer(&p.From) != 0 { - if p.To.Type == obj.TYPE_REG { - p.From.Type = obj.TYPE_REG - p.From.Reg = ppc64.REGZERO - if copyprop(r) { - excise(r) - t++ - } else if subprop(r) && copyprop(r) { - excise(r) - t++ - } - } - } - } - } - } - - if t != 0 { - goto loop1 - } - - /* - * look for MOVB x,R; MOVB R,R (for small MOVs not handled above) - */ - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - default: - continue - - case ppc64.AMOVH, - ppc64.AMOVHZ, - ppc64.AMOVB, - ppc64.AMOVBZ, - ppc64.AMOVW, - ppc64.AMOVWZ: - if p.To.Type != obj.TYPE_REG { - continue - } - } - - r1 = r.Link - if r1 == nil { - continue - } - p1 = r1.Prog - if p1.As != p.As { - continue - } - if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg { - continue - } - if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg { - continue - } - excise(r1) - } - - if gc.Debug['D'] > 1 { - goto ret /* allow following code improvement to be suppressed */ - } - - /* - * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R - * when OP can set condition codes correctly - */ - for r = g.Start; r != nil; r = r.Link { - p = r.Prog - switch p.As { - case ppc64.ACMP, - ppc64.ACMPW: /* always safe? */ - if regzer(&p.To) == 0 { - continue - } - r1 = r.S1 - if r1 == nil { - continue - } - switch r1.Prog.As { - default: - continue - - /* the conditions can be complex and these are currently little used */ - case ppc64.ABCL, - ppc64.ABC: - continue - - case ppc64.ABEQ, - ppc64.ABGE, - ppc64.ABGT, - ppc64.ABLE, - ppc64.ABLT, - ppc64.ABNE, - ppc64.ABVC, - ppc64.ABVS: - break - } - - r1 = r - for { - r1 = gc.Uniqp(r1) - if r1 == nil || r1.Prog.As != obj.ANOP { - break - } - } - - if r1 == nil { - continue - } - p1 = r1.Prog - if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg { - continue - } - switch p1.As { - /* irregular instructions */ - case ppc64.ASUB, - ppc64.AADD, - ppc64.AXOR, - ppc64.AOR: - if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR { - continue - } - } - - switch p1.As { - default: - continue - - case ppc64.AMOVW, - ppc64.AMOVD: - if p1.From.Type != obj.TYPE_REG { - continue - } - continue - - case ppc64.AANDCC, - ppc64.AANDNCC, - ppc64.AORCC, - ppc64.AORNCC, - ppc64.AXORCC, - ppc64.ASUBCC, - ppc64.ASUBECC, - ppc64.ASUBMECC, - ppc64.ASUBZECC, - ppc64.AADDCC, - ppc64.AADDCCC, - ppc64.AADDECC, - ppc64.AADDMECC, - ppc64.AADDZECC, - ppc64.ARLWMICC, - ppc64.ARLWNMCC, - /* don't deal with floating point instructions for now */ - /* - case AFABS: - case AFADD: - case AFADDS: - case AFCTIW: - case AFCTIWZ: - case AFDIV: - case AFDIVS: - case AFMADD: - case AFMADDS: - case AFMOVD: - case AFMSUB: - case AFMSUBS: - case AFMUL: - case AFMULS: - case AFNABS: - case AFNEG: - case AFNMADD: - case AFNMADDS: - case AFNMSUB: - case AFNMSUBS: - case AFRSP: - case AFSUB: - case AFSUBS: - case ACNTLZW: - case AMTFSB0: - case AMTFSB1: - */ - ppc64.AADD, - ppc64.AADDV, - ppc64.AADDC, - ppc64.AADDCV, - ppc64.AADDME, - ppc64.AADDMEV, - ppc64.AADDE, - ppc64.AADDEV, - ppc64.AADDZE, - ppc64.AADDZEV, - ppc64.AAND, - ppc64.AANDN, - ppc64.ADIVW, - ppc64.ADIVWV, - ppc64.ADIVWU, - ppc64.ADIVWUV, - ppc64.ADIVD, - ppc64.ADIVDV, - ppc64.ADIVDU, - ppc64.ADIVDUV, - ppc64.AEQV, - ppc64.AEXTSB, - ppc64.AEXTSH, - ppc64.AEXTSW, - ppc64.AMULHW, - ppc64.AMULHWU, - ppc64.AMULLW, - ppc64.AMULLWV, - ppc64.AMULHD, - ppc64.AMULHDU, - ppc64.AMULLD, - ppc64.AMULLDV, - ppc64.ANAND, - ppc64.ANEG, - ppc64.ANEGV, - ppc64.ANOR, - ppc64.AOR, - ppc64.AORN, - ppc64.AREM, - ppc64.AREMV, - ppc64.AREMU, - ppc64.AREMUV, - ppc64.AREMD, - ppc64.AREMDV, - ppc64.AREMDU, - ppc64.AREMDUV, - ppc64.ARLWMI, - ppc64.ARLWNM, - ppc64.ASLW, - ppc64.ASRAW, - ppc64.ASRW, - ppc64.ASLD, - ppc64.ASRAD, - ppc64.ASRD, - ppc64.ASUB, - ppc64.ASUBV, - ppc64.ASUBC, - ppc64.ASUBCV, - ppc64.ASUBME, - ppc64.ASUBMEV, - ppc64.ASUBE, - ppc64.ASUBEV, - ppc64.ASUBZE, - ppc64.ASUBZEV, - ppc64.AXOR: - t = variant2as(int(p1.As), as2variant(int(p1.As))|V_CC) - } - - if gc.Debug['D'] != 0 { - fmt.Printf("cmp %v; %v -> ", p1, p) - } - p1.As = int16(t) - if gc.Debug['D'] != 0 { - fmt.Printf("%v\n", p1) - } - excise(r) - continue - } - } - -ret: - gc.Flowend(g) -} - -func excise(r *gc.Flow) { - var p *obj.Prog - - p = r.Prog - if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { - fmt.Printf("%v ===delete===\n", p) - } - obj.Nopout(p) - gc.Ostats.Ndelmov++ -} - -/* - * regzer returns 1 if a's value is 0 (a is R0 or $0) - */ -func regzer(a *obj.Addr) int { - if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR { - if a.Sym == nil && a.Reg == 0 { - if a.Offset == 0 { - return 1 - } - } - } - if a.Type == obj.TYPE_REG { - if a.Reg == ppc64.REGZERO { - return 1 - } - } - return 0 -} - -func regtyp(a *obj.Addr) bool { - // TODO(rsc): Floating point register exclusions? - return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO -} - -/* - * the idea is to substitute - * one register for another - * from one MOV to another - * MOV a, R1 - * ADD b, R1 / no use of R2 - * MOV R1, R2 - * would be converted to - * MOV a, R2 - * ADD b, R2 - * MOV R2, R1 - * hopefully, then the former or latter MOV - * will be eliminated by copy propagation. - * - * r0 (the argument, not the register) is the MOV at the end of the - * above sequences. This returns 1 if it modified any instructions. - */ -func subprop(r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - var r *gc.Flow - var t int - var info gc.ProgInfo - - p = r0.Prog - v1 = &p.From - if !regtyp(v1) { - return false - } - v2 = &p.To - if !regtyp(v2) { - return false - } - for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { - if gc.Uniqs(r) == nil { - break - } - p = r.Prog - if p.As == obj.AVARDEF || p.As == obj.AVARKILL { - continue - } - proginfo(&info, p) - if info.Flags&gc.Call != 0 { - return false - } - - if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite { - if p.To.Type == v1.Type { - if p.To.Reg == v1.Reg { - goto gotit - } - } - } - - if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) { - break - } - if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { - break - } - } - - return false - -gotit: - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) - if p.From.Type == v2.Type { - fmt.Printf(" excise") - } - fmt.Printf("\n") - } - - for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { - p = r.Prog - copysub(&p.From, v1, v2, 1) - copysub1(p, v1, v2, 1) - copysub(&p.To, v1, v2, 1) - if gc.Debug['P'] != 0 { - fmt.Printf("%v\n", r.Prog) - } - } - - t = int(v1.Reg) - v1.Reg = v2.Reg - v2.Reg = int16(t) - if gc.Debug['P'] != 0 { - fmt.Printf("%v last\n", r.Prog) - } - return true -} - -/* - * The idea is to remove redundant copies. - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * use v2 return fail (v1->v2 move must remain) - * ----------------- - * v1->v2 F=0 - * (use v2 s/v2/v1/)* - * set v1 F=1 - * set v2 return success (caller can remove v1->v2 move) - */ -func copyprop(r0 *gc.Flow) bool { - var p *obj.Prog - var v1 *obj.Addr - var v2 *obj.Addr - - p = r0.Prog - v1 = &p.From - v2 = &p.To - if copyas(v1, v2) { - if gc.Debug['P'] != 0 { - fmt.Printf("eliminating self-move\n", r0.Prog) - } - return true - } - - gactive++ - if gc.Debug['P'] != 0 { - fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog) - } - return copy1(v1, v2, r0.S1, 0) -} - -// copy1 replaces uses of v2 with v1 starting at r and returns 1 if -// all uses were rewritten. -func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { - var t int - var p *obj.Prog - - if uint32(r.Active) == gactive { - if gc.Debug['P'] != 0 { - fmt.Printf("act set; return 1\n") - } - return true - } - - r.Active = int32(gactive) - if gc.Debug['P'] != 0 { - fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f) - } - for ; r != nil; r = r.S1 { - p = r.Prog - if gc.Debug['P'] != 0 { - fmt.Printf("%v", p) - } - if f == 0 && gc.Uniqp(r) == nil { - // Multiple predecessors; conservatively - // assume v1 was set on other path - f = 1 - - if gc.Debug['P'] != 0 { - fmt.Printf("; merge; f=%d", f) - } - } - - t = copyu(p, v2, nil) - switch t { - case 2: /* rar, can't split */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) - } - return false - - case 3: /* set */ - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - - case 1, /* used, substitute */ - 4: /* use and set */ - if f != 0 { - if gc.Debug['P'] == 0 { - return false - } - if t == 4 { - fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } else { - fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) - } - return false - } - - if copyu(p, v2, v1) != 0 { - if gc.Debug['P'] != 0 { - fmt.Printf("; sub fail; return 0\n") - } - return false - } - - if gc.Debug['P'] != 0 { - fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p) - } - if t == 4 { - if gc.Debug['P'] != 0 { - fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) - } - return true - } - } - - if f == 0 { - t = copyu(p, v1, nil) - if f == 0 && (t == 2 || t == 3 || t == 4) { - f = 1 - if gc.Debug['P'] != 0 { - fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) - } - } - } - - if gc.Debug['P'] != 0 { - fmt.Printf("\n") - } - if r.S2 != nil { - if !copy1(v1, v2, r.S2, f) { - return false - } - } - } - - return true -} - -// If s==nil, copyu returns the set/use of v in p; otherwise, it -// modifies p to replace reads of v with reads of s and returns 0 for -// success or non-zero for failure. -// -// If s==nil, copy returns one of the following values: -// 1 if v only used -// 2 if v is set and used in one address (read-alter-rewrite; -// can't substitute) -// 3 if v is only set -// 4 if v is set in one address and used in another (so addresses -// can be rewritten independently) -// 0 otherwise (not touched) -func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { - if p.From3.Type != obj.TYPE_NONE { - // 9g never generates a from3 - fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(&p.From3)) - } - - switch p.As { - default: - fmt.Printf("copyu: can't find %v\n", ppc64.Aconv(int(p.As))) - return 2 - - case obj.ANOP, /* read p->from, write p->to */ - ppc64.AMOVH, - ppc64.AMOVHZ, - ppc64.AMOVB, - ppc64.AMOVBZ, - ppc64.AMOVW, - ppc64.AMOVWZ, - ppc64.AMOVD, - ppc64.ANEG, - ppc64.ANEGCC, - ppc64.AADDME, - ppc64.AADDMECC, - ppc64.AADDZE, - ppc64.AADDZECC, - ppc64.ASUBME, - ppc64.ASUBMECC, - ppc64.ASUBZE, - ppc64.ASUBZECC, - ppc64.AFCTIW, - ppc64.AFCTIWZ, - ppc64.AFCTID, - ppc64.AFCTIDZ, - ppc64.AFCFID, - ppc64.AFCFIDCC, - ppc64.AFMOVS, - ppc64.AFMOVD, - ppc64.AFRSP, - ppc64.AFNEG, - ppc64.AFNEGCC: - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - - // Update only indirect uses of v in p->to - if !copyas(&p.To, v) { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - } - return 0 - } - - if copyas(&p.To, v) { - // Fix up implicit from - if p.From.Type == obj.TYPE_NONE { - p.From = p.To - } - if copyau(&p.From, v) { - return 4 - } - return 3 - } - - if copyau(&p.From, v) { - return 1 - } - if copyau(&p.To, v) { - // p->to only indirectly uses v - return 1 - } - - return 0 - - case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */ - ppc64.AMOVBZU, - ppc64.AMOVHU, - ppc64.AMOVHZU, - ppc64.AMOVWZU, - ppc64.AMOVDU: - if p.From.Type == obj.TYPE_MEM { - if copyas(&p.From, v) { - // No s!=nil check; need to fail - // anyway in that case - return 2 - } - - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyas(&p.To, v) { - return 3 - } - } else if p.To.Type == obj.TYPE_MEM { - if copyas(&p.To, v) { - return 2 - } - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.From, v) { - return 1 - } - } else { - fmt.Printf("copyu: bad %v\n", p) - } - - return 0 - - case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */ - ppc64.ARLWMICC: - if copyas(&p.To, v) { - return 2 - } - fallthrough - - /* fall through */ - case ppc64.AADD, - /* read p->from, read p->reg, write p->to */ - ppc64.AADDC, - ppc64.AADDE, - ppc64.ASUB, - ppc64.ASLW, - ppc64.ASRW, - ppc64.ASRAW, - ppc64.ASLD, - ppc64.ASRD, - ppc64.ASRAD, - ppc64.AOR, - ppc64.AORCC, - ppc64.AORN, - ppc64.AORNCC, - ppc64.AAND, - ppc64.AANDCC, - ppc64.AANDN, - ppc64.AANDNCC, - ppc64.ANAND, - ppc64.ANANDCC, - ppc64.ANOR, - ppc64.ANORCC, - ppc64.AXOR, - ppc64.AMULHW, - ppc64.AMULHWU, - ppc64.AMULLW, - ppc64.AMULLD, - ppc64.ADIVW, - ppc64.ADIVD, - ppc64.ADIVWU, - ppc64.ADIVDU, - ppc64.AREM, - ppc64.AREMU, - ppc64.AREMD, - ppc64.AREMDU, - ppc64.ARLWNM, - ppc64.ARLWNMCC, - ppc64.AFADDS, - ppc64.AFADD, - ppc64.AFSUBS, - ppc64.AFSUB, - ppc64.AFMULS, - ppc64.AFMUL, - ppc64.AFDIVS, - ppc64.AFDIV: - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - if copysub1(p, v, s, 1) != 0 { - return 1 - } - - // Update only indirect uses of v in p->to - if !copyas(&p.To, v) { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - } - return 0 - } - - if copyas(&p.To, v) { - if p.Reg == 0 { - // Fix up implicit reg (e.g., ADD - // R3,R4 -> ADD R3,R4,R4) so we can - // update reg and to separately. - p.Reg = p.To.Reg - } - - if copyau(&p.From, v) { - return 4 - } - if copyau1(p, v) { - return 4 - } - return 3 - } - - if copyau(&p.From, v) { - return 1 - } - if copyau1(p, v) { - return 1 - } - if copyau(&p.To, v) { - return 1 - } - return 0 - - case ppc64.ABEQ, - ppc64.ABGT, - ppc64.ABGE, - ppc64.ABLT, - ppc64.ABLE, - ppc64.ABNE, - ppc64.ABVC, - ppc64.ABVS: - return 0 - - case obj.ACHECKNIL, /* read p->from */ - ppc64.ACMP, /* read p->from, read p->to */ - ppc64.ACMPU, - ppc64.ACMPW, - ppc64.ACMPWU, - ppc64.AFCMPO, - ppc64.AFCMPU: - if s != nil { - if copysub(&p.From, v, s, 1) != 0 { - return 1 - } - return copysub(&p.To, v, s, 1) - } - - if copyau(&p.From, v) { - return 1 - } - if copyau(&p.To, v) { - return 1 - } - return 0 - - // 9g never generates a branch to a GPR (this isn't - // even a normal instruction; liblink turns it in to a - // mov and a branch). - case ppc64.ABR: /* read p->to */ - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 1 - } - return 0 - - case ppc64.ARETURN: /* funny */ - if s != nil { - return 0 - } - - // All registers die at this point, so claim - // everything is set (and not used). - return 3 - - case ppc64.ABL: /* funny */ - if v.Type == obj.TYPE_REG { - // TODO(rsc): REG_R0 and REG_F0 used to be - // (when register numbers started at 0) exregoffset and exfregoffset, - // which are unset entirely. - // It's strange that this handles R0 and F0 differently from the other - // registers. Possible failure to optimize? - if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT { - return 2 - } - if v.Reg == ppc64.REGARG { - return 2 - } - if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT { - return 2 - } - } - - if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg { - return 2 - } - - if s != nil { - if copysub(&p.To, v, s, 1) != 0 { - return 1 - } - return 0 - } - - if copyau(&p.To, v) { - return 4 - } - return 3 - - // R0 is zero, used by DUFFZERO, cannot be substituted. - // R3 is ptr to memory, used and set, cannot be substituted. - case obj.ADUFFZERO: - if v.Type == obj.TYPE_REG { - if v.Reg == 0 { - return 1 - } - if v.Reg == 3 { - return 2 - } - } - - return 0 - - // R3, R4 are ptr to src, dst, used and set, cannot be substituted. - // R5 is scratch, set by DUFFCOPY, cannot be substituted. - case obj.ADUFFCOPY: - if v.Type == obj.TYPE_REG { - if v.Reg == 3 || v.Reg == 4 { - return 2 - } - if v.Reg == 5 { - return 3 - } - } - - return 0 - - case obj.ATEXT: /* funny */ - if v.Type == obj.TYPE_REG { - if v.Reg == ppc64.REGARG { - return 3 - } - } - return 0 - - case obj.APCDATA, - obj.AFUNCDATA, - obj.AVARDEF, - obj.AVARKILL: - return 0 - } -} - -// copyas returns 1 if a and v address the same register. -// -// If a is the from operand, this means this operation reads the -// register in v. If a is the to operand, this means this operation -// writes the register in v. -func copyas(a *obj.Addr, v *obj.Addr) bool { - if regtyp(v) { - if a.Type == v.Type { - if a.Reg == v.Reg { - return true - } - } - } - return false -} - -// copyau returns 1 if a either directly or indirectly addresses the -// same register as v. -// -// If a is the from operand, this means this operation reads the -// register in v. If a is the to operand, this means the operation -// either reads or writes the register in v (if !copyas(a, v), then -// the operation reads the register in v). -func copyau(a *obj.Addr, v *obj.Addr) bool { - if copyas(a, v) { - return true - } - if v.Type == obj.TYPE_REG { - if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) { - if v.Reg == a.Reg { - return true - } - } - } - return false -} - -// copyau1 returns 1 if p->reg references the same register as v and v -// is a direct reference. -func copyau1(p *obj.Prog, v *obj.Addr) bool { - if regtyp(v) && v.Reg != 0 { - if p.Reg == v.Reg { - return true - } - } - return false -} - -// copysub replaces v with s in a if f!=0 or indicates it if could if f==0. -// Returns 1 on failure to substitute (it always succeeds on ppc64). -func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { - if f != 0 { - if copyau(a, v) { - a.Reg = s.Reg - } - } - return 0 -} - -// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0. -// Returns 1 on failure to substitute (it always succeeds on ppc64). -func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int { - if f != 0 { - if copyau1(p1, v) { - p1.Reg = s.Reg - } - } - return 0 -} - -func sameaddr(a *obj.Addr, v *obj.Addr) bool { - if a.Type != v.Type { - return false - } - if regtyp(v) && a.Reg == v.Reg { - return true - } - if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM { - if v.Offset == a.Offset { - return true - } - } - return false -} - -func smallindir(a *obj.Addr, reg *obj.Addr) bool { - return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096 -} - -func stackaddr(a *obj.Addr) bool { - return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGSP -} diff --git a/src/cmd/new9g/prog.go b/src/cmd/new9g/prog.go deleted file mode 100644 index e188f0dc65..0000000000 --- a/src/cmd/new9g/prog.go +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -import ( - "cmd/internal/obj" - "cmd/internal/obj/ppc64" -) -import "cmd/internal/gc" - -const ( - LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite - RightRdwr uint32 = gc.RightRead | gc.RightWrite -) - -// This table gives the basic information about instruction -// generated by the compiler and processed in the optimizer. -// See opt.h for bit definitions. -// -// Instructions not generated need not be listed. -// As an exception to that rule, we typically write down all the -// size variants of an operation even if we just use a subset. -// -// The table is formatted for 8-space tabs. -var progtable = [ppc64.ALAST]gc.ProgInfo{ - obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0}, - obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0}, - obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0}, - obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0}, - obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0}, - obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0}, - - // NOP is an internal no-op that also stands - // for USED and SET annotations, not the Power opcode. - obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0}, - - // Integer - ppc64.AADD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ASUB: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ANEG: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AAND: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AOR: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AXOR: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AMULLD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AMULLW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AMULHD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AMULHDU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ADIVD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ADIVDU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ASLD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ASRD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ASRAD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.ACMP: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0}, - ppc64.ACMPU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0}, - ppc64.ATD: gc.ProgInfo{gc.SizeQ | gc.RightRead, 0, 0, 0}, - - // Floating point. - ppc64.AFADD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFADDS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFSUB: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFSUBS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFMUL: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFMULS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFDIV: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFDIVS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFCTIDZ: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFCFID: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0}, - ppc64.AFCMPU: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0}, - ppc64.AFRSP: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0}, - - // Moves - ppc64.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0}, - ppc64.AMOVBZ: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AMOVH: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0}, - ppc64.AMOVHZ: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AMOVW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - - // there is no AMOVWU. - ppc64.AMOVWZU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0}, - ppc64.AMOVWZ: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AMOVD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - ppc64.AMOVDU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc, 0, 0, 0}, - ppc64.AFMOVS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0}, - ppc64.AFMOVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0}, - - // Jumps - ppc64.ABR: gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0}, - ppc64.ABL: gc.ProgInfo{gc.Call, 0, 0, 0}, - ppc64.ABEQ: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ABNE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ABGE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ABLT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ABGT: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ABLE: gc.ProgInfo{gc.Cjmp, 0, 0, 0}, - ppc64.ARETURN: gc.ProgInfo{gc.Break, 0, 0, 0}, - obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0}, - obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0}, -} - -var initproginfo_initialized int - -func initproginfo() { - var addvariant = []int{V_CC, V_V, V_CC | V_V} - var as int - var as2 int - var i int - var variant int - - if initproginfo_initialized != 0 { - return - } - initproginfo_initialized = 1 - - // Perform one-time expansion of instructions in progtable to - // their CC, V, and VCC variants - for as = 0; as < len(progtable); as++ { - if progtable[as].Flags == 0 { - continue - } - variant = as2variant(as) - for i = 0; i < len(addvariant); i++ { - as2 = variant2as(as, variant|addvariant[i]) - if as2 != 0 && progtable[as2].Flags == 0 { - progtable[as2] = progtable[as] - } - } - } -} - -func proginfo(info *gc.ProgInfo, p *obj.Prog) { - initproginfo() - - *info = progtable[p.As] - if info.Flags == 0 { - *info = progtable[ppc64.AADD] - gc.Fatal("proginfo: unknown instruction %v", p) - } - - if (info.Flags&gc.RegRead != 0) && p.Reg == 0 { - info.Flags &^= gc.RegRead - info.Flags |= gc.RightRead /*CanRegRead |*/ - } - - if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 { - info.Regindex |= RtoB(int(p.From.Reg)) - if info.Flags&gc.PostInc != 0 { - info.Regset |= RtoB(int(p.From.Reg)) - } - } - - if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 { - info.Regindex |= RtoB(int(p.To.Reg)) - if info.Flags&gc.PostInc != 0 { - info.Regset |= RtoB(int(p.To.Reg)) - } - } - - if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) { - info.Flags &^= gc.LeftRead - info.Flags |= gc.LeftAddr - } - - if p.As == obj.ADUFFZERO { - info.Reguse |= 1<<0 | RtoB(ppc64.REG_R3) - info.Regset |= RtoB(ppc64.REG_R3) - } - - if p.As == obj.ADUFFCOPY { - // TODO(austin) Revisit when duffcopy is implemented - info.Reguse |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) | RtoB(ppc64.REG_R5) - - info.Regset |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) - } -} - -// Instruction variants table. Initially this contains entries only -// for the "base" form of each instruction. On the first call to -// as2variant or variant2as, we'll add the variants to the table. -var varianttable = [ppc64.ALAST][4]int{ - ppc64.AADD: [4]int{ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC}, - ppc64.AADDC: [4]int{ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC}, - ppc64.AADDE: [4]int{ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC}, - ppc64.AADDME: [4]int{ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC}, - ppc64.AADDZE: [4]int{ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC}, - ppc64.AAND: [4]int{ppc64.AAND, ppc64.AANDCC, 0, 0}, - ppc64.AANDN: [4]int{ppc64.AANDN, ppc64.AANDNCC, 0, 0}, - ppc64.ACNTLZD: [4]int{ppc64.ACNTLZD, ppc64.ACNTLZDCC, 0, 0}, - ppc64.ACNTLZW: [4]int{ppc64.ACNTLZW, ppc64.ACNTLZWCC, 0, 0}, - ppc64.ADIVD: [4]int{ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC}, - ppc64.ADIVDU: [4]int{ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC}, - ppc64.ADIVW: [4]int{ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC}, - ppc64.ADIVWU: [4]int{ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC}, - ppc64.AEQV: [4]int{ppc64.AEQV, ppc64.AEQVCC, 0, 0}, - ppc64.AEXTSB: [4]int{ppc64.AEXTSB, ppc64.AEXTSBCC, 0, 0}, - ppc64.AEXTSH: [4]int{ppc64.AEXTSH, ppc64.AEXTSHCC, 0, 0}, - ppc64.AEXTSW: [4]int{ppc64.AEXTSW, ppc64.AEXTSWCC, 0, 0}, - ppc64.AFABS: [4]int{ppc64.AFABS, ppc64.AFABSCC, 0, 0}, - ppc64.AFADD: [4]int{ppc64.AFADD, ppc64.AFADDCC, 0, 0}, - ppc64.AFADDS: [4]int{ppc64.AFADDS, ppc64.AFADDSCC, 0, 0}, - ppc64.AFCFID: [4]int{ppc64.AFCFID, ppc64.AFCFIDCC, 0, 0}, - ppc64.AFCTID: [4]int{ppc64.AFCTID, ppc64.AFCTIDCC, 0, 0}, - ppc64.AFCTIDZ: [4]int{ppc64.AFCTIDZ, ppc64.AFCTIDZCC, 0, 0}, - ppc64.AFCTIW: [4]int{ppc64.AFCTIW, ppc64.AFCTIWCC, 0, 0}, - ppc64.AFCTIWZ: [4]int{ppc64.AFCTIWZ, ppc64.AFCTIWZCC, 0, 0}, - ppc64.AFDIV: [4]int{ppc64.AFDIV, ppc64.AFDIVCC, 0, 0}, - ppc64.AFDIVS: [4]int{ppc64.AFDIVS, ppc64.AFDIVSCC, 0, 0}, - ppc64.AFMADD: [4]int{ppc64.AFMADD, ppc64.AFMADDCC, 0, 0}, - ppc64.AFMADDS: [4]int{ppc64.AFMADDS, ppc64.AFMADDSCC, 0, 0}, - ppc64.AFMOVD: [4]int{ppc64.AFMOVD, ppc64.AFMOVDCC, 0, 0}, - ppc64.AFMSUB: [4]int{ppc64.AFMSUB, ppc64.AFMSUBCC, 0, 0}, - ppc64.AFMSUBS: [4]int{ppc64.AFMSUBS, ppc64.AFMSUBSCC, 0, 0}, - ppc64.AFMUL: [4]int{ppc64.AFMUL, ppc64.AFMULCC, 0, 0}, - ppc64.AFMULS: [4]int{ppc64.AFMULS, ppc64.AFMULSCC, 0, 0}, - ppc64.AFNABS: [4]int{ppc64.AFNABS, ppc64.AFNABSCC, 0, 0}, - ppc64.AFNEG: [4]int{ppc64.AFNEG, ppc64.AFNEGCC, 0, 0}, - ppc64.AFNMADD: [4]int{ppc64.AFNMADD, ppc64.AFNMADDCC, 0, 0}, - ppc64.AFNMADDS: [4]int{ppc64.AFNMADDS, ppc64.AFNMADDSCC, 0, 0}, - ppc64.AFNMSUB: [4]int{ppc64.AFNMSUB, ppc64.AFNMSUBCC, 0, 0}, - ppc64.AFNMSUBS: [4]int{ppc64.AFNMSUBS, ppc64.AFNMSUBSCC, 0, 0}, - ppc64.AFRES: [4]int{ppc64.AFRES, ppc64.AFRESCC, 0, 0}, - ppc64.AFRSP: [4]int{ppc64.AFRSP, ppc64.AFRSPCC, 0, 0}, - ppc64.AFRSQRTE: [4]int{ppc64.AFRSQRTE, ppc64.AFRSQRTECC, 0, 0}, - ppc64.AFSEL: [4]int{ppc64.AFSEL, ppc64.AFSELCC, 0, 0}, - ppc64.AFSQRT: [4]int{ppc64.AFSQRT, ppc64.AFSQRTCC, 0, 0}, - ppc64.AFSQRTS: [4]int{ppc64.AFSQRTS, ppc64.AFSQRTSCC, 0, 0}, - ppc64.AFSUB: [4]int{ppc64.AFSUB, ppc64.AFSUBCC, 0, 0}, - ppc64.AFSUBS: [4]int{ppc64.AFSUBS, ppc64.AFSUBSCC, 0, 0}, - ppc64.AMTFSB0: [4]int{ppc64.AMTFSB0, ppc64.AMTFSB0CC, 0, 0}, - ppc64.AMTFSB1: [4]int{ppc64.AMTFSB1, ppc64.AMTFSB1CC, 0, 0}, - ppc64.AMULHD: [4]int{ppc64.AMULHD, ppc64.AMULHDCC, 0, 0}, - ppc64.AMULHDU: [4]int{ppc64.AMULHDU, ppc64.AMULHDUCC, 0, 0}, - ppc64.AMULHW: [4]int{ppc64.AMULHW, ppc64.AMULHWCC, 0, 0}, - ppc64.AMULHWU: [4]int{ppc64.AMULHWU, ppc64.AMULHWUCC, 0, 0}, - ppc64.AMULLD: [4]int{ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC}, - ppc64.AMULLW: [4]int{ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC}, - ppc64.ANAND: [4]int{ppc64.ANAND, ppc64.ANANDCC, 0, 0}, - ppc64.ANEG: [4]int{ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC}, - ppc64.ANOR: [4]int{ppc64.ANOR, ppc64.ANORCC, 0, 0}, - ppc64.AOR: [4]int{ppc64.AOR, ppc64.AORCC, 0, 0}, - ppc64.AORN: [4]int{ppc64.AORN, ppc64.AORNCC, 0, 0}, - ppc64.AREM: [4]int{ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC}, - ppc64.AREMD: [4]int{ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC}, - ppc64.AREMDU: [4]int{ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC}, - ppc64.AREMU: [4]int{ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC}, - ppc64.ARLDC: [4]int{ppc64.ARLDC, ppc64.ARLDCCC, 0, 0}, - ppc64.ARLDCL: [4]int{ppc64.ARLDCL, ppc64.ARLDCLCC, 0, 0}, - ppc64.ARLDCR: [4]int{ppc64.ARLDCR, ppc64.ARLDCRCC, 0, 0}, - ppc64.ARLDMI: [4]int{ppc64.ARLDMI, ppc64.ARLDMICC, 0, 0}, - ppc64.ARLWMI: [4]int{ppc64.ARLWMI, ppc64.ARLWMICC, 0, 0}, - ppc64.ARLWNM: [4]int{ppc64.ARLWNM, ppc64.ARLWNMCC, 0, 0}, - ppc64.ASLD: [4]int{ppc64.ASLD, ppc64.ASLDCC, 0, 0}, - ppc64.ASLW: [4]int{ppc64.ASLW, ppc64.ASLWCC, 0, 0}, - ppc64.ASRAD: [4]int{ppc64.ASRAD, ppc64.ASRADCC, 0, 0}, - ppc64.ASRAW: [4]int{ppc64.ASRAW, ppc64.ASRAWCC, 0, 0}, - ppc64.ASRD: [4]int{ppc64.ASRD, ppc64.ASRDCC, 0, 0}, - ppc64.ASRW: [4]int{ppc64.ASRW, ppc64.ASRWCC, 0, 0}, - ppc64.ASUB: [4]int{ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC}, - ppc64.ASUBC: [4]int{ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC}, - ppc64.ASUBE: [4]int{ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC}, - ppc64.ASUBME: [4]int{ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC}, - ppc64.ASUBZE: [4]int{ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC}, - ppc64.AXOR: [4]int{ppc64.AXOR, ppc64.AXORCC, 0, 0}, -} - -var initvariants_initialized int - -func initvariants() { - var i int - var j int - - if initvariants_initialized != 0 { - return - } - initvariants_initialized = 1 - - for i = 0; i < len(varianttable); i++ { - if varianttable[i][0] == 0 { - // Instruction has no variants - varianttable[i][0] = i - - continue - } - - // Copy base form to other variants - if varianttable[i][0] == i { - for j = 0; j < len(varianttable[i]); j++ { - varianttable[varianttable[i][j]] = varianttable[i] - } - } - } -} - -// as2variant returns the variant (V_*) flags of instruction as. -func as2variant(as int) int { - var i int - initvariants() - for i = 0; i < len(varianttable[as]); i++ { - if varianttable[as][i] == as { - return i - } - } - gc.Fatal("as2variant: instruction %v is not a variant of itself", ppc64.Aconv(as)) - return 0 -} - -// variant2as returns the instruction as with the given variant (V_*) flags. -// If no such variant exists, this returns 0. -func variant2as(as int, flags int) int { - initvariants() - return varianttable[as][flags] -} diff --git a/src/cmd/new9g/reg.go b/src/cmd/new9g/reg.go deleted file mode 100644 index faed60d0ee..0000000000 --- a/src/cmd/new9g/reg.go +++ /dev/null @@ -1,164 +0,0 @@ -// Derived from Inferno utils/6c/reg.c -// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package main - -import "cmd/internal/obj/ppc64" -import "cmd/internal/gc" - -const ( - NREGVAR = 64 -) - -var regname = []string{ - ".R0", - ".R1", - ".R2", - ".R3", - ".R4", - ".R5", - ".R6", - ".R7", - ".R8", - ".R9", - ".R10", - ".R11", - ".R12", - ".R13", - ".R14", - ".R15", - ".R16", - ".R17", - ".R18", - ".R19", - ".R20", - ".R21", - ".R22", - ".R23", - ".R24", - ".R25", - ".R26", - ".R27", - ".R28", - ".R29", - ".R30", - ".R31", - ".F0", - ".F1", - ".F2", - ".F3", - ".F4", - ".F5", - ".F6", - ".F7", - ".F8", - ".F9", - ".F10", - ".F11", - ".F12", - ".F13", - ".F14", - ".F15", - ".F16", - ".F17", - ".F18", - ".F19", - ".F20", - ".F21", - ".F22", - ".F23", - ".F24", - ".F25", - ".F26", - ".F27", - ".F28", - ".F29", - ".F30", - ".F31", -} - -func regnames(n *int) []string { - *n = NREGVAR - return regname -} - -func excludedregs() uint64 { - var regbits uint64 - - // Exclude registers with fixed functions - regbits = 1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS) - - // Also exclude floating point registers with fixed constants - regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.REG_F31) - - return regbits -} - -func doregbits(r int) uint64 { - return 0 -} - -/* - * track register variables including external registers: - * bit reg - * 0 R0 - * 1 R1 - * ... ... - * 31 R31 - * 32+0 F0 - * 32+1 F1 - * ... ... - * 32+31 F31 - */ -func RtoB(r int) uint64 { - if r > ppc64.REG_R0 && r <= ppc64.REG_R31 { - return 1 << uint(r-ppc64.REG_R0) - } - if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 { - return 1 << uint(32+r-ppc64.REG_F0) - } - return 0 -} - -func BtoR(b uint64) int { - b &= 0xffffffff - if b == 0 { - return 0 - } - return gc.Bitno(b) + ppc64.REG_R0 -} - -func BtoF(b uint64) int { - b >>= 32 - if b == 0 { - return 0 - } - return gc.Bitno(b) + ppc64.REG_F0 -} diff --git a/src/cmd/new9g/util.go b/src/cmd/new9g/util.go deleted file mode 100644 index bb5eedb15a..0000000000 --- a/src/cmd/new9g/util.go +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package main - -func bool2int(b bool) int { - if b { - return 1 - } - return 0 -} diff --git a/src/cmd/objwriter/main.go b/src/cmd/objwriter/main.go deleted file mode 100644 index df83298ecc..0000000000 --- a/src/cmd/objwriter/main.go +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Objwriter reads an object file description in an unspecified format -// and writes a Go object file. It is invoked by parts of the toolchain -// that have not yet been converted from C to Go and should not be -// used otherwise. -package main - -import ( - "bufio" - "bytes" - "flag" - "fmt" - "io" - "io/ioutil" - "log" - "math" - "os" - "runtime/pprof" - "strconv" - "strings" - - "cmd/internal/obj" - "cmd/internal/obj/arm" - "cmd/internal/obj/i386" - "cmd/internal/obj/ppc64" - "cmd/internal/obj/x86" -) - -var arch *obj.LinkArch -var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file") -var memprofile = flag.String("memprofile", "", "write memory profile to this file") - -func main() { - log.SetPrefix("goobj: ") - log.SetFlags(0) - flag.Parse() - - if flag.NArg() == 1 && flag.Arg(0) == "ping" { - // old invocation from liblink, just testing that objwriter exists - return - } - - if flag.NArg() != 4 { - fmt.Fprintf(os.Stderr, "usage: goobj infile objfile offset goarch\n") - os.Exit(2) - } - - if *cpuprofile != "" { - f, err := os.Create(*cpuprofile) - if err != nil { - log.Fatal(err) - } - pprof.StartCPUProfile(f) - defer pprof.StopCPUProfile() - } - if *memprofile != "" { - f, err := os.Create(*memprofile) - if err != nil { - log.Fatal(err) - } - defer pprof.WriteHeapProfile(f) - } - - switch flag.Arg(3) { - case "amd64": - arch = &x86.Linkamd64 - case "amd64p32": - arch = &x86.Linkamd64p32 - case "386": - // TODO(rsc): Move Link386 to package x86. - arch = &i386.Link386 - case "arm": - arch = &arm.Linkarm - case "ppc64": - arch = &ppc64.Linkppc64 - case "ppc64le": - arch = &ppc64.Linkppc64le - } - - input() -} - -const ( - // must match liblink/objfilego.c - TypeEnd = iota - TypeCtxt - TypePlist - TypeSym - TypeProg - TypeAddr - TypeHist -) - -var ( - ctxt *obj.Link - plists = map[int64]*obj.Plist{} - syms = map[int64]*obj.LSym{} - progs = map[int64]*obj.Prog{} - hists = map[int64]*obj.Hist{} - undef = map[interface{}]bool{} -) - -func input() { - args := flag.Args() - ctxt = obj.Linknew(arch) - ctxt.Debugasm = 1 - ctxt.Bso = obj.Binitw(os.Stdout) - defer obj.Bflush(ctxt.Bso) - ctxt.Diag = log.Fatalf - f, err := os.Open(args[0]) - if err != nil { - log.Fatal(err) - } - - b := bufio.NewReaderSize(f, 1<<20) - if v := rdint(b); v != TypeCtxt { - log.Fatalf("invalid input - missing ctxt - got %d", v) - } - name := rdstring(b) - if name != ctxt.Arch.Name { - log.Fatalf("bad arch %s - want %s", name, ctxt.Arch.Name) - } - - ctxt.Goarm = int32(rdint(b)) - ctxt.Debugasm = int32(rdint(b)) - ctxt.Trimpath = rdstring(b) - ctxt.Plist = rdplist(b) - ctxt.Plast = rdplist(b) - ctxt.Hist = rdhist(b) - ctxt.Ehist = rdhist(b) - for { - i := rdint(b) - if i < 0 { - break - } - ctxt.Hash[i] = rdsym(b) - } - last := int64(TypeCtxt) - -Loop: - for { - t := rdint(b) - switch t { - default: - log.Fatalf("unexpected input after type %d: %v", last, t) - case TypeEnd: - break Loop - case TypePlist: - readplist(b, rdplist(b)) - case TypeSym: - readsym(b, rdsym(b)) - case TypeProg: - readprog(b, rdprog(b)) - case TypeHist: - readhist(b, rdhist(b)) - } - last = t - } - - if len(undef) > 0 { - panic("missing definitions") - } - - var buf bytes.Buffer - obuf := obj.Binitw(&buf) - obj.Writeobjdirect(ctxt, obuf) - obj.Bflush(obuf) - - data, err := ioutil.ReadFile(args[1]) - if err != nil { - log.Fatal(err) - } - - offset, err := strconv.Atoi(args[2]) - if err != nil { - log.Fatalf("bad offset: %v", err) - } - if offset > len(data) { - log.Fatalf("offset too large: %v > %v", offset, len(data)) - } - - old := data[offset:] - if len(old) > 0 && !bytes.Equal(old, buf.Bytes()) { - out := strings.TrimSuffix(args[0], ".in") + ".out" - if err := ioutil.WriteFile(out, append(data[:offset:offset], buf.Bytes()...), 0666); err != nil { - log.Fatal(err) - } - log.Fatalf("goobj produced different output:\n\toriginal: %s\n\tgoobj: %s", args[1], out) - } - - if len(old) == 0 { - data = append(data, buf.Bytes()...) - if err := ioutil.WriteFile(args[1], data, 0666); err != nil { - log.Fatal(err) - } - } -} - -func rdstring(b *bufio.Reader) string { - v := rdint(b) - buf := make([]byte, v) - io.ReadFull(b, buf) - return string(buf) -} - -func rdint(b *bufio.Reader) int64 { - var v uint64 - shift := uint(0) - for { - b, err := b.ReadByte() - if err != nil { - log.Fatal(err) - } - v |= uint64(b&0x7F) << shift - shift += 7 - if b&0x80 == 0 { - break - } - } - return int64(v>>1) ^ int64(v<<63)>>63 -} - -func rdplist(b *bufio.Reader) *obj.Plist { - id := rdint(b) - if id == 0 { - return nil - } - pl := plists[id] - if pl == nil { - pl = new(obj.Plist) - plists[id] = pl - undef[pl] = true - } - return pl -} - -func rdsym(b *bufio.Reader) *obj.LSym { - id := rdint(b) - if id == 0 { - return nil - } - sym := syms[id] - if sym == nil { - sym = new(obj.LSym) - syms[id] = sym - undef[sym] = true - } - return sym -} - -func rdprog(b *bufio.Reader) *obj.Prog { - id := rdint(b) - if id == 0 { - return nil - } - prog := progs[id] - if prog == nil { - prog = new(obj.Prog) - prog.Ctxt = ctxt - progs[id] = prog - undef[prog] = true - } - return prog -} - -func rdhist(b *bufio.Reader) *obj.Hist { - id := rdint(b) - if id == 0 { - return nil - } - h := hists[id] - if h == nil { - h = new(obj.Hist) - hists[id] = h - undef[h] = true - } - return h -} - -func readplist(b *bufio.Reader, pl *obj.Plist) { - if !undef[pl] { - panic("double-def") - } - delete(undef, pl) - pl.Recur = int(rdint(b)) - pl.Name = rdsym(b) - pl.Firstpc = rdprog(b) - pl.Link = rdplist(b) -} - -func readsym(b *bufio.Reader, s *obj.LSym) { - if !undef[s] { - panic("double-def") - } - delete(undef, s) - s.Name = rdstring(b) - s.Extname = rdstring(b) - s.Type = int16(rdint(b)) - s.Version = int16(rdint(b)) - s.Dupok = uint8(rdint(b)) - s.External = uint8(rdint(b)) - s.Nosplit = uint8(rdint(b)) - s.Reachable = uint8(rdint(b)) - s.Cgoexport = uint8(rdint(b)) - s.Special = uint8(rdint(b)) - s.Stkcheck = uint8(rdint(b)) - s.Hide = uint8(rdint(b)) - s.Leaf = uint8(rdint(b)) - s.Fnptr = uint8(rdint(b)) - s.Seenglobl = uint8(rdint(b)) - s.Onlist = uint8(rdint(b)) - s.Symid = int16(rdint(b)) - s.Dynid = int32(rdint(b)) - s.Sig = int32(rdint(b)) - s.Plt = int32(rdint(b)) - s.Got = int32(rdint(b)) - s.Align = int32(rdint(b)) - s.Elfsym = int32(rdint(b)) - s.Args = int32(rdint(b)) - s.Locals = int32(rdint(b)) - s.Value = rdint(b) - s.Size = rdint(b) - s.Hash = rdsym(b) - s.Allsym = rdsym(b) - s.Next = rdsym(b) - s.Sub = rdsym(b) - s.Outer = rdsym(b) - s.Gotype = rdsym(b) - s.Reachparent = rdsym(b) - s.Queue = rdsym(b) - s.File = rdstring(b) - s.Dynimplib = rdstring(b) - s.Dynimpvers = rdstring(b) - s.Text = rdprog(b) - s.Etext = rdprog(b) - n := int(rdint(b)) - if n > 0 { - s.P = make([]byte, n) - io.ReadFull(b, s.P) - } - s.R = make([]obj.Reloc, int(rdint(b))) - for i := range s.R { - r := &s.R[i] - r.Off = int32(rdint(b)) - r.Siz = uint8(rdint(b)) - r.Done = uint8(rdint(b)) - r.Type = int32(rdint(b)) - r.Add = rdint(b) - r.Xadd = rdint(b) - r.Sym = rdsym(b) - r.Xsym = rdsym(b) - } -} - -func readprog(b *bufio.Reader, p *obj.Prog) { - if !undef[p] { - panic("double-def") - } - delete(undef, p) - p.Pc = rdint(b) - p.Lineno = int32(rdint(b)) - p.Link = rdprog(b) - p.As = int16(rdint(b)) - p.Reg = int16(rdint(b)) - p.Scond = uint8(rdint(b)) - p.Width = int8(rdint(b)) - readaddr(b, &p.From) - readaddr(b, &p.From3) - readaddr(b, &p.To) -} - -func readaddr(b *bufio.Reader, a *obj.Addr) { - if rdint(b) != TypeAddr { - log.Fatal("out of sync") - } - a.Offset = rdint(b) - a.U.Dval = rdfloat(b) - buf := make([]byte, 8) - io.ReadFull(b, buf) - a.U.Sval = string(buf) - a.U.Branch = rdprog(b) - a.Sym = rdsym(b) - a.Gotype = rdsym(b) - a.Type = int16(rdint(b)) - a.Index = int16(rdint(b)) - a.Scale = int8(rdint(b)) - a.Reg = int16(rdint(b)) - a.Name = int8(rdint(b)) - a.Class = int8(rdint(b)) - a.Etype = uint8(rdint(b)) - a.U.Argsize = int32(rdint(b)) - a.Width = rdint(b) -} - -func readhist(b *bufio.Reader, h *obj.Hist) { - if !undef[h] { - panic("double-def") - } - delete(undef, h) - h.Link = rdhist(b) - h.Name = rdstring(b) - h.Line = int32(rdint(b)) - h.Offset = int32(rdint(b)) -} - -func rdfloat(b *bufio.Reader) float64 { - return math.Float64frombits(uint64(rdint(b))) -} -- cgit v1.2.3-54-g00ecf