Add Go frontend, libgo library, and Go testsuite.
gcc/: * gcc.c (default_compilers): Add entry for ".go". * common.opt: Add -static-libgo as a driver option. * doc/install.texi (Configuration): Mention libgo as an option for --enable-shared. Mention go as an option for --enable-languages. * doc/invoke.texi (Overall Options): Mention .go as a file name suffix. Mention go as a -x option. * doc/frontends.texi (G++ and GCC): Mention Go as a supported language. * doc/sourcebuild.texi (Top Level): Mention libgo. * doc/standards.texi (Standards): Add section on Go language. Move references for other languages into their own section. * doc/contrib.texi (Contributors): Mention that I contributed the Go frontend. gcc/testsuite/: * lib/go.exp: New file. * lib/go-dg.exp: New file. * lib/go-torture.exp: New file. * lib/target-supports.exp (check_compile): Match // Go. From-SVN: r167407
This commit is contained in:
parent
1aa6700378
commit
7a9389330e
1565 changed files with 351565 additions and 12 deletions
|
@ -1,3 +1,19 @@
|
|||
2010-12-02 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* gcc.c (default_compilers): Add entry for ".go".
|
||||
* common.opt: Add -static-libgo as a driver option.
|
||||
* doc/install.texi (Configuration): Mention libgo as an option for
|
||||
--enable-shared. Mention go as an option for --enable-languages.
|
||||
* doc/invoke.texi (Overall Options): Mention .go as a file name
|
||||
suffix. Mention go as a -x option.
|
||||
* doc/frontends.texi (G++ and GCC): Mention Go as a supported
|
||||
language.
|
||||
* doc/sourcebuild.texi (Top Level): Mention libgo.
|
||||
* doc/standards.texi (Standards): Add section on Go language.
|
||||
Move references for other languages into their own section.
|
||||
* doc/contrib.texi (Contributors): Mention that I contributed the
|
||||
Go frontend.
|
||||
|
||||
2010-12-03 Laurynas Biveinis <laurynas.biveinis@gmail.com>
|
||||
|
||||
* tree.h (struct call_expr_arg_iterator_d): Remove GTY tag.
|
||||
|
|
|
@ -2272,6 +2272,10 @@ Driver
|
|||
static-libstdc++
|
||||
Driver
|
||||
|
||||
static-libgo
|
||||
Driver
|
||||
; Documented for Go, but always accepted by driver.
|
||||
|
||||
symbolic
|
||||
Driver
|
||||
|
||||
|
|
|
@ -900,8 +900,8 @@ Jeff Sturm for Java porting help, bug fixes, and encouragement.
|
|||
Shigeya Suzuki for this fixes for the bsdi platforms.
|
||||
|
||||
@item
|
||||
Ian Lance Taylor for his mips16 work, general configury hacking,
|
||||
fixincludes, etc.
|
||||
Ian Lance Taylor for the Go frontend, the initial mips16 and mips64
|
||||
support, general configury hacking, fixincludes, etc.
|
||||
|
||||
@item
|
||||
Holger Teutsch provided the support for the Clipper CPU@.
|
||||
|
|
|
@ -11,13 +11,14 @@
|
|||
@cindex GNU C Compiler
|
||||
@cindex Ada
|
||||
@cindex Fortran
|
||||
@cindex Go
|
||||
@cindex Java
|
||||
@cindex Objective-C
|
||||
@cindex Objective-C++
|
||||
GCC stands for ``GNU Compiler Collection''. GCC is an integrated
|
||||
distribution of compilers for several major programming languages. These
|
||||
languages currently include C, C++, Objective-C, Objective-C++, Java,
|
||||
Fortran, and Ada.
|
||||
Fortran, Ada, and Go.
|
||||
|
||||
The abbreviation @dfn{GCC} has multiple meanings in common use. The
|
||||
current official meaning is ``GNU Compiler Collection'', which refers
|
||||
|
|
|
@ -884,7 +884,7 @@ only for the listed packages. For other packages, only static libraries
|
|||
will be built. Package names currently recognized in the GCC tree are
|
||||
@samp{libgcc} (also known as @samp{gcc}), @samp{libstdc++} (not
|
||||
@samp{libstdc++-v3}), @samp{libffi}, @samp{zlib}, @samp{boehm-gc},
|
||||
@samp{ada}, @samp{libada}, @samp{libjava} and @samp{libobjc}.
|
||||
@samp{ada}, @samp{libada}, @samp{libjava}, @samp{libgo}, and @samp{libobjc}.
|
||||
Note @samp{libiberty} does not support shared libraries at all.
|
||||
|
||||
Use @option{--disable-shared} to build only static libraries. Note that
|
||||
|
@ -1305,15 +1305,12 @@ their runtime libraries should be built. For a list of valid values for
|
|||
grep language= */config-lang.in
|
||||
@end smallexample
|
||||
Currently, you can use any of the following:
|
||||
@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran}, @code{java},
|
||||
@code{objc}, @code{obj-c++}.
|
||||
@code{all}, @code{ada}, @code{c}, @code{c++}, @code{fortran},
|
||||
@code{go}, @code{java}, @code{objc}, @code{obj-c++}.
|
||||
Building the Ada compiler has special requirements, see below.
|
||||
If you do not pass this flag, or specify the option @code{all}, then all
|
||||
default languages available in the @file{gcc} sub-tree will be configured.
|
||||
Ada and Objective-C++ are not default languages; the rest are.
|
||||
Re-defining @code{LANGUAGES} when calling @samp{make} @strong{does not}
|
||||
work anymore, as those language sub-directories might not have been
|
||||
configured!
|
||||
Ada, Go and Objective-C++ are not default languages; the rest are.
|
||||
|
||||
@item --enable-stage1-languages=@var{lang1},@var{lang2},@dots{}
|
||||
Specify that a particular subset of compilers and their runtime
|
||||
|
|
|
@ -1070,6 +1070,9 @@ Free form Fortran source code which should not be preprocessed.
|
|||
Free form Fortran source code which must be preprocessed (with the
|
||||
traditional preprocessor).
|
||||
|
||||
@item @var{file}.go
|
||||
Go source code.
|
||||
|
||||
@c FIXME: Descriptions of Java file types.
|
||||
@c @var{file}.java
|
||||
@c @var{file}.class
|
||||
|
@ -1123,6 +1126,7 @@ objective-c++ objective-c++-header objective-c++-cpp-output
|
|||
assembler assembler-with-cpp
|
||||
ada
|
||||
f77 f77-cpp-input f95 f95-cpp-input
|
||||
go
|
||||
java
|
||||
@end smallexample
|
||||
|
||||
|
|
|
@ -81,6 +81,10 @@ The GCC runtime library.
|
|||
@item libgfortran
|
||||
The Fortran runtime library.
|
||||
|
||||
@item libgo
|
||||
The Go runtime library. The bulk of this library is mirrored from the
|
||||
@uref{http://code.google.com/@/p/@/go, master Go repository}.
|
||||
|
||||
@item libgomp
|
||||
The GNU OpenMP runtime library.
|
||||
|
||||
|
|
|
@ -271,6 +271,18 @@ The authoritative manual on Objective-C 2.0 is available from Apple:
|
|||
For more information concerning the history of Objective-C that is
|
||||
available online, see @uref{http://gcc.gnu.org/readings.html}
|
||||
|
||||
@section Go language
|
||||
|
||||
The Go language continues to evolve as of this writing; see the
|
||||
@uref{http://golang.org/@/doc/@/go_spec.html, current language
|
||||
specifications}. At present there are no specific versions of Go, and
|
||||
there is no way to describe the language supported by GCC in terms of
|
||||
a specific version. In general GCC tracks the evolving specification
|
||||
closely, and any given release will support the language as of the
|
||||
date that the release was frozen.
|
||||
|
||||
@section References for other languages
|
||||
|
||||
@xref{Top, GNAT Reference Manual, About This Guide, gnat_rm,
|
||||
GNAT Reference Manual}, for information on standard
|
||||
conformance and compatibility of the Ada compiler.
|
||||
|
|
|
@ -896,6 +896,7 @@ static const struct compiler default_compilers[] =
|
|||
{".p", "#Pascal", 0, 0, 0}, {".pas", "#Pascal", 0, 0, 0},
|
||||
{".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
|
||||
{".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
|
||||
{".go", "#Go", 0, 1, 0},
|
||||
/* Next come the entries for C. */
|
||||
{".c", "@c", 0, 0, 1},
|
||||
{"@c",
|
||||
|
|
267
gcc/go/Make-lang.in
Normal file
267
gcc/go/Make-lang.in
Normal file
|
@ -0,0 +1,267 @@
|
|||
# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend.
|
||||
|
||||
# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GCC.
|
||||
|
||||
# GCC 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 3, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GCC 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 GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This file provides the language dependent support in the main Makefile.
|
||||
|
||||
# Installation name.
|
||||
|
||||
GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)')
|
||||
GCCGO_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccgo|sed '$(program_transform_name)')
|
||||
|
||||
# The name for selecting go in LANGUAGES.
|
||||
go: go1$(exeext)
|
||||
|
||||
.PHONY: go
|
||||
|
||||
gospec.o: $(srcdir)/go/gospec.c $(SYSTEM_H) coretypes.h $(TM_H) $(GCC_H) \
|
||||
$(CONFIG_H) opts.h
|
||||
(SHLIB_LINK='$(SHLIB_LINK)'; \
|
||||
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(DRIVER_DEFINES) \
|
||||
$(INCLUDES) $(srcdir)/go/gospec.c)
|
||||
|
||||
GCCGO_OBJS = $(GCC_OBJS) gospec.o intl.o prefix.o version.o
|
||||
gccgo$(exeext): $(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBDEPS)
|
||||
$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
|
||||
$(GCCGO_OBJS) $(EXTRA_GCC_OBJS) $(LIBS)
|
||||
|
||||
# Use strict warnings.
|
||||
go-warn = $(STRICT_WARN)
|
||||
|
||||
GO_OBJS = \
|
||||
go/dataflow.o \
|
||||
go/export.o \
|
||||
go/expressions.o \
|
||||
go/go-dump.o \
|
||||
go/go-lang.o \
|
||||
go/go.o \
|
||||
go/gogo-tree.o \
|
||||
go/gogo.o \
|
||||
go/import.o \
|
||||
go/import-archive.o \
|
||||
go/lex.o \
|
||||
go/parse.o \
|
||||
go/statements.o \
|
||||
go/types.o \
|
||||
go/unsafe.o
|
||||
|
||||
go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS)
|
||||
$(CXX) $(ALL_CXXFLAGS) $(LDFLAGS) -o $@ \
|
||||
$(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
|
||||
|
||||
# Documentation.
|
||||
|
||||
GO_TEXI_FILES = \
|
||||
go/gccgo.texi \
|
||||
$(gcc_docdir)/include/fdl.texi \
|
||||
$(gcc_docdir)/include/gpl_v3.texi \
|
||||
$(gcc_docdir)/include/gcc-common.texi \
|
||||
gcc-vers.texi
|
||||
|
||||
doc/gccgo.info: $(GO_TEXI_FILES)
|
||||
if test "x$(BUILD_INFO)" = xinfo; then \
|
||||
rm -f doc/gccgo.info*; \
|
||||
$(MAKEINFO) $(MAKEINFOFLAGS) -I $(gcc_docdir) \
|
||||
-I $(gcc_docdir)/include -o $@ $<; \
|
||||
else true; fi
|
||||
|
||||
doc/gccgo.dvi: $(GO_TEXI_FILES)
|
||||
$(TEXI2DVI) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
|
||||
|
||||
doc/gccgo.pdf: $(GO_TEXI_FILES)
|
||||
$(TEXI2PDF) -I $(abs_docdir) -I $(abs_docdir)/include -o $@ $<
|
||||
|
||||
$(build_htmldir)/go/index.html: $(GO_TEXI_FILES)
|
||||
$(mkinstalldirs) $(@D)
|
||||
rm -f $(@D)/*
|
||||
$(TEXI2HTML) -I $(gcc_docdir) -I $(gcc_docdir)/include \
|
||||
-I $(srcdir)/go -o $(@D) $<
|
||||
|
||||
.INTERMEDIATE: gccgo.pod
|
||||
|
||||
gccgo.pod: go/gccgo.texi
|
||||
-$(TEXI2POD) -D gccgo < $< > $@
|
||||
|
||||
# Build hooks.
|
||||
|
||||
go.all.cross: gccgo$(exeext)
|
||||
go.start.encap: gccgo$(exeext)
|
||||
go.rest.encap:
|
||||
go.info: doc/gccgo.info
|
||||
go.dvi: doc/gccgo.dvi
|
||||
go.pdf: doc/gccgo.pdf
|
||||
go.html: $(build_htmldir)/go/index.html
|
||||
go.srcinfo: doc/gccgo.info
|
||||
-cp -p $^ $(srcdir)/doc
|
||||
go.srcextra:
|
||||
go.tags: force
|
||||
cd $(srcdir)/go; \
|
||||
etags -o TAGS.sub *.c *.h gofrontend/*.h gofrontend/*.cc; \
|
||||
etags --include TAGS.sub --include ../TAGS.sub
|
||||
go.man: doc/gccgo.1
|
||||
go.srcman: doc/gccgo.1
|
||||
-cp -p $^ $(srcdir)/doc
|
||||
|
||||
check-go:
|
||||
lang_checks += check-go
|
||||
|
||||
# Install hooks.
|
||||
|
||||
go.install-common: installdirs
|
||||
-rm -f $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
|
||||
-rm -f $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext)
|
||||
$(INSTALL_PROGRAM) gccgo$(exeext) $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
|
||||
if test -f $(DESTDIR)$(bindir)$(GCCGO_TARGET_INSTALL_NAME)$(exeext); then \
|
||||
:; \
|
||||
else \
|
||||
cd $(DESTDIR)$(bindir) && \
|
||||
$(LN) $(GCCGO_INSTALL_NAME)$(exeext) $(GCCGO_TARGET_INSTALL_NAME)$(exeext); \
|
||||
fi
|
||||
|
||||
go.install-plugin:
|
||||
|
||||
go.install-info: $(DESTDIR)$(infodir)/gccgo.info
|
||||
|
||||
go.install-pdf: doc/gccgo.pdf
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(pdfdir)" || $(mkinstalldirs) "$(DESTDIR)$(pdfdir)/gcc"
|
||||
@for p in doc/gccgo.pdf; do \
|
||||
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
|
||||
f=$(pdf__strip_dir) \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/gcc/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/gcc/$$f"; \
|
||||
done
|
||||
|
||||
go.install-html: $(build_htmldir)/go
|
||||
@$(NORMAL_INSTALL)
|
||||
test -z "$(htmldir)" || $(mkinstalldirs) "$(DESTDIR)$(htmldir)"
|
||||
@for p in $(build_htmldir)/go; do \
|
||||
if test -f "$$p" || test -d "$$p"; then d=""; else d="$(srcdir)/"; fi; \
|
||||
f=$(html__strip_dir) \
|
||||
if test -d "$$d$$p"; then \
|
||||
echo " $(mkinstalldirs) '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(mkinstalldirs) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
|
||||
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
else \
|
||||
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
|
||||
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
|
||||
fi; \
|
||||
done
|
||||
|
||||
go.install-man: $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext)
|
||||
|
||||
$(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext): doc/gccgo.1 installdirs
|
||||
-rm -f $@
|
||||
-$(INSTALL_DATA) $< $@
|
||||
-chmod a-x $@
|
||||
|
||||
go.uninstall:
|
||||
rm -rf $(DESTDIR)$(bindir)/$(GCCGO_INSTALL_NAME)$(exeext)
|
||||
rm -rf $(DESTDIR)$(man1dir)/$(GCCGO_INSTALL_NAME)$(man1ext)
|
||||
rm -rf $(DESTDIR)$(bindir)/$(GCCGO_TARGET_INSTALL_NAME)$(exeext)
|
||||
rm -rf $(DESTDIR)$(infodir)/gccgo.info*
|
||||
|
||||
# Clean hooks.
|
||||
|
||||
go.mostlyclean:
|
||||
-rm -f go/*$(objext)
|
||||
-rm -f go/*$(coverageexts)
|
||||
go.clean:
|
||||
go.distclean:
|
||||
go.maintainer-clean:
|
||||
-rm -f $(docobjdir)/gccgo.1
|
||||
|
||||
# Stage hooks.
|
||||
|
||||
go.stage1: stage1-start
|
||||
-mv go/*$(objext) stage1/go
|
||||
go.stage2: stage2-start
|
||||
-mv go/*$(objext) stage2/go
|
||||
go.stage3: stage3-start
|
||||
-mv go/*$(objext) stage3/go
|
||||
go.stage4: stage4-start
|
||||
-mv go/*$(objext) stage4/go
|
||||
go.stageprofile: stageprofile-start
|
||||
-mv go/*$(objext) stageprofile/go
|
||||
go.stagefeedback: stagefeedback-start
|
||||
-mv go/*$(objext) stagefeedback/go
|
||||
|
||||
GO_SYSTEM_H = go/go-system.h $(CONFIG_H) $(SYSTEM_H) coretypes.h \
|
||||
$(DIAGNOSTIC_CORE_H) $(INPUT_H)
|
||||
|
||||
GO_C_H = go/go-c.h $(MACHMODE_H)
|
||||
GO_LEX_H = go/gofrontend/lex.h go/gofrontend/operator.h
|
||||
GO_PARSE_H = go/gofrontend/parse.h
|
||||
GO_GOGO_H = go/gofrontend/gogo.h
|
||||
GO_TYPES_H = go/gofrontend/types.h
|
||||
GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h
|
||||
GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h
|
||||
GO_IMPORT_H = go/gofrontend/import.h go/gofrontend/export.h
|
||||
|
||||
go/go-lang.o: go/go-lang.c $(GO_SYSTEM_H) coretypes.h opts.h $(TREE_H) \
|
||||
$(GIMPLE_H) $(GGC_H) $(TOPLEV_H) debug.h options.h $(FLAGS_H) \
|
||||
convert.h langhooks.h $(LANGHOOKS_DEF_H) $(EXCEPT_H) $(TARGET_H) \
|
||||
$(DIAGNOSTIC_H) $(GO_C_H) gt-go-go-lang.h gtype-go.h
|
||||
|
||||
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
|
||||
|
||||
go/%.o: go/gofrontend/%.cc
|
||||
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
|
||||
|
||||
go/dataflow.o: go/gofrontend/dataflow.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \
|
||||
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) go/gofrontend/dataflow.h
|
||||
go/export.o: go/gofrontend/export.cc $(GO_SYSTEM_H) \
|
||||
$(srcdir)/../include/sha1.h $(MACHMODE_H) output.h $(TARGET_H) \
|
||||
$(GO_GOGO_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) go/gofrontend/export.h
|
||||
go/expressions.o: go/gofrontend/expressions.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
|
||||
intl.h $(TREE_H) $(GIMPLE_H) tree-iterator.h convert.h $(REAL_H) \
|
||||
realmpfr.h $(TM_H) $(TM_P_H) $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \
|
||||
go/gofrontend/export.h $(GO_IMPORT_H) $(GO_STATEMENTS_H) $(GO_LEX_H) \
|
||||
$(GO_EXPRESSIONS_H)
|
||||
go/go.o: go/gofrontend/go.cc $(GO_SYSTEM_H) $(GO_C_H) $(GO_LEX_H) \
|
||||
$(GO_PARSE_H) $(GO_GOGO_H)
|
||||
go/go-dump.o: go/gofrontend/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) \
|
||||
go/gofrontend/go-dump.h
|
||||
go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TM_H) $(TOPLEV_H) \
|
||||
$(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
|
||||
convert.h output.h $(DIAGNOSTIC_H) $(RTL_H) $(GO_TYPES_H) \
|
||||
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H)
|
||||
go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
|
||||
go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
|
||||
$(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_IMPORT_H) \
|
||||
go/gofrontend/export.h $(GO_GOGO_H)
|
||||
go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \
|
||||
$(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \
|
||||
$(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/gofrontend/export.h \
|
||||
$(GO_IMPORT_H)
|
||||
go/import-archive.o: go/gofrontend/import-archive.cc $(GO_SYSTEM_H) \
|
||||
$(GO_IMPORT_H)
|
||||
go/lex.o: go/gofrontend/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H)
|
||||
go/parse.o: go/gofrontend/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) \
|
||||
$(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H)
|
||||
go/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \
|
||||
$(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H) \
|
||||
$(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \
|
||||
$(GO_STATEMENTS_H)
|
||||
go/types.o: go/gofrontend/types.cc $(GO_SYSTEM_H) $(TOPLEV_H) intl.h $(TREE_H) \
|
||||
$(GIMPLE_H) $(REAL_H) convert.h $(GO_C_H) $(GO_GOGO_H) \
|
||||
go/gofrontend/operator.h $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) \
|
||||
go/gofrontend/export.h $(GO_IMPORT_H) $(GO_TYPES_H)
|
||||
go/unsafe.o: go/gofrontend/unsafe.cc $(GO_SYSTEM_H) $(GO_TYPES_H) $(GO_GOGO_H)
|
3
gcc/go/README.gcc
Normal file
3
gcc/go/README.gcc
Normal file
|
@ -0,0 +1,3 @@
|
|||
The files in the gofrontend subdirectory are mirrored from the
|
||||
gofrontend project hosted at http://code.google.com/p/gofrontend.
|
||||
These files are the ones in the go subdirectory of that project.
|
37
gcc/go/config-lang.in
Normal file
37
gcc/go/config-lang.in
Normal file
|
@ -0,0 +1,37 @@
|
|||
# config-lang.in -- Top level configure fragment for gcc Go frontend.
|
||||
|
||||
# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
# This file is part of GCC.
|
||||
|
||||
# GCC 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 3, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# GCC 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 GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Configure looks for the existence of this file to auto-config each language.
|
||||
# We define several parameters used by configure:
|
||||
#
|
||||
# language - name of language as it would appear in $(LANGUAGES)
|
||||
# compilers - value to add to $(COMPILERS)
|
||||
|
||||
language="go"
|
||||
|
||||
compilers="go1\$(exeext)"
|
||||
|
||||
target_libs="target-libgo target-libffi"
|
||||
|
||||
# The Go frontend is written in C++, so we need to build the C++
|
||||
# compiler during stage 1.
|
||||
lang_requires_boot_languages=c++
|
||||
|
||||
gtfiles="\$(srcdir)/go/go-lang.c"
|
348
gcc/go/gccgo.texi
Normal file
348
gcc/go/gccgo.texi
Normal file
|
@ -0,0 +1,348 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@setfilename gccgo.info
|
||||
@settitle The GNU Go Compiler
|
||||
|
||||
@c Merge the standard indexes into a single one.
|
||||
@syncodeindex fn cp
|
||||
@syncodeindex vr cp
|
||||
@syncodeindex ky cp
|
||||
@syncodeindex pg cp
|
||||
@syncodeindex tp cp
|
||||
|
||||
@include gcc-common.texi
|
||||
|
||||
@c Copyright years for this manual.
|
||||
@set copyrights-go 2010
|
||||
|
||||
@copying
|
||||
@c man begin COPYRIGHT
|
||||
Copyright @copyright{} @value{copyrights-go} Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
any later version published by the Free Software Foundation; with no
|
||||
Invariant Sections, the Front-Cover Texts being (a) (see below), and
|
||||
with the Back-Cover Texts being (b) (see below).
|
||||
A copy of the license is included in the
|
||||
@c man end
|
||||
section entitled ``GNU Free Documentation License''.
|
||||
@ignore
|
||||
@c man begin COPYRIGHT
|
||||
man page gfdl(7).
|
||||
@c man end
|
||||
@end ignore
|
||||
|
||||
@c man begin COPYRIGHT
|
||||
|
||||
(a) The FSF's Front-Cover Text is:
|
||||
|
||||
A GNU Manual
|
||||
|
||||
(b) The FSF's Back-Cover Text is:
|
||||
|
||||
You have freedom to copy and modify this GNU Manual, like GNU
|
||||
software. Copies published by the Free Software Foundation raise
|
||||
funds for GNU development.
|
||||
@c man end
|
||||
@end copying
|
||||
|
||||
@ifinfo
|
||||
@format
|
||||
@dircategory Software development
|
||||
@direntry
|
||||
* Gccgo: (gccgo). A GCC-based compiler for the Go language
|
||||
@end direntry
|
||||
@end format
|
||||
|
||||
@insertcopying
|
||||
@end ifinfo
|
||||
|
||||
@titlepage
|
||||
@title The GNU Go Compiler
|
||||
@versionsubtitle
|
||||
@author Ian Lance Taylor
|
||||
|
||||
@page
|
||||
@vskip 0pt plus 1filll
|
||||
Published by the Free Software Foundation @*
|
||||
51 Franklin Street, Fifth Floor@*
|
||||
Boston, MA 02110-1301, USA@*
|
||||
@sp 1
|
||||
@insertcopying
|
||||
@end titlepage
|
||||
@contents
|
||||
@page
|
||||
|
||||
@node Top
|
||||
@top Introduction
|
||||
|
||||
This manual describes how to use @command{gccgo}, the GNU compiler for
|
||||
the Go programming language. This manual is specifically about
|
||||
@command{gccgo}. For more information about the Go programming
|
||||
language in general, including language specifications and standard
|
||||
package documentation, see @uref{http://golang.org/}.
|
||||
|
||||
@menu
|
||||
* Copying:: The GNU General Public License.
|
||||
* GNU Free Documentation License::
|
||||
How you can share and copy this manual.
|
||||
* Invoking gccgo:: How to run gccgo.
|
||||
* Import and Export:: Importing and exporting package data.
|
||||
* C Interoperability:: Calling C from Go and vice-vera.
|
||||
* Index:: Index.
|
||||
@end menu
|
||||
|
||||
|
||||
@include gpl_v3.texi
|
||||
|
||||
@include fdl.texi
|
||||
|
||||
|
||||
@node Invoking gccgo
|
||||
@chapter Invoking gccgo
|
||||
|
||||
@c man title gccgo A GCC-based compiler for the Go language
|
||||
|
||||
@ignore
|
||||
@c man begin SYNOPSIS gccgo
|
||||
gccgo [@option{-c}|@option{-S}]
|
||||
[@option{-g}] [@option{-pg}] [@option{-O}@var{level}]
|
||||
[@option{-I}@var{dir}@dots{}] [@option{-L}@var{dir}@dots{}]
|
||||
[@option{-o} @var{outfile}] @var{infile}@dots{}
|
||||
|
||||
Only the most useful options are listed here; see below for the
|
||||
remainder.
|
||||
@c man end
|
||||
@c man begin SEEALSO
|
||||
gpl(7), gfdl(7), fsf-funding(7), gcc(1)
|
||||
and the Info entries for @file{gccgo} and @file{gcc}.
|
||||
@c man end
|
||||
@end ignore
|
||||
|
||||
@c man begin DESCRIPTION gccgo
|
||||
|
||||
The @command{gccgo} command is a frontend to @command{gcc} and
|
||||
supports many of the same options. @xref{Option Summary, , Option
|
||||
Summary, gcc, Using the GNU Compiler Collection (GCC)}. This manual
|
||||
only documents the options specific to @command{gccgo}.
|
||||
|
||||
The @command{gccgo} command may be used to compile Go source code into
|
||||
an object file, link a collection of object files together, or do both
|
||||
in sequence.
|
||||
|
||||
Go source code is compiled as packages. A package consists of one or
|
||||
more Go source files. All the files in a single package must be
|
||||
compiled together, by passing all the files as arguments to
|
||||
@command{gccgo}. A single invocation of @command{gccgo} may only
|
||||
compile a single package.
|
||||
|
||||
One Go package may @code{import} a different Go package. The imported
|
||||
package must have already been compiled; @command{gccgo} will read
|
||||
the import data directly from the compiled package. When this package
|
||||
is later linked, the compiled form of the package must be included in
|
||||
the link command.
|
||||
|
||||
@c man end
|
||||
|
||||
@c man begin OPTIONS gccgo
|
||||
|
||||
@table @gcctabopt
|
||||
@item -I@var{dir}
|
||||
@cindex @option{-I}
|
||||
Specify a directory to use when searching for an import package at
|
||||
compile time.
|
||||
|
||||
@item -L@var{dir}
|
||||
@cindex @option{-L}
|
||||
When compiling, synonymous with @option{-I}. When linking, specify a
|
||||
library search directory, as with @command{gcc}.
|
||||
|
||||
@item -fgo-prefix=@var{string}
|
||||
@cindex @option{-fgo-prefix}
|
||||
Go permits a single program to include more than one package with the
|
||||
same name. This option is required to make this work with
|
||||
@command{gccgo}. The argument to this option may be any string. Each
|
||||
package with the same name must use a distinct @option{-fgo-prefix}
|
||||
option. The argument is typically the full path under which the
|
||||
package will be installed, as that must obviously be unique.
|
||||
|
||||
@item -frequire-return-statement
|
||||
@itemx -fno-require-return-statement
|
||||
@cindex @option{-frequire-return-statement}
|
||||
@cindex @option{-fno-require-return-statement}
|
||||
By default @command{gccgo} will warn about functions which have one or
|
||||
more return parameters but lack an explicit @code{return} statement.
|
||||
This warning may be disabled using
|
||||
@option{-fno-require-return-statement}.
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
||||
@node Import and Export
|
||||
@chapter Import and Export
|
||||
|
||||
When @command{gccgo} compiles a package which exports anything, the
|
||||
export information will be stored directly in the object file. When a
|
||||
package is imported, @command{gccgo} must be able to find the file.
|
||||
|
||||
@cindex @file{.gox}
|
||||
When Go code imports the package @file{gopackage}, @command{gccgo}
|
||||
will look for the import data using the following filenames, using the
|
||||
first one that it finds.
|
||||
|
||||
@table @file
|
||||
@item @var{gopackage}.gox
|
||||
@item lib@var{gopackage}.so
|
||||
@item lib@var{gopackage}.a
|
||||
@item @var{gopackage}.o
|
||||
@end table
|
||||
|
||||
The compiler will search for these files in the directories named by
|
||||
any @option{-I} or @option{-L} options, in order in which the
|
||||
directories appear on the command line. The compiler will then search
|
||||
several standard system directories. Finally the compiler will search
|
||||
the current directory (to search the current directory earlier, use
|
||||
@samp{-I.}).
|
||||
|
||||
The compiler will extract the export information directly from the
|
||||
compiled object file. The file @file{@var{gopackage}.gox} will
|
||||
typically contain nothing but export data. This can be generated from
|
||||
@file{@var{gopackage}.o} via
|
||||
|
||||
@smallexample
|
||||
objcopy -j .go_export @var{gopackage}.o @var{gopackage}.gox
|
||||
@end smallexample
|
||||
|
||||
For example, it may be desirable to extract the export information
|
||||
from several different packages into their independent
|
||||
@file{@var{gopackage}.gox} files, and then to combine the different
|
||||
package object files together into a single shared library or archive.
|
||||
|
||||
At link time you must explicitly tell @command{gccgo} which files to
|
||||
link together into the executable, as is usual with @command{gcc}.
|
||||
This is different from the behaviour of other Go compilers.
|
||||
|
||||
@node C Interoperability
|
||||
@chapter C Interoperability
|
||||
|
||||
When using @command{gccgo} there is limited interoperability with C,
|
||||
or with C++ code compiled using @code{extern "C"}.
|
||||
|
||||
@menu
|
||||
* C Type Interoperability:: How C and Go types match up.
|
||||
* Function Names:: How Go functions are named.
|
||||
@end menu
|
||||
|
||||
@node C Type Interoperability
|
||||
@section C Type Interoperability
|
||||
|
||||
Basic types map directly: an @code{int} in Go is an @code{int} in C,
|
||||
etc. Go @code{byte} is equivalent to C @code{unsigned char}.
|
||||
Pointers in Go are pointers in C. A Go @code{struct} is the same as C
|
||||
@code{struct} with the same field names and types.
|
||||
|
||||
@cindex @code{string} in C
|
||||
The Go @code{string} type is currently defined as a two-element
|
||||
structure:
|
||||
|
||||
@smallexample
|
||||
struct __go_string @{
|
||||
const unsigned char *__data;
|
||||
int __length;
|
||||
@};
|
||||
@end smallexample
|
||||
|
||||
You can't pass arrays between C and Go. However, a pointer to an
|
||||
array in Go is equivalent to a C pointer to the equivalent of the
|
||||
element type. For example, Go @code{*[10]int} is equivalent to C
|
||||
@code{int*}, assuming that the C pointer does point to 10 elements.
|
||||
|
||||
@cindex @code{slice} in C
|
||||
A slice in Go is a structure. The current definition is:
|
||||
|
||||
@smallexample
|
||||
struct __go_slice @{
|
||||
void *__values;
|
||||
int __count;
|
||||
int __capacity;
|
||||
@};
|
||||
@end smallexample
|
||||
|
||||
The type of a Go function with no receiver is equivalent to a C
|
||||
function whose parameter types are equivalent. When a Go function
|
||||
returns more than one value, the C function returns a struct. For
|
||||
example, these functions have equivalent types:
|
||||
|
||||
@smallexample
|
||||
func GoFunction(int) (int, float)
|
||||
struct @{ int i; float f; @} CFunction(int)
|
||||
@end smallexample
|
||||
|
||||
A pointer to a Go function is equivalent to a pointer to a C function
|
||||
when the functions have equivalent types.
|
||||
|
||||
Go @code{interface}, @code{channel}, and @code{map} types have no
|
||||
corresponding C type (@code{interface} is a two-element struct and
|
||||
@code{channel} and @code{map} are pointers to structs in C, but the
|
||||
structs are deliberately undocumented). C @code{enum} types
|
||||
correspond to some integer type, but precisely which one is difficult
|
||||
to predict in general; use a cast. C @code{union} types have no
|
||||
corresponding Go type. C @code{struct} types containing bitfields
|
||||
have no corresponding Go type. C++ @code{class} types have no
|
||||
corresponding Go type.
|
||||
|
||||
Memory allocation is completely different between C and Go, as Go uses
|
||||
garbage collection. The exact guidelines in this area are
|
||||
undetermined, but it is likely that it will be permitted to pass a
|
||||
pointer to allocated memory from C to Go. The responsibility of
|
||||
eventually freeing the pointer will remain with C side, and of course
|
||||
if the C side frees the pointer while the Go side still has a copy the
|
||||
program will fail. When passing a pointer from Go to C, the Go
|
||||
function must retain a visible copy of it in some Go variable.
|
||||
Otherwise the Go garbage collector may delete the pointer while the C
|
||||
function is still using it.
|
||||
|
||||
@node Function Names
|
||||
@section Function Names
|
||||
|
||||
@cindex @code{__asm__}
|
||||
Go code can call C functions directly using a Go extension implemented
|
||||
in @command{gccgo}: a function declaration may be followed by
|
||||
@code{__asm__ ("@var{name}")}. For example, here is how the C function
|
||||
@code{open} can be declared in Go:
|
||||
|
||||
@smallexample
|
||||
func c_open(name *byte, mode int, perm int) int __asm__ ("open");
|
||||
@end smallexample
|
||||
|
||||
The C function naturally expects a nul terminated string, which in Go
|
||||
is equivalent to a pointer to an array (not a slice!) of @code{byte}
|
||||
with a terminating zero byte. So a sample call from Go would look
|
||||
like (after importing the @code{os} package):
|
||||
|
||||
@smallexample
|
||||
var name = [4]byte@{'f', 'o', 'o', 0@};
|
||||
i := c_open(&name[0], os.O_RDONLY, 0);
|
||||
@end smallexample
|
||||
|
||||
Note that this serves as an example only. To open a file in Go please
|
||||
use Go's @code{os.Open} function instead.
|
||||
|
||||
The name of Go functions accessed from C is subject to change. At
|
||||
present the name of a Go function that does not have a receiver is
|
||||
@code{prefix.package.Functionname}. The prefix is set by the
|
||||
@option{-fgo-prefix} option used when the package is compiled; if the
|
||||
option is not used, the default is simply @code{go}. To call the
|
||||
function from C you must set the name using the @command{gcc}
|
||||
extension similar to the @command{gccgo} extension.
|
||||
|
||||
@smallexample
|
||||
extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
|
||||
@end smallexample
|
||||
|
||||
@node Index
|
||||
@unnumbered Index
|
||||
|
||||
@printindex cp
|
||||
|
||||
@bye
|
66
gcc/go/go-c.h
Normal file
66
gcc/go/go-c.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* go-c.h -- Header file for go frontend gcc C interface.
|
||||
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC 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 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC 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 GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef GO_GO_C_H
|
||||
#define GO_GO_C_H
|
||||
|
||||
#ifdef ENABLE_BUILD_WITH_CXX
|
||||
#define GO_EXTERN_C
|
||||
#else
|
||||
#define GO_EXTERN_C extern "C"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "machmode.h"
|
||||
|
||||
/* Functions defined in the Go frontend proper called by the GCC
|
||||
interface. */
|
||||
|
||||
extern int go_enable_dump (const char*);
|
||||
extern void go_set_prefix (const char*);
|
||||
|
||||
extern void go_add_search_path (const char*);
|
||||
|
||||
extern void go_create_gogo (int int_type_size, int float_type_size,
|
||||
int pointer_size);
|
||||
|
||||
extern void go_parse_input_files (const char**, unsigned int,
|
||||
bool only_check_syntax,
|
||||
bool require_return_statement);
|
||||
extern void go_write_globals (void);
|
||||
|
||||
extern tree go_type_for_size (unsigned int bits, int unsignedp);
|
||||
extern tree go_type_for_mode (enum machine_mode, int unsignedp);
|
||||
|
||||
/* Functions defined in the GCC interface called by the Go frontend
|
||||
proper. */
|
||||
|
||||
extern void go_preserve_from_gc (tree);
|
||||
|
||||
extern const char *go_localize_identifier (const char*);
|
||||
|
||||
#if defined(__cplusplus) && !defined(ENABLE_BUILD_WITH_CXX)
|
||||
} /* End extern "C". */
|
||||
#endif
|
||||
|
||||
#endif /* !defined(GO_GO_C_H) */
|
404
gcc/go/go-lang.c
Normal file
404
gcc/go/go-lang.c
Normal file
|
@ -0,0 +1,404 @@
|
|||
/* go-lang.c -- Go frontend gcc interface.
|
||||
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC 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 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC 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 GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "ansidecl.h"
|
||||
#include "coretypes.h"
|
||||
#include "opts.h"
|
||||
#include "tree.h"
|
||||
#include "gimple.h"
|
||||
#include "ggc.h"
|
||||
#include "toplev.h"
|
||||
#include "debug.h"
|
||||
#include "options.h"
|
||||
#include "flags.h"
|
||||
#include "convert.h"
|
||||
#include "diagnostic.h"
|
||||
#include "langhooks.h"
|
||||
#include "langhooks-def.h"
|
||||
#include "except.h"
|
||||
#include "target.h"
|
||||
|
||||
#include <mpfr.h>
|
||||
|
||||
#include "go-c.h"
|
||||
|
||||
/* Language-dependent contents of a type. */
|
||||
|
||||
struct GTY(()) lang_type
|
||||
{
|
||||
char dummy;
|
||||
};
|
||||
|
||||
/* Language-dependent contents of a decl. */
|
||||
|
||||
struct GTY(()) lang_decl
|
||||
{
|
||||
char dummy;
|
||||
};
|
||||
|
||||
/* Language-dependent contents of an identifier. This must include a
|
||||
tree_identifier. */
|
||||
|
||||
struct GTY(()) lang_identifier
|
||||
{
|
||||
struct tree_identifier common;
|
||||
};
|
||||
|
||||
/* The resulting tree type. */
|
||||
|
||||
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
|
||||
chain_next ("(union lang_tree_node *) TREE_CHAIN (&%h.generic)")))
|
||||
lang_tree_node
|
||||
{
|
||||
union tree_node GTY((tag ("0"),
|
||||
desc ("tree_node_structure (&%h)"))) generic;
|
||||
struct lang_identifier GTY((tag ("1"))) identifier;
|
||||
};
|
||||
|
||||
/* We don't use language_function. */
|
||||
|
||||
struct GTY(()) language_function
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
/* Language hooks. */
|
||||
|
||||
static bool
|
||||
go_langhook_init (void)
|
||||
{
|
||||
build_common_tree_nodes (false);
|
||||
|
||||
/* The sizetype may be "unsigned long" or "unsigned long long". */
|
||||
if (TYPE_MODE (long_unsigned_type_node) == ptr_mode)
|
||||
size_type_node = long_unsigned_type_node;
|
||||
else if (TYPE_MODE (long_long_unsigned_type_node) == ptr_mode)
|
||||
size_type_node = long_long_unsigned_type_node;
|
||||
else
|
||||
size_type_node = long_unsigned_type_node;
|
||||
set_sizetype (size_type_node);
|
||||
|
||||
build_common_tree_nodes_2 (0);
|
||||
|
||||
/* We must create the gogo IR after calling build_common_tree_nodes
|
||||
(because Gogo::define_builtin_function_trees refers indirectly
|
||||
to, e.g., unsigned_char_type_node) but before calling
|
||||
build_common_builtin_nodes (because it calls, indirectly,
|
||||
go_type_for_size). */
|
||||
go_create_gogo (INT_TYPE_SIZE, FLOAT_TYPE_SIZE, POINTER_SIZE);
|
||||
|
||||
build_common_builtin_nodes ();
|
||||
|
||||
/* I don't know why this is not done by any of the above. */
|
||||
void_list_node = build_tree_list (NULL_TREE, void_type_node);
|
||||
|
||||
/* The default precision for floating point numbers. This is used
|
||||
for floating point constants with abstract type. This may
|
||||
eventually be controllable by a command line option. */
|
||||
mpfr_set_default_prec (128);
|
||||
|
||||
/* Go uses exceptions. */
|
||||
using_eh_for_cleanups ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The option mask. */
|
||||
|
||||
static unsigned int
|
||||
go_langhook_option_lang_mask (void)
|
||||
{
|
||||
return CL_Go;
|
||||
}
|
||||
|
||||
/* Initialize the options structure. */
|
||||
|
||||
static void
|
||||
go_langhook_init_options_struct (struct gcc_options *opts)
|
||||
{
|
||||
/* Go says that signed overflow is precisely defined. */
|
||||
opts->x_flag_wrapv = 1;
|
||||
|
||||
/* We default to using strict aliasing, since Go pointers are safe.
|
||||
This is turned off for code that imports the "unsafe" package,
|
||||
because using unsafe.pointer violates C style aliasing
|
||||
requirements. */
|
||||
opts->x_flag_strict_aliasing = 1;
|
||||
|
||||
/* Default to avoiding range issues for complex multiply and
|
||||
divide. */
|
||||
opts->x_flag_complex_method = 2;
|
||||
|
||||
/* The builtin math functions should not set errno. */
|
||||
opts->x_flag_errno_math = 0;
|
||||
|
||||
/* By default assume that floating point math does not trap. */
|
||||
opts->x_flag_trapping_math = 0;
|
||||
|
||||
/* We turn on stack splitting if we can. */
|
||||
if (targetm.supports_split_stack (false, opts))
|
||||
opts->x_flag_split_stack = 1;
|
||||
|
||||
/* Exceptions are used to handle recovering from panics. */
|
||||
opts->x_flag_exceptions = 1;
|
||||
opts->x_flag_non_call_exceptions = 1;
|
||||
}
|
||||
|
||||
/* Handle Go specific options. Return 0 if we didn't do anything. */
|
||||
|
||||
static bool
|
||||
go_langhook_handle_option (
|
||||
size_t scode,
|
||||
const char *arg,
|
||||
int value ATTRIBUTE_UNUSED,
|
||||
int kind ATTRIBUTE_UNUSED,
|
||||
location_t loc ATTRIBUTE_UNUSED,
|
||||
const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
|
||||
{
|
||||
enum opt_code code = (enum opt_code) scode;
|
||||
bool ret = true;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case OPT_I:
|
||||
case OPT_L:
|
||||
/* For the compiler, we currently handle -I and -L exactly the
|
||||
same way: they give us a directory to search for import
|
||||
statements. */
|
||||
go_add_search_path (arg);
|
||||
break;
|
||||
|
||||
case OPT_fgo_dump_:
|
||||
ret = go_enable_dump (arg) ? true : false;
|
||||
break;
|
||||
|
||||
case OPT_fgo_prefix_:
|
||||
go_set_prefix (arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Just return 1 to indicate that the option is valid. */
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Run after parsing options. */
|
||||
|
||||
static bool
|
||||
go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_assert (num_in_fnames > 0);
|
||||
|
||||
if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
|
||||
flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
|
||||
|
||||
/* Returning false means that the backend should be used. */
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
go_langhook_parse_file (void)
|
||||
{
|
||||
go_parse_input_files (in_fnames, num_in_fnames, flag_syntax_only,
|
||||
go_require_return_statement);
|
||||
}
|
||||
|
||||
static tree
|
||||
go_langhook_type_for_size (unsigned int bits, int unsignedp)
|
||||
{
|
||||
return go_type_for_size (bits, unsignedp);
|
||||
}
|
||||
|
||||
static tree
|
||||
go_langhook_type_for_mode (enum machine_mode mode, int unsignedp)
|
||||
{
|
||||
return go_type_for_mode (mode, unsignedp);
|
||||
}
|
||||
|
||||
/* Record a builtin function. We just ignore builtin functions. */
|
||||
|
||||
static tree
|
||||
go_langhook_builtin_function (tree decl)
|
||||
{
|
||||
return decl;
|
||||
}
|
||||
|
||||
static int
|
||||
go_langhook_global_bindings_p (void)
|
||||
{
|
||||
return current_function_decl == NULL ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Push a declaration into the current binding level. We can't
|
||||
usefully implement this since we don't want to convert from tree
|
||||
back to one of our internal data structures. I think the only way
|
||||
this is used is to record a decl which is to be returned by
|
||||
getdecls, and we could implement it for that purpose if
|
||||
necessary. */
|
||||
|
||||
static tree
|
||||
go_langhook_pushdecl (tree decl ATTRIBUTE_UNUSED)
|
||||
{
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* This hook is used to get the current list of declarations as trees.
|
||||
We don't support that; instead we use the write_globals hook. This
|
||||
can't simply crash because it is called by -gstabs. */
|
||||
|
||||
static tree
|
||||
go_langhook_getdecls (void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Write out globals. */
|
||||
|
||||
static void
|
||||
go_langhook_write_globals (void)
|
||||
{
|
||||
go_write_globals ();
|
||||
}
|
||||
|
||||
/* Go specific gimplification. We need to gimplify
|
||||
CALL_EXPR_STATIC_CHAIN, because the gimplifier doesn't handle
|
||||
it. */
|
||||
|
||||
static int
|
||||
go_langhook_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
|
||||
{
|
||||
if (TREE_CODE (*expr_p) == CALL_EXPR
|
||||
&& CALL_EXPR_STATIC_CHAIN (*expr_p) != NULL_TREE)
|
||||
gimplify_expr (&CALL_EXPR_STATIC_CHAIN (*expr_p), pre_p, post_p,
|
||||
is_gimple_val, fb_rvalue);
|
||||
return GS_UNHANDLED;
|
||||
}
|
||||
|
||||
/* Return a decl for the exception personality function. The function
|
||||
itself is implemented in libgo/runtime/go-unwind.c. */
|
||||
|
||||
static tree
|
||||
go_langhook_eh_personality (void)
|
||||
{
|
||||
static tree personality_decl;
|
||||
if (personality_decl == NULL_TREE)
|
||||
{
|
||||
personality_decl = build_personality_function ("gccgo");
|
||||
go_preserve_from_gc (personality_decl);
|
||||
}
|
||||
return personality_decl;
|
||||
}
|
||||
|
||||
/* Functions called directly by the generic backend. */
|
||||
|
||||
tree
|
||||
convert (tree type, tree expr)
|
||||
{
|
||||
if (type == error_mark_node
|
||||
|| expr == error_mark_node
|
||||
|| TREE_TYPE (expr) == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (type == TREE_TYPE (expr))
|
||||
return expr;
|
||||
|
||||
if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
|
||||
return fold_convert (type, expr);
|
||||
|
||||
switch (TREE_CODE (type))
|
||||
{
|
||||
case VOID_TYPE:
|
||||
case BOOLEAN_TYPE:
|
||||
return fold_convert (type, expr);
|
||||
case INTEGER_TYPE:
|
||||
return fold (convert_to_integer (type, expr));
|
||||
case POINTER_TYPE:
|
||||
return fold (convert_to_pointer (type, expr));
|
||||
case REAL_TYPE:
|
||||
return fold (convert_to_real (type, expr));
|
||||
case COMPLEX_TYPE:
|
||||
return fold (convert_to_complex (type, expr));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* FIXME: This is a hack to preserve trees that we create from the
|
||||
garbage collector. */
|
||||
|
||||
static GTY(()) tree go_gc_root;
|
||||
|
||||
void
|
||||
go_preserve_from_gc (tree t)
|
||||
{
|
||||
go_gc_root = tree_cons (NULL_TREE, t, go_gc_root);
|
||||
}
|
||||
|
||||
/* Convert an identifier for use in an error message. */
|
||||
|
||||
const char *
|
||||
go_localize_identifier (const char *ident)
|
||||
{
|
||||
return identifier_to_locale (ident);
|
||||
}
|
||||
|
||||
#undef LANG_HOOKS_NAME
|
||||
#undef LANG_HOOKS_INIT
|
||||
#undef LANG_HOOKS_OPTION_LANG_MASK
|
||||
#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
|
||||
#undef LANG_HOOKS_HANDLE_OPTION
|
||||
#undef LANG_HOOKS_POST_OPTIONS
|
||||
#undef LANG_HOOKS_PARSE_FILE
|
||||
#undef LANG_HOOKS_TYPE_FOR_MODE
|
||||
#undef LANG_HOOKS_TYPE_FOR_SIZE
|
||||
#undef LANG_HOOKS_BUILTIN_FUNCTION
|
||||
#undef LANG_HOOKS_GLOBAL_BINDINGS_P
|
||||
#undef LANG_HOOKS_PUSHDECL
|
||||
#undef LANG_HOOKS_GETDECLS
|
||||
#undef LANG_HOOKS_WRITE_GLOBALS
|
||||
#undef LANG_HOOKS_GIMPLIFY_EXPR
|
||||
#undef LANG_HOOKS_EH_PERSONALITY
|
||||
|
||||
#define LANG_HOOKS_NAME "GNU Go"
|
||||
#define LANG_HOOKS_INIT go_langhook_init
|
||||
#define LANG_HOOKS_OPTION_LANG_MASK go_langhook_option_lang_mask
|
||||
#define LANG_HOOKS_INIT_OPTIONS_STRUCT go_langhook_init_options_struct
|
||||
#define LANG_HOOKS_HANDLE_OPTION go_langhook_handle_option
|
||||
#define LANG_HOOKS_POST_OPTIONS go_langhook_post_options
|
||||
#define LANG_HOOKS_PARSE_FILE go_langhook_parse_file
|
||||
#define LANG_HOOKS_TYPE_FOR_MODE go_langhook_type_for_mode
|
||||
#define LANG_HOOKS_TYPE_FOR_SIZE go_langhook_type_for_size
|
||||
#define LANG_HOOKS_BUILTIN_FUNCTION go_langhook_builtin_function
|
||||
#define LANG_HOOKS_GLOBAL_BINDINGS_P go_langhook_global_bindings_p
|
||||
#define LANG_HOOKS_PUSHDECL go_langhook_pushdecl
|
||||
#define LANG_HOOKS_GETDECLS go_langhook_getdecls
|
||||
#define LANG_HOOKS_WRITE_GLOBALS go_langhook_write_globals
|
||||
#define LANG_HOOKS_GIMPLIFY_EXPR go_langhook_gimplify_expr
|
||||
#define LANG_HOOKS_EH_PERSONALITY go_langhook_eh_personality
|
||||
|
||||
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
|
||||
|
||||
#include "gt-go-go-lang.h"
|
||||
#include "gtype-go.h"
|
153
gcc/go/go-system.h
Normal file
153
gcc/go/go-system.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
// go-system.h -- Go frontend inclusion of gcc header files -*- C++ -*-
|
||||
// Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
// This file is part of GCC.
|
||||
|
||||
// GCC 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 3, or (at your option) any later
|
||||
// version.
|
||||
|
||||
// GCC 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 GCC; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef GO_SYSTEM_H
|
||||
#define GO_SYSTEM_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// These must be included before the #poison declarations in system.h.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#if defined(HAVE_UNORDERED_MAP)
|
||||
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
|
||||
# define Unordered_map(KEYTYPE, VALTYPE) \
|
||||
std::unordered_map<KEYTYPE, VALTYPE>
|
||||
|
||||
# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
|
||||
std::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
|
||||
|
||||
# define Unordered_set(KEYTYPE) \
|
||||
std::unordered_set<KEYTYPE>
|
||||
|
||||
# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
|
||||
std::unordered_set<KEYTYPE, HASHFN, EQFN>
|
||||
|
||||
#elif defined(HAVE_TR1_UNORDERED_MAP)
|
||||
|
||||
# include <tr1/unordered_map>
|
||||
# include <tr1/unordered_set>
|
||||
|
||||
# define Unordered_map(KEYTYPE, VALTYPE) \
|
||||
std::tr1::unordered_map<KEYTYPE, VALTYPE>
|
||||
|
||||
# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
|
||||
std::tr1::unordered_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
|
||||
|
||||
# define Unordered_set(KEYTYPE) \
|
||||
std::tr1::unordered_set<KEYTYPE>
|
||||
|
||||
# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
|
||||
std::tr1::unordered_set<KEYTYPE, HASHFN, EQFN>
|
||||
|
||||
#elif defined(HAVE_EXT_HASH_MAP)
|
||||
|
||||
# include <ext/hash_map>
|
||||
# include <ext/hash_set>
|
||||
|
||||
# define Unordered_map(KEYTYPE, VALTYPE) \
|
||||
__gnu_cxx::hash_map<KEYTYPE, VALTYPE>
|
||||
|
||||
# define Unordered_map_hash(KEYTYPE, VALTYPE, HASHFN, EQFN) \
|
||||
__gnu_cxx::hash_map<KEYTYPE, VALTYPE, HASHFN, EQFN>
|
||||
|
||||
# define Unordered_set(KEYTYPE) \
|
||||
__gnu_cxx::hash_set<KEYTYPE>
|
||||
|
||||
# define Unordered_set_hash(KEYTYPE, HASHFN, EQFN) \
|
||||
__gnu_cxx::hash_set<KEYTYPE, HASHFN, EQFN>
|
||||
|
||||
// Provide hash functions for strings and pointers.
|
||||
|
||||
namespace __gnu_cxx
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<std::string>
|
||||
{
|
||||
size_t
|
||||
operator()(std::string s) const
|
||||
{ return __stl_hash_string(s.c_str()); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct hash<T*>
|
||||
{
|
||||
size_t
|
||||
operator()(T* p) const
|
||||
{ return reinterpret_cast<size_t>(p); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define Unordered_map(KEYTYPE, VALTYPE) \
|
||||
std::map<KEYTYPE, VALTYPE>
|
||||
|
||||
# define Unordered_set(KEYTYPE) \
|
||||
std::set<KEYTYPE>
|
||||
|
||||
// We could make this work by writing an adapter class which
|
||||
// implemented operator< in terms of the hash function.
|
||||
# error "requires hash table type"
|
||||
|
||||
#endif
|
||||
|
||||
// We don't really need iostream, but some versions of gmp.h include
|
||||
// it when compiled with C++, which means that we need to include it
|
||||
// before the macro magic of safe-ctype.h, which is included by
|
||||
// system.h.
|
||||
#include <iostream>
|
||||
|
||||
// Some versions of gmp.h assume that #include <iostream> will define
|
||||
// std::FILE. This is not true with libstdc++ 4.3 and later. This is
|
||||
// fixed in GMP 4.3, but at this point we don't know which version of
|
||||
// GMP is in use. Since the top level configure script accepts GMP
|
||||
// 4.2, at least for now we #include <cstdio> to ensure that GMP 4.2
|
||||
// will work. FIXME: This can be removed when we require GMP 4.3 or
|
||||
// later.
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
#include "ansidecl.h"
|
||||
#include "coretypes.h"
|
||||
|
||||
#include "diagnostic-core.h" /* For error_at and friends. */
|
||||
#include "input.h" /* For source_location. */
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
} // End extern "C"
|
||||
#endif
|
||||
|
||||
#endif // !defined(GO_SYSTEM_H)
|
42
gcc/go/gofrontend/LICENSE
Normal file
42
gcc/go/gofrontend/LICENSE
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Subject to the terms and conditions of this License, Google hereby
|
||||
// grants to You a perpetual, worldwide, non-exclusive, no-charge,
|
||||
// royalty-free, irrevocable (except as stated in this section) patent
|
||||
// license to make, have made, use, offer to sell, sell, import, and
|
||||
// otherwise transfer this implementation of Go, where such license
|
||||
// applies only to those patent claims licensable by Google that are
|
||||
// necessarily infringed by use of this implementation of Go. If You
|
||||
// institute patent litigation against any entity (including a
|
||||
// cross-claim or counterclaim in a lawsuit) alleging that this
|
||||
// implementation of Go or a Contribution incorporated within this
|
||||
// implementation of Go constitutes direct or contributory patent
|
||||
// infringement, then any patent licenses granted to You under this
|
||||
// License for this implementation of Go shall terminate as of the date
|
||||
// such litigation is filed.
|
57
gcc/go/gofrontend/README
Normal file
57
gcc/go/gofrontend/README
Normal file
|
@ -0,0 +1,57 @@
|
|||
See ../README.
|
||||
|
||||
The frontend is written in C++.
|
||||
|
||||
The frontend lexes and parses the input into an IR specific to this
|
||||
frontend known as gogo. It then runs a series of passes over the
|
||||
code.
|
||||
|
||||
Finally it converts gogo to gcc's GENERIC. A goal is to move the gcc
|
||||
support code into a gcc-interface subdirectory. The gcc code will be
|
||||
put under the GPL. The rest of the frontend will not include any gcc
|
||||
header files.
|
||||
|
||||
Issues to be faced in this transition:
|
||||
|
||||
* Representation of source locations.
|
||||
+ Currently the frontend uses gcc's source_location codes, using the
|
||||
interface in libcpp/line-map.h.
|
||||
|
||||
* Handling of error messages.
|
||||
+ Currently the frontend uses gcc's error_at and warning_at
|
||||
functions.
|
||||
+ Currently the frontend uses gcc's diagnostic formatter, using
|
||||
features such as %<%> for appropriate quoting.
|
||||
+ Localization may be an issue.
|
||||
|
||||
* Use of gcc_assert and gcc_unreachable.
|
||||
|
||||
This compiler works, but the code is a work in progress. Notably, the
|
||||
support for garbage collection is ineffective and needs a complete
|
||||
rethinking. The frontend pays little attention to its memory usage
|
||||
and rarely frees any memory. The code could use a general cleanup
|
||||
which we have not had time to do.
|
||||
|
||||
Contributing
|
||||
=============
|
||||
|
||||
To contribute patches to the files in this directory, please see
|
||||
http://golang.org/doc/gccgo_contribute.html .
|
||||
|
||||
Changes to these files require a copyright assignment to Google. This
|
||||
is required to permit the changes to be copied to the gcc repository,
|
||||
as Google has a copyright assignment with the Free Software
|
||||
Foundation.
|
||||
|
||||
If you are the copyright holder, you will need to agree to the
|
||||
individual contributor license agreement at
|
||||
http://code.google.com/legal/individual-cla-v1.0.html. This agreement
|
||||
can be completed online.
|
||||
|
||||
If your organization is the copyright holder, the organization will
|
||||
need to agree to the corporate contributor license agreement at
|
||||
http://code.google.com/legal/corporate-cla-v1.0.html.
|
||||
|
||||
If the copyright holder for your code has already completed the
|
||||
agreement in connection with another Google open source project, it
|
||||
does not need to be completed again.
|
278
gcc/go/gofrontend/dataflow.cc
Normal file
278
gcc/go/gofrontend/dataflow.cc
Normal file
|
@ -0,0 +1,278 @@
|
|||
// dataflow.cc -- Go frontend dataflow.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "gogo.h"
|
||||
#include "expressions.h"
|
||||
#include "statements.h"
|
||||
#include "dataflow.h"
|
||||
|
||||
// This class is used to traverse the tree to look for uses of
|
||||
// variables.
|
||||
|
||||
class Dataflow_traverse_expressions : public Traverse
|
||||
{
|
||||
public:
|
||||
Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement)
|
||||
: Traverse(traverse_blocks | traverse_expressions),
|
||||
dataflow_(dataflow), statement_(statement)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
// Only look at top-level expressions: do not descend into blocks.
|
||||
// They will be examined via Dataflow_traverse_statements.
|
||||
int
|
||||
block(Block*)
|
||||
{ return TRAVERSE_SKIP_COMPONENTS; }
|
||||
|
||||
int
|
||||
expression(Expression**);
|
||||
|
||||
private:
|
||||
// The dataflow information.
|
||||
Dataflow* dataflow_;
|
||||
// The Statement in which we are looking.
|
||||
Statement* statement_;
|
||||
};
|
||||
|
||||
// Given an expression, return the Named_object that it refers to, if
|
||||
// it is a local variable.
|
||||
|
||||
static Named_object*
|
||||
get_var(Expression* expr)
|
||||
{
|
||||
Var_expression* ve = expr->var_expression();
|
||||
if (ve == NULL)
|
||||
return NULL;
|
||||
Named_object* no = ve->named_object();
|
||||
gcc_assert(no->is_variable() || no->is_result_variable());
|
||||
if (no->is_variable() && no->var_value()->is_global())
|
||||
return NULL;
|
||||
return no;
|
||||
}
|
||||
|
||||
// Look for a reference to a variable in an expression.
|
||||
|
||||
int
|
||||
Dataflow_traverse_expressions::expression(Expression** expr)
|
||||
{
|
||||
Named_object* no = get_var(*expr);
|
||||
if (no != NULL)
|
||||
this->dataflow_->add_ref(no, this->statement_);
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// This class is used to handle an assignment statement.
|
||||
|
||||
class Dataflow_traverse_assignment : public Traverse_assignments
|
||||
{
|
||||
public:
|
||||
Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement)
|
||||
: dataflow_(dataflow), statement_(statement)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
void
|
||||
initialize_variable(Named_object*);
|
||||
|
||||
void
|
||||
assignment(Expression** lhs, Expression** rhs);
|
||||
|
||||
void
|
||||
value(Expression**, bool, bool);
|
||||
|
||||
private:
|
||||
// The dataflow information.
|
||||
Dataflow* dataflow_;
|
||||
// The Statement in which we are looking.
|
||||
Statement* statement_;
|
||||
};
|
||||
|
||||
// Handle a variable initialization.
|
||||
|
||||
void
|
||||
Dataflow_traverse_assignment::initialize_variable(Named_object* var)
|
||||
{
|
||||
Expression* init = var->var_value()->init();
|
||||
this->dataflow_->add_def(var, init, this->statement_, true);
|
||||
if (init != NULL)
|
||||
{
|
||||
Expression* e = init;
|
||||
this->value(&e, true, true);
|
||||
gcc_assert(e == init);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an assignment in a statement.
|
||||
|
||||
void
|
||||
Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs)
|
||||
{
|
||||
Named_object* no = get_var(*plhs);
|
||||
if (no != NULL)
|
||||
{
|
||||
Expression* rhs = prhs == NULL ? NULL : *prhs;
|
||||
this->dataflow_->add_def(no, rhs, this->statement_, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If this is not a variable it may be some computed lvalue, and
|
||||
// we want to look for references to variables in that lvalue.
|
||||
this->value(plhs, false, false);
|
||||
}
|
||||
if (prhs != NULL)
|
||||
this->value(prhs, true, false);
|
||||
}
|
||||
|
||||
// Handle a value in a statement.
|
||||
|
||||
void
|
||||
Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool)
|
||||
{
|
||||
Named_object* no = get_var(*pexpr);
|
||||
if (no != NULL)
|
||||
this->dataflow_->add_ref(no, this->statement_);
|
||||
else
|
||||
{
|
||||
Dataflow_traverse_expressions dte(this->dataflow_, this->statement_);
|
||||
Expression::traverse(pexpr, &dte);
|
||||
}
|
||||
}
|
||||
|
||||
// This class is used to traverse the tree to look for statements.
|
||||
|
||||
class Dataflow_traverse_statements : public Traverse
|
||||
{
|
||||
public:
|
||||
Dataflow_traverse_statements(Dataflow* dataflow)
|
||||
: Traverse(traverse_statements),
|
||||
dataflow_(dataflow)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
int
|
||||
statement(Block*, size_t* pindex, Statement*);
|
||||
|
||||
private:
|
||||
// The dataflow information.
|
||||
Dataflow* dataflow_;
|
||||
};
|
||||
|
||||
// For each Statement, we look for expressions.
|
||||
|
||||
int
|
||||
Dataflow_traverse_statements::statement(Block* block, size_t* pindex,
|
||||
Statement *statement)
|
||||
{
|
||||
Dataflow_traverse_assignment dta(this->dataflow_, statement);
|
||||
if (!statement->traverse_assignments(&dta))
|
||||
{
|
||||
Dataflow_traverse_expressions dte(this->dataflow_, statement);
|
||||
statement->traverse(block, pindex, &dte);
|
||||
}
|
||||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
// Compare variables.
|
||||
|
||||
bool
|
||||
Dataflow::Compare_vars::operator()(const Named_object* no1,
|
||||
const Named_object* no2) const
|
||||
{
|
||||
if (no1->name() < no2->name())
|
||||
return true;
|
||||
if (no1->name() > no2->name())
|
||||
return false;
|
||||
|
||||
// We can have two different variables with the same name.
|
||||
source_location loc1 = no1->location();
|
||||
source_location loc2 = no2->location();
|
||||
if (loc1 < loc2)
|
||||
return false;
|
||||
if (loc1 > loc2)
|
||||
return true;
|
||||
|
||||
if (no1 == no2)
|
||||
return false;
|
||||
|
||||
// We can't have two variables with the same name in the same
|
||||
// location.
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
// Class Dataflow.
|
||||
|
||||
Dataflow::Dataflow()
|
||||
: defs_(), refs_()
|
||||
{
|
||||
}
|
||||
|
||||
// Build the dataflow information.
|
||||
|
||||
void
|
||||
Dataflow::initialize(Gogo* gogo)
|
||||
{
|
||||
Dataflow_traverse_statements dts(this);
|
||||
gogo->traverse(&dts);
|
||||
}
|
||||
|
||||
// Add a definition of a variable.
|
||||
|
||||
void
|
||||
Dataflow::add_def(Named_object* var, Expression* val, Statement* statement,
|
||||
bool is_init)
|
||||
{
|
||||
Defs* defnull = NULL;
|
||||
std::pair<Defmap::iterator, bool> ins =
|
||||
this->defs_.insert(std::make_pair(var, defnull));
|
||||
if (ins.second)
|
||||
ins.first->second = new Defs;
|
||||
Def def;
|
||||
def.statement = statement;
|
||||
def.val = val;
|
||||
def.is_init = is_init;
|
||||
ins.first->second->push_back(def);
|
||||
}
|
||||
|
||||
// Add a reference to a variable.
|
||||
|
||||
void
|
||||
Dataflow::add_ref(Named_object* var, Statement* statement)
|
||||
{
|
||||
Refs* refnull = NULL;
|
||||
std::pair<Refmap::iterator, bool> ins =
|
||||
this->refs_.insert(std::make_pair(var, refnull));
|
||||
if (ins.second)
|
||||
ins.first->second = new Refs;
|
||||
Ref ref;
|
||||
ref.statement = statement;
|
||||
ins.first->second->push_back(ref);
|
||||
}
|
||||
|
||||
// Return the definitions of a variable.
|
||||
|
||||
const Dataflow::Defs*
|
||||
Dataflow::find_defs(Named_object* var) const
|
||||
{
|
||||
Defmap::const_iterator p = this->defs_.find(var);
|
||||
if (p == this->defs_.end())
|
||||
return NULL;
|
||||
else
|
||||
return p->second;
|
||||
}
|
||||
|
||||
// Return the references of a variable.
|
||||
|
||||
const Dataflow::Refs*
|
||||
Dataflow::find_refs(Named_object* var) const
|
||||
{
|
||||
Refmap::const_iterator p = this->refs_.find(var);
|
||||
if (p == this->refs_.end())
|
||||
return NULL;
|
||||
else
|
||||
return p->second;
|
||||
}
|
91
gcc/go/gofrontend/dataflow.h
Normal file
91
gcc/go/gofrontend/dataflow.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
// dataflow.h -- Go frontend dataflow. -*- C++ -*-
|
||||
|
||||
// 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 GO_DATAFLOW_H
|
||||
#define GO_DATAFLOW_H
|
||||
|
||||
class Expression;
|
||||
class Named_object;
|
||||
class Statement;
|
||||
|
||||
// Dataflow information about the Go program.
|
||||
|
||||
class Dataflow
|
||||
{
|
||||
public:
|
||||
// A variable definition.
|
||||
struct Def
|
||||
{
|
||||
// The statement where the variable is defined.
|
||||
Statement* statement;
|
||||
// The value to which the variable is set. This may be NULL.
|
||||
Expression* val;
|
||||
// Whether this is an initialization of the variable.
|
||||
bool is_init;
|
||||
};
|
||||
|
||||
// A variable reference.
|
||||
struct Ref
|
||||
{
|
||||
// The statement where the variable is referenced.
|
||||
Statement* statement;
|
||||
};
|
||||
|
||||
// A list of defs.
|
||||
typedef std::vector<Def> Defs;
|
||||
|
||||
// A list of refs.
|
||||
typedef std::vector<Ref> Refs;
|
||||
|
||||
Dataflow();
|
||||
|
||||
// Initialize the dataflow information.
|
||||
void
|
||||
initialize(Gogo*);
|
||||
|
||||
// Add a definition of a variable. STATEMENT assigns a value to
|
||||
// VAR. VAL is the value if it is known, NULL otherwise.
|
||||
void
|
||||
add_def(Named_object* var, Expression* val, Statement* statement,
|
||||
bool is_init);
|
||||
|
||||
// Add a reference to a variable. VAR is the variable, and
|
||||
// STATEMENT is the statement which refers to it.
|
||||
void
|
||||
add_ref(Named_object* var, Statement* statement);
|
||||
|
||||
// Return the definitions of VAR--the places where it is set.
|
||||
const Defs*
|
||||
find_defs(Named_object* var) const;
|
||||
|
||||
// Return the references to VAR--the places where it is used.
|
||||
const Refs*
|
||||
find_refs(Named_object* var) const;
|
||||
|
||||
private:
|
||||
// Order variables in the map.
|
||||
struct Compare_vars
|
||||
{
|
||||
bool
|
||||
operator()(const Named_object*, const Named_object*) const;
|
||||
};
|
||||
|
||||
// Map from variables to a list of defs of the variable. We use a
|
||||
// map rather than a hash table because the order in which we
|
||||
// process variables may affect the resulting code.
|
||||
typedef std::map<Named_object*, Defs*, Compare_vars> Defmap;
|
||||
|
||||
// Map from variables to a list of refs to the vairable.
|
||||
typedef std::map<Named_object*, Refs*, Compare_vars> Refmap;
|
||||
|
||||
// Variable defs.
|
||||
Defmap defs_;
|
||||
// Variable refs;
|
||||
Refmap refs_;
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(GO_DATAFLOW_H)
|
441
gcc/go/gofrontend/export.cc
Normal file
441
gcc/go/gofrontend/export.cc
Normal file
|
@ -0,0 +1,441 @@
|
|||
// export.cc -- Export declarations in Go frontend.
|
||||
|
||||
// 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 "go-system.h"
|
||||
#include "sha1.h"
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "machmode.h"
|
||||
#include "output.h"
|
||||
#include "target.h"
|
||||
|
||||
#ifndef ENABLE_BUILD_WITH_CXX
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "gogo.h"
|
||||
#include "types.h"
|
||||
#include "statements.h"
|
||||
#include "export.h"
|
||||
|
||||
// This file handles exporting global declarations.
|
||||
|
||||
// Class Export.
|
||||
|
||||
// Version 1 magic number.
|
||||
|
||||
const int Export::v1_magic_len;
|
||||
|
||||
const char Export::v1_magic[Export::v1_magic_len] =
|
||||
{
|
||||
'v', '1', ';', '\n'
|
||||
};
|
||||
|
||||
const int Export::v1_checksum_len;
|
||||
|
||||
// Constructor.
|
||||
|
||||
Export::Export(Stream* stream)
|
||||
: stream_(stream), type_refs_(), type_index_(1)
|
||||
{
|
||||
}
|
||||
|
||||
// A functor to sort Named_object pointers by name.
|
||||
|
||||
struct Sort_bindings
|
||||
{
|
||||
bool
|
||||
operator()(const Named_object* n1, const Named_object* n2) const
|
||||
{ return n1->name() < n2->name(); }
|
||||
};
|
||||
|
||||
// Return true if we should export NO.
|
||||
|
||||
static bool
|
||||
should_export(Named_object* no)
|
||||
{
|
||||
// We only export objects which are locally defined.
|
||||
if (no->package() != NULL)
|
||||
return false;
|
||||
|
||||
// We don't export packages.
|
||||
if (no->is_package())
|
||||
return false;
|
||||
|
||||
// We don't export hidden names.
|
||||
if (Gogo::is_hidden_name(no->name()))
|
||||
return false;
|
||||
|
||||
// We don't export nested functions.
|
||||
if (no->is_function() && no->func_value()->enclosing() != NULL)
|
||||
return false;
|
||||
|
||||
// We don't export thunks.
|
||||
if (no->is_function() && Gogo::is_thunk(no))
|
||||
return false;
|
||||
|
||||
// Methods are exported with the type, not here.
|
||||
if (no->is_function()
|
||||
&& no->func_value()->type()->is_method())
|
||||
return false;
|
||||
if (no->is_function_declaration()
|
||||
&& no->func_declaration_value()->type()->is_method())
|
||||
return false;
|
||||
|
||||
// Don't export dummy global variables created for initializers when
|
||||
// used with sinks.
|
||||
if (no->is_variable() && no->name()[0] == '_' && no->name()[1] == '.')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Export those identifiers marked for exporting.
|
||||
|
||||
void
|
||||
Export::export_globals(const std::string& package_name,
|
||||
const std::string& unique_prefix,
|
||||
int package_priority,
|
||||
const std::string& import_init_fn,
|
||||
const std::set<Import_init>& imported_init_fns,
|
||||
const Bindings* bindings)
|
||||
{
|
||||
// If there have been any errors so far, don't try to export
|
||||
// anything. That way the export code doesn't have to worry about
|
||||
// mismatched types or other confusions.
|
||||
if (saw_errors())
|
||||
return;
|
||||
|
||||
// Export the symbols in sorted order. That will reduce cases where
|
||||
// irrelevant changes to the source code affect the exported
|
||||
// interface.
|
||||
std::vector<Named_object*> exports;
|
||||
exports.reserve(bindings->size_definitions());
|
||||
|
||||
for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
|
||||
p != bindings->end_definitions();
|
||||
++p)
|
||||
if (should_export(*p))
|
||||
exports.push_back(*p);
|
||||
|
||||
for (Bindings::const_declarations_iterator p =
|
||||
bindings->begin_declarations();
|
||||
p != bindings->end_declarations();
|
||||
++p)
|
||||
{
|
||||
// We export a function declaration as it may be implemented in
|
||||
// supporting C code. We do not export type declarations.
|
||||
if (p->second->is_function_declaration()
|
||||
&& should_export(p->second))
|
||||
exports.push_back(p->second);
|
||||
}
|
||||
|
||||
std::sort(exports.begin(), exports.end(), Sort_bindings());
|
||||
|
||||
// Although the export data is readable, at least this version is,
|
||||
// it is conceptually a binary format. Start with a four byte
|
||||
// verison number.
|
||||
this->write_bytes(Export::v1_magic, Export::v1_magic_len);
|
||||
|
||||
// The package name.
|
||||
this->write_c_string("package ");
|
||||
this->write_string(package_name);
|
||||
this->write_c_string(";\n");
|
||||
|
||||
// The unique prefix. This prefix is used for all global symbols.
|
||||
this->write_c_string("prefix ");
|
||||
this->write_string(unique_prefix);
|
||||
this->write_c_string(";\n");
|
||||
|
||||
// The package priority.
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof buf, "priority %d;\n", package_priority);
|
||||
this->write_c_string(buf);
|
||||
|
||||
this->write_imported_init_fns(package_name, package_priority, import_init_fn,
|
||||
imported_init_fns);
|
||||
|
||||
// FIXME: It might be clever to add something about the processor
|
||||
// and ABI being used, although ideally any problems in that area
|
||||
// would be caught by the linker.
|
||||
|
||||
for (std::vector<Named_object*>::const_iterator p = exports.begin();
|
||||
p != exports.end();
|
||||
++p)
|
||||
(*p)->export_named_object(this);
|
||||
|
||||
std::string checksum = this->stream_->checksum();
|
||||
std::string s = "checksum ";
|
||||
for (std::string::const_iterator p = checksum.begin();
|
||||
p != checksum.end();
|
||||
++p)
|
||||
{
|
||||
unsigned char c = *p;
|
||||
unsigned int dig = c >> 4;
|
||||
s += dig < 10 ? '0' + dig : 'A' + dig - 10;
|
||||
dig = c & 0xf;
|
||||
s += dig < 10 ? '0' + dig : 'A' + dig - 10;
|
||||
}
|
||||
s += ";\n";
|
||||
this->stream_->write_checksum(s);
|
||||
}
|
||||
|
||||
// Write out the import control variables for this package.
|
||||
|
||||
void
|
||||
Export::write_imported_init_fns(
|
||||
const std::string& package_name,
|
||||
int priority,
|
||||
const std::string& import_init_fn,
|
||||
const std::set<Import_init>& imported_init_fns)
|
||||
{
|
||||
if (import_init_fn.empty() && imported_init_fns.empty())
|
||||
return;
|
||||
|
||||
this->write_c_string("import");
|
||||
|
||||
if (!import_init_fn.empty())
|
||||
{
|
||||
this->write_c_string(" ");
|
||||
this->write_string(package_name);
|
||||
this->write_c_string(" ");
|
||||
this->write_string(import_init_fn);
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof buf, " %d", priority);
|
||||
this->write_c_string(buf);
|
||||
}
|
||||
|
||||
if (!imported_init_fns.empty())
|
||||
{
|
||||
// Sort the list of functions for more consistent output.
|
||||
std::vector<Import_init> v;
|
||||
for (std::set<Import_init>::const_iterator p = imported_init_fns.begin();
|
||||
p != imported_init_fns.end();
|
||||
++p)
|
||||
v.push_back(*p);
|
||||
std::sort(v.begin(), v.end());
|
||||
|
||||
for (std::vector<Import_init>::const_iterator p = v.begin();
|
||||
p != v.end();
|
||||
++p)
|
||||
{
|
||||
this->write_c_string(" ");
|
||||
this->write_string(p->package_name());
|
||||
this->write_c_string(" ");
|
||||
this->write_string(p->init_name());
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof buf, " %d", p->priority());
|
||||
this->write_c_string(buf);
|
||||
}
|
||||
}
|
||||
|
||||
this->write_c_string(";\n");
|
||||
}
|
||||
|
||||
// Export a type. We have to ensure that on import we create a single
|
||||
// Named_type node for each named type. We do this by keeping a hash
|
||||
// table mapping named types to reference numbers. The first time we
|
||||
// see a named type we assign it a reference number by making an entry
|
||||
// in the hash table. If we see it again, we just refer to the
|
||||
// reference number.
|
||||
|
||||
// Named types are, of course, associated with packages. Note that we
|
||||
// may see a named type when importing one package, and then later see
|
||||
// the same named type when importing a different package. The home
|
||||
// package may or may not be imported during this compilation. The
|
||||
// reference number scheme has to get this all right. Basic approach
|
||||
// taken from "On the Linearization of Graphs and Writing Symbol
|
||||
// Files" by Robert Griesemer.
|
||||
|
||||
void
|
||||
Export::write_type(const Type* type)
|
||||
{
|
||||
// We don't want to assign a reference number to a forward
|
||||
// declaration to a type which was defined later.
|
||||
type = type->forwarded();
|
||||
|
||||
Type_refs::const_iterator p = this->type_refs_.find(type);
|
||||
if (p != this->type_refs_.end())
|
||||
{
|
||||
// This type was already in the table.
|
||||
int index = p->second;
|
||||
gcc_assert(index != 0);
|
||||
char buf[30];
|
||||
snprintf(buf, sizeof buf, "<type %d>", index);
|
||||
this->write_c_string(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
const Named_type* named_type = type->named_type();
|
||||
const Forward_declaration_type* forward = type->forward_declaration_type();
|
||||
|
||||
int index = this->type_index_;
|
||||
++this->type_index_;
|
||||
|
||||
char buf[30];
|
||||
snprintf(buf, sizeof buf, "<type %d ", index);
|
||||
this->write_c_string(buf);
|
||||
|
||||
if (named_type != NULL || forward != NULL)
|
||||
{
|
||||
const Named_object* named_object;
|
||||
if (named_type != NULL)
|
||||
{
|
||||
// The builtin types should have been predefined.
|
||||
gcc_assert(named_type->location() != BUILTINS_LOCATION
|
||||
|| (named_type->named_object()->package()->name()
|
||||
== "unsafe"));
|
||||
named_object = named_type->named_object();
|
||||
}
|
||||
else
|
||||
named_object = forward->named_object();
|
||||
|
||||
const Package* package = named_object->package();
|
||||
|
||||
std::string s = "\"";
|
||||
if (package != NULL && !Gogo::is_hidden_name(named_object->name()))
|
||||
{
|
||||
s += package->unique_prefix();
|
||||
s += '.';
|
||||
s += package->name();
|
||||
s += '.';
|
||||
}
|
||||
s += named_object->name();
|
||||
s += "\" ";
|
||||
this->write_string(s);
|
||||
|
||||
// We must add a named type to the table now, since the
|
||||
// definition of the type may refer to the named type via a
|
||||
// pointer.
|
||||
this->type_refs_[type] = index;
|
||||
}
|
||||
|
||||
type->export_type(this);
|
||||
|
||||
this->write_c_string(">");
|
||||
|
||||
if (named_type == NULL)
|
||||
this->type_refs_[type] = index;
|
||||
}
|
||||
|
||||
// Add the builtin types to the export table.
|
||||
|
||||
void
|
||||
Export::register_builtin_types(Gogo* gogo)
|
||||
{
|
||||
this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
|
||||
this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
|
||||
this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
|
||||
this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
|
||||
this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
|
||||
this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
|
||||
this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
|
||||
this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
|
||||
this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
|
||||
this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
|
||||
this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
|
||||
this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
|
||||
this->register_builtin_type(gogo, "int", BUILTIN_INT);
|
||||
this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
|
||||
this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
|
||||
this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
|
||||
this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
|
||||
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
|
||||
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
|
||||
}
|
||||
|
||||
// Register one builtin type in the export table.
|
||||
|
||||
void
|
||||
Export::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
|
||||
{
|
||||
Named_object* named_object = gogo->lookup_global(name);
|
||||
gcc_assert(named_object != NULL && named_object->is_type());
|
||||
std::pair<Type_refs::iterator, bool> ins =
|
||||
this->type_refs_.insert(std::make_pair(named_object->type_value(), code));
|
||||
gcc_assert(ins.second);
|
||||
|
||||
// We also insert the underlying type. We can see the underlying
|
||||
// type at least for string and bool.
|
||||
Type* real_type = named_object->type_value()->real_type();
|
||||
ins = this->type_refs_.insert(std::make_pair(real_type, code));
|
||||
gcc_assert(ins.second);
|
||||
}
|
||||
|
||||
// Class Export::Stream.
|
||||
|
||||
Export::Stream::Stream()
|
||||
{
|
||||
this->checksum_ = new sha1_ctx;
|
||||
memset(this->checksum_, 0, sizeof(sha1_ctx));
|
||||
sha1_init_ctx(this->checksum_);
|
||||
}
|
||||
|
||||
Export::Stream::~Stream()
|
||||
{
|
||||
}
|
||||
|
||||
// Write bytes to the stream. This keeps a checksum of bytes as they
|
||||
// go by.
|
||||
|
||||
void
|
||||
Export::Stream::write_and_sum_bytes(const char* bytes, size_t length)
|
||||
{
|
||||
sha1_process_bytes(bytes, length, this->checksum_);
|
||||
this->do_write(bytes, length);
|
||||
}
|
||||
|
||||
// Get the checksum.
|
||||
|
||||
std::string
|
||||
Export::Stream::checksum()
|
||||
{
|
||||
// Use a union to provide the required alignment.
|
||||
union
|
||||
{
|
||||
char checksum[Export::v1_checksum_len];
|
||||
long align;
|
||||
} u;
|
||||
sha1_finish_ctx(this->checksum_, u.checksum);
|
||||
return std::string(u.checksum, Export::v1_checksum_len);
|
||||
}
|
||||
|
||||
// Write the checksum string to the export data.
|
||||
|
||||
void
|
||||
Export::Stream::write_checksum(const std::string& s)
|
||||
{
|
||||
this->do_write(s.data(), s.length());
|
||||
}
|
||||
|
||||
// Class Stream_to_section.
|
||||
|
||||
Stream_to_section::Stream_to_section()
|
||||
: section_(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// Write data to a section.
|
||||
|
||||
void
|
||||
Stream_to_section::do_write(const char* bytes, size_t length)
|
||||
{
|
||||
section* sec = (section*) this->section_;
|
||||
if (sec == NULL)
|
||||
{
|
||||
gcc_assert(targetm.have_named_sections);
|
||||
|
||||
sec = get_section(".go_export", SECTION_DEBUG, NULL);
|
||||
this->section_ = (void*) sec;
|
||||
}
|
||||
|
||||
switch_to_section(sec);
|
||||
assemble_string(bytes, length);
|
||||
}
|
191
gcc/go/gofrontend/export.h
Normal file
191
gcc/go/gofrontend/export.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
// export.h -- Export declarations in Go frontend. -*- C++ -*-
|
||||
|
||||
// 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 GO_EXPORT_H
|
||||
#define GO_EXPORT_H
|
||||
|
||||
struct sha1_ctx;
|
||||
class Gogo;
|
||||
class Import_init;
|
||||
class Bindings;
|
||||
class Type;
|
||||
|
||||
// Codes used for the builtin types. These are all negative to make
|
||||
// them easily distinct from the codes assigned by Export::write_type.
|
||||
// Note that these codes may not be changed! Changing them would
|
||||
// break existing export data.
|
||||
|
||||
enum Builtin_code
|
||||
{
|
||||
BUILTIN_INT8 = -1,
|
||||
BUILTIN_INT16 = -2,
|
||||
BUILTIN_INT32 = -3,
|
||||
BUILTIN_INT64 = -4,
|
||||
BUILTIN_UINT8 = -5,
|
||||
BUILTIN_UINT16 = -6,
|
||||
BUILTIN_UINT32 = -7,
|
||||
BUILTIN_UINT64 = -8,
|
||||
BUILTIN_FLOAT32 = -9,
|
||||
BUILTIN_FLOAT64 = -10,
|
||||
BUILTIN_INT = -11,
|
||||
BUILTIN_UINT = -12,
|
||||
BUILTIN_UINTPTR = -13,
|
||||
BUILTIN_FLOAT = -14,
|
||||
BUILTIN_BOOL = -15,
|
||||
BUILTIN_STRING = -16,
|
||||
BUILTIN_COMPLEX64 = -17,
|
||||
BUILTIN_COMPLEX128 = -18,
|
||||
BUILTIN_COMPLEX = -19,
|
||||
|
||||
SMALLEST_BUILTIN_CODE = -19
|
||||
};
|
||||
|
||||
// This class manages exporting Go declarations. It handles the main
|
||||
// loop of exporting. A pointer to this class is also passed to the
|
||||
// various specific export implementations.
|
||||
|
||||
class Export
|
||||
{
|
||||
public:
|
||||
// The Stream class is an interface used to output the exported
|
||||
// information. The caller should instantiate a child of this
|
||||
// class.
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
Stream();
|
||||
virtual ~Stream();
|
||||
|
||||
// Write a string.
|
||||
void
|
||||
write_string(const std::string& s)
|
||||
{ this->write_and_sum_bytes(s.data(), s.length()); }
|
||||
|
||||
// Write a nul terminated string.
|
||||
void
|
||||
write_c_string(const char* s)
|
||||
{ this->write_and_sum_bytes(s, strlen(s)); }
|
||||
|
||||
// Write some bytes.
|
||||
void
|
||||
write_bytes(const char* bytes, size_t length)
|
||||
{ this->write_and_sum_bytes(bytes, length); }
|
||||
|
||||
// Return the raw bytes of the checksum data.
|
||||
std::string
|
||||
checksum();
|
||||
|
||||
// Write a checksum string to the stream. This will be called at
|
||||
// the end of the other output.
|
||||
void
|
||||
write_checksum(const std::string&);
|
||||
|
||||
protected:
|
||||
// This function is called with data to export. This data must be
|
||||
// made available as a contiguous stream for the importer.
|
||||
virtual void
|
||||
do_write(const char* bytes, size_t length) = 0;
|
||||
|
||||
private:
|
||||
void
|
||||
write_and_sum_bytes(const char*, size_t);
|
||||
|
||||
// The checksum.
|
||||
sha1_ctx* checksum_;
|
||||
};
|
||||
|
||||
Export(Stream*);
|
||||
|
||||
// The magic code for version 1 export data.
|
||||
static const int v1_magic_len = 4;
|
||||
static const char v1_magic[v1_magic_len];
|
||||
|
||||
// The length of the v1 checksum string.
|
||||
static const int v1_checksum_len = 20;
|
||||
|
||||
// Register the builtin types.
|
||||
void
|
||||
register_builtin_types(Gogo*);
|
||||
|
||||
// Export the identifiers in BINDINGS which are marked for export.
|
||||
// The exporting is done via a series of calls to THIS->STREAM_. If
|
||||
// is nothing to export, this->stream_->write will not be called.
|
||||
// UNIQUE_PREFIX is a prefix for all global symbols.
|
||||
// PACKAGE_PRIORITY is the priority to use for this package.
|
||||
// IMPORT_INIT_FN is the name of the import initialization function
|
||||
// for this package; it will be empty if none is needed.
|
||||
// IMPORTED_INIT_FNS is the list of initialization functions for
|
||||
// imported packages.
|
||||
void
|
||||
export_globals(const std::string& package_name,
|
||||
const std::string& unique_prefix,
|
||||
int package_priority,
|
||||
const std::string& import_init_fn,
|
||||
const std::set<Import_init>& imported_init_fns,
|
||||
const Bindings* bindings);
|
||||
|
||||
// Write a string to the export stream.
|
||||
void
|
||||
write_string(const std::string& s)
|
||||
{ this->stream_->write_string(s); }
|
||||
|
||||
// Write a nul terminated string to the export stream.
|
||||
void
|
||||
write_c_string(const char* s)
|
||||
{ this->stream_->write_c_string(s); }
|
||||
|
||||
// Write some bytes to the export stream.
|
||||
void
|
||||
write_bytes(const char* bytes, size_t length)
|
||||
{ this->stream_->write_bytes(bytes, length); }
|
||||
|
||||
// Write out a type. This handles references back to previous
|
||||
// definitions.
|
||||
void
|
||||
write_type(const Type*);
|
||||
|
||||
private:
|
||||
Export(const Export&);
|
||||
Export& operator=(const Export&);
|
||||
|
||||
// Write out the imported initialization functions.
|
||||
void
|
||||
write_imported_init_fns(const std::string& package_name, int priority,
|
||||
const std::string&, const std::set<Import_init>&);
|
||||
|
||||
// Register one builtin type.
|
||||
void
|
||||
register_builtin_type(Gogo*, const char* name, Builtin_code);
|
||||
|
||||
// Mapping from Type objects to a constant index.
|
||||
typedef Unordered_map(const Type*, int) Type_refs;
|
||||
|
||||
// The stream to which we are writing data.
|
||||
Stream* stream_;
|
||||
// Type mappings.
|
||||
Type_refs type_refs_;
|
||||
// Index number of next type.
|
||||
int type_index_;
|
||||
};
|
||||
|
||||
// An export streamer which puts the export stream in a named section.
|
||||
|
||||
class Stream_to_section : public Export::Stream
|
||||
{
|
||||
public:
|
||||
Stream_to_section();
|
||||
|
||||
protected:
|
||||
void
|
||||
do_write(const char*, size_t);
|
||||
|
||||
private:
|
||||
// The section we are writing to; this is really union section
|
||||
// defined in output.h.
|
||||
void* section_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_EXPORT_H)
|
12264
gcc/go/gofrontend/expressions.cc
Normal file
12264
gcc/go/gofrontend/expressions.cc
Normal file
File diff suppressed because it is too large
Load diff
1920
gcc/go/gofrontend/expressions.h
Normal file
1920
gcc/go/gofrontend/expressions.h
Normal file
File diff suppressed because it is too large
Load diff
53
gcc/go/gofrontend/go-dump.cc
Normal file
53
gcc/go/gofrontend/go-dump.cc
Normal file
|
@ -0,0 +1,53 @@
|
|||
// go-dump.cc -- Go frontend debug dumps.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "go-c.h"
|
||||
#include "go-dump.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// The list of dumps.
|
||||
|
||||
Go_dump* dumps;
|
||||
|
||||
} // End empty namespace.
|
||||
|
||||
// Create a new dump.
|
||||
|
||||
Go_dump::Go_dump(const char* name)
|
||||
: next_(dumps), name_(name), is_enabled_(false)
|
||||
{
|
||||
dumps = this;
|
||||
}
|
||||
|
||||
// Enable a dump by name.
|
||||
|
||||
bool
|
||||
Go_dump::enable_by_name(const char* name)
|
||||
{
|
||||
bool is_all = strcmp(name, "all") == 0;
|
||||
bool found = false;
|
||||
for (Go_dump* p = dumps; p != NULL; p = p->next_)
|
||||
{
|
||||
if (is_all || strcmp(name, p->name_) == 0)
|
||||
{
|
||||
p->is_enabled_ = true;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// Enable a dump. Return 1 if this is a real name, 0 if not.
|
||||
|
||||
GO_EXTERN_C
|
||||
int
|
||||
go_enable_dump(const char* name)
|
||||
{
|
||||
return Go_dump::enable_by_name(name) ? 1 : 0;
|
||||
}
|
38
gcc/go/gofrontend/go-dump.h
Normal file
38
gcc/go/gofrontend/go-dump.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// go-dump.h -- Go frontend debug dumps. -*- C++ -*-
|
||||
|
||||
// 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 GO_DUMP_H
|
||||
#define GO_DUMP_H
|
||||
|
||||
// This class manages different arguments to -fgo-dump-XXX. If you
|
||||
// want to create a new dump, create a variable of this type with the
|
||||
// name to use for XXX. You can then use is_enabled to see whether
|
||||
// the -fgo-dump-XXX option was used on the command line.
|
||||
|
||||
class Go_dump
|
||||
{
|
||||
public:
|
||||
Go_dump(const char* name);
|
||||
|
||||
// Whether this dump was enabled.
|
||||
bool
|
||||
is_enabled() const
|
||||
{ return this->is_enabled_; }
|
||||
|
||||
// Enable a dump by name. Return true if the dump was found.
|
||||
static bool
|
||||
enable_by_name(const char*);
|
||||
|
||||
private:
|
||||
// The next dump. These are not in any order.
|
||||
Go_dump* next_;
|
||||
// The name of this dump.
|
||||
const char* name_;
|
||||
// Whether this dump was enabled.
|
||||
bool is_enabled_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_DUMP_H)
|
153
gcc/go/gofrontend/go.cc
Normal file
153
gcc/go/gofrontend/go.cc
Normal file
|
@ -0,0 +1,153 @@
|
|||
// go.cc -- Go frontend main file for gcc.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "go-c.h"
|
||||
|
||||
#include "lex.h"
|
||||
#include "parse.h"
|
||||
#include "gogo.h"
|
||||
|
||||
// The unique prefix to use for exported symbols. This is set during
|
||||
// option processing.
|
||||
|
||||
static std::string unique_prefix;
|
||||
|
||||
// The data structures we build to represent the file.
|
||||
static Gogo* gogo;
|
||||
|
||||
// Create the main IR data structure.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_create_gogo(int int_type_size, int float_type_size, int pointer_size)
|
||||
{
|
||||
gcc_assert(::gogo == NULL);
|
||||
::gogo = new Gogo(int_type_size, float_type_size, pointer_size);
|
||||
if (!unique_prefix.empty())
|
||||
::gogo->set_unique_prefix(unique_prefix);
|
||||
}
|
||||
|
||||
// Set the unique prefix we use for exported symbols.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_set_prefix(const char* arg)
|
||||
{
|
||||
unique_prefix = arg;
|
||||
for (size_t i = 0; i < unique_prefix.length(); ++i)
|
||||
{
|
||||
char c = unique_prefix[i];
|
||||
if ((c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
|| (c >= '0' && c <= '9')
|
||||
|| c == '_')
|
||||
;
|
||||
else
|
||||
unique_prefix[i] = '_';
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the input files.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_parse_input_files(const char** filenames, unsigned int filename_count,
|
||||
bool only_check_syntax, bool require_return_statement)
|
||||
{
|
||||
gcc_assert(filename_count > 0);
|
||||
for (unsigned int i = 0; i < filename_count; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
::gogo->clear_file_scope();
|
||||
|
||||
const char* filename = filenames[i];
|
||||
FILE* file;
|
||||
if (strcmp(filename, "-") == 0)
|
||||
file = stdin;
|
||||
else
|
||||
{
|
||||
file = fopen(filename, "r");
|
||||
if (file == NULL)
|
||||
fatal_error("cannot open %s: %m", filename);
|
||||
}
|
||||
|
||||
Lex lexer(filename, file);
|
||||
|
||||
Parse parse(&lexer, ::gogo);
|
||||
parse.program();
|
||||
|
||||
if (strcmp(filename, "-") != 0)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
::gogo->clear_file_scope();
|
||||
|
||||
// If the global predeclared names are referenced but not defined,
|
||||
// define them now.
|
||||
::gogo->define_global_names();
|
||||
|
||||
// Finalize method lists and build stub methods for named types.
|
||||
::gogo->finalize_methods();
|
||||
|
||||
// Now that we have seen all the names, lower the parse tree into a
|
||||
// form which is easier to use.
|
||||
::gogo->lower_parse_tree();
|
||||
|
||||
// Now that we have seen all the names, verify that types are
|
||||
// correct.
|
||||
::gogo->verify_types();
|
||||
|
||||
// Work out types of unspecified constants and variables.
|
||||
::gogo->determine_types();
|
||||
|
||||
// Check types and issue errors as appropriate.
|
||||
::gogo->check_types();
|
||||
|
||||
if (only_check_syntax)
|
||||
return;
|
||||
|
||||
// Check that functions have return statements.
|
||||
if (require_return_statement)
|
||||
::gogo->check_return_statements();
|
||||
|
||||
// Export global identifiers as appropriate.
|
||||
::gogo->do_exports();
|
||||
|
||||
// Build required interface method tables.
|
||||
::gogo->build_interface_method_tables();
|
||||
|
||||
// Turn short-cut operators (&&, ||) into explicit if statements.
|
||||
::gogo->remove_shortcuts();
|
||||
|
||||
// Use temporary variables to force order of evaluation.
|
||||
::gogo->order_evaluations();
|
||||
|
||||
// Build thunks for functions which call recover.
|
||||
::gogo->build_recover_thunks();
|
||||
|
||||
// Convert complicated go and defer statements into simpler ones.
|
||||
::gogo->simplify_thunk_statements();
|
||||
}
|
||||
|
||||
// Write out globals.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_write_globals()
|
||||
{
|
||||
return ::gogo->write_globals();
|
||||
}
|
||||
|
||||
// Return the global IR structure. This is used by some of the
|
||||
// langhooks to pass to other code.
|
||||
|
||||
Gogo*
|
||||
go_get_gogo()
|
||||
{
|
||||
return ::gogo;
|
||||
}
|
3105
gcc/go/gofrontend/gogo-tree.cc
Normal file
3105
gcc/go/gofrontend/gogo-tree.cc
Normal file
File diff suppressed because it is too large
Load diff
4274
gcc/go/gofrontend/gogo.cc
Normal file
4274
gcc/go/gofrontend/gogo.cc
Normal file
File diff suppressed because it is too large
Load diff
2484
gcc/go/gofrontend/gogo.h
Normal file
2484
gcc/go/gofrontend/gogo.h
Normal file
File diff suppressed because it is too large
Load diff
661
gcc/go/gofrontend/import-archive.cc
Normal file
661
gcc/go/gofrontend/import-archive.cc
Normal file
|
@ -0,0 +1,661 @@
|
|||
// import-archive.cc -- Go frontend read import data from an archive file.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "import.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
// Archive magic numbers.
|
||||
|
||||
static const char armag[] =
|
||||
{
|
||||
'!', '<', 'a', 'r', 'c', 'h', '>', '\n'
|
||||
};
|
||||
|
||||
static const char armagt[] =
|
||||
{
|
||||
'!', '<', 't', 'h', 'i', 'n', '>', '\n'
|
||||
};
|
||||
|
||||
static const char arfmag[2] = { '`', '\n' };
|
||||
|
||||
// The header of an entry in an archive. This is all readable text,
|
||||
// padded with spaces where necesary.
|
||||
|
||||
struct Archive_header
|
||||
{
|
||||
// The entry name.
|
||||
char ar_name[16];
|
||||
// The file modification time.
|
||||
char ar_date[12];
|
||||
// The user's UID in decimal.
|
||||
char ar_uid[6];
|
||||
// The user's GID in decimal.
|
||||
char ar_gid[6];
|
||||
// The file mode in octal.
|
||||
char ar_mode[8];
|
||||
// The file size in decimal.
|
||||
char ar_size[10];
|
||||
// The final magic code.
|
||||
char ar_fmag[2];
|
||||
};
|
||||
|
||||
// The functions in this file extract Go export data from an archive.
|
||||
|
||||
const int Import::archive_magic_len;
|
||||
|
||||
// Return true if BYTES, which are from the start of the file, are an
|
||||
// archive magic number.
|
||||
|
||||
bool
|
||||
Import::is_archive_magic(const char* bytes)
|
||||
{
|
||||
return (memcmp(bytes, armag, Import::archive_magic_len) == 0
|
||||
|| memcmp(bytes, armagt, Import::archive_magic_len) == 0);
|
||||
}
|
||||
|
||||
// An object used to read an archive file.
|
||||
|
||||
class Archive_file
|
||||
{
|
||||
public:
|
||||
Archive_file(const std::string& filename, int fd, source_location location)
|
||||
: filename_(filename), fd_(fd), filesize_(-1), extended_names_(),
|
||||
is_thin_archive_(false), location_(location), nested_archives_()
|
||||
{ }
|
||||
|
||||
// Initialize.
|
||||
bool
|
||||
initialize();
|
||||
|
||||
// Return the file name.
|
||||
const std::string&
|
||||
filename() const
|
||||
{ return this->filename_; }
|
||||
|
||||
// Get the file size.
|
||||
off_t
|
||||
filesize() const
|
||||
{ return this->filesize_; }
|
||||
|
||||
// Return whether this is a thin archive.
|
||||
bool
|
||||
is_thin_archive() const
|
||||
{ return this->is_thin_archive_; }
|
||||
|
||||
// Return the location of the import statement.
|
||||
source_location
|
||||
location() const
|
||||
{ return this->location_; }
|
||||
|
||||
// Read bytes.
|
||||
bool
|
||||
read(off_t offset, off_t size, char*);
|
||||
|
||||
// Read the archive header at OFF, setting *PNAME, *SIZE, and
|
||||
// *NESTED_OFF.
|
||||
bool
|
||||
read_header(off_t off, std::string* pname, off_t* size, off_t* nested_off);
|
||||
|
||||
// Interpret the header of HDR, the header of the archive member at
|
||||
// file offset OFF. Return whether it succeeded. Set *SIZE to the
|
||||
// size of the member. Set *PNAME to the name of the member. Set
|
||||
// *NESTED_OFF to the offset in a nested archive.
|
||||
bool
|
||||
interpret_header(const Archive_header* hdr, off_t off,
|
||||
std::string* pname, off_t* size, off_t* nested_off) const;
|
||||
|
||||
// Get the file and offset for an archive member.
|
||||
bool
|
||||
get_file_and_offset(off_t off, const std::string& hdrname,
|
||||
off_t nested_off, int* memfd, off_t* memoff,
|
||||
std::string* memname);
|
||||
|
||||
private:
|
||||
// For keeping track of open nested archives in a thin archive file.
|
||||
typedef std::map<std::string, Archive_file*> Nested_archive_table;
|
||||
|
||||
// The name of the file.
|
||||
std::string filename_;
|
||||
// The file descriptor.
|
||||
int fd_;
|
||||
// The file size;
|
||||
off_t filesize_;
|
||||
// The extended name table.
|
||||
std::string extended_names_;
|
||||
// Whether this is a thin archive.
|
||||
bool is_thin_archive_;
|
||||
// The location of the import statements.
|
||||
source_location location_;
|
||||
// Table of nested archives.
|
||||
Nested_archive_table nested_archives_;
|
||||
};
|
||||
|
||||
bool
|
||||
Archive_file::initialize()
|
||||
{
|
||||
struct stat st;
|
||||
if (fstat(this->fd_, &st) < 0)
|
||||
{
|
||||
error_at(this->location_, "%s: %m", this->filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
this->filesize_ = st.st_size;
|
||||
|
||||
char buf[sizeof(armagt)];
|
||||
if (::lseek(this->fd_, 0, SEEK_SET) < 0
|
||||
|| ::read(this->fd_, buf, sizeof(armagt)) != sizeof(armagt))
|
||||
{
|
||||
error_at(this->location_, "%s: %m", this->filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
this->is_thin_archive_ = memcmp(buf, armagt, sizeof(armagt)) == 0;
|
||||
|
||||
if (this->filesize_ == sizeof(armag))
|
||||
{
|
||||
// Empty archive.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Look for the extended name table.
|
||||
std::string filename;
|
||||
off_t size;
|
||||
if (!this->read_header(sizeof(armagt), &filename, &size, NULL))
|
||||
return false;
|
||||
if (filename.empty())
|
||||
{
|
||||
// We found the symbol table.
|
||||
off_t off = sizeof(armagt) + sizeof(Archive_header) + size;
|
||||
if ((off & 1) != 0)
|
||||
++off;
|
||||
if (!this->read_header(off, &filename, &size, NULL))
|
||||
filename.clear();
|
||||
}
|
||||
if (filename == "/")
|
||||
{
|
||||
char* buf = new char[size];
|
||||
if (::read(this->fd_, buf, size) != size)
|
||||
{
|
||||
error_at(this->location_, "%s: could not read extended names",
|
||||
filename.c_str());
|
||||
delete buf;
|
||||
return false;
|
||||
}
|
||||
this->extended_names_.assign(buf, size);
|
||||
delete buf;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read bytes from the file.
|
||||
|
||||
bool
|
||||
Archive_file::read(off_t offset, off_t size, char* buf)
|
||||
{
|
||||
if (::lseek(this->fd_, offset, SEEK_SET) < 0
|
||||
|| ::read(this->fd_, buf, size) != size)
|
||||
{
|
||||
error_at(this->location_, "%s: %m", this->filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read the header at OFF. Set *PNAME to the name, *SIZE to the size,
|
||||
// and *NESTED_OFF to the nested offset.
|
||||
|
||||
bool
|
||||
Archive_file::read_header(off_t off, std::string* pname, off_t* size,
|
||||
off_t* nested_off)
|
||||
{
|
||||
Archive_header hdr;
|
||||
if (::lseek(this->fd_, off, SEEK_SET) < 0)
|
||||
{
|
||||
error_at(this->location_, "%s: %m", this->filename_.c_str());
|
||||
return false;
|
||||
}
|
||||
ssize_t got = ::read(this->fd_, &hdr, sizeof hdr);
|
||||
if (got != sizeof hdr)
|
||||
{
|
||||
if (got < 0)
|
||||
error_at(this->location_, "%s: %m", this->filename_.c_str());
|
||||
else if (got > 0)
|
||||
error_at(this->location_, "%s: short archive header at %ld",
|
||||
this->filename_.c_str(), static_cast<long>(off));
|
||||
else
|
||||
error_at(this->location_, "%s: unexpected EOF at %ld",
|
||||
this->filename_.c_str(), static_cast<long>(off));
|
||||
}
|
||||
off_t local_nested_off;
|
||||
if (!this->interpret_header(&hdr, off, pname, size, &local_nested_off))
|
||||
return false;
|
||||
if (nested_off != NULL)
|
||||
*nested_off = local_nested_off;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Interpret the header of HDR, the header of the archive member at
|
||||
// file offset OFF.
|
||||
|
||||
bool
|
||||
Archive_file::interpret_header(const Archive_header* hdr, off_t off,
|
||||
std::string* pname, off_t* size,
|
||||
off_t* nested_off) const
|
||||
{
|
||||
if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
|
||||
{
|
||||
error_at(this->location_, "%s: malformed archive header at %lu",
|
||||
this->filename_.c_str(), static_cast<unsigned long>(off));
|
||||
return false;
|
||||
}
|
||||
|
||||
const int size_string_size = sizeof hdr->ar_size;
|
||||
char size_string[size_string_size + 1];
|
||||
memcpy(size_string, hdr->ar_size, size_string_size);
|
||||
char* ps = size_string + size_string_size;
|
||||
while (ps[-1] == ' ')
|
||||
--ps;
|
||||
*ps = '\0';
|
||||
|
||||
errno = 0;
|
||||
char* end;
|
||||
*size = strtol(size_string, &end, 10);
|
||||
if (*end != '\0'
|
||||
|| *size < 0
|
||||
|| (*size == LONG_MAX && errno == ERANGE))
|
||||
{
|
||||
error_at(this->location_, "%s: malformed archive header size at %lu",
|
||||
this->filename_.c_str(), static_cast<unsigned long>(off));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hdr->ar_name[0] != '/')
|
||||
{
|
||||
const char* name_end = strchr(hdr->ar_name, '/');
|
||||
if (name_end == NULL
|
||||
|| name_end - hdr->ar_name >= static_cast<int>(sizeof hdr->ar_name))
|
||||
{
|
||||
error_at(this->location_, "%s: malformed archive header name at %lu",
|
||||
this->filename_.c_str(), static_cast<unsigned long>(off));
|
||||
return false;
|
||||
}
|
||||
pname->assign(hdr->ar_name, name_end - hdr->ar_name);
|
||||
*nested_off = 0;
|
||||
}
|
||||
else if (hdr->ar_name[1] == ' ')
|
||||
{
|
||||
// This is the symbol table.
|
||||
pname->clear();
|
||||
}
|
||||
else if (hdr->ar_name[1] == '/')
|
||||
{
|
||||
// This is the extended name table.
|
||||
pname->assign(1, '/');
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
long x = strtol(hdr->ar_name + 1, &end, 10);
|
||||
long y = 0;
|
||||
if (*end == ':')
|
||||
y = strtol(end + 1, &end, 10);
|
||||
if (*end != ' '
|
||||
|| x < 0
|
||||
|| (x == LONG_MAX && errno == ERANGE)
|
||||
|| static_cast<size_t>(x) >= this->extended_names_.size())
|
||||
{
|
||||
error_at(this->location_, "%s: bad extended name index at %lu",
|
||||
this->filename_.c_str(), static_cast<unsigned long>(off));
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* name = this->extended_names_.data() + x;
|
||||
const char* name_end = strchr(name, '\n');
|
||||
if (static_cast<size_t>(name_end - name) > this->extended_names_.size()
|
||||
|| name_end[-1] != '/')
|
||||
{
|
||||
error_at(this->location_, "%s: bad extended name entry at header %lu",
|
||||
this->filename_.c_str(), static_cast<unsigned long>(off));
|
||||
return false;
|
||||
}
|
||||
pname->assign(name, name_end - 1 - name);
|
||||
if (nested_off != NULL)
|
||||
*nested_off = y;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the file and offset for an archive member.
|
||||
|
||||
bool
|
||||
Archive_file::get_file_and_offset(off_t off, const std::string& hdrname,
|
||||
off_t nested_off, int* memfd, off_t* memoff,
|
||||
std::string* memname)
|
||||
{
|
||||
if (!this->is_thin_archive_)
|
||||
{
|
||||
*memfd = this->fd_;
|
||||
*memoff = off + sizeof(Archive_header);
|
||||
*memname = this->filename_ + '(' + hdrname + ')';
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string filename = hdrname;
|
||||
if (!IS_ABSOLUTE_PATH(filename.c_str()))
|
||||
{
|
||||
const char* archive_path = this->filename_.c_str();
|
||||
const char* basename = lbasename(archive_path);
|
||||
if (basename > archive_path)
|
||||
filename.replace(0, 0,
|
||||
this->filename_.substr(0, basename - archive_path));
|
||||
}
|
||||
|
||||
if (nested_off > 0)
|
||||
{
|
||||
// This is a member of a nested archive.
|
||||
Archive_file* nfile;
|
||||
Nested_archive_table::const_iterator p =
|
||||
this->nested_archives_.find(filename);
|
||||
if (p != this->nested_archives_.end())
|
||||
nfile = p->second;
|
||||
else
|
||||
{
|
||||
int nfd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (nfd < 0)
|
||||
{
|
||||
error_at(this->location_, "%s: can't open nested archive %s",
|
||||
this->filename_.c_str(), filename.c_str());
|
||||
return false;
|
||||
}
|
||||
nfile = new Archive_file(filename, nfd, this->location_);
|
||||
if (!nfile->initialize())
|
||||
{
|
||||
delete nfile;
|
||||
return false;
|
||||
}
|
||||
this->nested_archives_[filename] = nfile;
|
||||
}
|
||||
|
||||
std::string nname;
|
||||
off_t nsize;
|
||||
off_t nnested_off;
|
||||
if (!nfile->read_header(nested_off, &nname, &nsize, &nnested_off))
|
||||
return false;
|
||||
return nfile->get_file_and_offset(nested_off, nname, nnested_off,
|
||||
memfd, memoff, memname);
|
||||
}
|
||||
|
||||
// An external member of a thin archive.
|
||||
*memfd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (*memfd < 0)
|
||||
{
|
||||
error_at(this->location_, "%s: %m", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
*memoff = 0;
|
||||
*memname = filename;
|
||||
return true;
|
||||
}
|
||||
|
||||
// An archive member iterator. This is more-or-less copied from gold.
|
||||
|
||||
class Archive_iterator
|
||||
{
|
||||
public:
|
||||
// The header of an archive member. This is what this iterator
|
||||
// points to.
|
||||
struct Header
|
||||
{
|
||||
// The name of the member.
|
||||
std::string name;
|
||||
// The file offset of the member.
|
||||
off_t off;
|
||||
// The file offset of a nested archive member.
|
||||
off_t nested_off;
|
||||
// The size of the member.
|
||||
off_t size;
|
||||
};
|
||||
|
||||
Archive_iterator(Archive_file* afile, off_t off)
|
||||
: afile_(afile), off_(off)
|
||||
{ this->read_next_header(); }
|
||||
|
||||
const Header&
|
||||
operator*() const
|
||||
{ return this->header_; }
|
||||
|
||||
const Header*
|
||||
operator->() const
|
||||
{ return &this->header_; }
|
||||
|
||||
Archive_iterator&
|
||||
operator++()
|
||||
{
|
||||
if (this->off_ == this->afile_->filesize())
|
||||
return *this;
|
||||
this->off_ += sizeof(Archive_header);
|
||||
if (!this->afile_->is_thin_archive())
|
||||
this->off_ += this->header_.size;
|
||||
if ((this->off_ & 1) != 0)
|
||||
++this->off_;
|
||||
this->read_next_header();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Archive_iterator
|
||||
operator++(int)
|
||||
{
|
||||
Archive_iterator ret = *this;
|
||||
++*this;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const Archive_iterator p) const
|
||||
{ return this->off_ == p->off; }
|
||||
|
||||
bool
|
||||
operator!=(const Archive_iterator p) const
|
||||
{ return this->off_ != p->off; }
|
||||
|
||||
private:
|
||||
void
|
||||
read_next_header();
|
||||
|
||||
// The underlying archive file.
|
||||
Archive_file* afile_;
|
||||
// The current offset in the file.
|
||||
off_t off_;
|
||||
// The current archive header.
|
||||
Header header_;
|
||||
};
|
||||
|
||||
// Read the next archive header.
|
||||
|
||||
void
|
||||
Archive_iterator::read_next_header()
|
||||
{
|
||||
off_t filesize = this->afile_->filesize();
|
||||
while (true)
|
||||
{
|
||||
if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
|
||||
{
|
||||
if (filesize != this->off_)
|
||||
{
|
||||
error_at(this->afile_->location(),
|
||||
"%s: short archive header at %lu",
|
||||
this->afile_->filename().c_str(),
|
||||
static_cast<unsigned long>(this->off_));
|
||||
this->off_ = filesize;
|
||||
}
|
||||
this->header_.off = filesize;
|
||||
return;
|
||||
}
|
||||
|
||||
char buf[sizeof(Archive_header)];
|
||||
if (!this->afile_->read(this->off_, sizeof(Archive_header), buf))
|
||||
{
|
||||
this->header_.off = filesize;
|
||||
return;
|
||||
}
|
||||
|
||||
const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
|
||||
if (!this->afile_->interpret_header(hdr, this->off_, &this->header_.name,
|
||||
&this->header_.size,
|
||||
&this->header_.nested_off))
|
||||
{
|
||||
this->header_.off = filesize;
|
||||
return;
|
||||
}
|
||||
this->header_.off = this->off_;
|
||||
|
||||
// Skip special members.
|
||||
if (!this->header_.name.empty() && this->header_.name != "/")
|
||||
return;
|
||||
|
||||
this->off_ += sizeof(Archive_header) + this->header_.size;
|
||||
if ((this->off_ & 1) != 0)
|
||||
++this->off_;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial iterator.
|
||||
|
||||
Archive_iterator
|
||||
archive_begin(Archive_file* afile)
|
||||
{
|
||||
return Archive_iterator(afile, sizeof(armag));
|
||||
}
|
||||
|
||||
// Final iterator.
|
||||
|
||||
Archive_iterator
|
||||
archive_end(Archive_file* afile)
|
||||
{
|
||||
return Archive_iterator(afile, afile->filesize());
|
||||
}
|
||||
|
||||
// A type of Import_stream which concatenates other Import_streams
|
||||
// together.
|
||||
|
||||
class Stream_concatenate : public Import::Stream
|
||||
{
|
||||
public:
|
||||
Stream_concatenate()
|
||||
: inputs_()
|
||||
{ }
|
||||
|
||||
// Add a new stream.
|
||||
void
|
||||
add(Import::Stream* is)
|
||||
{ this->inputs_.push_back(is); }
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_peek(size_t, const char**);
|
||||
|
||||
void
|
||||
do_advance(size_t);
|
||||
|
||||
private:
|
||||
std::list<Import::Stream*> inputs_;
|
||||
};
|
||||
|
||||
// Peek ahead.
|
||||
|
||||
bool
|
||||
Stream_concatenate::do_peek(size_t length, const char** bytes)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (this->inputs_.empty())
|
||||
return false;
|
||||
if (this->inputs_.front()->peek(length, bytes))
|
||||
return true;
|
||||
delete this->inputs_.front();
|
||||
this->inputs_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
// Advance.
|
||||
|
||||
void
|
||||
Stream_concatenate::do_advance(size_t skip)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (this->inputs_.empty())
|
||||
return;
|
||||
if (!this->inputs_.front()->at_eof())
|
||||
{
|
||||
// We just assume that this will do the right thing. It
|
||||
// should be OK since we should never want to skip past
|
||||
// multiple streams.
|
||||
this->inputs_.front()->advance(skip);
|
||||
return;
|
||||
}
|
||||
delete this->inputs_.front();
|
||||
this->inputs_.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
// Import data from an archive. We walk through the archive and
|
||||
// import data from each member.
|
||||
|
||||
Import::Stream*
|
||||
Import::find_archive_export_data(const std::string& filename, int fd,
|
||||
source_location location)
|
||||
{
|
||||
Archive_file afile(filename, fd, location);
|
||||
if (!afile.initialize())
|
||||
return NULL;
|
||||
|
||||
Stream_concatenate* ret = new Stream_concatenate;
|
||||
|
||||
bool any_data = false;
|
||||
bool any_members = false;
|
||||
Archive_iterator pend = archive_end(&afile);
|
||||
for (Archive_iterator p = archive_begin(&afile); p != pend; p++)
|
||||
{
|
||||
any_members = true;
|
||||
int member_fd;
|
||||
off_t member_off;
|
||||
std::string member_name;
|
||||
if (!afile.get_file_and_offset(p->off, p->name, p->nested_off,
|
||||
&member_fd, &member_off, &member_name))
|
||||
return NULL;
|
||||
|
||||
Import::Stream* is = Import::find_object_export_data(member_name,
|
||||
member_fd,
|
||||
member_off,
|
||||
location);
|
||||
if (is != NULL)
|
||||
{
|
||||
ret->add(is);
|
||||
any_data = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!any_members)
|
||||
{
|
||||
// It's normal to have an empty archive file when using gobuild.
|
||||
return new Stream_from_string("");
|
||||
}
|
||||
|
||||
if (!any_data)
|
||||
{
|
||||
delete ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
892
gcc/go/gofrontend/import.cc
Normal file
892
gcc/go/gofrontend/import.cc
Normal file
|
@ -0,0 +1,892 @@
|
|||
// import.cc -- Go frontend import declarations.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "filenames.h"
|
||||
#include "simple-object.h"
|
||||
|
||||
#include "go-c.h"
|
||||
#include "gogo.h"
|
||||
#include "types.h"
|
||||
#include "export.h"
|
||||
#include "import.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
// The list of paths we search for import files.
|
||||
|
||||
static std::vector<std::string> search_path;
|
||||
|
||||
// Add a directory to the search path. This is called from the option
|
||||
// handling language hook.
|
||||
|
||||
GO_EXTERN_C
|
||||
void
|
||||
go_add_search_path(const char* path)
|
||||
{
|
||||
search_path.push_back(std::string(path));
|
||||
}
|
||||
|
||||
// The name used for parameters, receivers, and results in imported
|
||||
// function types.
|
||||
|
||||
const char* const Import::import_marker = "*imported*";
|
||||
|
||||
// Find import data. This searches the file system for FILENAME and
|
||||
// returns a pointer to a Stream object to read the data that it
|
||||
// exports. If the file is not found, it returns NULL.
|
||||
|
||||
// When FILENAME is not an absolute path, we use the search path
|
||||
// provided by -I and -L options.
|
||||
|
||||
// When FILENAME does not exist, we try modifying FILENAME to find the
|
||||
// file. We use the first of these which exists:
|
||||
// * We append ".gox".
|
||||
// * We turn the base of FILENAME into libFILENAME.so.
|
||||
// * We turn the base of FILENAME into libFILENAME.a.
|
||||
// * We append ".o".
|
||||
|
||||
// When using a search path, we apply each of these transformations at
|
||||
// each entry on the search path before moving on to the next entry.
|
||||
// If the file exists, but does not contain any Go export data, we
|
||||
// stop; we do not keep looking for another file with the same name
|
||||
// later in the search path.
|
||||
|
||||
Import::Stream*
|
||||
Import::open_package(const std::string& filename, source_location location)
|
||||
{
|
||||
if (!IS_ABSOLUTE_PATH(filename))
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator p = search_path.begin();
|
||||
p != search_path.end();
|
||||
++p)
|
||||
{
|
||||
std::string indir = *p;
|
||||
if (!indir.empty() && indir[indir.size() - 1] != '/')
|
||||
indir += '/';
|
||||
indir += filename;
|
||||
Stream* s = Import::try_package_in_directory(indir, location);
|
||||
if (s != NULL)
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
Stream* s = Import::try_package_in_directory(filename, location);
|
||||
if (s != NULL)
|
||||
return s;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try to find the export data for FILENAME.
|
||||
|
||||
Import::Stream*
|
||||
Import::try_package_in_directory(const std::string& filename,
|
||||
source_location location)
|
||||
{
|
||||
std::string found_filename = filename;
|
||||
int fd = open(found_filename.c_str(), O_RDONLY | O_BINARY);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
struct stat s;
|
||||
if (fstat(fd, &s) >= 0 && S_ISDIR(s.st_mode))
|
||||
{
|
||||
close(fd);
|
||||
fd = -1;
|
||||
errno = EISDIR;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno != ENOENT && errno != EISDIR)
|
||||
warning_at(location, 0, "%s: %m", filename.c_str());
|
||||
|
||||
fd = Import::try_suffixes(&found_filename);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The export data may not be in this file.
|
||||
Stream* s = Import::find_export_data(found_filename, fd, location);
|
||||
if (s != NULL)
|
||||
return s;
|
||||
|
||||
close(fd);
|
||||
|
||||
error_at(location, "%s exists but does not contain any Go export data",
|
||||
found_filename.c_str());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Given import "*PFILENAME", where *PFILENAME does not exist, try
|
||||
// various suffixes. If we find one, set *PFILENAME to the one we
|
||||
// found. Return the open file descriptor.
|
||||
|
||||
int
|
||||
Import::try_suffixes(std::string* pfilename)
|
||||
{
|
||||
std::string filename = *pfilename + ".gox";
|
||||
int fd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
*pfilename = filename;
|
||||
return fd;
|
||||
}
|
||||
|
||||
const char* basename = lbasename(pfilename->c_str());
|
||||
size_t basename_pos = basename - pfilename->c_str();
|
||||
filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".so";
|
||||
fd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
*pfilename = filename;
|
||||
return fd;
|
||||
}
|
||||
|
||||
filename = pfilename->substr(0, basename_pos) + "lib" + basename + ".a";
|
||||
fd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
*pfilename = filename;
|
||||
return fd;
|
||||
}
|
||||
|
||||
filename = *pfilename + ".o";
|
||||
fd = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
*pfilename = filename;
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Look for export data in the file descriptor FD.
|
||||
|
||||
Import::Stream*
|
||||
Import::find_export_data(const std::string& filename, int fd,
|
||||
source_location location)
|
||||
{
|
||||
// See if we can read this as an object file.
|
||||
Import::Stream* stream = Import::find_object_export_data(filename, fd, 0,
|
||||
location);
|
||||
if (stream != NULL)
|
||||
return stream;
|
||||
|
||||
const int len = MAX(Export::v1_magic_len, Import::archive_magic_len);
|
||||
|
||||
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||
{
|
||||
error_at(location, "lseek %s failed: %m", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char buf[len];
|
||||
ssize_t c = read(fd, buf, len);
|
||||
if (c < len)
|
||||
return NULL;
|
||||
|
||||
// Check for a file containing nothing but Go export data.
|
||||
if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0)
|
||||
return new Stream_from_file(fd);
|
||||
|
||||
// See if we can read this as an archive.
|
||||
if (Import::is_archive_magic(buf))
|
||||
return Import::find_archive_export_data(filename, fd, location);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Look for export data in a simple_object.
|
||||
|
||||
Import::Stream*
|
||||
Import::find_object_export_data(const std::string& filename,
|
||||
int fd,
|
||||
off_t offset,
|
||||
source_location location)
|
||||
{
|
||||
const char* errmsg;
|
||||
int err;
|
||||
simple_object_read* sobj = simple_object_start_read(fd, offset,
|
||||
"__GNU_GO",
|
||||
&errmsg, &err);
|
||||
if (sobj == NULL)
|
||||
return NULL;
|
||||
|
||||
off_t sec_offset;
|
||||
off_t sec_length;
|
||||
int found = simple_object_find_section(sobj, ".go_export", &sec_offset,
|
||||
&sec_length, &errmsg, &err);
|
||||
|
||||
simple_object_release_read(sobj);
|
||||
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
if (lseek(fd, offset + sec_offset, SEEK_SET) < 0)
|
||||
{
|
||||
error_at(location, "lseek %s failed: %m", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* buf = new char[sec_length];
|
||||
ssize_t c = read(fd, buf, sec_length);
|
||||
if (c < 0)
|
||||
{
|
||||
error_at(location, "read %s failed: %m", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
if (c < sec_length)
|
||||
{
|
||||
error_at(location, "%s: short read", filename.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new Stream_from_buffer(buf, sec_length);
|
||||
}
|
||||
|
||||
// Class Import.
|
||||
|
||||
// Construct an Import object. We make the builtin_types_ vector
|
||||
// large enough to hold all the builtin types.
|
||||
|
||||
Import::Import(Stream* stream, source_location location)
|
||||
: gogo_(NULL), stream_(stream), location_(location), package_(NULL),
|
||||
add_to_globals_(false),
|
||||
builtin_types_((- SMALLEST_BUILTIN_CODE) + 1),
|
||||
types_()
|
||||
{
|
||||
}
|
||||
|
||||
// Import the data in the associated stream.
|
||||
|
||||
Package*
|
||||
Import::import(Gogo* gogo, const std::string& local_name,
|
||||
bool is_local_name_exported)
|
||||
{
|
||||
// Hold on to the Gogo structure. Otherwise we need to pass it
|
||||
// through all the import functions, because we need it when reading
|
||||
// a type.
|
||||
this->gogo_ = gogo;
|
||||
|
||||
// A stream of export data can include data from more than one input
|
||||
// file. Here we loop over each input file.
|
||||
Stream* stream = this->stream_;
|
||||
while (!stream->at_eof() && !stream->saw_error())
|
||||
{
|
||||
// The vector of types is package specific.
|
||||
this->types_.clear();
|
||||
|
||||
stream->require_bytes(this->location_, Export::v1_magic,
|
||||
Export::v1_magic_len);
|
||||
|
||||
this->require_c_string("package ");
|
||||
std::string package_name = this->read_identifier();
|
||||
this->require_c_string(";\n");
|
||||
|
||||
this->require_c_string("prefix ");
|
||||
std::string unique_prefix = this->read_identifier();
|
||||
this->require_c_string(";\n");
|
||||
|
||||
this->package_ = gogo->add_imported_package(package_name, local_name,
|
||||
is_local_name_exported,
|
||||
unique_prefix,
|
||||
this->location_,
|
||||
&this->add_to_globals_);
|
||||
if (this->package_ == NULL)
|
||||
{
|
||||
stream->set_saw_error();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
this->require_c_string("priority ");
|
||||
std::string priority_string = this->read_identifier();
|
||||
int prio;
|
||||
if (!this->string_to_int(priority_string, false, &prio))
|
||||
return NULL;
|
||||
this->package_->set_priority(prio);
|
||||
this->require_c_string(";\n");
|
||||
|
||||
if (stream->match_c_string("import "))
|
||||
this->read_import_init_fns(gogo);
|
||||
|
||||
// Loop over all the input data for this package.
|
||||
while (!stream->saw_error())
|
||||
{
|
||||
if (stream->match_c_string("const "))
|
||||
this->import_const();
|
||||
else if (stream->match_c_string("type "))
|
||||
this->import_type();
|
||||
else if (stream->match_c_string("var "))
|
||||
this->import_var();
|
||||
else if (stream->match_c_string("func "))
|
||||
this->import_func(this->package_);
|
||||
else if (stream->match_c_string("checksum "))
|
||||
break;
|
||||
else
|
||||
{
|
||||
error_at(this->location_,
|
||||
("error in import data at %d: "
|
||||
"expected %<const%>, %<type%>, %<var%>, "
|
||||
"%<func%>, or %<checksum%>"),
|
||||
stream->pos());
|
||||
stream->set_saw_error();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// We currently ignore the checksum. In the future we could
|
||||
// store the checksum somewhere in the generated object and then
|
||||
// verify that the checksum matches at link time or at dynamic
|
||||
// load time.
|
||||
this->require_c_string("checksum ");
|
||||
stream->advance(Export::v1_checksum_len * 2);
|
||||
this->require_c_string(";\n");
|
||||
}
|
||||
|
||||
return this->package_;
|
||||
}
|
||||
|
||||
// Read the list of import control functions.
|
||||
|
||||
void
|
||||
Import::read_import_init_fns(Gogo* gogo)
|
||||
{
|
||||
this->require_c_string("import");
|
||||
while (!this->match_c_string(";"))
|
||||
{
|
||||
this->require_c_string(" ");
|
||||
std::string package_name = this->read_identifier();
|
||||
this->require_c_string(" ");
|
||||
std::string init_name = this->read_identifier();
|
||||
this->require_c_string(" ");
|
||||
std::string prio_string = this->read_identifier();
|
||||
int prio;
|
||||
if (!this->string_to_int(prio_string, false, &prio))
|
||||
return;
|
||||
gogo->add_import_init_fn(package_name, init_name, prio);
|
||||
}
|
||||
this->require_c_string(";\n");
|
||||
}
|
||||
|
||||
// Import a constant.
|
||||
|
||||
void
|
||||
Import::import_const()
|
||||
{
|
||||
std::string name;
|
||||
Type* type;
|
||||
Expression* expr;
|
||||
Named_constant::import_const(this, &name, &type, &expr);
|
||||
Typed_identifier tid(name, type, this->location_);
|
||||
Named_object* no = this->package_->add_constant(tid, expr);
|
||||
if (this->add_to_globals_)
|
||||
this->gogo_->add_named_object(no);
|
||||
}
|
||||
|
||||
// Import a type.
|
||||
|
||||
void
|
||||
Import::import_type()
|
||||
{
|
||||
Named_type* type;
|
||||
Named_type::import_named_type(this, &type);
|
||||
|
||||
// The named type has been added to the package by the type import
|
||||
// process. Here we need to make it visible to the parser, and it
|
||||
// to the global bindings if necessary.
|
||||
type->set_is_visible();
|
||||
|
||||
if (this->add_to_globals_)
|
||||
this->gogo_->add_named_type(type);
|
||||
}
|
||||
|
||||
// Import a variable.
|
||||
|
||||
void
|
||||
Import::import_var()
|
||||
{
|
||||
std::string name;
|
||||
Type* type;
|
||||
Variable::import_var(this, &name, &type);
|
||||
Variable* var = new Variable(type, NULL, true, false, false,
|
||||
this->location_);
|
||||
Named_object* no;
|
||||
no = this->package_->add_variable(name, var);
|
||||
if (this->add_to_globals_)
|
||||
this->gogo_->add_named_object(no);
|
||||
}
|
||||
|
||||
// Import a function into PACKAGE. PACKAGE is normally
|
||||
// THIS->PACKAGE_, but it will be different for a method associated
|
||||
// with a type defined in a different package.
|
||||
|
||||
Named_object*
|
||||
Import::import_func(Package* package)
|
||||
{
|
||||
std::string name;
|
||||
Typed_identifier* receiver;
|
||||
Typed_identifier_list* parameters;
|
||||
Typed_identifier_list* results;
|
||||
bool is_varargs;
|
||||
Function::import_func(this, &name, &receiver, ¶meters, &results,
|
||||
&is_varargs);
|
||||
Function_type *fntype = Type::make_function_type(receiver, parameters,
|
||||
results, this->location_);
|
||||
if (is_varargs)
|
||||
fntype->set_is_varargs();
|
||||
|
||||
source_location loc = this->location_;
|
||||
Named_object* no;
|
||||
if (fntype->is_method())
|
||||
{
|
||||
Type* rtype = receiver->type()->deref();
|
||||
if (rtype->is_error_type())
|
||||
return NULL;
|
||||
Named_type* named_rtype = rtype->named_type();
|
||||
gcc_assert(named_rtype != NULL);
|
||||
no = named_rtype->add_method_declaration(name, package, fntype, loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
no = package->add_function_declaration(name, fntype, loc);
|
||||
if (this->add_to_globals_)
|
||||
this->gogo_->add_named_object(no);
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
// Read a type in the import stream. This records the type by the
|
||||
// type index. If the type is named, it registers the name, but marks
|
||||
// it as invisible.
|
||||
|
||||
Type*
|
||||
Import::read_type()
|
||||
{
|
||||
Stream* stream = this->stream_;
|
||||
this->require_c_string("<type ");
|
||||
|
||||
std::string number;
|
||||
int c;
|
||||
while (true)
|
||||
{
|
||||
c = stream->get_char();
|
||||
if (c != '-' && (c < '0' || c > '9'))
|
||||
break;
|
||||
number += c;
|
||||
}
|
||||
|
||||
int index;
|
||||
if (!this->string_to_int(number, true, &index))
|
||||
return Type::make_error_type();
|
||||
|
||||
if (c == '>')
|
||||
{
|
||||
// This type was already defined.
|
||||
if (index < 0
|
||||
? (static_cast<size_t>(- index) >= this->builtin_types_.size()
|
||||
|| this->builtin_types_[- index] == NULL)
|
||||
: (static_cast<size_t>(index) >= this->types_.size()
|
||||
|| this->types_[index] == NULL))
|
||||
{
|
||||
error_at(this->location_,
|
||||
"error in import data at %d: bad type index %d",
|
||||
stream->pos(), index);
|
||||
stream->set_saw_error();
|
||||
return Type::make_error_type();
|
||||
}
|
||||
|
||||
return index < 0 ? this->builtin_types_[- index] : this->types_[index];
|
||||
}
|
||||
|
||||
if (c != ' ')
|
||||
{
|
||||
if (!stream->saw_error())
|
||||
error_at(this->location_,
|
||||
"error in import data at %d: expect %< %> or %<>%>'",
|
||||
stream->pos());
|
||||
stream->set_saw_error();
|
||||
stream->advance(1);
|
||||
return Type::make_error_type();
|
||||
}
|
||||
|
||||
if (index <= 0
|
||||
|| (static_cast<size_t>(index) < this->types_.size()
|
||||
&& this->types_[index] != NULL))
|
||||
{
|
||||
error_at(this->location_,
|
||||
"error in import data at %d: type index already defined",
|
||||
stream->pos());
|
||||
stream->set_saw_error();
|
||||
return Type::make_error_type();
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(index) >= this->types_.size())
|
||||
{
|
||||
int newsize = std::max(static_cast<size_t>(index) + 1,
|
||||
this->types_.size() * 2);
|
||||
this->types_.resize(newsize, NULL);
|
||||
}
|
||||
|
||||
if (stream->peek_char() != '"')
|
||||
{
|
||||
Type* type = Type::import_type(this);
|
||||
this->require_c_string(">");
|
||||
this->types_[index] = type;
|
||||
return type;
|
||||
}
|
||||
|
||||
// This type has a name.
|
||||
|
||||
stream->advance(1);
|
||||
std::string type_name;
|
||||
while ((c = stream->get_char()) != '"')
|
||||
type_name += c;
|
||||
|
||||
// If this type is in the current package, the name will be
|
||||
// .PREFIX.PACKAGE.NAME or simply NAME with no dots. Otherwise, a
|
||||
// non-hidden symbol will be PREFIX.PACKAGE.NAME and a hidden symbol
|
||||
// will be .PREFIX.PACKAGE.NAME.
|
||||
std::string package_name;
|
||||
std::string unique_prefix;
|
||||
if (type_name.find('.') != std::string::npos)
|
||||
{
|
||||
bool is_hidden = false;
|
||||
size_t start = 0;
|
||||
if (type_name[0] == '.')
|
||||
{
|
||||
++start;
|
||||
is_hidden = true;
|
||||
}
|
||||
size_t dot1 = type_name.find('.', start);
|
||||
size_t dot2;
|
||||
if (dot1 == std::string::npos)
|
||||
dot2 = std::string::npos;
|
||||
else
|
||||
dot2 = type_name.find('.', dot1 + 1);
|
||||
if (dot1 == std::string::npos || dot2 == std::string::npos)
|
||||
{
|
||||
error_at(this->location_,
|
||||
("error at import data at %d: missing dot in type name"),
|
||||
stream->pos());
|
||||
stream->set_saw_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
unique_prefix = type_name.substr(start, dot1 - start);
|
||||
package_name = type_name.substr(dot1 + 1, dot2 - (dot1 + 1));
|
||||
}
|
||||
if (!is_hidden)
|
||||
type_name.erase(0, dot2 + 1);
|
||||
}
|
||||
|
||||
this->require_c_string(" ");
|
||||
|
||||
// Declare the type in the appropriate package. If we haven't seen
|
||||
// it before, mark it as invisible. We declare it before we read
|
||||
// the actual definition of the type, since the definition may refer
|
||||
// to the type itself.
|
||||
Package* package;
|
||||
if (package_name.empty())
|
||||
package = this->package_;
|
||||
else
|
||||
package = this->gogo_->register_package(package_name, unique_prefix,
|
||||
UNKNOWN_LOCATION);
|
||||
|
||||
Named_object* no = package->bindings()->lookup(type_name);
|
||||
if (no == NULL)
|
||||
no = package->add_type_declaration(type_name, this->location_);
|
||||
else if (!no->is_type_declaration() && !no->is_type())
|
||||
{
|
||||
error_at(this->location_, "imported %<%s.%s%> both type and non-type",
|
||||
Gogo::message_name(package->name()).c_str(),
|
||||
Gogo::message_name(type_name).c_str());
|
||||
stream->set_saw_error();
|
||||
return Type::make_error_type();
|
||||
}
|
||||
else
|
||||
gcc_assert(no->package() == package);
|
||||
|
||||
if (this->types_[index] == NULL)
|
||||
{
|
||||
if (no->is_type_declaration())
|
||||
{
|
||||
// FIXME: It's silly to make a forward declaration every time.
|
||||
this->types_[index] = Type::make_forward_declaration(no);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert(no->is_type());
|
||||
this->types_[index] = no->type_value();
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no type definition, then this is just a forward
|
||||
// declaration of a type defined in some other file.
|
||||
Type* type;
|
||||
if (this->match_c_string(">"))
|
||||
type = this->types_[index];
|
||||
else
|
||||
{
|
||||
type = this->read_type();
|
||||
|
||||
if (no->is_type_declaration())
|
||||
{
|
||||
// We can define the type now.
|
||||
|
||||
no = package->add_type(type_name, type, this->location_);
|
||||
Named_type* ntype = no->type_value();
|
||||
|
||||
// This type has not yet been imported.
|
||||
ntype->clear_is_visible();
|
||||
|
||||
type = ntype;
|
||||
}
|
||||
else if (no->is_type())
|
||||
{
|
||||
// We have seen this type before. FIXME: it would be a good
|
||||
// idea to check that the two imported types are identical,
|
||||
// but we have not finalized the methds yet, which means
|
||||
// that we can nt reliably compare interface types.
|
||||
type = no->type_value();
|
||||
|
||||
// Don't change the visibility of the existing type.
|
||||
}
|
||||
|
||||
this->types_[index] = type;
|
||||
|
||||
// Read the type methods.
|
||||
if (this->match_c_string("\n"))
|
||||
{
|
||||
this->advance(1);
|
||||
while (this->match_c_string(" func"))
|
||||
{
|
||||
this->advance(1);
|
||||
this->import_func(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->require_c_string(">");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
// Register the builtin types.
|
||||
|
||||
void
|
||||
Import::register_builtin_types(Gogo* gogo)
|
||||
{
|
||||
this->register_builtin_type(gogo, "int8", BUILTIN_INT8);
|
||||
this->register_builtin_type(gogo, "int16", BUILTIN_INT16);
|
||||
this->register_builtin_type(gogo, "int32", BUILTIN_INT32);
|
||||
this->register_builtin_type(gogo, "int64", BUILTIN_INT64);
|
||||
this->register_builtin_type(gogo, "uint8", BUILTIN_UINT8);
|
||||
this->register_builtin_type(gogo, "uint16", BUILTIN_UINT16);
|
||||
this->register_builtin_type(gogo, "uint32", BUILTIN_UINT32);
|
||||
this->register_builtin_type(gogo, "uint64", BUILTIN_UINT64);
|
||||
this->register_builtin_type(gogo, "float32", BUILTIN_FLOAT32);
|
||||
this->register_builtin_type(gogo, "float64", BUILTIN_FLOAT64);
|
||||
this->register_builtin_type(gogo, "complex64", BUILTIN_COMPLEX64);
|
||||
this->register_builtin_type(gogo, "complex128", BUILTIN_COMPLEX128);
|
||||
this->register_builtin_type(gogo, "int", BUILTIN_INT);
|
||||
this->register_builtin_type(gogo, "uint", BUILTIN_UINT);
|
||||
this->register_builtin_type(gogo, "uintptr", BUILTIN_UINTPTR);
|
||||
this->register_builtin_type(gogo, "float", BUILTIN_FLOAT);
|
||||
this->register_builtin_type(gogo, "complex", BUILTIN_COMPLEX);
|
||||
this->register_builtin_type(gogo, "bool", BUILTIN_BOOL);
|
||||
this->register_builtin_type(gogo, "string", BUILTIN_STRING);
|
||||
}
|
||||
|
||||
// Register a single builtin type.
|
||||
|
||||
void
|
||||
Import::register_builtin_type(Gogo* gogo, const char* name, Builtin_code code)
|
||||
{
|
||||
Named_object* named_object = gogo->lookup_global(name);
|
||||
gcc_assert(named_object != NULL && named_object->is_type());
|
||||
int index = - static_cast<int>(code);
|
||||
gcc_assert(index > 0
|
||||
&& static_cast<size_t>(index) < this->builtin_types_.size());
|
||||
this->builtin_types_[index] = named_object->type_value();
|
||||
}
|
||||
|
||||
// Read an identifier from the stream.
|
||||
|
||||
std::string
|
||||
Import::read_identifier()
|
||||
{
|
||||
std::string ret;
|
||||
Stream* stream = this->stream_;
|
||||
int c;
|
||||
while (true)
|
||||
{
|
||||
c = stream->peek_char();
|
||||
if (c == -1 || c == ' ' || c == ';')
|
||||
break;
|
||||
ret += c;
|
||||
stream->advance(1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Turn a string into a integer with appropriate error handling.
|
||||
|
||||
bool
|
||||
Import::string_to_int(const std::string &s, bool is_neg_ok, int* ret)
|
||||
{
|
||||
char* end;
|
||||
long prio = strtol(s.c_str(), &end, 10);
|
||||
if (*end != '\0' || prio > 0x7fffffff || (prio < 0 && !is_neg_ok))
|
||||
{
|
||||
error_at(this->location_, "invalid integer in import data at %d",
|
||||
this->stream_->pos());
|
||||
this->stream_->set_saw_error();
|
||||
return false;
|
||||
}
|
||||
*ret = prio;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Class Import::Stream.
|
||||
|
||||
Import::Stream::Stream()
|
||||
: pos_(0), saw_error_(false)
|
||||
{
|
||||
}
|
||||
|
||||
Import::Stream::~Stream()
|
||||
{
|
||||
}
|
||||
|
||||
// Return the next character to come from the stream.
|
||||
|
||||
int
|
||||
Import::Stream::peek_char()
|
||||
{
|
||||
const char* read;
|
||||
if (!this->do_peek(1, &read))
|
||||
return -1;
|
||||
// Make sure we return an unsigned char, so that we don't get
|
||||
// confused by \xff.
|
||||
unsigned char ret = *read;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Return true if the next LENGTH characters from the stream match
|
||||
// BYTES
|
||||
|
||||
bool
|
||||
Import::Stream::match_bytes(const char* bytes, size_t length)
|
||||
{
|
||||
const char* read;
|
||||
if (!this->do_peek(length, &read))
|
||||
return false;
|
||||
return memcmp(bytes, read, length) == 0;
|
||||
}
|
||||
|
||||
// Require that the next LENGTH bytes from the stream match BYTES.
|
||||
|
||||
void
|
||||
Import::Stream::require_bytes(source_location location, const char* bytes,
|
||||
size_t length)
|
||||
{
|
||||
const char* read;
|
||||
if (!this->do_peek(length, &read)
|
||||
|| memcmp(bytes, read, length) != 0)
|
||||
{
|
||||
if (!this->saw_error_)
|
||||
error_at(location, "import error at %d: expected %<%.*s%>",
|
||||
this->pos(), static_cast<int>(length), bytes);
|
||||
this->saw_error_ = true;
|
||||
return;
|
||||
}
|
||||
this->advance(length);
|
||||
}
|
||||
|
||||
// Class Stream_from_file.
|
||||
|
||||
Stream_from_file::Stream_from_file(int fd)
|
||||
: fd_(fd), data_()
|
||||
{
|
||||
if (lseek(fd, 0, SEEK_SET) != 0)
|
||||
{
|
||||
error("lseek failed: %m");
|
||||
this->set_saw_error();
|
||||
}
|
||||
}
|
||||
|
||||
Stream_from_file::~Stream_from_file()
|
||||
{
|
||||
close(this->fd_);
|
||||
}
|
||||
|
||||
// Read next bytes.
|
||||
|
||||
bool
|
||||
Stream_from_file::do_peek(size_t length, const char** bytes)
|
||||
{
|
||||
if (this->data_.length() <= length)
|
||||
{
|
||||
*bytes = this->data_.data();
|
||||
return true;
|
||||
}
|
||||
// Don't bother to handle the general case, since we don't need it.
|
||||
gcc_assert(length < 64);
|
||||
char buf[64];
|
||||
ssize_t got = read(this->fd_, buf, length);
|
||||
|
||||
if (got < 0)
|
||||
{
|
||||
if (!this->saw_error())
|
||||
error("read failed: %m");
|
||||
this->set_saw_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lseek(this->fd_, - got, SEEK_CUR) != 0)
|
||||
{
|
||||
if (!this->saw_error())
|
||||
error("lseek failed: %m");
|
||||
this->set_saw_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(got) < length)
|
||||
return false;
|
||||
|
||||
this->data_.assign(buf, got);
|
||||
|
||||
*bytes = this->data_.data();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Advance.
|
||||
|
||||
void
|
||||
Stream_from_file::do_advance(size_t skip)
|
||||
{
|
||||
if (lseek(this->fd_, skip, SEEK_CUR) != 0)
|
||||
{
|
||||
if (!this->saw_error())
|
||||
error("lseek failed: %m");
|
||||
this->set_saw_error();
|
||||
}
|
||||
if (!this->data_.empty())
|
||||
{
|
||||
if (this->data_.length() < skip)
|
||||
this->data_.erase(0, skip);
|
||||
else
|
||||
this->data_.clear();
|
||||
}
|
||||
}
|
351
gcc/go/gofrontend/import.h
Normal file
351
gcc/go/gofrontend/import.h
Normal file
|
@ -0,0 +1,351 @@
|
|||
// import.h -- Go frontend import declarations. -*- C++ -*-
|
||||
|
||||
// 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 GO_IMPORT_H
|
||||
#define GO_IMPORT_H
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class Gogo;
|
||||
class Package;
|
||||
class Type;
|
||||
class Named_object;
|
||||
class Named_type;
|
||||
class Expression;
|
||||
|
||||
// This class manages importing Go declarations.
|
||||
|
||||
class Import
|
||||
{
|
||||
public:
|
||||
// The Stream class is an interface used to read the data. The
|
||||
// caller should instantiate a child of this class.
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
Stream();
|
||||
virtual ~Stream();
|
||||
|
||||
// Return whether we have seen an error.
|
||||
bool
|
||||
saw_error() const
|
||||
{ return this->saw_error_; }
|
||||
|
||||
// Record that we've seen an error.
|
||||
void
|
||||
set_saw_error()
|
||||
{ this->saw_error_ = true; }
|
||||
|
||||
// Return the next character (a value from 0 to 0xff) without
|
||||
// advancing. Returns -1 at end of stream.
|
||||
int
|
||||
peek_char();
|
||||
|
||||
// Look for LENGTH characters, setting *BYTES to point to them.
|
||||
// Returns false if the bytes are not available. Does not
|
||||
// advance.
|
||||
bool
|
||||
peek(size_t length, const char** bytes)
|
||||
{ return this->do_peek(length, bytes); }
|
||||
|
||||
// Return the next character (a value from 0 to 0xff) and advance
|
||||
// the read position by 1. Returns -1 at end of stream.
|
||||
int
|
||||
get_char()
|
||||
{
|
||||
int c = this->peek_char();
|
||||
this->advance(1);
|
||||
return c;
|
||||
}
|
||||
|
||||
// Return true if at the end of the stream.
|
||||
bool
|
||||
at_eof()
|
||||
{ return this->peek_char() == -1; }
|
||||
|
||||
// Return true if the next bytes match STR.
|
||||
bool
|
||||
match_c_string(const char* str)
|
||||
{ return this->match_bytes(str, strlen(str)); }
|
||||
|
||||
// Return true if the next LENGTH bytes match BYTES.
|
||||
bool
|
||||
match_bytes(const char* bytes, size_t length);
|
||||
|
||||
// Give an error if the next bytes do not match STR. Advance the
|
||||
// read position by the length of STR.
|
||||
void
|
||||
require_c_string(source_location location, const char* str)
|
||||
{ this->require_bytes(location, str, strlen(str)); }
|
||||
|
||||
// Given an error if the next LENGTH bytes do not match BYTES.
|
||||
// Advance the read position by LENGTH.
|
||||
void
|
||||
require_bytes(source_location, const char* bytes, size_t length);
|
||||
|
||||
// Advance the read position by SKIP bytes.
|
||||
void
|
||||
advance(size_t skip)
|
||||
{
|
||||
this->do_advance(skip);
|
||||
this->pos_ += skip;
|
||||
}
|
||||
|
||||
// Return the current read position. This returns int because it
|
||||
// is more convenient in error reporting. FIXME.
|
||||
int
|
||||
pos()
|
||||
{ return static_cast<int>(this->pos_); }
|
||||
|
||||
protected:
|
||||
// This function should set *BYTES to point to a buffer holding
|
||||
// the LENGTH bytes at the current read position. It should
|
||||
// return false if the bytes are not available. This should not
|
||||
// change the current read position.
|
||||
virtual bool
|
||||
do_peek(size_t length, const char** bytes) = 0;
|
||||
|
||||
// This function should advance the current read position LENGTH
|
||||
// bytes.
|
||||
virtual void
|
||||
do_advance(size_t skip) = 0;
|
||||
|
||||
private:
|
||||
// The current read position.
|
||||
size_t pos_;
|
||||
// True if we've seen an error reading from this stream.
|
||||
bool saw_error_;
|
||||
};
|
||||
|
||||
// Find import data. This searches the file system for FILENAME and
|
||||
// returns a pointer to a Stream object to read the data that it
|
||||
// exports. LOCATION is the location of the import statement.
|
||||
static Stream*
|
||||
open_package(const std::string& filename, source_location location);
|
||||
|
||||
// Constructor.
|
||||
Import(Stream*, source_location);
|
||||
|
||||
// Register the builtin types.
|
||||
void
|
||||
register_builtin_types(Gogo*);
|
||||
|
||||
// Import everything defined in the stream. LOCAL_NAME is the local
|
||||
// name to be used for bindings; if it is the string "." then
|
||||
// bindings should be inserted in the global scope. If LOCAL_NAME
|
||||
// is the empty string then the name of the package itself is the
|
||||
// local name. This returns the imported package, or NULL on error.
|
||||
Package*
|
||||
import(Gogo*, const std::string& local_name, bool is_local_name_exported);
|
||||
|
||||
// The location of the import statement.
|
||||
source_location
|
||||
location() const
|
||||
{ return this->location_; }
|
||||
|
||||
// Return the next character.
|
||||
int
|
||||
peek_char()
|
||||
{ return this->stream_->peek_char(); }
|
||||
|
||||
// Return the next character and advance.
|
||||
int
|
||||
get_char()
|
||||
{ return this->stream_->get_char(); }
|
||||
|
||||
// Return true at the end of the stream.
|
||||
bool
|
||||
at_eof()
|
||||
{ return this->stream_->at_eof(); }
|
||||
|
||||
// Return whether the next bytes match STR.
|
||||
bool
|
||||
match_c_string(const char* str)
|
||||
{ return this->stream_->match_c_string(str); }
|
||||
|
||||
// Require that the next bytes match STR.
|
||||
void
|
||||
require_c_string(const char* str)
|
||||
{ this->stream_->require_c_string(this->location_, str); }
|
||||
|
||||
// Advance the stream SKIP bytes.
|
||||
void
|
||||
advance(size_t skip)
|
||||
{ this->stream_->advance(skip); }
|
||||
|
||||
// Read an identifier.
|
||||
std::string
|
||||
read_identifier();
|
||||
|
||||
// Read a type.
|
||||
Type*
|
||||
read_type();
|
||||
|
||||
// The name used for parameters, receivers, and results in imported
|
||||
// function types.
|
||||
static const char* const import_marker;
|
||||
|
||||
private:
|
||||
static Stream*
|
||||
try_package_in_directory(const std::string&, source_location);
|
||||
|
||||
static int
|
||||
try_suffixes(std::string*);
|
||||
|
||||
static Stream*
|
||||
find_export_data(const std::string& filename, int fd, source_location);
|
||||
|
||||
static Stream*
|
||||
find_object_export_data(const std::string& filename, int fd,
|
||||
off_t offset, source_location);
|
||||
|
||||
static const int archive_magic_len = 8;
|
||||
|
||||
static bool
|
||||
is_archive_magic(const char*);
|
||||
|
||||
static Stream*
|
||||
find_archive_export_data(const std::string& filename, int fd,
|
||||
source_location);
|
||||
|
||||
// Read the import control functions.
|
||||
void
|
||||
read_import_init_fns(Gogo*);
|
||||
|
||||
// Import a constant.
|
||||
void
|
||||
import_const();
|
||||
|
||||
// Import a type.
|
||||
void
|
||||
import_type();
|
||||
|
||||
// Import a variable.
|
||||
void
|
||||
import_var();
|
||||
|
||||
// Import a function.
|
||||
Named_object*
|
||||
import_func(Package*);
|
||||
|
||||
// Register a single builtin type.
|
||||
void
|
||||
register_builtin_type(Gogo*, const char* name, Builtin_code);
|
||||
|
||||
// Get an integer from a string.
|
||||
bool
|
||||
string_to_int(const std::string&, bool is_neg_ok, int* ret);
|
||||
|
||||
// The general IR.
|
||||
Gogo* gogo_;
|
||||
// The stream from which to read import data.
|
||||
Stream* stream_;
|
||||
// The location of the import statement we are processing.
|
||||
source_location location_;
|
||||
// The package we are importing.
|
||||
Package* package_;
|
||||
// Whether to add new objects to the global scope, rather than to a
|
||||
// package scope.
|
||||
bool add_to_globals_;
|
||||
// Mapping from negated builtin type codes to Type structures.
|
||||
std::vector<Named_type*> builtin_types_;
|
||||
// Mapping from exported type codes to Type structures.
|
||||
std::vector<Type*> types_;
|
||||
};
|
||||
|
||||
// Read import data from a string.
|
||||
|
||||
class Stream_from_string : public Import::Stream
|
||||
{
|
||||
public:
|
||||
Stream_from_string(const std::string& str)
|
||||
: str_(str), pos_(0)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_peek(size_t length, const char** bytes)
|
||||
{
|
||||
if (this->pos_ + length > this->str_.length())
|
||||
return false;
|
||||
*bytes = this->str_.data() + this->pos_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
do_advance(size_t len)
|
||||
{ this->pos_ += len; }
|
||||
|
||||
private:
|
||||
// The string of data we are reading.
|
||||
std::string str_;
|
||||
// The current position within the string.
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
// Read import data from an allocated buffer.
|
||||
|
||||
class Stream_from_buffer : public Import::Stream
|
||||
{
|
||||
public:
|
||||
Stream_from_buffer(char* buf, size_t length)
|
||||
: buf_(buf), length_(length), pos_(0)
|
||||
{ }
|
||||
|
||||
~Stream_from_buffer()
|
||||
{ delete[] this->buf_; }
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_peek(size_t length, const char** bytes)
|
||||
{
|
||||
if (this->pos_ + length > this->length_)
|
||||
return false;
|
||||
*bytes = this->buf_ + this->pos_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
do_advance(size_t len)
|
||||
{ this->pos_ += len; }
|
||||
|
||||
private:
|
||||
// The data we are reading.
|
||||
char* buf_;
|
||||
// The length of the buffer.
|
||||
size_t length_;
|
||||
// The current position within the buffer.
|
||||
size_t pos_;
|
||||
};
|
||||
|
||||
// Read import data from an open file descriptor.
|
||||
|
||||
class Stream_from_file : public Import::Stream
|
||||
{
|
||||
public:
|
||||
Stream_from_file(int fd);
|
||||
|
||||
~Stream_from_file();
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_peek(size_t, const char**);
|
||||
|
||||
void
|
||||
do_advance(size_t);
|
||||
|
||||
private:
|
||||
// No copying.
|
||||
Stream_from_file(const Stream_from_file&);
|
||||
Stream_from_file& operator=(const Stream_from_file&);
|
||||
|
||||
// The file descriptor.
|
||||
int fd_;
|
||||
// Data read from the file.
|
||||
std::string data_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_IMPORT_H)
|
2287
gcc/go/gofrontend/lex.cc
Normal file
2287
gcc/go/gofrontend/lex.cc
Normal file
File diff suppressed because it is too large
Load diff
446
gcc/go/gofrontend/lex.h
Normal file
446
gcc/go/gofrontend/lex.h
Normal file
|
@ -0,0 +1,446 @@
|
|||
// lex.h -- Go frontend lexer. -*- C++ -*-
|
||||
|
||||
// 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 GO_LEX_H
|
||||
#define GO_LEX_H
|
||||
|
||||
#include <gmp.h>
|
||||
#include <mpfr.h>
|
||||
|
||||
#include "operator.h"
|
||||
|
||||
struct Unicode_range;
|
||||
|
||||
// The keywords. These must be in sorted order, other than
|
||||
// KEYWORD_INVALID. They must match the Keywords::mapping_ array in
|
||||
// lex.cc.
|
||||
|
||||
enum Keyword
|
||||
{
|
||||
KEYWORD_INVALID, // Not a keyword.
|
||||
KEYWORD_ASM,
|
||||
KEYWORD_BREAK,
|
||||
KEYWORD_CASE,
|
||||
KEYWORD_CHAN,
|
||||
KEYWORD_CONST,
|
||||
KEYWORD_CONTINUE,
|
||||
KEYWORD_DEFAULT,
|
||||
KEYWORD_DEFER,
|
||||
KEYWORD_ELSE,
|
||||
KEYWORD_FALLTHROUGH,
|
||||
KEYWORD_FOR,
|
||||
KEYWORD_FUNC,
|
||||
KEYWORD_GO,
|
||||
KEYWORD_GOTO,
|
||||
KEYWORD_IF,
|
||||
KEYWORD_IMPORT,
|
||||
KEYWORD_INTERFACE,
|
||||
KEYWORD_MAP,
|
||||
KEYWORD_PACKAGE,
|
||||
KEYWORD_RANGE,
|
||||
KEYWORD_RETURN,
|
||||
KEYWORD_SELECT,
|
||||
KEYWORD_STRUCT,
|
||||
KEYWORD_SWITCH,
|
||||
KEYWORD_TYPE,
|
||||
KEYWORD_VAR
|
||||
};
|
||||
|
||||
// A token returned from the lexer.
|
||||
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
// Token classification.
|
||||
enum Classification
|
||||
{
|
||||
// Token is invalid.
|
||||
TOKEN_INVALID,
|
||||
// Token indicates end of input.
|
||||
TOKEN_EOF,
|
||||
// Token is a keyword.
|
||||
TOKEN_KEYWORD,
|
||||
// Token is an identifier.
|
||||
TOKEN_IDENTIFIER,
|
||||
// Token is a string of characters.
|
||||
TOKEN_STRING,
|
||||
// Token is an operator.
|
||||
TOKEN_OPERATOR,
|
||||
// Token is an integer.
|
||||
TOKEN_INTEGER,
|
||||
// Token is a floating point number.
|
||||
TOKEN_FLOAT,
|
||||
// Token is an imaginary number.
|
||||
TOKEN_IMAGINARY
|
||||
};
|
||||
|
||||
~Token();
|
||||
Token(const Token&);
|
||||
Token& operator=(const Token&);
|
||||
|
||||
// Get token classification.
|
||||
Classification
|
||||
classification() const
|
||||
{ return this->classification_; }
|
||||
|
||||
// Make a token for an invalid value.
|
||||
static Token
|
||||
make_invalid_token(source_location location)
|
||||
{ return Token(TOKEN_INVALID, location); }
|
||||
|
||||
// Make a token representing end of file.
|
||||
static Token
|
||||
make_eof_token(source_location location)
|
||||
{ return Token(TOKEN_EOF, location); }
|
||||
|
||||
// Make a keyword token.
|
||||
static Token
|
||||
make_keyword_token(Keyword keyword, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_KEYWORD, location);
|
||||
tok.u_.keyword = keyword;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make an identifier token.
|
||||
static Token
|
||||
make_identifier_token(const std::string& value, bool is_exported,
|
||||
source_location location)
|
||||
{
|
||||
Token tok(TOKEN_IDENTIFIER, location);
|
||||
tok.u_.identifier_value.name = new std::string(value);
|
||||
tok.u_.identifier_value.is_exported = is_exported;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make a quoted string token.
|
||||
static Token
|
||||
make_string_token(const std::string& value, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_STRING, location);
|
||||
tok.u_.string_value = new std::string(value);
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make an operator token.
|
||||
static Token
|
||||
make_operator_token(Operator op, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_OPERATOR, location);
|
||||
tok.u_.op = op;
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make an integer token.
|
||||
static Token
|
||||
make_integer_token(mpz_t val, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_INTEGER, location);
|
||||
mpz_init(tok.u_.integer_value);
|
||||
mpz_swap(tok.u_.integer_value, val);
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make a float token.
|
||||
static Token
|
||||
make_float_token(mpfr_t val, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_FLOAT, location);
|
||||
mpfr_init(tok.u_.float_value);
|
||||
mpfr_swap(tok.u_.float_value, val);
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Make a token for an imaginary number.
|
||||
static Token
|
||||
make_imaginary_token(mpfr_t val, source_location location)
|
||||
{
|
||||
Token tok(TOKEN_IMAGINARY, location);
|
||||
mpfr_init(tok.u_.float_value);
|
||||
mpfr_swap(tok.u_.float_value, val);
|
||||
return tok;
|
||||
}
|
||||
|
||||
// Get the location of the token.
|
||||
source_location
|
||||
location() const
|
||||
{ return this->location_; }
|
||||
|
||||
// Return whether this is an invalid token.
|
||||
bool
|
||||
is_invalid() const
|
||||
{ return this->classification_ == TOKEN_INVALID; }
|
||||
|
||||
// Return whether this is the EOF token.
|
||||
bool
|
||||
is_eof() const
|
||||
{ return this->classification_ == TOKEN_EOF; }
|
||||
|
||||
// Return the keyword value for a keyword token.
|
||||
Keyword
|
||||
keyword() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_KEYWORD);
|
||||
return this->u_.keyword;
|
||||
}
|
||||
|
||||
// Return whether this is an identifier.
|
||||
bool
|
||||
is_identifier() const
|
||||
{ return this->classification_ == TOKEN_IDENTIFIER; }
|
||||
|
||||
// Return the identifier.
|
||||
const std::string&
|
||||
identifier() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_IDENTIFIER);
|
||||
return *this->u_.identifier_value.name;
|
||||
}
|
||||
|
||||
// Return whether the identifier is exported.
|
||||
bool
|
||||
is_identifier_exported() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_IDENTIFIER);
|
||||
return this->u_.identifier_value.is_exported;
|
||||
}
|
||||
|
||||
// Return whether this is a string.
|
||||
bool
|
||||
is_string() const
|
||||
{
|
||||
return this->classification_ == TOKEN_STRING;
|
||||
}
|
||||
|
||||
// Return the value of a string. The returned value is a string of
|
||||
// UTF-8 characters.
|
||||
std::string
|
||||
string_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_STRING);
|
||||
return *this->u_.string_value;
|
||||
}
|
||||
|
||||
// Return the value of an integer.
|
||||
const mpz_t*
|
||||
integer_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_INTEGER);
|
||||
return &this->u_.integer_value;
|
||||
}
|
||||
|
||||
// Return the value of a float.
|
||||
const mpfr_t*
|
||||
float_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_FLOAT);
|
||||
return &this->u_.float_value;
|
||||
}
|
||||
|
||||
// Return the value of an imaginary number.
|
||||
const mpfr_t*
|
||||
imaginary_value() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_IMAGINARY);
|
||||
return &this->u_.float_value;
|
||||
}
|
||||
|
||||
// Return the operator value for an operator token.
|
||||
Operator
|
||||
op() const
|
||||
{
|
||||
gcc_assert(this->classification_ == TOKEN_OPERATOR);
|
||||
return this->u_.op;
|
||||
}
|
||||
|
||||
// Return whether this token is KEYWORD.
|
||||
bool
|
||||
is_keyword(Keyword keyword) const
|
||||
{
|
||||
return (this->classification_ == TOKEN_KEYWORD
|
||||
&& this->u_.keyword == keyword);
|
||||
}
|
||||
|
||||
// Return whether this token is OP.
|
||||
bool
|
||||
is_op(Operator op) const
|
||||
{ return this->classification_ == TOKEN_OPERATOR && this->u_.op == op; }
|
||||
|
||||
// Print the token for debugging.
|
||||
void
|
||||
print(FILE*) const;
|
||||
|
||||
private:
|
||||
// Private constructor used by make_..._token functions above.
|
||||
Token(Classification, source_location);
|
||||
|
||||
// Clear the token.
|
||||
void
|
||||
clear();
|
||||
|
||||
// The token classification.
|
||||
Classification classification_;
|
||||
union
|
||||
{
|
||||
// The keyword value for TOKEN_KEYWORD.
|
||||
Keyword keyword;
|
||||
// The token value for TOKEN_IDENTIFIER.
|
||||
struct
|
||||
{
|
||||
// The name of the identifier. This has been mangled to only
|
||||
// include ASCII characters.
|
||||
std::string* name;
|
||||
// Whether this name should be exported. This is true if the
|
||||
// first letter in the name is upper case.
|
||||
bool is_exported;
|
||||
} identifier_value;
|
||||
// The string value for TOKEN_STRING.
|
||||
std::string* string_value;
|
||||
// The token value for TOKEN_INTEGER.
|
||||
mpz_t integer_value;
|
||||
// The token value for TOKEN_FLOAT or TOKEN_IMAGINARY.
|
||||
mpfr_t float_value;
|
||||
// The token value for TOKEN_OPERATOR or the keyword value
|
||||
Operator op;
|
||||
} u_;
|
||||
// The source location.
|
||||
source_location location_;
|
||||
};
|
||||
|
||||
// The lexer itself.
|
||||
|
||||
class Lex
|
||||
{
|
||||
public:
|
||||
Lex(const char* input_file_name, FILE* input_file);
|
||||
|
||||
~Lex();
|
||||
|
||||
// Return the next token.
|
||||
Token
|
||||
next_token();
|
||||
|
||||
// Return whether the identifier NAME should be exported. NAME is a
|
||||
// mangled name which includes only ASCII characters.
|
||||
static bool
|
||||
is_exported_name(const std::string& name);
|
||||
|
||||
// A helper function. Append V to STR. IS_CHARACTER is true if V
|
||||
// is a Unicode character which should be converted into UTF-8,
|
||||
// false if it is a byte value to be appended directly. The
|
||||
// location is used to warn about an out of range character.
|
||||
static void
|
||||
append_char(unsigned int v, bool is_charater, std::string* str,
|
||||
source_location);
|
||||
|
||||
// A helper function. Fetch a UTF-8 character from STR and store it
|
||||
// in *VALUE. Return the number of bytes read from STR. Return 0
|
||||
// if STR does not point to a valid UTF-8 character.
|
||||
static int
|
||||
fetch_char(const char* str, unsigned int *value);
|
||||
|
||||
private:
|
||||
ssize_t
|
||||
get_line();
|
||||
|
||||
bool
|
||||
require_line();
|
||||
|
||||
// The current location.
|
||||
source_location
|
||||
location() const;
|
||||
|
||||
// A position CHARS column positions before the current location.
|
||||
source_location
|
||||
earlier_location(int chars) const;
|
||||
|
||||
static bool
|
||||
is_hex_digit(char);
|
||||
|
||||
static unsigned char
|
||||
octal_value(char c)
|
||||
{ return c - '0'; }
|
||||
|
||||
Token
|
||||
make_invalid_token()
|
||||
{ return Token::make_invalid_token(this->location()); }
|
||||
|
||||
Token
|
||||
make_eof_token()
|
||||
{ return Token::make_eof_token(this->location()); }
|
||||
|
||||
Token
|
||||
make_operator(Operator op, int chars)
|
||||
{ return Token::make_operator_token(op, this->earlier_location(chars)); }
|
||||
|
||||
Token
|
||||
gather_identifier();
|
||||
|
||||
Token
|
||||
gather_number();
|
||||
|
||||
Token
|
||||
gather_character();
|
||||
|
||||
Token
|
||||
gather_string();
|
||||
|
||||
Token
|
||||
gather_raw_string();
|
||||
|
||||
const char*
|
||||
advance_one_utf8_char(const char*, unsigned int*, bool*);
|
||||
|
||||
const char*
|
||||
advance_one_char(const char*, bool, unsigned int*, bool*);
|
||||
|
||||
static bool
|
||||
is_unicode_digit(unsigned int c);
|
||||
|
||||
static bool
|
||||
is_unicode_letter(unsigned int c);
|
||||
|
||||
static bool
|
||||
is_unicode_uppercase(unsigned int c);
|
||||
|
||||
static bool
|
||||
is_in_unicode_range(unsigned int C, const Unicode_range* ranges,
|
||||
size_t range_size);
|
||||
|
||||
Operator
|
||||
three_character_operator(char, char, char);
|
||||
|
||||
Operator
|
||||
two_character_operator(char, char);
|
||||
|
||||
Operator
|
||||
one_character_operator(char);
|
||||
|
||||
bool
|
||||
skip_c_comment();
|
||||
|
||||
void
|
||||
skip_cpp_comment();
|
||||
|
||||
// The input file name.
|
||||
const char* input_file_name_;
|
||||
// The input file.
|
||||
FILE* input_file_;
|
||||
// The line buffer. This holds the current line.
|
||||
char* linebuf_;
|
||||
// The size of the line buffer.
|
||||
size_t linebufsize_;
|
||||
// The nmber of characters in the current line.
|
||||
size_t linesize_;
|
||||
// The current offset in linebuf_.
|
||||
size_t lineoff_;
|
||||
// The current line number.
|
||||
size_t lineno_;
|
||||
// Whether to add a semicolon if we see a newline now.
|
||||
bool add_semi_at_eol_;
|
||||
};
|
||||
|
||||
#endif // !defined(GO_LEX_H)
|
66
gcc/go/gofrontend/operator.h
Normal file
66
gcc/go/gofrontend/operator.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
// operator.h -- Go frontend operators. -*- C++ -*-
|
||||
|
||||
// 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 GO_OPERATOR_H
|
||||
#define GO_OPERATOR_H
|
||||
|
||||
// The operators.
|
||||
|
||||
enum Operator
|
||||
{
|
||||
OPERATOR_INVALID,
|
||||
OPERATOR_OROR, // ||
|
||||
OPERATOR_ANDAND, // &&
|
||||
OPERATOR_EQEQ, // ==
|
||||
OPERATOR_NOTEQ, // !=
|
||||
OPERATOR_LT, // <
|
||||
OPERATOR_LE, // <=
|
||||
OPERATOR_GT, // >
|
||||
OPERATOR_GE, // >=
|
||||
OPERATOR_PLUS, // +
|
||||
OPERATOR_MINUS, // -
|
||||
OPERATOR_OR, // |
|
||||
OPERATOR_XOR, // ^
|
||||
OPERATOR_MULT, // *
|
||||
OPERATOR_DIV, // /
|
||||
OPERATOR_MOD, // %
|
||||
OPERATOR_LSHIFT, // <<
|
||||
OPERATOR_RSHIFT, // >>
|
||||
OPERATOR_AND, // &
|
||||
OPERATOR_NOT, // !
|
||||
OPERATOR_BITCLEAR, // &^
|
||||
OPERATOR_CHANOP, // <-
|
||||
|
||||
OPERATOR_EQ, // =
|
||||
OPERATOR_PLUSEQ, // +=
|
||||
OPERATOR_MINUSEQ, // -=
|
||||
OPERATOR_OREQ, // |=
|
||||
OPERATOR_XOREQ, // ^=
|
||||
OPERATOR_MULTEQ, // *=
|
||||
OPERATOR_DIVEQ, // /=
|
||||
OPERATOR_MODEQ, // %=
|
||||
OPERATOR_LSHIFTEQ, // <<=
|
||||
OPERATOR_RSHIFTEQ, // >>=
|
||||
OPERATOR_ANDEQ, // &=
|
||||
OPERATOR_BITCLEAREQ, // &^=
|
||||
OPERATOR_PLUSPLUS, // ++
|
||||
OPERATOR_MINUSMINUS, // --
|
||||
|
||||
OPERATOR_COLON, // :
|
||||
OPERATOR_COLONEQ, // :=
|
||||
OPERATOR_SEMICOLON, // ;
|
||||
OPERATOR_DOT, // .
|
||||
OPERATOR_ELLIPSIS, // ...
|
||||
OPERATOR_COMMA, // ,
|
||||
OPERATOR_LPAREN, // (
|
||||
OPERATOR_RPAREN, // )
|
||||
OPERATOR_LCURLY, // {
|
||||
OPERATOR_RCURLY, // }
|
||||
OPERATOR_LSQUARE, // [
|
||||
OPERATOR_RSQUARE // ]
|
||||
};
|
||||
|
||||
#endif // !defined(GO_OPERATOR_H)
|
4730
gcc/go/gofrontend/parse.cc
Normal file
4730
gcc/go/gofrontend/parse.cc
Normal file
File diff suppressed because it is too large
Load diff
307
gcc/go/gofrontend/parse.h
Normal file
307
gcc/go/gofrontend/parse.h
Normal file
|
@ -0,0 +1,307 @@
|
|||
// parse.h -- Go frontend parser. -*- C++ -*-
|
||||
|
||||
// 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 GO_PARSE_H
|
||||
#define GO_PARSE_H
|
||||
|
||||
class Set_iota_traverse;
|
||||
class Lex;
|
||||
class Gogo;
|
||||
class Named_object;
|
||||
class Type;
|
||||
class Typed_identifier;
|
||||
class Typed_identifier_list;
|
||||
class Function_type;
|
||||
class Block;
|
||||
class Expression;
|
||||
class Expression_list;
|
||||
class Struct_field_list;
|
||||
class Case_clauses;
|
||||
class Type_case_clauses;
|
||||
class Select_clauses;
|
||||
class Statement;
|
||||
class Label;
|
||||
|
||||
// Parse the program.
|
||||
|
||||
class Parse
|
||||
{
|
||||
public:
|
||||
Parse(Lex*, Gogo*);
|
||||
|
||||
// Parse a program.
|
||||
void
|
||||
program();
|
||||
|
||||
private:
|
||||
// Precedence values.
|
||||
enum Precedence
|
||||
{
|
||||
PRECEDENCE_INVALID = -1,
|
||||
PRECEDENCE_NORMAL = 0,
|
||||
PRECEDENCE_OROR,
|
||||
PRECEDENCE_ANDAND,
|
||||
PRECEDENCE_CHANOP,
|
||||
PRECEDENCE_RELOP,
|
||||
PRECEDENCE_ADDOP,
|
||||
PRECEDENCE_MULOP
|
||||
};
|
||||
|
||||
// We use this when parsing the range clause of a for statement.
|
||||
struct Range_clause
|
||||
{
|
||||
// Set to true if we found a range clause.
|
||||
bool found;
|
||||
// The index expression.
|
||||
Expression* index;
|
||||
// The value expression.
|
||||
Expression* value;
|
||||
// The range expression.
|
||||
Expression* range;
|
||||
|
||||
Range_clause()
|
||||
: found(false), index(NULL), value(NULL), range(NULL)
|
||||
{ }
|
||||
};
|
||||
|
||||
// We use this when parsing the statement at the start of a switch,
|
||||
// in order to recognize type switches.
|
||||
struct Type_switch
|
||||
{
|
||||
// Set to true if we find a type switch.
|
||||
bool found;
|
||||
// The variable name.
|
||||
std::string name;
|
||||
// The location of the variable.
|
||||
source_location location;
|
||||
// The expression.
|
||||
Expression* expr;
|
||||
|
||||
Type_switch()
|
||||
: found(false), name(), location(UNKNOWN_LOCATION), expr(NULL)
|
||||
{ }
|
||||
};
|
||||
|
||||
// A variable defined in an enclosing function referenced by the
|
||||
// current function.
|
||||
class Enclosing_var
|
||||
{
|
||||
public:
|
||||
Enclosing_var(Named_object* var, Named_object* in_function,
|
||||
unsigned int index)
|
||||
: var_(var), in_function_(in_function), index_(index)
|
||||
{ }
|
||||
|
||||
// We put these in a vector, so we need a default constructor.
|
||||
Enclosing_var()
|
||||
: var_(NULL), in_function_(NULL), index_(-1U)
|
||||
{ }
|
||||
|
||||
Named_object*
|
||||
var() const
|
||||
{ return this->var_; }
|
||||
|
||||
Named_object*
|
||||
in_function() const
|
||||
{ return this->in_function_; }
|
||||
|
||||
unsigned int
|
||||
index() const
|
||||
{ return this->index_; }
|
||||
|
||||
private:
|
||||
// The variable which is being referred to.
|
||||
Named_object* var_;
|
||||
// The function where the variable is defined.
|
||||
Named_object* in_function_;
|
||||
// The index of the field in this function's closure struct for
|
||||
// this variable.
|
||||
unsigned int index_;
|
||||
};
|
||||
|
||||
// We store Enclosing_var entries in a set, so we need a comparator.
|
||||
struct Enclosing_var_comparison
|
||||
{
|
||||
bool
|
||||
operator()(const Enclosing_var&, const Enclosing_var&);
|
||||
};
|
||||
|
||||
// A set of Enclosing_var entries.
|
||||
typedef std::set<Enclosing_var, Enclosing_var_comparison> Enclosing_vars;
|
||||
|
||||
// Peek at the current token from the lexer.
|
||||
const Token*
|
||||
peek_token();
|
||||
|
||||
// Consume the current token, return the next one.
|
||||
const Token*
|
||||
advance_token();
|
||||
|
||||
// Push a token back on the input stream.
|
||||
void
|
||||
unget_token(const Token&);
|
||||
|
||||
// The location of the current token.
|
||||
source_location
|
||||
location();
|
||||
|
||||
// For break and continue we keep a stack of statements with
|
||||
// associated labels (if any). The top of the stack is used for a
|
||||
// break or continue statement with no label.
|
||||
typedef std::vector<std::pair<Statement*, const Label*> > Bc_stack;
|
||||
|
||||
// Parser nonterminals.
|
||||
void identifier_list(Typed_identifier_list*);
|
||||
Expression_list* expression_list(Expression*, bool may_be_sink);
|
||||
bool qualified_ident(std::string*, Named_object**);
|
||||
Type* type();
|
||||
bool type_may_start_here();
|
||||
Type* type_name(bool issue_error);
|
||||
Type* array_type(bool may_use_ellipsis);
|
||||
Type* map_type();
|
||||
Type* struct_type();
|
||||
void field_decl(Struct_field_list*);
|
||||
Type* pointer_type();
|
||||
Type* channel_type();
|
||||
Function_type* signature(Typed_identifier*, source_location);
|
||||
Typed_identifier_list* parameters(bool* is_varargs);
|
||||
Typed_identifier_list* parameter_list(bool* is_varargs);
|
||||
void parameter_decl(bool, Typed_identifier_list*, bool*, bool*);
|
||||
Typed_identifier_list* result();
|
||||
source_location block();
|
||||
Type* interface_type();
|
||||
bool method_spec(Typed_identifier_list*);
|
||||
void declaration();
|
||||
bool declaration_may_start_here();
|
||||
void decl(void (Parse::*)(void*), void*);
|
||||
void list(void (Parse::*)(void*), void*, bool);
|
||||
void const_decl();
|
||||
void const_spec(Type**, Expression_list**);
|
||||
void type_decl();
|
||||
void type_spec(void*);
|
||||
void var_decl();
|
||||
void var_spec(void*);
|
||||
void init_vars(const Typed_identifier_list*, Type*, Expression_list*,
|
||||
bool is_coloneq, source_location);
|
||||
bool init_vars_from_call(const Typed_identifier_list*, Type*, Expression*,
|
||||
bool is_coloneq, source_location);
|
||||
bool init_vars_from_map(const Typed_identifier_list*, Type*, Expression*,
|
||||
bool is_coloneq, source_location);
|
||||
bool init_vars_from_receive(const Typed_identifier_list*, Type*,
|
||||
Expression*, bool is_coloneq, source_location);
|
||||
bool init_vars_from_type_guard(const Typed_identifier_list*, Type*,
|
||||
Expression*, bool is_coloneq,
|
||||
source_location);
|
||||
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
|
||||
bool is_coloneq, bool type_from_init, bool* is_new);
|
||||
void simple_var_decl_or_assignment(const std::string&, source_location,
|
||||
Range_clause*, Type_switch*);
|
||||
void function_decl();
|
||||
Typed_identifier* receiver();
|
||||
Expression* operand(bool may_be_sink);
|
||||
Expression* enclosing_var_reference(Named_object*, Named_object*,
|
||||
source_location);
|
||||
Expression* composite_lit(Type*, int depth, source_location);
|
||||
Expression* function_lit();
|
||||
Expression* create_closure(Named_object* function, Enclosing_vars*,
|
||||
source_location);
|
||||
Expression* primary_expr(bool may_be_sink, bool may_be_composite_lit,
|
||||
bool* is_type_switch);
|
||||
Expression* selector(Expression*, bool* is_type_switch);
|
||||
Expression* index(Expression*);
|
||||
Expression* call(Expression*);
|
||||
Expression* expression(Precedence, bool may_be_sink,
|
||||
bool may_be_composite_lit, bool* is_type_switch);
|
||||
bool expression_may_start_here();
|
||||
Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
|
||||
bool* is_type_switch);
|
||||
Expression* qualified_expr(Expression*, source_location);
|
||||
Expression* id_to_expression(const std::string&, source_location);
|
||||
void statement(const Label*);
|
||||
bool statement_may_start_here();
|
||||
void labeled_stmt(const std::string&, source_location);
|
||||
Expression* simple_stat(bool, bool, Range_clause*, Type_switch*);
|
||||
bool simple_stat_may_start_here();
|
||||
void statement_list();
|
||||
bool statement_list_may_start_here();
|
||||
void expression_stat(Expression*);
|
||||
void inc_dec_stat(Expression*);
|
||||
void assignment(Expression*, Range_clause*);
|
||||
void tuple_assignment(Expression_list*, Range_clause*);
|
||||
void send();
|
||||
void go_or_defer_stat();
|
||||
void return_stat();
|
||||
void if_stat();
|
||||
void switch_stat(const Label*);
|
||||
Statement* expr_switch_body(const Label*, Expression*, source_location);
|
||||
void expr_case_clause(Case_clauses*);
|
||||
Expression_list* expr_switch_case(bool*);
|
||||
Statement* type_switch_body(const Label*, const Type_switch&,
|
||||
source_location);
|
||||
void type_case_clause(Named_object*, Type_case_clauses*);
|
||||
void type_switch_case(std::vector<Type*>*, bool*);
|
||||
void select_stat(const Label*);
|
||||
void comm_clause(Select_clauses*);
|
||||
bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
|
||||
bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
|
||||
void for_stat(const Label*);
|
||||
void for_clause(Expression**, Block**);
|
||||
void range_clause_decl(const Typed_identifier_list*, Range_clause*);
|
||||
void range_clause_expr(const Expression_list*, Range_clause*);
|
||||
void push_break_statement(Statement*, const Label*);
|
||||
void push_continue_statement(Statement*, const Label*);
|
||||
void pop_break_statement();
|
||||
void pop_continue_statement();
|
||||
Statement* find_bc_statement(const Bc_stack*, const std::string&);
|
||||
void break_stat();
|
||||
void continue_stat();
|
||||
void goto_stat();
|
||||
void package_clause();
|
||||
void import_decl();
|
||||
void import_spec(void*);
|
||||
|
||||
void reset_iota();
|
||||
int iota_value();
|
||||
void increment_iota();
|
||||
|
||||
// Skip past an error looking for a semicolon or OP. Return true if
|
||||
// all is well, false if we found EOF.
|
||||
bool
|
||||
skip_past_error(Operator op);
|
||||
|
||||
// Verify that an expression is not a sink, and return either the
|
||||
// expression or an error.
|
||||
Expression*
|
||||
verify_not_sink(Expression*);
|
||||
|
||||
// Return the statement associated with a label in a Bc_stack, or
|
||||
// NULL.
|
||||
Statement*
|
||||
find_bc_statement(const Bc_stack*, const std::string&) const;
|
||||
|
||||
// The lexer output we are parsing.
|
||||
Lex* lex_;
|
||||
// The current token.
|
||||
Token token_;
|
||||
// A token pushed back on the input stream.
|
||||
Token unget_token_;
|
||||
// Whether unget_token_ is valid.
|
||||
bool unget_token_valid_;
|
||||
// The code we are generating.
|
||||
Gogo* gogo_;
|
||||
// A stack of statements for which break may be used.
|
||||
Bc_stack break_stack_;
|
||||
// A stack of statements for which continue may be used.
|
||||
Bc_stack continue_stack_;
|
||||
// The current iota value.
|
||||
int iota_;
|
||||
// References from the local function to variables defined in
|
||||
// enclosing functions.
|
||||
Enclosing_vars enclosing_vars_;
|
||||
};
|
||||
|
||||
|
||||
#endif // !defined(GO_PARSE_H)
|
5146
gcc/go/gofrontend/statements.cc
Normal file
5146
gcc/go/gofrontend/statements.cc
Normal file
File diff suppressed because it is too large
Load diff
1420
gcc/go/gofrontend/statements.h
Normal file
1420
gcc/go/gofrontend/statements.h
Normal file
File diff suppressed because it is too large
Load diff
8078
gcc/go/gofrontend/types.cc
Normal file
8078
gcc/go/gofrontend/types.cc
Normal file
File diff suppressed because it is too large
Load diff
2730
gcc/go/gofrontend/types.h
Normal file
2730
gcc/go/gofrontend/types.h
Normal file
File diff suppressed because it is too large
Load diff
134
gcc/go/gofrontend/unsafe.cc
Normal file
134
gcc/go/gofrontend/unsafe.cc
Normal file
|
@ -0,0 +1,134 @@
|
|||
// unsafe.cc -- Go frontend builtin unsafe package.
|
||||
|
||||
// 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 "go-system.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "gogo.h"
|
||||
|
||||
// Set up the builtin unsafe package. This should probably be driven
|
||||
// by a table.
|
||||
|
||||
void
|
||||
Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
|
||||
source_location location)
|
||||
{
|
||||
location_t bloc = BUILTINS_LOCATION;
|
||||
|
||||
bool add_to_globals;
|
||||
Package* package = this->add_imported_package("unsafe", local_name,
|
||||
is_local_name_exported,
|
||||
"libgo_unsafe",
|
||||
location, &add_to_globals);
|
||||
package->set_is_imported();
|
||||
|
||||
Bindings* bindings = package->bindings();
|
||||
|
||||
// The type may have already been created by an import.
|
||||
Named_object* no = package->bindings()->lookup("Pointer");
|
||||
if (no == NULL)
|
||||
{
|
||||
Type* type = Type::make_pointer_type(Type::make_void_type());
|
||||
no = bindings->add_type("Pointer", package, type, UNKNOWN_LOCATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert(no->package() == package);
|
||||
gcc_assert(no->is_type());
|
||||
gcc_assert(no->type_value()->is_unsafe_pointer_type());
|
||||
no->type_value()->set_is_visible();
|
||||
}
|
||||
Named_type* pointer_type = no->type_value();
|
||||
if (add_to_globals)
|
||||
this->add_named_type(pointer_type);
|
||||
|
||||
Type* int_type = this->lookup_global("int")->type_value();
|
||||
|
||||
// Sizeof.
|
||||
Typed_identifier_list* results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", int_type, bloc));
|
||||
Function_type* fntype = Type::make_function_type(NULL, NULL, results, bloc);
|
||||
fntype->set_is_builtin();
|
||||
no = bindings->add_function_declaration("Sizeof", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Offsetof.
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", int_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, NULL, results, bloc);
|
||||
fntype->set_is_varargs();
|
||||
fntype->set_is_builtin();
|
||||
no = bindings->add_function_declaration("Offsetof", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Alignof.
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", int_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, NULL, results, bloc);
|
||||
fntype->set_is_varargs();
|
||||
fntype->set_is_builtin();
|
||||
no = bindings->add_function_declaration("Alignof", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Typeof.
|
||||
Type* empty_interface = Type::make_interface_type(NULL, bloc);
|
||||
Typed_identifier_list* parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("i", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Typeof", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Reflect.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("it", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Reflect", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// Unreflect.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
parameters->push_back(Typed_identifier("addr", pointer_type, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", empty_interface, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("Unreflect", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// New.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("New", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
// NewArray.
|
||||
parameters = new Typed_identifier_list;
|
||||
parameters->push_back(Typed_identifier("typ", empty_interface, bloc));
|
||||
parameters->push_back(Typed_identifier("n", int_type, bloc));
|
||||
results = new Typed_identifier_list;
|
||||
results->push_back(Typed_identifier("", pointer_type, bloc));
|
||||
fntype = Type::make_function_type(NULL, parameters, results, bloc);
|
||||
no = bindings->add_function_declaration("NewArray", package, fntype, bloc);
|
||||
if (add_to_globals)
|
||||
this->add_named_object(no);
|
||||
|
||||
this->imported_unsafe_ = true;
|
||||
}
|
327
gcc/go/gospec.c
Normal file
327
gcc/go/gospec.c
Normal file
|
@ -0,0 +1,327 @@
|
|||
/* gospec.c -- Specific flags and argument handling of the gcc Go front end.
|
||||
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC 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 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC 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 GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "gcc.h"
|
||||
#include "opts.h"
|
||||
|
||||
/* This bit is set if we saw a `-xfoo' language specification. */
|
||||
#define LANGSPEC (1<<1)
|
||||
/* This bit is set if they did `-lm' or `-lmath'. */
|
||||
#define MATHLIB (1<<2)
|
||||
/* This bit is set if they did `-lpthread'. */
|
||||
#define THREADLIB (1<<3)
|
||||
/* This bit is set if they did `-lc'. */
|
||||
#define WITHLIBC (1<<4)
|
||||
/* Skip this option. */
|
||||
#define SKIPOPT (1<<5)
|
||||
|
||||
#ifndef MATH_LIBRARY
|
||||
#define MATH_LIBRARY "m"
|
||||
#endif
|
||||
#ifndef MATH_LIBRARY_PROFILE
|
||||
#define MATH_LIBRARY_PROFILE MATH_LIBRARY
|
||||
#endif
|
||||
|
||||
#define THREAD_LIBRARY "pthread"
|
||||
#define THREAD_LIBRARY_PROFILE THREAD_LIBRARY
|
||||
|
||||
#define LIBGO "go"
|
||||
#define LIBGO_PROFILE LIBGO
|
||||
#define LIBGOBEGIN "gobegin"
|
||||
|
||||
void
|
||||
lang_specific_driver (struct cl_decoded_option **in_decoded_options,
|
||||
unsigned int *in_decoded_options_count,
|
||||
int *in_added_libraries)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
/* If true, the user gave us the `-p' or `-pg' flag. */
|
||||
bool saw_profile_flag = false;
|
||||
|
||||
/* This is a tristate:
|
||||
-1 means we should not link in libgo
|
||||
0 means we should link in libgo if it is needed
|
||||
1 means libgo is needed and should be linked in.
|
||||
2 means libgo is needed and should be linked statically. */
|
||||
int library = 0;
|
||||
|
||||
/* The new argument list will be contained in this. */
|
||||
struct cl_decoded_option *new_decoded_options;
|
||||
|
||||
/* "-lm" or "-lmath" if it appears on the command line. */
|
||||
const struct cl_decoded_option *saw_math = 0;
|
||||
|
||||
/* "-lpthread" if it appears on the command line. */
|
||||
const struct cl_decoded_option *saw_thread = 0;
|
||||
|
||||
/* "-lc" if it appears on the command line. */
|
||||
const struct cl_decoded_option *saw_libc = 0;
|
||||
|
||||
/* An array used to flag each argument that needs a bit set for
|
||||
LANGSPEC, MATHLIB, or WITHLIBC. */
|
||||
int *args;
|
||||
|
||||
/* Whether we need the thread library. */
|
||||
int need_thread = 0;
|
||||
|
||||
/* By default, we throw on the math library if we have one. */
|
||||
int need_math = (MATH_LIBRARY[0] != '\0');
|
||||
|
||||
/* True if we saw -static. */
|
||||
int static_link = 0;
|
||||
|
||||
/* True if we should add -shared-libgcc to the command-line. */
|
||||
int shared_libgcc = 1;
|
||||
|
||||
/* The total number of arguments with the new stuff. */
|
||||
unsigned int argc;
|
||||
|
||||
/* The argument list. */
|
||||
struct cl_decoded_option *decoded_options;
|
||||
|
||||
/* The number of libraries added in. */
|
||||
int added_libraries;
|
||||
|
||||
/* The total number of arguments with the new stuff. */
|
||||
int num_args = 1;
|
||||
|
||||
argc = *in_decoded_options_count;
|
||||
decoded_options = *in_decoded_options;
|
||||
added_libraries = *in_added_libraries;
|
||||
|
||||
args = XCNEWVEC (int, argc);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
const char *arg = decoded_options[i].arg;
|
||||
|
||||
switch (decoded_options[i].opt_index)
|
||||
{
|
||||
case OPT_nostdlib:
|
||||
case OPT_nodefaultlibs:
|
||||
library = -1;
|
||||
break;
|
||||
|
||||
case OPT_l:
|
||||
if (strcmp (arg, MATH_LIBRARY) == 0)
|
||||
{
|
||||
args[i] |= MATHLIB;
|
||||
need_math = 0;
|
||||
}
|
||||
else if (strcmp (arg, THREAD_LIBRARY) == 0)
|
||||
args[i] |= THREADLIB;
|
||||
else if (strcmp (arg, "c") == 0)
|
||||
args[i] |= WITHLIBC;
|
||||
else
|
||||
/* Unrecognized libraries (e.g. -lfoo) may require libgo. */
|
||||
library = (library == 0) ? 1 : library;
|
||||
break;
|
||||
|
||||
case OPT_pg:
|
||||
case OPT_p:
|
||||
saw_profile_flag = true;
|
||||
break;
|
||||
|
||||
case OPT_x:
|
||||
if (library == 0 && strcmp (arg, "go") == 0)
|
||||
library = 1;
|
||||
break;
|
||||
|
||||
case OPT_Xlinker:
|
||||
case OPT_Wl_:
|
||||
/* Arguments that go directly to the linker might be .o files,
|
||||
or something, and so might cause libgo to be needed. */
|
||||
if (library == 0)
|
||||
library = 1;
|
||||
break;
|
||||
|
||||
case OPT_c:
|
||||
case OPT_S:
|
||||
case OPT_E:
|
||||
case OPT_M:
|
||||
case OPT_MM:
|
||||
case OPT_fsyntax_only:
|
||||
/* Don't specify libraries if we won't link, since that would
|
||||
cause a warning. */
|
||||
library = -1;
|
||||
break;
|
||||
|
||||
case OPT_static:
|
||||
static_link = 1;
|
||||
break;
|
||||
|
||||
case OPT_static_libgcc:
|
||||
shared_libgcc = 0;
|
||||
break;
|
||||
|
||||
case OPT_static_libgo:
|
||||
library = library >= 0 ? 2 : library;
|
||||
args[i] |= SKIPOPT;
|
||||
break;
|
||||
|
||||
case OPT_SPECIAL_input_file:
|
||||
if (library == 0)
|
||||
library = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* There's no point adding -shared-libgcc if we don't have a shared
|
||||
libgcc. */
|
||||
#ifndef ENABLE_SHARED_LIBGCC
|
||||
shared_libgcc = 0;
|
||||
#endif
|
||||
|
||||
/* Make sure to have room for the trailing NULL argument. */
|
||||
num_args = argc + need_math + shared_libgcc + (library > 0) * 5 + 5;
|
||||
new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
||||
/* Copy the 0th argument, i.e., the name of the program itself. */
|
||||
new_decoded_options[j++] = decoded_options[i++];
|
||||
|
||||
/* If we are linking, pass -fsplit-stack if it is supported. */
|
||||
#ifdef TARGET_CAN_SPLIT_STACK
|
||||
if (library >= 0)
|
||||
{
|
||||
generate_option (OPT_fsplit_stack, NULL, 1, CL_DRIVER,
|
||||
&new_decoded_options[j]);
|
||||
j++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* NOTE: We start at 1 now, not 0. */
|
||||
while (i < argc)
|
||||
{
|
||||
new_decoded_options[j] = decoded_options[i];
|
||||
|
||||
/* Make sure -lgo is before the math library, since libgo itself
|
||||
uses those math routines. */
|
||||
if (!saw_math && (args[i] & MATHLIB) && library > 0)
|
||||
{
|
||||
--j;
|
||||
saw_math = &decoded_options[i];
|
||||
}
|
||||
|
||||
if (!saw_thread && (args[i] & THREADLIB) && library > 0)
|
||||
{
|
||||
--j;
|
||||
saw_thread = &decoded_options[i];
|
||||
}
|
||||
|
||||
if (!saw_libc && (args[i] & WITHLIBC) && library > 0)
|
||||
{
|
||||
--j;
|
||||
saw_libc = &decoded_options[i];
|
||||
}
|
||||
|
||||
if ((args[i] & SKIPOPT) != 0)
|
||||
--j;
|
||||
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
/* Add `-lgo' if we haven't already done so. */
|
||||
if (library > 0)
|
||||
{
|
||||
generate_option (OPT_l, LIBGOBEGIN, 1, CL_DRIVER,
|
||||
&new_decoded_options[j]);
|
||||
added_libraries++;
|
||||
j++;
|
||||
|
||||
#ifdef HAVE_LD_STATIC_DYNAMIC
|
||||
if (library > 1 && !static_link)
|
||||
{
|
||||
generate_option (OPT_Wl_, "-Bstatic", 1, CL_DRIVER,
|
||||
&new_decoded_options[j]);
|
||||
j++;
|
||||
}
|
||||
#endif
|
||||
|
||||
generate_option (OPT_l, saw_profile_flag ? LIBGO_PROFILE : LIBGO, 1,
|
||||
CL_DRIVER, &new_decoded_options[j]);
|
||||
added_libraries++;
|
||||
j++;
|
||||
|
||||
#ifdef HAVE_LD_STATIC_DYNAMIC
|
||||
if (library > 1 && !static_link)
|
||||
{
|
||||
generate_option (OPT_Wl_, "-Bdynamic", 1, CL_DRIVER,
|
||||
&new_decoded_options[j]);
|
||||
j++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* When linking libgo statically we also need to link with the
|
||||
pthread library. */
|
||||
if (library > 1 || static_link)
|
||||
need_thread = 1;
|
||||
}
|
||||
|
||||
if (saw_thread)
|
||||
new_decoded_options[j++] = *saw_thread;
|
||||
else if (library > 0 && need_thread)
|
||||
{
|
||||
generate_option (OPT_l,
|
||||
(saw_profile_flag
|
||||
? THREAD_LIBRARY_PROFILE
|
||||
: THREAD_LIBRARY),
|
||||
1, CL_DRIVER, &new_decoded_options[j]);
|
||||
added_libraries++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (saw_math)
|
||||
new_decoded_options[j++] = *saw_math;
|
||||
else if (library > 0 && need_math)
|
||||
{
|
||||
generate_option (OPT_l,
|
||||
saw_profile_flag ? MATH_LIBRARY_PROFILE : MATH_LIBRARY,
|
||||
1, CL_DRIVER, &new_decoded_options[j]);
|
||||
added_libraries++;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (saw_libc)
|
||||
new_decoded_options[j++] = *saw_libc;
|
||||
if (shared_libgcc && !static_link)
|
||||
generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
|
||||
&new_decoded_options[j++]);
|
||||
|
||||
*in_decoded_options_count = j;
|
||||
*in_decoded_options = new_decoded_options;
|
||||
*in_added_libraries = added_libraries;
|
||||
}
|
||||
|
||||
/* Called before linking. Returns 0 on success and -1 on failure. */
|
||||
int lang_specific_pre_link (void) /* Not used for Go. */
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Number of extra output files that lang_specific_pre_link may generate. */
|
||||
int lang_specific_extra_outfiles = 0; /* Not used for Go. */
|
25
gcc/go/lang-specs.h
Normal file
25
gcc/go/lang-specs.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* lang-specs.h -- gcc driver specs for Go frontend.
|
||||
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC 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 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC 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 GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
/* This is the contribution to the `default_compilers' array in gcc.c
|
||||
for the Go language. */
|
||||
|
||||
{".go", "@go", 0, 1, 0},
|
||||
{"@go", "go1 %i %(cc1_options) %{I*} %{L*} %D %{!fsyntax-only:%(invoke_as)}",
|
||||
0, 1, 0},
|
56
gcc/go/lang.opt
Normal file
56
gcc/go/lang.opt
Normal file
|
@ -0,0 +1,56 @@
|
|||
; lang.opt -- Options for the gcc Go front end.
|
||||
|
||||
; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
;
|
||||
; This file is part of GCC.
|
||||
;
|
||||
; GCC 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 3, or (at your option) any later
|
||||
; version.
|
||||
;
|
||||
; GCC 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 GCC; see the file COPYING3. If not see
|
||||
; <http://www.gnu.org/licenses/>.
|
||||
|
||||
; See the GCC internals manual for a description of this file's format.
|
||||
|
||||
; Please try to keep this file in ASCII collating order.
|
||||
|
||||
Language
|
||||
Go
|
||||
|
||||
I
|
||||
Go Joined Separate
|
||||
; Documented in c.opt
|
||||
|
||||
L
|
||||
Go Joined Separate
|
||||
; Not documented
|
||||
|
||||
Wall
|
||||
Go
|
||||
; Documented in c.opt
|
||||
|
||||
fgo-dump-
|
||||
Go Joined RejectNegative
|
||||
-fgo-dump-<type> Dump Go frontend internal information
|
||||
|
||||
fgo-prefix=
|
||||
Go Joined RejectNegative
|
||||
-fgo-prefix=<string> Set package-specific prefix for exported Go names
|
||||
|
||||
frequire-return-statement
|
||||
Go Var(go_require_return_statement) Init(1) Warning
|
||||
Functions which return values must end with return statements
|
||||
|
||||
o
|
||||
Go Joined Separate
|
||||
; Documented in common.opt
|
||||
|
||||
; This comment is to ensure we retain the blank line above.
|
|
@ -1,4 +1,11 @@
|
|||
2010-11-02 Eric Botcazou <ebotcazou@adacore.com>
|
||||
2010-12-02 Ian Lance Taylor <iant@google.com>
|
||||
|
||||
* lib/go.exp: New file.
|
||||
* lib/go-dg.exp: New file.
|
||||
* lib/go-torture.exp: New file.
|
||||
* lib/target-supports.exp (check_compile): Match // Go.
|
||||
|
||||
2010-12-02 Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
* gcc.dg/pr46685.c: New test.
|
||||
|
||||
|
|
36
gcc/testsuite/go.dg/dg.exp
Normal file
36
gcc/testsuite/go.dg/dg.exp
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2009 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 3 of the License, 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 GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# GCC testsuite that uses the `dg.exp' driver.
|
||||
|
||||
# Load support procs.
|
||||
load_lib go-dg.exp
|
||||
|
||||
# If a testcase doesn't have special options, use these.
|
||||
global DEFAULT_GOCFLAGS
|
||||
if ![info exists DEFAULT_GOCFLAGS] then {
|
||||
set DEFAULT_GOCFLAGS " -pedantic-errors"
|
||||
}
|
||||
|
||||
# Initialize `dg'.
|
||||
dg-init
|
||||
|
||||
# Main loop.
|
||||
go-dg-runtest [lsort \
|
||||
[glob -nocomplain $srcdir/$subdir/*.go ] ] $DEFAULT_GOCFLAGS
|
||||
|
||||
# All done.
|
||||
dg-finish
|
7
gcc/testsuite/go.dg/err-1.go
Normal file
7
gcc/testsuite/go.dg/err-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var ret; // { dg-error "expected type" }
|
||||
}
|
7
gcc/testsuite/go.dg/goto-1.go
Normal file
7
gcc/testsuite/go.dg/goto-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
goto lab; // { dg-error "undefined label" }
|
||||
}
|
7
gcc/testsuite/go.dg/undef-1.go
Normal file
7
gcc/testsuite/go.dg/undef-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
// { dg-do compile }
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
sys.Exit(i) // { dg-error "undefined" }
|
||||
}
|
10
gcc/testsuite/go.go-torture/execute/array-1.go
Normal file
10
gcc/testsuite/go.go-torture/execute/array-1.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package main
|
||||
var a [2]int;
|
||||
func fn() {
|
||||
a[0] = 1;
|
||||
a[1] = 1;
|
||||
}
|
||||
func main() {
|
||||
fn();
|
||||
if a[0] != a[1] { panic(0) }
|
||||
}
|
19
gcc/testsuite/go.go-torture/execute/array-2.go
Normal file
19
gcc/testsuite/go.go-torture/execute/array-2.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
func fn(a []int) int {
|
||||
alen := len(a);
|
||||
for i := 0; i < alen; i++ {
|
||||
a[i] = i
|
||||
}
|
||||
return alen;
|
||||
}
|
||||
|
||||
func main() {
|
||||
var a [2]int;
|
||||
if fn(a[0:]) != 2 {
|
||||
panic(0);
|
||||
}
|
||||
if a[0] != 0 || a[1] != 1 {
|
||||
panic(1);
|
||||
}
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/chan-1.go
Normal file
7
gcc/testsuite/go.go-torture/execute/chan-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
c := make(chan int, 1);
|
||||
c <- 0;
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
6
gcc/testsuite/go.go-torture/execute/const-1.go
Normal file
6
gcc/testsuite/go.go-torture/execute/const-1.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
const c = 2;
|
||||
if c != 2 { panic(0) }
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/const-2.go
Normal file
7
gcc/testsuite/go.go-torture/execute/const-2.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
const c = 3;
|
||||
|
||||
func main() {
|
||||
if c != 3 { panic(0) }
|
||||
}
|
33
gcc/testsuite/go.go-torture/execute/execute.exp
Normal file
33
gcc/testsuite/go.go-torture/execute/execute.exp
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Copyright (C) 2009 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 3 of the License, 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 GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This is based on a file written by Rob Savoye (rob@cygnus.com) and
|
||||
# Jeffrey Wheat (cassidy@cygnus.com).
|
||||
|
||||
if $tracelevel then {
|
||||
strace $tracelevel
|
||||
}
|
||||
|
||||
# load support procs
|
||||
load_lib go-torture.exp
|
||||
|
||||
foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.go]] {
|
||||
# If we're only testing specific files and this isn't one of them, skip it.
|
||||
if ![runtest_file_p $runtests $testcase] then {
|
||||
continue
|
||||
}
|
||||
go-torture-execute $testcase
|
||||
}
|
11
gcc/testsuite/go.go-torture/execute/expr-1.go
Normal file
11
gcc/testsuite/go.go-torture/execute/expr-1.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var v1 = 1;
|
||||
var v2 = 1;
|
||||
var v3 = (v1 + v2) / (v1 + v2);
|
||||
var v4 = (v3 * v3) % (v3 * v3);
|
||||
if v4 != 0 {
|
||||
panic(0)
|
||||
}
|
||||
}
|
9
gcc/testsuite/go.go-torture/execute/for-1.go
Normal file
9
gcc/testsuite/go.go-torture/execute/for-1.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
sum := 0;
|
||||
for i := 0; i < 10; i++ {
|
||||
sum += i;
|
||||
}
|
||||
if sum != 45 { panic(0) }
|
||||
}
|
52
gcc/testsuite/go.go-torture/execute/for-2.go
Normal file
52
gcc/testsuite/go.go-torture/execute/for-2.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package main
|
||||
|
||||
func f1() {
|
||||
j := 0;
|
||||
for i := 0; i < 10; i++ {
|
||||
if i > 2 {
|
||||
break;
|
||||
}
|
||||
j = i;
|
||||
}
|
||||
if (j != 2) {
|
||||
panic(0);
|
||||
}
|
||||
}
|
||||
|
||||
func f2() {
|
||||
for i := 0; i < 10; i++ {
|
||||
if i >= 0 {
|
||||
continue;
|
||||
}
|
||||
panic(1);
|
||||
}
|
||||
}
|
||||
|
||||
func f3() {
|
||||
lab1:
|
||||
for i := 0; i < 10; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
if j > 2 {
|
||||
break lab1;
|
||||
}
|
||||
}
|
||||
panic(2);
|
||||
}
|
||||
}
|
||||
|
||||
func f4() {
|
||||
lab1:
|
||||
for i := 0; i < 10; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
continue lab1;
|
||||
}
|
||||
panic(3);
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
f1();
|
||||
f2();
|
||||
f3();
|
||||
f4()
|
||||
}
|
9
gcc/testsuite/go.go-torture/execute/function-1.go
Normal file
9
gcc/testsuite/go.go-torture/execute/function-1.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func subr() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
if subr() != 0 { panic(0) }
|
||||
}
|
9
gcc/testsuite/go.go-torture/execute/function-2.go
Normal file
9
gcc/testsuite/go.go-torture/execute/function-2.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package main
|
||||
|
||||
func subr(p int) int {
|
||||
return p
|
||||
}
|
||||
|
||||
func main() {
|
||||
if subr(0) != 0 { panic(0) }
|
||||
}
|
11
gcc/testsuite/go.go-torture/execute/go-1.go
Normal file
11
gcc/testsuite/go.go-torture/execute/go-1.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func send_one(c chan <- int) {
|
||||
c <- 0;
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int);
|
||||
go send_one(c);
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
11
gcc/testsuite/go.go-torture/execute/go-2.go
Normal file
11
gcc/testsuite/go.go-torture/execute/go-2.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package main
|
||||
|
||||
func send_one(c chan <- int, val int) {
|
||||
c <- val;
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int);
|
||||
go send_one(c, 0);
|
||||
if <-c != 0 { panic(0) }
|
||||
}
|
14
gcc/testsuite/go.go-torture/execute/go-3.go
Normal file
14
gcc/testsuite/go.go-torture/execute/go-3.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package main
|
||||
|
||||
type I interface { send(chan <- int) }
|
||||
|
||||
type S struct { v int }
|
||||
func (p *S) send(c chan <- int) { c <- p.v }
|
||||
|
||||
func main() {
|
||||
s := S{0};
|
||||
var i I = &s;
|
||||
c := make(chan int);
|
||||
go i.send(c);
|
||||
if <- c != 0 { panic(0) }
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/goto-1.go
Normal file
7
gcc/testsuite/go.go-torture/execute/goto-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
goto lab;
|
||||
panic(0);
|
||||
lab:
|
||||
}
|
46
gcc/testsuite/go.go-torture/execute/map-1.go
Normal file
46
gcc/testsuite/go.go-torture/execute/map-1.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
v := make(map[int] int);
|
||||
v[0] = 0;
|
||||
v[1000000] = 1;
|
||||
if v[0] != 0 {
|
||||
panic(1)
|
||||
}
|
||||
val, present := v[0];
|
||||
if !present || val != 0 {
|
||||
panic(2)
|
||||
}
|
||||
val = 5;
|
||||
val, present = v[1];
|
||||
if present || val != 0 {
|
||||
panic(3);
|
||||
}
|
||||
if v[2] != 0 {
|
||||
panic(4)
|
||||
}
|
||||
val, present = v[2];
|
||||
if present {
|
||||
panic(5)
|
||||
}
|
||||
if len(v) != 2 {
|
||||
panic(6)
|
||||
}
|
||||
v[0] = 0, false;
|
||||
if len(v) != 1 {
|
||||
panic(7)
|
||||
}
|
||||
|
||||
w := make(map[string] string);
|
||||
if len(w) != 0 {
|
||||
panic(8)
|
||||
}
|
||||
w["Hello"] = "world";
|
||||
w["Goodbye"] = "sweet prince";
|
||||
if w["Hello"] != "world" {
|
||||
panic(9)
|
||||
}
|
||||
if w["Hej"] != "" {
|
||||
panic(10)
|
||||
}
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/method-1.go
Normal file
7
gcc/testsuite/go.go-torture/execute/method-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
type s struct { i int };
|
||||
func (v *s) val() int { return v.i }
|
||||
func main() {
|
||||
p := new(s);
|
||||
if p.val() != 0 { panic(0) }
|
||||
}
|
4
gcc/testsuite/go.go-torture/execute/nested-1.go
Normal file
4
gcc/testsuite/go.go-torture/execute/nested-1.go
Normal file
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
func main() {
|
||||
if func (i int) int { return i} (0) != 0 { panic(0) }
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/pointer-1.go
Normal file
7
gcc/testsuite/go.go-torture/execute/pointer-1.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
p := new(int);
|
||||
*p = 0;
|
||||
if *p != 0 { panic(0) }
|
||||
}
|
4
gcc/testsuite/go.go-torture/execute/return-1.go
Normal file
4
gcc/testsuite/go.go-torture/execute/return-1.go
Normal file
|
@ -0,0 +1,4 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
}
|
18
gcc/testsuite/go.go-torture/execute/return-2.go
Normal file
18
gcc/testsuite/go.go-torture/execute/return-2.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package main
|
||||
|
||||
func fn() (i, j int) {
|
||||
i = 1;
|
||||
j = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i, j = fn();
|
||||
var ret int;
|
||||
if i == 1 && j == 2 {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
16
gcc/testsuite/go.go-torture/execute/return-3.go
Normal file
16
gcc/testsuite/go.go-torture/execute/return-3.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
func fn() (i, j int) {
|
||||
return 1, 2
|
||||
}
|
||||
|
||||
func main() {
|
||||
var i, j = fn();
|
||||
var ret int;
|
||||
if i == 1 && j == 2 {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
28
gcc/testsuite/go.go-torture/execute/select-1.go
Normal file
28
gcc/testsuite/go.go-torture/execute/select-1.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
ch1 := make(chan int);
|
||||
ch2 := make(chan int);
|
||||
go func (ch1, ch2 chan int) { ch1 <- 1; ch2 <- 2; } (ch1, ch2);
|
||||
count := 0;
|
||||
var v int;
|
||||
for count != 2 {
|
||||
select
|
||||
{
|
||||
case v := <- ch1:
|
||||
if v != 1 {
|
||||
panic(0)
|
||||
}
|
||||
count++
|
||||
|
||||
case v = <- ch2:
|
||||
if v != 2 {
|
||||
panic(1)
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
if v != 2 {
|
||||
panic(2)
|
||||
}
|
||||
}
|
15
gcc/testsuite/go.go-torture/execute/string-1.go
Normal file
15
gcc/testsuite/go.go-torture/execute/string-1.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package main
|
||||
|
||||
func fn(s string) int {
|
||||
if s[0] != 'a' || s[1] != 'b' || s[2] != 'c' {
|
||||
panic(0);
|
||||
}
|
||||
return len(s);
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := "abc";
|
||||
if fn(s) != 3 {
|
||||
panic(1);
|
||||
}
|
||||
}
|
16
gcc/testsuite/go.go-torture/execute/string-2.go
Normal file
16
gcc/testsuite/go.go-torture/execute/string-2.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
func fn(s string) string {
|
||||
if len(s) != 3 {
|
||||
panic(0)
|
||||
}
|
||||
i := len(s) - 1;
|
||||
return s + s[0 : i];
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := fn("abc");
|
||||
if s != "abcab" {
|
||||
panic(1)
|
||||
}
|
||||
}
|
8
gcc/testsuite/go.go-torture/execute/struct-1.go
Normal file
8
gcc/testsuite/go.go-torture/execute/struct-1.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
type s struct { x int; };
|
||||
var ret s;
|
||||
ret.x = 1;
|
||||
if ret.x != 1 { panic(0) }
|
||||
}
|
7
gcc/testsuite/go.go-torture/execute/struct-2.go
Normal file
7
gcc/testsuite/go.go-torture/execute/struct-2.go
Normal file
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
type s struct { x int; y int; };
|
||||
var ret s = s{1, 2};
|
||||
if ret.y - (ret.x + ret.x) != 0 { panic(0) }
|
||||
}
|
68
gcc/testsuite/go.go-torture/execute/switch-1.go
Normal file
68
gcc/testsuite/go.go-torture/execute/switch-1.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
package main
|
||||
|
||||
func f1(i int) bool {
|
||||
switch j := i; j {
|
||||
case 3: fallthrough
|
||||
case 1: return true
|
||||
case 2: return false
|
||||
default: return false
|
||||
case 4: return true
|
||||
}
|
||||
}
|
||||
|
||||
func f2(i int) int {
|
||||
switch {
|
||||
case i < 0: return -1
|
||||
case i > 0: return 1
|
||||
default: return 0
|
||||
case i != 0: return 1000
|
||||
}
|
||||
panic(0)
|
||||
}
|
||||
|
||||
func f3(i int) int {
|
||||
lab:
|
||||
switch i {
|
||||
case 1: break
|
||||
case 2: return 2
|
||||
case 3, 4:
|
||||
switch i {
|
||||
case 3: break lab
|
||||
case 4: break
|
||||
}
|
||||
return 4
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func main() {
|
||||
if !f1(1) {
|
||||
panic(1);
|
||||
}
|
||||
if f1(2) {
|
||||
panic(2);
|
||||
}
|
||||
if !f1(3) {
|
||||
panic(3);
|
||||
}
|
||||
if !f1(4) {
|
||||
panic(4);
|
||||
}
|
||||
if f1(5) {
|
||||
panic(5);
|
||||
}
|
||||
|
||||
if f2(-100) != -1 {
|
||||
panic(6);
|
||||
}
|
||||
if f2(1000) != 1 {
|
||||
panic(7);
|
||||
}
|
||||
if f2(0) != 0 {
|
||||
panic(8);
|
||||
}
|
||||
|
||||
if f3(1) != 1 || f3(2) != 2 || f3(3) != 1 || f3(4) != 4 {
|
||||
panic(9);
|
||||
}
|
||||
}
|
6
gcc/testsuite/go.go-torture/execute/var-1.go
Normal file
6
gcc/testsuite/go.go-torture/execute/var-1.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var ret = 0;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
6
gcc/testsuite/go.go-torture/execute/var-2.go
Normal file
6
gcc/testsuite/go.go-torture/execute/var-2.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
var ret int;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
6
gcc/testsuite/go.go-torture/execute/var-3.go
Normal file
6
gcc/testsuite/go.go-torture/execute/var-3.go
Normal file
|
@ -0,0 +1,6 @@
|
|||
package main
|
||||
|
||||
func main() {
|
||||
ret := 0;
|
||||
if ret != 0 { panic(0) }
|
||||
}
|
666
gcc/testsuite/go.test/go-test.exp
Normal file
666
gcc/testsuite/go.test/go-test.exp
Normal file
|
@ -0,0 +1,666 @@
|
|||
# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
|
||||
# Written by Ian Lance Taylor <iant@google.com>.
|
||||
|
||||
# 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 3 of the License, 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 GCC; see the file COPYING3. If not see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# Test using the testsuite for the gc Go compiler. In these tests the
|
||||
# first line is a shell script to run. That line expects the
|
||||
# following environment variables to be set:
|
||||
# A The file extension of the object file and the name of the executable
|
||||
# G The name of the compiler
|
||||
# L The name of the linker
|
||||
# F The basename of the test
|
||||
# D The directory of the test.
|
||||
#
|
||||
# Typical command lines:
|
||||
# // $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
# // $G $D/$F.go && $L $F.$A || echo BUG: known to fail incorrectly
|
||||
# // $G $D/$F.go && echo BUG: compilation succeeds incorrectly
|
||||
# // $G $D/$F.go || echo BUG: compilation should succeed
|
||||
|
||||
load_lib go-dg.exp
|
||||
load_lib go-torture.exp
|
||||
|
||||
# Implement errchk
|
||||
proc errchk { test } {
|
||||
global dg-do-what-default
|
||||
global DEFAULT_GOCFLAGS
|
||||
|
||||
set saved-dg-do-what-default ${dg-do-what-default}
|
||||
set dg-do-what-default compile
|
||||
set filename [file tail $test]
|
||||
if { "$filename" == "$test" } {
|
||||
set filename "errchk-$filename"
|
||||
}
|
||||
set fdin [open $test r]
|
||||
fconfigure $fdin -encoding binary
|
||||
set fdout [open $filename w]
|
||||
fconfigure $fdout -encoding binary
|
||||
while { [gets $fdin copy_line] >= 0 } {
|
||||
regsub "// \(GCCGO_\)?ERROR \"\(\[^\"\]*\)\".*$" $copy_line "// \{ dg-error \"\\2\" \}" out_line
|
||||
if [string match "*dg-error*.\**" $out_line] {
|
||||
# I worked out the right number of backslashes by
|
||||
# experimentation, not analysis.
|
||||
regsub -all "\\.\\*" $out_line "\\\\\[ -~\\\\\]*" out_line
|
||||
}
|
||||
if [string match "*dg-error*\{*" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -start $index -all "\{" $out_line "\\\\\[\\\{\\\\\]" out_line
|
||||
}
|
||||
if [string match "*dg-error*\}*\}" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -start $index -all "\}\(.\)" $out_line "\\\\\[\\\}\\\\\]\\1" out_line
|
||||
}
|
||||
if [string match "*dg-error*\[.\]*" $out_line] {
|
||||
set index [string first "dg-error" $out_line]
|
||||
regsub -all "\\\[\\.\\\]" $out_line "\\\\\[.\\\\\]" out_line
|
||||
}
|
||||
puts $fdout $out_line
|
||||
}
|
||||
close $fdin
|
||||
close $fdout
|
||||
go-dg-runtest $filename "-fno-show-column $DEFAULT_GOCFLAGS"
|
||||
file delete $filename
|
||||
set dg-do-what-default ${saved-dg-do-what-default}
|
||||
}
|
||||
|
||||
# This is an execution test which should fail.
|
||||
proc go-execute-xfail { test } {
|
||||
global DEFAULT_GOCFLAGS
|
||||
|
||||
set filename [file tail $test]
|
||||
set fdin [open $test r]
|
||||
set fdout [open $filename w]
|
||||
puts $fdout "// { dg-do run { xfail *-*-* } }"
|
||||
while { [gets $fdin copy_line] >= 0 } {
|
||||
puts $fdout $copy_line
|
||||
}
|
||||
close $fdin
|
||||
close $fdout
|
||||
go-dg-runtest $filename "-w $DEFAULT_GOCFLAGS"
|
||||
file delete $filename
|
||||
}
|
||||
|
||||
proc go-gc-tests { } {
|
||||
global srcdir subdir
|
||||
global runtests
|
||||
global GCC_UNDER_TEST
|
||||
global TOOL_OPTIONS
|
||||
global TORTURE_OPTIONS
|
||||
global dg-do-what-default
|
||||
global go_execute_args
|
||||
global target_triplet
|
||||
|
||||
# If a testcase doesn't have special options, use these.
|
||||
global DEFAULT_GOCFLAGS
|
||||
if ![info exists DEFAULT_GOCFLAGS] {
|
||||
set DEFAULT_GOCFLAGS " -pedantic-errors"
|
||||
}
|
||||
|
||||
# Running all the torture options takes too long and, since the
|
||||
# frontend ignores the standard options, it doesn't significantly
|
||||
# improve testing.
|
||||
set saved_torture_options $TORTURE_OPTIONS
|
||||
set TORTURE_OPTIONS [ list { -O2 -g }]
|
||||
|
||||
set saved-dg-do-what-default ${dg-do-what-default}
|
||||
|
||||
set testdir [pwd]
|
||||
|
||||
set tests [lsort [find $srcdir/$subdir *.go]]
|
||||
foreach test $tests {
|
||||
if ![runtest_file_p $runtests $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
# Skip the files in bench and garbage; they are not tests.
|
||||
if [string match "*go.test/test/bench/*" $test] {
|
||||
continue
|
||||
}
|
||||
if [string match "*go.test/test/garbage/*" $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
# Skip files in sub-subdirectories: they are components of
|
||||
# other tests.
|
||||
if [string match "*go.test/test/*/*/*" $test] {
|
||||
continue
|
||||
}
|
||||
|
||||
set name [dg-trim-dirname $srcdir $test]
|
||||
|
||||
# Skip certain tests if target is RTEMS OS.
|
||||
if [istarget "*-*-rtems*"] {
|
||||
if { [string match "*go.test/test/args.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/env.go" \
|
||||
$test] } {
|
||||
untested "$name: uses the command-line or environment variables"
|
||||
continue
|
||||
}
|
||||
|
||||
if { [string match "*go.test/test/stack.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/peano.go" \
|
||||
$test] \
|
||||
|| [string match "*go.test/test/chan/goroutines.go" \
|
||||
$test] } {
|
||||
untested "$name: has very high memory requirement"
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
set fd [open $test r]
|
||||
|
||||
set lines_ok 1
|
||||
|
||||
while 1 {
|
||||
if { [gets $fd test_line] < 0 } {
|
||||
close $fd
|
||||
clone_output "$test: could not read first line"
|
||||
unresolved $name
|
||||
set lines_ok 0
|
||||
break
|
||||
}
|
||||
|
||||
if { [ string match "*nacl*exit 0*" $test_line ] \
|
||||
|| [ string match "*exit 0*nacl*" $test_line ] \
|
||||
|| [ string match "*Android*exit 0*" $test_line ] \
|
||||
|| [ string match "*exit 0*Android*" $test_line ] } {
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if { $lines_ok == 0 } {
|
||||
continue
|
||||
}
|
||||
|
||||
set lineno 1
|
||||
set test_line1 $test_line
|
||||
|
||||
while { [eval "string match \"//*&&\" \${test_line$lineno}"] } {
|
||||
set lineno [expr $lineno + 1]
|
||||
if { [eval "gets \$fd test_line$lineno"] < 0 } {
|
||||
close $fd
|
||||
clone_output "$test: could not read line $lineno"
|
||||
unresolved $name
|
||||
set lines_ok 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if { $lines_ok == 0 } {
|
||||
continue
|
||||
}
|
||||
|
||||
close $fd
|
||||
|
||||
set go_execute_args ""
|
||||
if { [regexp ".*\\\$A.out (\[^|&>\].*)\$" $test_line match progargs] } {
|
||||
set go_execute_args $progargs
|
||||
verbose -log "$test: go_execute_args is $go_execute_args"
|
||||
set index [string last " $progargs" $test_line]
|
||||
set test_line [string replace $test_line $index end]
|
||||
}
|
||||
|
||||
if { $test_line == "// \$G \$D/\$F\.go && \$L \$F\.\$A && \./\$A\.out >tmp.go &&" \
|
||||
&& $test_line2 == "// \$G tmp\.go && \$L tmp\.\$A && \./\$A\.out || echo BUG: 64bit" } {
|
||||
# 64bit.go is a special case.
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set base "[file rootname [file tail $test]]"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file >$base-out.go"] != 0 } {
|
||||
fail "$name execution"
|
||||
} else {
|
||||
pass "$name execution"
|
||||
file delete $base-out.x
|
||||
go-torture-execute "./$base-out.go"
|
||||
}
|
||||
file delete $base-out.go
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
|| $test_line == "// \$G \$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
|| $test_line == "// \$G \$F.go && \$L \$F.\$A &&./\$A.out" \
|
||||
|| $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && \$A.out" \
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && (./\$A.out || echo BUG*" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$F.go && \$L \$F.\$A && GOMAXPROCS=* ./\$A.out" \
|
||||
$test_line]
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >* || echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla execution test.
|
||||
go-torture-execute $test
|
||||
file delete core [glob -nocomplain core.*]
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.go && \$L \$F.\$A || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$F.go && \$L \$F.\$A #*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla compile and link test.
|
||||
set dg-do-what-default "link"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$F.go || echo BUG*" \
|
||||
$test_line] \
|
||||
|| [string match "// ! \$G \$D/\$F.go && echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a vanilla compile test.
|
||||
set dg-do-what-default "assemble"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go && echo BUG*" \
|
||||
$test_line] \
|
||||
|| $test_line == "// ! \$G \$D/\$F.go >/dev/null" \
|
||||
|| $test_line == "// ! \$G \$D/\$F.go" \
|
||||
|| $test_line == "// ! \$G \$F.go" \
|
||||
|| [string match "// ! \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
# This is a compile test which should fail.
|
||||
set dg-do-what-default "assemble"
|
||||
setup_xfail "*-*-*"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go && \$L \$F.\$A && ! ./\$A.out || echo BUG: *" \
|
||||
$test_line] \
|
||||
|| [string match "// \$G \$D/\$F.go && \$L \$F.\$A && (! ./\$A.out || echo BUG: *" \
|
||||
$test_line] \
|
||||
|| ($test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&"
|
||||
&& $test_line2 == "// ((! sh -c ./\$A.out) >/dev/null 2>&1 || echo BUG: should fail)") } {
|
||||
go-execute-xfail $test
|
||||
} elseif { [string match "// errchk \$G \$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G -e \$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "//errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// errchk \$G -e \$D/\$F.go" \
|
||||
$test_line] \
|
||||
|| [string match "// ! errchk \$G \$D/\$F.go" $test_line] \
|
||||
|| [string match "// ! errchk \$G -e \$D/\$F.go" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G -e \$D/\$F.go || true" \
|
||||
$test_line] \
|
||||
|| [string match "// errchk \$G \$D/\$F.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
errchk $test
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && errchk \$G \$D/\$F.dir/bug1.go" \
|
||||
$test_line] \
|
||||
|| [string match \
|
||||
"// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
|
||||
$test_line] } {
|
||||
if { [string match \
|
||||
"// \$G \$D/\$F.dir/p1.go && \$G \$D/\$F.dir/p2.go" \
|
||||
$test_line] } {
|
||||
set name1 "p1.go"
|
||||
set name2 "p2.go"
|
||||
} else {
|
||||
set name1 "bug0.go"
|
||||
set name2 "bug1.go"
|
||||
}
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/$name1" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/$name2" file2
|
||||
errchk $file2
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && (! \$G \$D/\$F.dir/bug1.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
setup_xfail "*-*-*"
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && (! \$G \$D/\$F.dir/bug2.go || echo BUG*" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file3
|
||||
setup_xfail "*-*-*"
|
||||
dg-test $file3 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
file delete "[file rootname [file tail $file2]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/bug0.go && \$G \$D/\$F.dir/bug1.go && errchk \$G \$D/\$F.dir/bug2.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file3
|
||||
errchk $file3
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
file delete "[file rootname [file tail $file2]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/bug160.dir/x.go && \$G \$D/bug160.dir/y.go && \$L y.\$A && ./\$A.out" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/x.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/y.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
set dg-do-what-default "link"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
verbose -log $comp_output
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/bug191.dir/a.go && \$G \$D/bug191.dir/b.go && \$G \$D/\$F.go && \$L \$F.\$A" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/a.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/b.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
dg-test -keep-output "$test" "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile3 "[file rootname [file tail $test]].o"
|
||||
set dg-do-what-default "link"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2 $ofile3" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
pass $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $ofile3 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/embed0.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" \
|
||||
$test_line ] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/embed0.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $test]].o"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/chanbug.go && \$G -I. \$D/\$F.dir/chanbug2.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/chanbug.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/chanbug2.go" file2
|
||||
dg-test $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match \
|
||||
"// (! \$G \$D/\$F.go) | grep 'initialization loop' *" \
|
||||
$test_line] } {
|
||||
set dg-do-what-default "assemble"
|
||||
setup_xfail "*-*-*"
|
||||
go-dg-runtest $test "-w $DEFAULT_GOCFLAGS"
|
||||
} elseif { [string match \
|
||||
"// \$G \$D/\$F.dir/x.go && errchk \$G \$D/\$F.dir/y.go" \
|
||||
$test_line] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/x.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
regsub "\\.go$" $test ".dir/y.go" file2
|
||||
errchk $file2
|
||||
file delete "[file rootname [file tail $file1]].o"
|
||||
set runtests $hold_runtests
|
||||
} elseif { [string match "// true*" $test_line] } {
|
||||
# Not a real test, just ignore.
|
||||
} elseif { $test_line == "// \$G \$D/\$F.dir/bug0.go &&" \
|
||||
&& $test_line2 == "// \$G \$D/\$F.dir/bug1.go &&" \
|
||||
&& $test_line3 == "// \$G \$D/\$F.dir/bug2.go &&" \
|
||||
&& $test_line4 == "// errchk \$G -e \$D/\$F.dir/bug3.go &&" \
|
||||
&& $test_line5 == "// \$L bug2.\$A &&" \
|
||||
&& [string match "// ./\$A.out || echo BUG*" $test_line6] } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "\\.go$" $test ".dir/bug0.go" file0
|
||||
dg-test -keep-output $file0 "-O -fgo-prefix=bug0" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile0 "[file rootname [file tail $file0]].o"
|
||||
regsub "\\.go$" $test ".dir/bug1.go" file1
|
||||
dg-test -keep-output $file1 "-O -fgo-prefix=bug1" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
regsub "\\.go$" $test ".dir/bug2.go" file2
|
||||
dg-test -keep-output $file2 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $file2]].o"
|
||||
regsub "\\.go$" $test ".dir/bug3.go" file3
|
||||
errchk $file3
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile0 $ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp-output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile0 $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/import2.go && \$G \$D/\$F\.go" } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/import2.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
file delete $ofile1
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/ddd2.go && \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out" } {
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "assemble"
|
||||
regsub "/\[^/\]*$" $test "/ddd2.go" file1
|
||||
dg-test -keep-output $file1 "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile1 "[file rootname [file tail $file1]].o"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set ofile2 "[file rootname [file tail $test]].o"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
set comp_output [go_target_compile "$ofile1 $ofile2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $ofile1 $ofile2 $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go \$D/cmplxdivide1.go && \$L \$D/\$F.\$A && ./\$A.out" } {
|
||||
regsub "/\[^/\]*$" $test "/cmplxdivide1.go" test2
|
||||
set output_file "./[file rootname [file tail $test]].o"
|
||||
set comp_output [go_target_compile "$test $test2" \
|
||||
$output_file "executable" "$DEFAULT_GOCFLAGS"]
|
||||
set comp_output [go-dg-prune $target_triplet $comp_output]
|
||||
if [string match "" $comp_output] {
|
||||
set result [go_load "$output_file" "" ""]
|
||||
set status [lindex $result 0]
|
||||
$status $name
|
||||
} else {
|
||||
verbose -log $comp_output
|
||||
fail $name
|
||||
}
|
||||
file delete $output_file
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A &&" \
|
||||
&& $test_line2 == "// ./\$A.out -pass 0 >tmp.go && \$G tmp.go && \$L -o tmp1.\$A tmp.\$A && ./tmp1.\$A &&" \
|
||||
&& $test_line3 == "// ./\$A.out -pass 1 >tmp.go && errchk \$G -e tmp.go &&" \
|
||||
&& $test_line4 == "// ./\$A.out -pass 2 >tmp.go && errchk \$G -e tmp.go" } {
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file -pass 0 >tmp.go"] != 0 } {
|
||||
fail "$name execution 0"
|
||||
} else {
|
||||
pass "$name execution 0"
|
||||
file delete tmp.x
|
||||
go-torture-execute "./tmp.go"
|
||||
}
|
||||
if { [catch "exec $output_file -pass 1 >tmp.go"] != 0 } {
|
||||
fail "$name execution 1"
|
||||
} else {
|
||||
pass "$name execution 1"
|
||||
errchk tmp.go
|
||||
}
|
||||
if { [catch "exec $output_file -pass 2 >tmp.go"] != 0 } {
|
||||
fail "$name execution 2"
|
||||
} else {
|
||||
pass "$name execution 2"
|
||||
errchk tmp.go
|
||||
}
|
||||
file delete tmp.go
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// \$G \$D/\$F.go && \$L \$F.\$A && ./\$A.out >tmp.go &&" \
|
||||
&& $test_line2 == "// errchk \$G -e tmp.go" } {
|
||||
set go_execute_args ""
|
||||
set hold_runtests $runtests
|
||||
set runtests "go-test.exp"
|
||||
set dg-do-what-default "link"
|
||||
dg-test -keep-output $test "-O" "-w $DEFAULT_GOCFLAGS"
|
||||
set output_file "./[file rootname [file tail $test]].exe"
|
||||
if [isnative] {
|
||||
if { [catch "exec $output_file >tmp.go"] != 0 } {
|
||||
fail "$name execution"
|
||||
} else {
|
||||
pass "$name execution"
|
||||
file delete tmp.x
|
||||
errchk tmp.go
|
||||
}
|
||||
}
|
||||
file delete $output_file
|
||||
set runtests $hold_runtests
|
||||
} elseif { $test_line == "// # generated by cmplxdivide.c" } {
|
||||
# Ignore.
|
||||
} elseif { $test_line == "// \$G \$D/bug302.dir/p.go && gopack grc pp.a p.\$A && \$G \$D/bug302.dir/main.go" \
|
||||
|| $test_line == "// \$G \$D/empty.go && errchk \$G \$D/\$F.go" } {
|
||||
# These tests import the same package under two different
|
||||
# names, which gccgo does not support.
|
||||
} elseif { $test_line == "// \$G -S \$D/\$F.go | egrep initdone >/dev/null && echo FAIL || true" } {
|
||||
# This tests whether initializers are written out
|
||||
# statically. gccgo does not provide a way to test that,
|
||||
# as an initializer will be generated for any code which
|
||||
# has global variables which need to be registered as GC
|
||||
# roots.
|
||||
} else {
|
||||
clone_output "$name: unrecognized test line: $test_line"
|
||||
unsupported $name
|
||||
}
|
||||
|
||||
set go_execute_args ""
|
||||
}
|
||||
|
||||
set dg-do-what-default ${saved-dg-do-what-default}
|
||||
set TORTURE_OPTIONS $saved_torture_options
|
||||
}
|
||||
|
||||
go-gc-tests
|
72
gcc/testsuite/go.test/test/235.go
Normal file
72
gcc/testsuite/go.test/test/235.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
// $G $F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// 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
|
||||
|
||||
type T chan uint64
|
||||
|
||||
func M(f uint64) (in, out T) {
|
||||
in = make(T, 100)
|
||||
out = make(T, 100)
|
||||
go func(in, out T, f uint64) {
|
||||
for {
|
||||
out <- f*<-in
|
||||
}
|
||||
}(in, out, f)
|
||||
return in, out
|
||||
}
|
||||
|
||||
|
||||
func min(xs []uint64) uint64 {
|
||||
m := xs[0]
|
||||
for i := 1; i < len(xs); i++ {
|
||||
if xs[i] < m {
|
||||
m = xs[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
F := []uint64{2, 3, 5}
|
||||
var n = len(F)
|
||||
OUT := []uint64{
|
||||
2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36,
|
||||
40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125,
|
||||
128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243, 250,
|
||||
256, 270, 288, 300, 320, 324, 360, 375, 384, 400, 405, 432, 450, 480,
|
||||
486, 500, 512, 540, 576, 600, 625, 640, 648, 675, 720, 729, 750, 768,
|
||||
800, 810, 864, 900, 960, 972, 1000, 1024, 1080, 1125, 1152, 1200, 1215,
|
||||
1250, 1280, 1296, 1350, 1440, 1458, 1500, 1536, 1600}
|
||||
|
||||
x := uint64(1)
|
||||
ins := make([]T, n)
|
||||
outs := make([]T, n)
|
||||
xs := make([]uint64, n)
|
||||
for i := 0; i < n; i++ {
|
||||
ins[i], outs[i] = M(F[i])
|
||||
xs[i] = x
|
||||
}
|
||||
|
||||
for i := 0; i < len(OUT); i++ {
|
||||
for i := 0; i < n; i++ {
|
||||
ins[i] <- x
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if xs[i] == x {
|
||||
xs[i] = <-outs[i]
|
||||
}
|
||||
}
|
||||
|
||||
x = min(xs)
|
||||
if x != OUT[i] {
|
||||
println("bad: ", x, " should be ", OUT[i])
|
||||
panic("235")
|
||||
}
|
||||
}
|
||||
}
|
709
gcc/testsuite/go.test/test/64bit.go
Normal file
709
gcc/testsuite/go.test/test/64bit.go
Normal file
|
@ -0,0 +1,709 @@
|
|||
// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
|
||||
// $G tmp.go && $L tmp.$A && ./$A.out || echo BUG: 64bit
|
||||
// rm -f tmp.go
|
||||
|
||||
// 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 test of 64-bit arithmetic.
|
||||
// Most synthesized routines have different cases for
|
||||
// constants vs variables and even the generated code has
|
||||
// different cases for large and small constants,
|
||||
// so try a good range of inputs.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var bout *bufio.Writer
|
||||
|
||||
// 64-bit math without using 64-bit numbers,
|
||||
// so that we can generate the test program even
|
||||
// if the compiler has buggy or missing 64-bit support.
|
||||
|
||||
type Uint64 struct {
|
||||
hi uint32
|
||||
lo uint32
|
||||
}
|
||||
|
||||
type Int64 struct {
|
||||
hi int32
|
||||
lo uint32
|
||||
}
|
||||
|
||||
func (a Uint64) Int64() (c Int64) {
|
||||
c.hi = int32(a.hi)
|
||||
c.lo = a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Cmp(b Uint64) int {
|
||||
switch {
|
||||
case a.hi < b.hi:
|
||||
return -1
|
||||
case a.hi > b.hi:
|
||||
return 1
|
||||
case a.lo < b.lo:
|
||||
return -1
|
||||
case a.lo > b.lo:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Uint64) LeftShift(b uint) (c Uint64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = 0
|
||||
c.lo = 0
|
||||
case b >= 32:
|
||||
c.hi = a.lo << (b - 32)
|
||||
c.lo = 0
|
||||
default:
|
||||
c.hi = a.hi<<b | a.lo>>(32-b)
|
||||
c.lo = a.lo << b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) RightShift(b uint) (c Uint64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = 0
|
||||
c.lo = a.hi
|
||||
case b >= 32:
|
||||
c.hi = 0
|
||||
c.lo = a.hi >> (b - 32)
|
||||
default:
|
||||
c.hi = a.hi >> b
|
||||
c.lo = a.hi<<(32-b) | a.lo>>b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.LeftShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Uint64) RightShift64(b Uint64) (c Uint64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.RightShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Uint64) Plus(b Uint64) (c Uint64) {
|
||||
var carry uint32
|
||||
if c.lo = a.lo + b.lo; c.lo < a.lo {
|
||||
carry = 1
|
||||
}
|
||||
c.hi = a.hi + b.hi + carry
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Minus(b Uint64) (c Uint64) {
|
||||
var borrow uint32
|
||||
if c.lo = a.lo - b.lo; c.lo > a.lo {
|
||||
borrow = 1
|
||||
}
|
||||
c.hi = a.hi - b.hi - borrow
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Neg() (c Uint64) {
|
||||
var zero Uint64
|
||||
return zero.Minus(a)
|
||||
}
|
||||
|
||||
func (a Uint64) Com() (c Uint64) {
|
||||
c.hi = ^a.hi
|
||||
c.lo = ^a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Len() int {
|
||||
switch {
|
||||
case a.hi != 0:
|
||||
for i := 31; i >= 0; i-- {
|
||||
if a.hi&(1<<uint(i)) != 0 {
|
||||
return i + 1 + 32
|
||||
}
|
||||
}
|
||||
case a.lo != 0:
|
||||
for i := 31; i >= 0; i-- {
|
||||
if a.lo&(1<<uint(i)) != 0 {
|
||||
return i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Uint64) HasBit(b uint) bool {
|
||||
switch {
|
||||
case b >= 64:
|
||||
return false
|
||||
case b >= 32:
|
||||
return a.hi&(1<<(b-32)) != 0
|
||||
}
|
||||
return a.lo&(1<<b) != 0
|
||||
}
|
||||
|
||||
func (a Uint64) Times(b Uint64) (c Uint64) {
|
||||
for i := uint(0); i < 64; i++ {
|
||||
if b.HasBit(i) {
|
||||
c = c.Plus(a.LeftShift(i))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
|
||||
n := a.Len() - b.Len()
|
||||
if n >= 0 {
|
||||
b = b.LeftShift(uint(n))
|
||||
for i := 0; i <= n; i++ {
|
||||
quo = quo.LeftShift(1)
|
||||
if b.Cmp(a) <= 0 { // b <= a
|
||||
quo.lo |= 1
|
||||
a = a.Minus(b)
|
||||
}
|
||||
b = b.RightShift(1)
|
||||
}
|
||||
}
|
||||
rem = a
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) And(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi & b.hi
|
||||
c.lo = a.lo & b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) AndNot(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi &^ b.hi
|
||||
c.lo = a.lo &^ b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Or(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi | b.hi
|
||||
c.lo = a.lo | b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) Xor(b Uint64) (c Uint64) {
|
||||
c.hi = a.hi ^ b.hi
|
||||
c.lo = a.lo ^ b.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Uint64) String() string { return fmt.Sprintf("%#x%08x", a.hi, a.lo) }
|
||||
|
||||
func (a Int64) Uint64() (c Uint64) {
|
||||
c.hi = uint32(a.hi)
|
||||
c.lo = a.lo
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) Cmp(b Int64) int {
|
||||
// Same body as Uint64.Cmp,
|
||||
// but behaves differently
|
||||
// because hi is uint32 not int32.
|
||||
switch {
|
||||
case a.hi < b.hi:
|
||||
return -1
|
||||
case a.hi > b.hi:
|
||||
return 1
|
||||
case a.lo < b.lo:
|
||||
return -1
|
||||
case a.lo > b.lo:
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int64() }
|
||||
|
||||
func (a Int64) RightShift(b uint) (c Int64) {
|
||||
switch {
|
||||
case b >= 64:
|
||||
c.hi = a.hi >> 31 // sign extend
|
||||
c.lo = uint32(c.hi)
|
||||
case b >= 32:
|
||||
c.hi = a.hi >> 31 // sign extend
|
||||
c.lo = uint32(a.hi >> (b - 32))
|
||||
default:
|
||||
c.hi = a.hi >> b
|
||||
c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) LeftShift64(b Uint64) (c Int64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return
|
||||
}
|
||||
return a.LeftShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Int64) RightShift64(b Uint64) (c Int64) {
|
||||
if b.hi != 0 || b.lo >= 64 {
|
||||
return a.RightShift(64)
|
||||
}
|
||||
return a.RightShift(uint(b.lo))
|
||||
}
|
||||
|
||||
func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Minus(b Int64) (c Int64) { return a.Uint64().Minus(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Neg() (c Int64) { return a.Uint64().Neg().Int64() }
|
||||
|
||||
func (a Int64) Com() (c Int64) { return a.Uint64().Com().Int64() }
|
||||
|
||||
func (a Int64) Times(b Int64) (c Int64) { return a.Uint64().Times(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
|
||||
var zero Int64
|
||||
|
||||
quoSign := +1
|
||||
remSign := +1
|
||||
if a.Cmp(zero) < 0 {
|
||||
quoSign = -1
|
||||
remSign = -1
|
||||
a = a.Neg()
|
||||
}
|
||||
if b.Cmp(zero) < 0 {
|
||||
quoSign = -quoSign
|
||||
b = b.Neg()
|
||||
}
|
||||
|
||||
q, r := a.Uint64().DivMod(b.Uint64())
|
||||
quo = q.Int64()
|
||||
rem = r.Int64()
|
||||
|
||||
if quoSign < 0 {
|
||||
quo = quo.Neg()
|
||||
}
|
||||
if remSign < 0 {
|
||||
rem = rem.Neg()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a Int64) And(b Int64) (c Int64) { return a.Uint64().And(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) AndNot(b Int64) (c Int64) { return a.Uint64().AndNot(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Or(b Int64) (c Int64) { return a.Uint64().Or(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) Xor(b Int64) (c Int64) { return a.Uint64().Xor(b.Uint64()).Int64() }
|
||||
|
||||
func (a Int64) String() string {
|
||||
if a.hi < 0 {
|
||||
return fmt.Sprintf("-%s", a.Neg().Uint64())
|
||||
}
|
||||
return a.Uint64().String()
|
||||
}
|
||||
|
||||
var int64Values = []Int64{
|
||||
Int64{0, 0},
|
||||
Int64{0, 1},
|
||||
Int64{0, 2},
|
||||
Int64{0, 3},
|
||||
Int64{0, 100},
|
||||
Int64{0, 10001},
|
||||
Int64{0, 1<<31 - 1},
|
||||
Int64{0, 1 << 31},
|
||||
Int64{0, 1<<31 + 1},
|
||||
Int64{0, 1<<32 - 1<<30},
|
||||
Int64{0, 1<<32 - 1},
|
||||
Int64{1, 0},
|
||||
Int64{1, 1},
|
||||
Int64{2, 0},
|
||||
Int64{1<<31 - 1, 1<<32 - 10000},
|
||||
Int64{1<<31 - 1, 1<<32 - 1},
|
||||
Int64{0x789abcde, 0xf0123456},
|
||||
|
||||
Int64{-1, 1<<32 - 1},
|
||||
Int64{-1, 1<<32 - 2},
|
||||
Int64{-1, 1<<32 - 3},
|
||||
Int64{-1, 1<<32 - 100},
|
||||
Int64{-1, 1<<32 - 10001},
|
||||
Int64{-1, 1<<32 - (1<<31 - 1)},
|
||||
Int64{-1, 1<<32 - 1<<31},
|
||||
Int64{-1, 1<<32 - (1<<31 + 1)},
|
||||
Int64{-1, 1<<32 - (1<<32 - 1<<30)},
|
||||
Int64{-1, 0},
|
||||
Int64{-1, 1},
|
||||
Int64{-2, 0},
|
||||
Int64{-(1 << 31), 10000},
|
||||
Int64{-(1 << 31), 1},
|
||||
Int64{-(1 << 31), 0},
|
||||
Int64{-0x789abcde, 0xf0123456},
|
||||
}
|
||||
|
||||
var uint64Values = []Uint64{
|
||||
Uint64{0, 0},
|
||||
Uint64{0, 1},
|
||||
Uint64{0, 2},
|
||||
Uint64{0, 3},
|
||||
Uint64{0, 100},
|
||||
Uint64{0, 10001},
|
||||
Uint64{0, 1<<31 - 1},
|
||||
Uint64{0, 1 << 31},
|
||||
Uint64{0, 1<<31 + 1},
|
||||
Uint64{0, 1<<32 - 1<<30},
|
||||
Uint64{0, 1<<32 - 1},
|
||||
Uint64{1, 0},
|
||||
Uint64{1, 1},
|
||||
Uint64{2, 0},
|
||||
Uint64{1<<31 - 1, 1<<32 - 10000},
|
||||
Uint64{1<<31 - 1, 1<<32 - 1},
|
||||
Uint64{1<<32 - 1<<30, 0},
|
||||
Uint64{1<<32 - 1, 0},
|
||||
Uint64{1<<32 - 1, 1<<32 - 100},
|
||||
Uint64{1<<32 - 1, 1<<32 - 1},
|
||||
Uint64{0x789abcde, 0xf0123456},
|
||||
Uint64{0xfedcba98, 0x76543210},
|
||||
}
|
||||
|
||||
var shiftValues = []Uint64{
|
||||
Uint64{0, 0},
|
||||
Uint64{0, 1},
|
||||
Uint64{0, 2},
|
||||
Uint64{0, 3},
|
||||
Uint64{0, 15},
|
||||
Uint64{0, 16},
|
||||
Uint64{0, 17},
|
||||
Uint64{0, 31},
|
||||
Uint64{0, 32},
|
||||
Uint64{0, 33},
|
||||
Uint64{0, 61},
|
||||
Uint64{0, 62},
|
||||
Uint64{0, 63},
|
||||
Uint64{0, 64},
|
||||
Uint64{0, 65},
|
||||
Uint64{0, 1<<32 - 1},
|
||||
Uint64{1, 0},
|
||||
Uint64{1, 1},
|
||||
Uint64{1 << 28, 0},
|
||||
Uint64{1 << 31, 0},
|
||||
Uint64{1<<32 - 1, 0},
|
||||
Uint64{1<<32 - 1, 1<<32 - 1},
|
||||
}
|
||||
|
||||
var ntest = 0
|
||||
|
||||
// Part 1 is tests of variable operations; generic functions
|
||||
// called by repetitive code. Could make a table but not worth it.
|
||||
|
||||
const prolog = "\n" +
|
||||
"package main\n" +
|
||||
"\n" +
|
||||
"import \"os\"\n" +
|
||||
"\n" +
|
||||
"var ok = true\n" +
|
||||
"\n" +
|
||||
"func testInt64Unary(a, plus, xor, minus int64) {\n" +
|
||||
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`int64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testInt64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot int64, dodiv bool) {\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`int64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testInt64Shift(a int64, b uint64, left, right int64) {\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint(b)) == b {\n" +
|
||||
" b := uint(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint16(b)) == b {\n" +
|
||||
" b := uint16(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint8(b)) == b {\n" +
|
||||
" b := uint8(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`int64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Unary(a, plus, xor, minus uint64) {\n" +
|
||||
" if n, op, want := +a, `+`, plus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := ^a, `^`, xor; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := -a, `-`, minus; n != want { ok=false; println(`uint64`, op, a, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Binary(a, b, add, sub, mul, div, mod, and, or, xor, andnot uint64, dodiv bool) {\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a % b, `%`, mod; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(`uint64`, a, op, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"func testUint64Shift(a, b, left, right uint64) {\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint64`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint(b)) == b {\n" +
|
||||
" b := uint(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint32`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint16(b)) == b {\n" +
|
||||
" b := uint16(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint16`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if uint64(uint8(b)) == b {\n" +
|
||||
" b := uint8(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(`uint64`, a, op, `uint8`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
func varTests() {
|
||||
fmt.Fprint(bout, prolog)
|
||||
for _, a := range int64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
|
||||
for _, b := range int64Values {
|
||||
var div, mod Int64
|
||||
dodiv := false
|
||||
var zero Int64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
// Can't divide by zero but also can't divide -0x8000...000 by -1.
|
||||
var bigneg = Int64{-0x80000000, 0}
|
||||
var minus1 = Int64{-1, ^uint32(0)}
|
||||
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestInt64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for _, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestInt64Shift(%v, %v, %v, %v);\n",
|
||||
a, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
|
||||
for _, a := range uint64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
|
||||
for _, b := range uint64Values {
|
||||
var div, mod Uint64
|
||||
dodiv := false
|
||||
var zero Uint64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestUint64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for _, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestUint64Shift(%v, %v, %v, %v);\n",
|
||||
a, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
// Part 2 is tests of operations involving one variable and one constant.
|
||||
|
||||
const binaryConstL = "func test%vBinaryL%v(b, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
|
||||
" const a %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `const`, a, op, `var`, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
const binaryConstR = "func test%vBinaryR%v(a, add, sub, mul, div, mod, and, or, xor, andnot %v, dodiv bool) {\n" +
|
||||
" const b %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, want := a + b, `+`, add; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a - b, `-`, sub; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a * b, `*`, mul; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if dodiv {\n" +
|
||||
" if n, op, want := a / b, `/`, div; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a %% b, `%%`, mod; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
" if n, op, want := a & b, `&`, and; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a | b, `|`, or; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a ^ b, `^`, xor; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, want := a &^ b, `&^`, andnot; n != want { ok=false; println(typ, `var`, a, op, `const`, b, `=`, n, `should be`, want); }\n" +
|
||||
"}\n" +
|
||||
"\n"
|
||||
|
||||
const shiftConstL = "func test%vShiftL%v(b uint64, left, right %v) {\n" +
|
||||
" const a %v = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if uint64(uint32(b)) == b {\n" +
|
||||
" b := uint32(b);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `const`, a, op, `var`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n"
|
||||
|
||||
const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
|
||||
" const b uint64 = %v;\n" +
|
||||
" const typ = `%s`;\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if b & 0xffffffff == b {\n" +
|
||||
" const b = uint32(b & 0xffffffff);\n" +
|
||||
" if n, op, s, want := a << b, `<<`, b, left; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" if n, op, s, want := a >> b, `>>`, b, right; n != want { ok=false; println(typ, `var`, a, op, `const`, s, `=`, n, `should be`, want); }\n" +
|
||||
" }\n" +
|
||||
"}\n"
|
||||
|
||||
func constTests() {
|
||||
for i, a := range int64Values {
|
||||
fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64")
|
||||
fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64")
|
||||
fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64")
|
||||
}
|
||||
for i, a := range uint64Values {
|
||||
fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
|
||||
}
|
||||
for i, a := range shiftValues {
|
||||
fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64")
|
||||
fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64")
|
||||
}
|
||||
for i, a := range int64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
for j, b := range int64Values {
|
||||
var div, mod Int64
|
||||
dodiv := false
|
||||
var zero Int64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
// Can't divide by zero but also can't divide -0x8000...000 by -1.
|
||||
var bigneg = Int64{-0x80000000, 0}
|
||||
var minus1 = Int64{-1, ^uint32(0)}
|
||||
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestInt64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
fmt.Fprintf(bout, "\ttestInt64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for j, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
|
||||
i, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
fmt.Fprintf(bout, "\ttestInt64ShiftR%v(%v, %v, %v);\n",
|
||||
j, a, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
for i, a := range uint64Values {
|
||||
fmt.Fprintf(bout, "func test%v() {\n", ntest)
|
||||
ntest++
|
||||
for j, b := range uint64Values {
|
||||
var div, mod Uint64
|
||||
dodiv := false
|
||||
var zero Uint64
|
||||
if b.Cmp(zero) != 0 { // b != 0
|
||||
div, mod = a.DivMod(b)
|
||||
dodiv = true
|
||||
}
|
||||
fmt.Fprintf(bout, "\ttestUint64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
fmt.Fprintf(bout, "\ttestUint64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
|
||||
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
|
||||
a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
|
||||
}
|
||||
for j, b := range shiftValues {
|
||||
fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
|
||||
i, b, a.LeftShift64(b), a.RightShift64(b))
|
||||
fmt.Fprintf(bout, "\ttestUint64ShiftR%v(%v, %v, %v);\n",
|
||||
j, a, a.LeftShift64(b), a.RightShift64(b))
|
||||
}
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
bout = bufio.NewWriter(os.Stdout)
|
||||
varTests()
|
||||
constTests()
|
||||
|
||||
fmt.Fprintf(bout, "func main() {\n")
|
||||
for i := 0; i < ntest; i++ {
|
||||
fmt.Fprintf(bout, "\ttest%v();\n", i)
|
||||
}
|
||||
fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
|
||||
fmt.Fprintf(bout, "}\n")
|
||||
bout.Flush()
|
||||
}
|
7
gcc/testsuite/go.test/test/README.gcc
Normal file
7
gcc/testsuite/go.test/test/README.gcc
Normal file
|
@ -0,0 +1,7 @@
|
|||
This directory is an exact copy (except for this file) of the Go
|
||||
testsuite from the test subdirectory of http://code.google.com/p/go.
|
||||
This is here so that we run the same tests as the gc Go compiler. We
|
||||
do not, however, run the tests in the same way. The gc compiler uses
|
||||
the run shell script in this directory. For gccgo, we use the file
|
||||
go-test.exp in the parent directory to run the tests in gcc's usual
|
||||
DejaGNU test harness.
|
21
gcc/testsuite/go.test/test/args.go
Normal file
21
gcc/testsuite/go.test/test/args.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
// $G $F.go && $L $F.$A && ./$A.out arg1 arg2
|
||||
|
||||
// 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 "os"
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 3 {
|
||||
panic("argc")
|
||||
}
|
||||
if os.Args[1] != "arg1" {
|
||||
panic("arg1")
|
||||
}
|
||||
if os.Args[2] != "arg2" {
|
||||
panic("arg2")
|
||||
}
|
||||
}
|
488
gcc/testsuite/go.test/test/arm-pass.txt
Normal file
488
gcc/testsuite/go.test/test/arm-pass.txt
Normal file
|
@ -0,0 +1,488 @@
|
|||
./235.go
|
||||
# ./64bit.go # fail, flaky on android build
|
||||
./args.go
|
||||
./assign.go
|
||||
./assign1.go
|
||||
./bigalg.go
|
||||
./bigmap.go
|
||||
./blank.go
|
||||
./blank1.go
|
||||
./chancap.go
|
||||
./char_lit.go
|
||||
./char_lit1.go
|
||||
./closedchan.go
|
||||
./closure.go
|
||||
./cmp1.go
|
||||
./cmp2.go
|
||||
./cmp3.go
|
||||
./cmp4.go
|
||||
./cmp5.go
|
||||
./cmplx.go
|
||||
# ./cmplxdivide.go # fail, BUG
|
||||
./cmplxdivide1.go
|
||||
./complit.go
|
||||
./compos.go
|
||||
./const.go
|
||||
./const1.go
|
||||
./const2.go
|
||||
./const3.go
|
||||
./convert.go
|
||||
./convert3.go
|
||||
./convlit.go
|
||||
./convlit1.go
|
||||
./copy.go
|
||||
./ddd.go
|
||||
./ddd1.go
|
||||
./ddd2.go
|
||||
./ddd3.go
|
||||
./decl.go
|
||||
./declbad.go
|
||||
./defer.go
|
||||
./deferprint.go
|
||||
./empty.go
|
||||
./env.go
|
||||
./escape.go
|
||||
./float_lit.go
|
||||
./floatcmp.go
|
||||
./for.go
|
||||
./func.go
|
||||
./func1.go
|
||||
./func2.go
|
||||
./func3.go
|
||||
./func4.go
|
||||
./func5.go
|
||||
./gc.go
|
||||
./gc1.go
|
||||
./hashmap.go
|
||||
./helloworld.go
|
||||
./if.go
|
||||
./if1.go
|
||||
./import.go
|
||||
./import1.go
|
||||
./import2.go
|
||||
./import3.go
|
||||
./import4.go
|
||||
./indirect.go
|
||||
./indirect1.go
|
||||
./initcomma.go
|
||||
./initialize.go
|
||||
./initializerr.go
|
||||
./initsyscall.go
|
||||
./int_lit.go
|
||||
./intcvt.go
|
||||
./iota.go
|
||||
./literal.go
|
||||
./malloc1.go
|
||||
# ./mallocfin.go # fail
|
||||
./mallocrand.go
|
||||
./mallocrep.go
|
||||
./mallocrep1.go
|
||||
# ./map.go # fail
|
||||
./method.go
|
||||
./method1.go
|
||||
./method2.go
|
||||
./method3.go
|
||||
./named.go
|
||||
./named1.go
|
||||
./nil.go
|
||||
./nul1.go
|
||||
./parentype.go
|
||||
./peano.go
|
||||
./printbig.go
|
||||
./range.go
|
||||
./recover.go
|
||||
./recover1.go
|
||||
./recover2.go
|
||||
# ./recover3.go # fail
|
||||
./rename.go
|
||||
./rename1.go
|
||||
./runtime.go
|
||||
./sieve.go
|
||||
./sigchld.go
|
||||
./simassign.go
|
||||
./sinit.go
|
||||
./stack.go
|
||||
./string_lit.go
|
||||
./stringrange.go
|
||||
./switch.go
|
||||
./switch1.go
|
||||
./test0.go
|
||||
./turing.go
|
||||
./typeswitch.go
|
||||
./typeswitch1.go
|
||||
./typeswitch2.go
|
||||
./undef.go
|
||||
./utf.go
|
||||
./varerr.go
|
||||
./varinit.go
|
||||
./vectors.go
|
||||
./zerodivide.go
|
||||
ken/array.go
|
||||
ken/chan.go
|
||||
ken/chan1.go
|
||||
ken/complit.go
|
||||
# ken/cplx0.go # output fail
|
||||
# ken/cplx1.go # fail
|
||||
# ken/cplx2.go # fail
|
||||
# ken/cplx3.go # output fail
|
||||
# ken/cplx4.go # fail, BUG
|
||||
# ken/cplx5.go # output fail
|
||||
ken/divconst.go
|
||||
ken/divmod.go
|
||||
ken/embed.go
|
||||
ken/for.go
|
||||
ken/interbasic.go
|
||||
ken/interfun.go
|
||||
ken/intervar.go
|
||||
ken/label.go
|
||||
ken/litfun.go
|
||||
ken/mfunc.go
|
||||
ken/modconst.go
|
||||
ken/ptrfun.go
|
||||
ken/ptrvar.go
|
||||
ken/range.go
|
||||
ken/rob1.go
|
||||
ken/rob2.go
|
||||
ken/robfor.go
|
||||
ken/robfunc.go
|
||||
ken/robif.go
|
||||
ken/shift.go
|
||||
ken/simparray.go
|
||||
ken/simpbool.go
|
||||
ken/simpconv.go
|
||||
ken/simpfun.go
|
||||
ken/simpprint.go
|
||||
ken/simpswitch.go
|
||||
ken/simpvar.go
|
||||
ken/slicearray.go
|
||||
ken/sliceslice.go
|
||||
ken/string.go
|
||||
ken/strvar.go
|
||||
chan/doubleselect.go
|
||||
chan/fifo.go
|
||||
chan/goroutines.go
|
||||
chan/nonblock.go
|
||||
chan/perm.go
|
||||
chan/powser1.go
|
||||
chan/powser2.go
|
||||
chan/select.go
|
||||
chan/select2.go
|
||||
# chan/select3.go # fail
|
||||
chan/sieve1.go
|
||||
chan/sieve2.go
|
||||
interface/bigdata.go
|
||||
interface/convert.go
|
||||
interface/convert1.go
|
||||
interface/convert2.go
|
||||
interface/embed.go
|
||||
interface/embed0.go
|
||||
interface/embed1.go
|
||||
interface/explicit.go
|
||||
interface/fail.go
|
||||
interface/fake.go
|
||||
interface/pointer.go
|
||||
interface/receiver.go
|
||||
interface/receiver1.go
|
||||
interface/recursive.go
|
||||
interface/returntype.go
|
||||
interface/struct.go
|
||||
nilptr/arrayindex.go
|
||||
nilptr/arrayindex1.go
|
||||
nilptr/arraytoslice.go
|
||||
nilptr/arraytoslice1.go
|
||||
nilptr/arraytoslice2.go
|
||||
nilptr/slicearray.go
|
||||
nilptr/structfield.go
|
||||
nilptr/structfield1.go
|
||||
nilptr/structfield2.go
|
||||
nilptr/structfieldaddr.go
|
||||
syntax/forvar.go
|
||||
syntax/import.go
|
||||
syntax/interface.go
|
||||
syntax/semi1.go
|
||||
syntax/semi2.go
|
||||
syntax/semi3.go
|
||||
syntax/semi4.go
|
||||
syntax/semi5.go
|
||||
syntax/semi6.go
|
||||
syntax/semi7.go
|
||||
syntax/slice.go
|
||||
syntax/topexpr.go
|
||||
syntax/vareq.go
|
||||
syntax/vareq1.go
|
||||
fixedbugs/bug000.go
|
||||
fixedbugs/bug001.go
|
||||
fixedbugs/bug002.go
|
||||
fixedbugs/bug003.go
|
||||
fixedbugs/bug004.go
|
||||
fixedbugs/bug005.go
|
||||
fixedbugs/bug006.go
|
||||
fixedbugs/bug007.go
|
||||
fixedbugs/bug008.go
|
||||
fixedbugs/bug009.go
|
||||
fixedbugs/bug010.go
|
||||
fixedbugs/bug011.go
|
||||
fixedbugs/bug012.go
|
||||
fixedbugs/bug013.go
|
||||
fixedbugs/bug014.go
|
||||
fixedbugs/bug015.go
|
||||
fixedbugs/bug016.go
|
||||
fixedbugs/bug017.go
|
||||
fixedbugs/bug020.go
|
||||
fixedbugs/bug021.go
|
||||
fixedbugs/bug022.go
|
||||
fixedbugs/bug023.go
|
||||
fixedbugs/bug024.go
|
||||
fixedbugs/bug026.go
|
||||
fixedbugs/bug027.go
|
||||
fixedbugs/bug028.go
|
||||
fixedbugs/bug030.go
|
||||
fixedbugs/bug031.go
|
||||
fixedbugs/bug035.go
|
||||
fixedbugs/bug036.go
|
||||
fixedbugs/bug037.go
|
||||
fixedbugs/bug038.go
|
||||
fixedbugs/bug039.go
|
||||
fixedbugs/bug040.go
|
||||
fixedbugs/bug045.go
|
||||
fixedbugs/bug046.go
|
||||
fixedbugs/bug047.go
|
||||
fixedbugs/bug048.go
|
||||
fixedbugs/bug049.go
|
||||
fixedbugs/bug050.go
|
||||
fixedbugs/bug051.go
|
||||
fixedbugs/bug052.go
|
||||
fixedbugs/bug053.go
|
||||
fixedbugs/bug054.go
|
||||
fixedbugs/bug055.go
|
||||
fixedbugs/bug056.go
|
||||
fixedbugs/bug057.go
|
||||
fixedbugs/bug058.go
|
||||
fixedbugs/bug059.go
|
||||
fixedbugs/bug060.go
|
||||
fixedbugs/bug061.go
|
||||
fixedbugs/bug062.go
|
||||
fixedbugs/bug063.go
|
||||
fixedbugs/bug064.go
|
||||
fixedbugs/bug065.go
|
||||
fixedbugs/bug066.go
|
||||
fixedbugs/bug067.go
|
||||
fixedbugs/bug068.go
|
||||
fixedbugs/bug069.go
|
||||
fixedbugs/bug070.go
|
||||
fixedbugs/bug071.go
|
||||
fixedbugs/bug072.go
|
||||
fixedbugs/bug073.go
|
||||
fixedbugs/bug074.go
|
||||
fixedbugs/bug075.go
|
||||
fixedbugs/bug076.go
|
||||
fixedbugs/bug077.go
|
||||
fixedbugs/bug078.go
|
||||
fixedbugs/bug080.go
|
||||
fixedbugs/bug081.go
|
||||
fixedbugs/bug082.go
|
||||
fixedbugs/bug083.go
|
||||
fixedbugs/bug084.go
|
||||
fixedbugs/bug085.go
|
||||
fixedbugs/bug086.go
|
||||
fixedbugs/bug087.go
|
||||
fixedbugs/bug088.go
|
||||
fixedbugs/bug089.go
|
||||
fixedbugs/bug090.go
|
||||
fixedbugs/bug091.go
|
||||
fixedbugs/bug092.go
|
||||
fixedbugs/bug093.go
|
||||
fixedbugs/bug094.go
|
||||
fixedbugs/bug096.go
|
||||
fixedbugs/bug097.go
|
||||
fixedbugs/bug098.go
|
||||
fixedbugs/bug099.go
|
||||
fixedbugs/bug101.go
|
||||
fixedbugs/bug102.go
|
||||
fixedbugs/bug103.go
|
||||
fixedbugs/bug104.go
|
||||
fixedbugs/bug106.go
|
||||
fixedbugs/bug107.go
|
||||
fixedbugs/bug108.go
|
||||
fixedbugs/bug109.go
|
||||
fixedbugs/bug110.go
|
||||
fixedbugs/bug111.go
|
||||
fixedbugs/bug112.go
|
||||
fixedbugs/bug113.go
|
||||
fixedbugs/bug114.go
|
||||
fixedbugs/bug115.go
|
||||
fixedbugs/bug116.go
|
||||
fixedbugs/bug117.go
|
||||
fixedbugs/bug118.go
|
||||
fixedbugs/bug119.go
|
||||
fixedbugs/bug120.go
|
||||
fixedbugs/bug121.go
|
||||
fixedbugs/bug122.go
|
||||
fixedbugs/bug123.go
|
||||
fixedbugs/bug126.go
|
||||
fixedbugs/bug127.go
|
||||
fixedbugs/bug128.go
|
||||
fixedbugs/bug129.go
|
||||
fixedbugs/bug130.go
|
||||
fixedbugs/bug131.go
|
||||
fixedbugs/bug132.go
|
||||
fixedbugs/bug133.go
|
||||
fixedbugs/bug135.go
|
||||
fixedbugs/bug136.go
|
||||
fixedbugs/bug137.go
|
||||
fixedbugs/bug139.go
|
||||
fixedbugs/bug140.go
|
||||
fixedbugs/bug141.go
|
||||
fixedbugs/bug142.go
|
||||
fixedbugs/bug143.go
|
||||
fixedbugs/bug144.go
|
||||
fixedbugs/bug145.go
|
||||
fixedbugs/bug146.go
|
||||
fixedbugs/bug147.go
|
||||
fixedbugs/bug148.go
|
||||
fixedbugs/bug149.go
|
||||
fixedbugs/bug150.go
|
||||
fixedbugs/bug151.go
|
||||
fixedbugs/bug152.go
|
||||
fixedbugs/bug154.go
|
||||
fixedbugs/bug155.go
|
||||
fixedbugs/bug156.go
|
||||
fixedbugs/bug157.go
|
||||
fixedbugs/bug158.go
|
||||
fixedbugs/bug159.go
|
||||
fixedbugs/bug160.go
|
||||
fixedbugs/bug161.go
|
||||
fixedbugs/bug163.go
|
||||
fixedbugs/bug164.go
|
||||
fixedbugs/bug165.go
|
||||
fixedbugs/bug167.go
|
||||
fixedbugs/bug168.go
|
||||
fixedbugs/bug169.go
|
||||
fixedbugs/bug170.go
|
||||
fixedbugs/bug171.go
|
||||
fixedbugs/bug172.go
|
||||
fixedbugs/bug173.go
|
||||
fixedbugs/bug174.go
|
||||
fixedbugs/bug175.go
|
||||
fixedbugs/bug176.go
|
||||
fixedbugs/bug177.go
|
||||
fixedbugs/bug178.go
|
||||
fixedbugs/bug179.go
|
||||
fixedbugs/bug180.go
|
||||
fixedbugs/bug181.go
|
||||
fixedbugs/bug182.go
|
||||
fixedbugs/bug183.go
|
||||
fixedbugs/bug184.go
|
||||
fixedbugs/bug185.go
|
||||
fixedbugs/bug186.go
|
||||
fixedbugs/bug187.go
|
||||
fixedbugs/bug188.go
|
||||
fixedbugs/bug189.go
|
||||
fixedbugs/bug190.go
|
||||
fixedbugs/bug191.go
|
||||
fixedbugs/bug192.go
|
||||
fixedbugs/bug193.go
|
||||
fixedbugs/bug194.go
|
||||
fixedbugs/bug195.go
|
||||
fixedbugs/bug196.go
|
||||
fixedbugs/bug197.go
|
||||
fixedbugs/bug198.go
|
||||
fixedbugs/bug199.go
|
||||
fixedbugs/bug200.go
|
||||
fixedbugs/bug201.go
|
||||
fixedbugs/bug202.go
|
||||
fixedbugs/bug203.go
|
||||
fixedbugs/bug204.go
|
||||
fixedbugs/bug205.go
|
||||
fixedbugs/bug206.go
|
||||
fixedbugs/bug207.go
|
||||
fixedbugs/bug208.go
|
||||
fixedbugs/bug209.go
|
||||
fixedbugs/bug211.go
|
||||
fixedbugs/bug212.go
|
||||
fixedbugs/bug213.go
|
||||
fixedbugs/bug214.go
|
||||
fixedbugs/bug215.go
|
||||
fixedbugs/bug216.go
|
||||
fixedbugs/bug217.go
|
||||
fixedbugs/bug218.go
|
||||
fixedbugs/bug219.go
|
||||
fixedbugs/bug220.go
|
||||
fixedbugs/bug221.go
|
||||
fixedbugs/bug222.go
|
||||
fixedbugs/bug223.go
|
||||
fixedbugs/bug224.go
|
||||
fixedbugs/bug225.go
|
||||
fixedbugs/bug226.go
|
||||
fixedbugs/bug227.go
|
||||
fixedbugs/bug228.go
|
||||
fixedbugs/bug229.go
|
||||
fixedbugs/bug230.go
|
||||
fixedbugs/bug231.go
|
||||
fixedbugs/bug232.go
|
||||
fixedbugs/bug233.go
|
||||
fixedbugs/bug234.go
|
||||
fixedbugs/bug235.go
|
||||
fixedbugs/bug236.go
|
||||
fixedbugs/bug237.go
|
||||
fixedbugs/bug238.go
|
||||
fixedbugs/bug239.go
|
||||
fixedbugs/bug240.go
|
||||
fixedbugs/bug241.go
|
||||
fixedbugs/bug242.go
|
||||
# fixedbugs/bug243.go # fail, flaky on android build
|
||||
fixedbugs/bug244.go
|
||||
fixedbugs/bug245.go
|
||||
fixedbugs/bug246.go
|
||||
fixedbugs/bug247.go
|
||||
fixedbugs/bug248.go
|
||||
fixedbugs/bug249.go
|
||||
fixedbugs/bug250.go
|
||||
fixedbugs/bug251.go
|
||||
fixedbugs/bug252.go
|
||||
fixedbugs/bug253.go
|
||||
fixedbugs/bug254.go
|
||||
fixedbugs/bug255.go
|
||||
fixedbugs/bug256.go
|
||||
fixedbugs/bug257.go
|
||||
fixedbugs/bug258.go
|
||||
fixedbugs/bug259.go
|
||||
fixedbugs/bug261.go
|
||||
fixedbugs/bug262.go
|
||||
fixedbugs/bug263.go
|
||||
fixedbugs/bug264.go
|
||||
fixedbugs/bug265.go
|
||||
fixedbugs/bug266.go
|
||||
fixedbugs/bug267.go
|
||||
fixedbugs/bug268.go
|
||||
fixedbugs/bug269.go
|
||||
fixedbugs/bug270.go
|
||||
fixedbugs/bug271.go
|
||||
fixedbugs/bug272.go
|
||||
fixedbugs/bug273.go
|
||||
fixedbugs/bug274.go
|
||||
fixedbugs/bug275.go
|
||||
fixedbugs/bug276.go
|
||||
fixedbugs/bug277.go
|
||||
fixedbugs/bug278.go
|
||||
fixedbugs/bug279.go
|
||||
fixedbugs/bug280.go
|
||||
fixedbugs/bug281.go
|
||||
fixedbugs/bug282.go
|
||||
fixedbugs/bug283.go
|
||||
fixedbugs/bug284.go
|
||||
fixedbugs/bug285.go
|
||||
fixedbugs/bug286.go
|
||||
fixedbugs/bug287.go
|
||||
fixedbugs/bug288.go
|
||||
fixedbugs/bug289.go
|
||||
fixedbugs/bug290.go
|
||||
fixedbugs/bug291.go
|
||||
fixedbugs/bug292.go
|
||||
fixedbugs/bug293.go
|
||||
fixedbugs/bug294.go
|
||||
fixedbugs/bug295.go
|
||||
fixedbugs/bug296.go
|
||||
fixedbugs/bug297.go
|
||||
fixedbugs/bug298.go
|
||||
# bugs/bug260.go # fail, BUG
|
53
gcc/testsuite/go.test/test/assign.go
Normal file
53
gcc/testsuite/go.test/test/assign.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// errchk $G -e $D/$F.go
|
||||
|
||||
// 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 "sync"
|
||||
|
||||
type T struct {
|
||||
int
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func main() {
|
||||
{
|
||||
var x, y sync.Mutex
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y T
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y [2]sync.Mutex
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
var x, y [2]T
|
||||
x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
|
||||
_ = x
|
||||
}
|
||||
{
|
||||
x := &sync.Mutex{} // ok
|
||||
var y sync.Mutex // ok
|
||||
y = *x // ERROR "assignment.*Mutex"
|
||||
*x = y // ERROR "assignment.*Mutex"
|
||||
_ = x
|
||||
_ = y
|
||||
}
|
||||
}
|
343
gcc/testsuite/go.test/test/assign1.go
Normal file
343
gcc/testsuite/go.test/test/assign1.go
Normal file
|
@ -0,0 +1,343 @@
|
|||
// errchk $G -e $D/$F.go
|
||||
|
||||
// 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
|
||||
|
||||
type (
|
||||
A [10]int
|
||||
B []int
|
||||
C chan int
|
||||
F func() int
|
||||
I interface {
|
||||
m() int
|
||||
}
|
||||
M map[int]int
|
||||
P *int
|
||||
S struct {
|
||||
X int
|
||||
}
|
||||
|
||||
A1 [10]int
|
||||
B1 []int
|
||||
C1 chan int
|
||||
F1 func() int
|
||||
I1 interface {
|
||||
m() int
|
||||
}
|
||||
M1 map[int]int
|
||||
P1 *int
|
||||
S1 struct {
|
||||
X int
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
a0 [10]int
|
||||
b0 []int
|
||||
c0 chan int
|
||||
f0 func() int
|
||||
i0 interface {
|
||||
m() int
|
||||
}
|
||||
m0 map[int]int
|
||||
p0 *int
|
||||
s0 struct {
|
||||
X int
|
||||
}
|
||||
|
||||
a A
|
||||
b B
|
||||
c C
|
||||
f F
|
||||
i I
|
||||
m M
|
||||
p P
|
||||
s S
|
||||
|
||||
a1 A1
|
||||
b1 B1
|
||||
c1 C1
|
||||
f1 F1
|
||||
i1 I1
|
||||
m1 M1
|
||||
p1 P1
|
||||
s1 S1
|
||||
|
||||
pa0 *[10]int
|
||||
pb0 *[]int
|
||||
pc0 *chan int
|
||||
pf0 *func() int
|
||||
pi0 *interface {
|
||||
m() int
|
||||
}
|
||||
pm0 *map[int]int
|
||||
pp0 **int
|
||||
ps0 *struct {
|
||||
X int
|
||||
}
|
||||
|
||||
pa *A
|
||||
pb *B
|
||||
pc *C
|
||||
pf *F
|
||||
pi *I
|
||||
pm *M
|
||||
pp *P
|
||||
ps *S
|
||||
|
||||
pa1 *A1
|
||||
pb1 *B1
|
||||
pc1 *C1
|
||||
pf1 *F1
|
||||
pi1 *I1
|
||||
pm1 *M1
|
||||
pp1 *P1
|
||||
ps1 *S1
|
||||
)
|
||||
|
||||
func main() {
|
||||
a0 = a
|
||||
a0 = a1
|
||||
a = a0
|
||||
a = a1 // ERROR "cannot use"
|
||||
a1 = a0
|
||||
a1 = a // ERROR "cannot use"
|
||||
|
||||
b0 = b
|
||||
b0 = b1
|
||||
b = b0
|
||||
b = b1 // ERROR "cannot use"
|
||||
b1 = b0
|
||||
b1 = b // ERROR "cannot use"
|
||||
|
||||
c0 = c
|
||||
c0 = c1
|
||||
c = c0
|
||||
c = c1 // ERROR "cannot use"
|
||||
c1 = c0
|
||||
c1 = c // ERROR "cannot use"
|
||||
|
||||
f0 = f
|
||||
f0 = f1
|
||||
f = f0
|
||||
f = f1 // ERROR "cannot use"
|
||||
f1 = f0
|
||||
f1 = f // ERROR "cannot use"
|
||||
|
||||
i0 = i
|
||||
i0 = i1
|
||||
i = i0
|
||||
i = i1
|
||||
i1 = i0
|
||||
i1 = i
|
||||
|
||||
m0 = m
|
||||
m0 = m1
|
||||
m = m0
|
||||
m = m1 // ERROR "cannot use"
|
||||
m1 = m0
|
||||
m1 = m // ERROR "cannot use"
|
||||
|
||||
p0 = p
|
||||
p0 = p1
|
||||
p = p0
|
||||
p = p1 // ERROR "cannot use"
|
||||
p1 = p0
|
||||
p1 = p // ERROR "cannot use"
|
||||
|
||||
s0 = s
|
||||
s0 = s1
|
||||
s = s0
|
||||
s = s1 // ERROR "cannot use"
|
||||
s1 = s0
|
||||
s1 = s // ERROR "cannot use"
|
||||
|
||||
pa0 = pa // ERROR "cannot use|incompatible"
|
||||
pa0 = pa1 // ERROR "cannot use|incompatible"
|
||||
pa = pa0 // ERROR "cannot use|incompatible"
|
||||
pa = pa1 // ERROR "cannot use|incompatible"
|
||||
pa1 = pa0 // ERROR "cannot use|incompatible"
|
||||
pa1 = pa // ERROR "cannot use|incompatible"
|
||||
|
||||
pb0 = pb // ERROR "cannot use|incompatible"
|
||||
pb0 = pb1 // ERROR "cannot use|incompatible"
|
||||
pb = pb0 // ERROR "cannot use|incompatible"
|
||||
pb = pb1 // ERROR "cannot use|incompatible"
|
||||
pb1 = pb0 // ERROR "cannot use|incompatible"
|
||||
pb1 = pb // ERROR "cannot use|incompatible"
|
||||
|
||||
pc0 = pc // ERROR "cannot use|incompatible"
|
||||
pc0 = pc1 // ERROR "cannot use|incompatible"
|
||||
pc = pc0 // ERROR "cannot use|incompatible"
|
||||
pc = pc1 // ERROR "cannot use|incompatible"
|
||||
pc1 = pc0 // ERROR "cannot use|incompatible"
|
||||
pc1 = pc // ERROR "cannot use|incompatible"
|
||||
|
||||
pf0 = pf // ERROR "cannot use|incompatible"
|
||||
pf0 = pf1 // ERROR "cannot use|incompatible"
|
||||
pf = pf0 // ERROR "cannot use|incompatible"
|
||||
pf = pf1 // ERROR "cannot use|incompatible"
|
||||
pf1 = pf0 // ERROR "cannot use|incompatible"
|
||||
pf1 = pf // ERROR "cannot use|incompatible"
|
||||
|
||||
pi0 = pi // ERROR "cannot use|incompatible"
|
||||
pi0 = pi1 // ERROR "cannot use|incompatible"
|
||||
pi = pi0 // ERROR "cannot use|incompatible"
|
||||
pi = pi1 // ERROR "cannot use|incompatible"
|
||||
pi1 = pi0 // ERROR "cannot use|incompatible"
|
||||
pi1 = pi // ERROR "cannot use|incompatible"
|
||||
|
||||
pm0 = pm // ERROR "cannot use|incompatible"
|
||||
pm0 = pm1 // ERROR "cannot use|incompatible"
|
||||
pm = pm0 // ERROR "cannot use|incompatible"
|
||||
pm = pm1 // ERROR "cannot use|incompatible"
|
||||
pm1 = pm0 // ERROR "cannot use|incompatible"
|
||||
pm1 = pm // ERROR "cannot use|incompatible"
|
||||
|
||||
pp0 = pp // ERROR "cannot use|incompatible"
|
||||
pp0 = pp1 // ERROR "cannot use|incompatible"
|
||||
pp = pp0 // ERROR "cannot use|incompatible"
|
||||
pp = pp1 // ERROR "cannot use|incompatible"
|
||||
pp1 = pp0 // ERROR "cannot use|incompatible"
|
||||
pp1 = pp // ERROR "cannot use|incompatible"
|
||||
|
||||
ps0 = ps // ERROR "cannot use|incompatible"
|
||||
ps0 = ps1 // ERROR "cannot use|incompatible"
|
||||
ps = ps0 // ERROR "cannot use|incompatible"
|
||||
ps = ps1 // ERROR "cannot use|incompatible"
|
||||
ps1 = ps0 // ERROR "cannot use|incompatible"
|
||||
ps1 = ps // ERROR "cannot use|incompatible"
|
||||
|
||||
|
||||
a0 = [10]int(a)
|
||||
a0 = [10]int(a1)
|
||||
a = A(a0)
|
||||
a = A(a1)
|
||||
a1 = A1(a0)
|
||||
a1 = A1(a)
|
||||
|
||||
b0 = []int(b)
|
||||
b0 = []int(b1)
|
||||
b = B(b0)
|
||||
b = B(b1)
|
||||
b1 = B1(b0)
|
||||
b1 = B1(b)
|
||||
|
||||
c0 = chan int(c)
|
||||
c0 = chan int(c1)
|
||||
c = C(c0)
|
||||
c = C(c1)
|
||||
c1 = C1(c0)
|
||||
c1 = C1(c)
|
||||
|
||||
f0 = func() int(f)
|
||||
f0 = func() int(f1)
|
||||
f = F(f0)
|
||||
f = F(f1)
|
||||
f1 = F1(f0)
|
||||
f1 = F1(f)
|
||||
|
||||
i0 = interface {
|
||||
m() int
|
||||
}(i)
|
||||
i0 = interface {
|
||||
m() int
|
||||
}(i1)
|
||||
i = I(i0)
|
||||
i = I(i1)
|
||||
i1 = I1(i0)
|
||||
i1 = I1(i)
|
||||
|
||||
m0 = map[int]int(m)
|
||||
m0 = map[int]int(m1)
|
||||
m = M(m0)
|
||||
m = M(m1)
|
||||
m1 = M1(m0)
|
||||
m1 = M1(m)
|
||||
|
||||
p0 = (*int)(p)
|
||||
p0 = (*int)(p1)
|
||||
p = P(p0)
|
||||
p = P(p1)
|
||||
p1 = P1(p0)
|
||||
p1 = P1(p)
|
||||
|
||||
s0 = struct {
|
||||
X int
|
||||
}(s)
|
||||
s0 = struct {
|
||||
X int
|
||||
}(s1)
|
||||
s = S(s0)
|
||||
s = S(s1)
|
||||
s1 = S1(s0)
|
||||
s1 = S1(s)
|
||||
|
||||
pa0 = (*[10]int)(pa)
|
||||
pa0 = (*[10]int)(pa1)
|
||||
pa = (*A)(pa0)
|
||||
pa = (*A)(pa1)
|
||||
pa1 = (*A1)(pa0)
|
||||
pa1 = (*A1)(pa)
|
||||
|
||||
pb0 = (*[]int)(pb)
|
||||
pb0 = (*[]int)(pb1)
|
||||
pb = (*B)(pb0)
|
||||
pb = (*B)(pb1)
|
||||
pb1 = (*B1)(pb0)
|
||||
pb1 = (*B1)(pb)
|
||||
|
||||
pc0 = (*chan int)(pc)
|
||||
pc0 = (*chan int)(pc1)
|
||||
pc = (*C)(pc0)
|
||||
pc = (*C)(pc1)
|
||||
pc1 = (*C1)(pc0)
|
||||
pc1 = (*C1)(pc)
|
||||
|
||||
pf0 = (*func() int)(pf)
|
||||
pf0 = (*func() int)(pf1)
|
||||
pf = (*F)(pf0)
|
||||
pf = (*F)(pf1)
|
||||
pf1 = (*F1)(pf0)
|
||||
pf1 = (*F1)(pf)
|
||||
|
||||
pi0 = (*interface {
|
||||
m() int
|
||||
})(pi)
|
||||
pi0 = (*interface {
|
||||
m() int
|
||||
})(pi1)
|
||||
pi = (*I)(pi0)
|
||||
pi = (*I)(pi1)
|
||||
pi1 = (*I1)(pi0)
|
||||
pi1 = (*I1)(pi)
|
||||
|
||||
pm0 = (*map[int]int)(pm)
|
||||
pm0 = (*map[int]int)(pm1)
|
||||
pm = (*M)(pm0)
|
||||
pm = (*M)(pm1)
|
||||
pm1 = (*M1)(pm0)
|
||||
pm1 = (*M1)(pm)
|
||||
|
||||
pp0 = (**int)(pp)
|
||||
pp0 = (**int)(pp1)
|
||||
pp = (*P)(pp0)
|
||||
pp = (*P)(pp1)
|
||||
pp1 = (*P1)(pp0)
|
||||
pp1 = (*P1)(pp)
|
||||
|
||||
ps0 = (*struct {
|
||||
X int
|
||||
})(ps)
|
||||
ps0 = (*struct {
|
||||
X int
|
||||
})(ps1)
|
||||
ps = (*S)(ps0)
|
||||
ps = (*S)(ps1)
|
||||
ps1 = (*S1)(ps0)
|
||||
ps1 = (*S1)(ps)
|
||||
|
||||
}
|
129
gcc/testsuite/go.test/test/bench/binary-tree-freelist.go
Normal file
129
gcc/testsuite/go.test/test/bench/binary-tree-freelist.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* based on C program by Kevin Carson
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 15, "depth")
|
||||
|
||||
type Node struct {
|
||||
item int
|
||||
left, right *Node
|
||||
}
|
||||
|
||||
type Arena struct {
|
||||
head *Node
|
||||
}
|
||||
|
||||
var arena Arena
|
||||
|
||||
func (n *Node) free() {
|
||||
if n.left != nil {
|
||||
n.left.free()
|
||||
}
|
||||
if n.right != nil {
|
||||
n.right.free()
|
||||
}
|
||||
n.left = arena.head
|
||||
arena.head = n
|
||||
}
|
||||
|
||||
func (a *Arena) New(item int, left, right *Node) *Node {
|
||||
if a.head == nil {
|
||||
nodes := make([]Node, 3<<uint(*n))
|
||||
for i := 0; i < len(nodes)-1; i++ {
|
||||
nodes[i].left = &nodes[i+1]
|
||||
}
|
||||
a.head = &nodes[0]
|
||||
}
|
||||
n := a.head
|
||||
a.head = a.head.left
|
||||
n.item = item
|
||||
n.left = left
|
||||
n.right = right
|
||||
return n
|
||||
}
|
||||
|
||||
func bottomUpTree(item, depth int) *Node {
|
||||
if depth <= 0 {
|
||||
return arena.New(item, nil, nil)
|
||||
}
|
||||
return arena.New(item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1))
|
||||
}
|
||||
|
||||
func (n *Node) itemCheck() int {
|
||||
if n.left == nil {
|
||||
return n.item
|
||||
}
|
||||
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||
}
|
||||
|
||||
const minDepth = 4
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
maxDepth := *n
|
||||
if minDepth+2 > *n {
|
||||
maxDepth = minDepth + 2
|
||||
}
|
||||
stretchDepth := maxDepth + 1
|
||||
|
||||
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||
|
||||
longLivedTree := bottomUpTree(0, maxDepth)
|
||||
|
||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||
check = 0
|
||||
|
||||
for i := 1; i <= iterations; i++ {
|
||||
t := bottomUpTree(i, depth)
|
||||
check += t.itemCheck()
|
||||
t.free()
|
||||
t = bottomUpTree(-i, depth)
|
||||
check += t.itemCheck()
|
||||
t.free()
|
||||
}
|
||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||
}
|
||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
stretch tree of depth 16 check: -1
|
||||
65536 trees of depth 4 check: -65536
|
||||
16384 trees of depth 6 check: -16384
|
||||
4096 trees of depth 8 check: -4096
|
||||
1024 trees of depth 10 check: -1024
|
||||
256 trees of depth 12 check: -256
|
||||
64 trees of depth 14 check: -64
|
||||
long lived tree of depth 15 check: -1
|
165
gcc/testsuite/go.test/test/bench/binary-tree.c
Normal file
165
gcc/testsuite/go.test/test/bench/binary-tree.c
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Shootout Benchmarks
|
||||
http://shootout.alioth.debian.org/
|
||||
|
||||
contributed by Kevin Carson
|
||||
compilation:
|
||||
gcc -O3 -fomit-frame-pointer -funroll-loops -static binary-trees.c -lm
|
||||
icc -O3 -ip -unroll -static binary-trees.c -lm
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct tn {
|
||||
struct tn* left;
|
||||
struct tn* right;
|
||||
long item;
|
||||
} treeNode;
|
||||
|
||||
|
||||
treeNode* NewTreeNode(treeNode* left, treeNode* right, long item)
|
||||
{
|
||||
treeNode* new;
|
||||
|
||||
new = (treeNode*)malloc(sizeof(treeNode));
|
||||
|
||||
new->left = left;
|
||||
new->right = right;
|
||||
new->item = item;
|
||||
|
||||
return new;
|
||||
} /* NewTreeNode() */
|
||||
|
||||
|
||||
long ItemCheck(treeNode* tree)
|
||||
{
|
||||
if (tree->left == NULL)
|
||||
return tree->item;
|
||||
else
|
||||
return tree->item + ItemCheck(tree->left) - ItemCheck(tree->right);
|
||||
} /* ItemCheck() */
|
||||
|
||||
|
||||
treeNode* BottomUpTree(long item, unsigned depth)
|
||||
{
|
||||
if (depth > 0)
|
||||
return NewTreeNode
|
||||
(
|
||||
BottomUpTree(2 * item - 1, depth - 1),
|
||||
BottomUpTree(2 * item, depth - 1),
|
||||
item
|
||||
);
|
||||
else
|
||||
return NewTreeNode(NULL, NULL, item);
|
||||
} /* BottomUpTree() */
|
||||
|
||||
|
||||
void DeleteTree(treeNode* tree)
|
||||
{
|
||||
if (tree->left != NULL)
|
||||
{
|
||||
DeleteTree(tree->left);
|
||||
DeleteTree(tree->right);
|
||||
}
|
||||
|
||||
free(tree);
|
||||
} /* DeleteTree() */
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned N, depth, minDepth, maxDepth, stretchDepth;
|
||||
treeNode *stretchTree, *longLivedTree, *tempTree;
|
||||
|
||||
N = atol(argv[1]);
|
||||
|
||||
minDepth = 4;
|
||||
|
||||
if ((minDepth + 2) > N)
|
||||
maxDepth = minDepth + 2;
|
||||
else
|
||||
maxDepth = N;
|
||||
|
||||
stretchDepth = maxDepth + 1;
|
||||
|
||||
stretchTree = BottomUpTree(0, stretchDepth);
|
||||
printf
|
||||
(
|
||||
"stretch tree of depth %u\t check: %li\n",
|
||||
stretchDepth,
|
||||
ItemCheck(stretchTree)
|
||||
);
|
||||
|
||||
DeleteTree(stretchTree);
|
||||
|
||||
longLivedTree = BottomUpTree(0, maxDepth);
|
||||
|
||||
for (depth = minDepth; depth <= maxDepth; depth += 2)
|
||||
{
|
||||
long i, iterations, check;
|
||||
|
||||
iterations = pow(2, maxDepth - depth + minDepth);
|
||||
|
||||
check = 0;
|
||||
|
||||
for (i = 1; i <= iterations; i++)
|
||||
{
|
||||
tempTree = BottomUpTree(i, depth);
|
||||
check += ItemCheck(tempTree);
|
||||
DeleteTree(tempTree);
|
||||
|
||||
tempTree = BottomUpTree(-i, depth);
|
||||
check += ItemCheck(tempTree);
|
||||
DeleteTree(tempTree);
|
||||
} /* for(i = 1...) */
|
||||
|
||||
printf
|
||||
(
|
||||
"%li\t trees of depth %u\t check: %li\n",
|
||||
iterations * 2,
|
||||
depth,
|
||||
check
|
||||
);
|
||||
} /* for(depth = minDepth...) */
|
||||
|
||||
printf
|
||||
(
|
||||
"long lived tree of depth %u\t check: %li\n",
|
||||
maxDepth,
|
||||
ItemCheck(longLivedTree)
|
||||
);
|
||||
|
||||
return 0;
|
||||
} /* main() */
|
92
gcc/testsuite/go.test/test/bench/binary-tree.go
Normal file
92
gcc/testsuite/go.test/test/bench/binary-tree.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* based on C program by Kevin Carson
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 15, "depth")
|
||||
|
||||
type Node struct {
|
||||
item int
|
||||
left, right *Node
|
||||
}
|
||||
|
||||
func bottomUpTree(item, depth int) *Node {
|
||||
if depth <= 0 {
|
||||
return &Node{item: item}
|
||||
}
|
||||
return &Node{item, bottomUpTree(2*item-1, depth-1), bottomUpTree(2*item, depth-1)}
|
||||
}
|
||||
|
||||
func (n *Node) itemCheck() int {
|
||||
if n.left == nil {
|
||||
return n.item
|
||||
}
|
||||
return n.item + n.left.itemCheck() - n.right.itemCheck()
|
||||
}
|
||||
|
||||
const minDepth = 4
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
maxDepth := *n
|
||||
if minDepth+2 > *n {
|
||||
maxDepth = minDepth + 2
|
||||
}
|
||||
stretchDepth := maxDepth + 1
|
||||
|
||||
check := bottomUpTree(0, stretchDepth).itemCheck()
|
||||
fmt.Printf("stretch tree of depth %d\t check: %d\n", stretchDepth, check)
|
||||
|
||||
longLivedTree := bottomUpTree(0, maxDepth)
|
||||
|
||||
for depth := minDepth; depth <= maxDepth; depth += 2 {
|
||||
iterations := 1 << uint(maxDepth-depth+minDepth)
|
||||
check = 0
|
||||
|
||||
for i := 1; i <= iterations; i++ {
|
||||
check += bottomUpTree(i, depth).itemCheck()
|
||||
check += bottomUpTree(-i, depth).itemCheck()
|
||||
}
|
||||
fmt.Printf("%d\t trees of depth %d\t check: %d\n", iterations*2, depth, check)
|
||||
}
|
||||
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
|
||||
}
|
8
gcc/testsuite/go.test/test/bench/binary-tree.txt
Normal file
8
gcc/testsuite/go.test/test/bench/binary-tree.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
stretch tree of depth 16 check: -1
|
||||
65536 trees of depth 4 check: -65536
|
||||
16384 trees of depth 6 check: -16384
|
||||
4096 trees of depth 8 check: -4096
|
||||
1024 trees of depth 10 check: -1024
|
||||
256 trees of depth 12 check: -256
|
||||
64 trees of depth 14 check: -64
|
||||
long lived tree of depth 15 check: -1
|
330
gcc/testsuite/go.test/test/bench/chameneosredux.c
Normal file
330
gcc/testsuite/go.test/test/bench/chameneosredux.c
Normal file
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
http://shootout.alioth.debian.org/
|
||||
|
||||
contributed by Michael Barker
|
||||
based on a Java contribution by Luzius Meisser
|
||||
|
||||
convert to C by dualamd
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
enum Colour
|
||||
{
|
||||
blue = 0,
|
||||
red = 1,
|
||||
yellow = 2,
|
||||
Invalid = 3
|
||||
};
|
||||
|
||||
const char* ColourName[] = {"blue", "red", "yellow"};
|
||||
const int STACK_SIZE = 32*1024;
|
||||
|
||||
typedef unsigned int BOOL;
|
||||
const BOOL TRUE = 1;
|
||||
const BOOL FALSE = 0;
|
||||
|
||||
int CreatureID = 0;
|
||||
|
||||
|
||||
enum Colour doCompliment(enum Colour c1, enum Colour c2)
|
||||
{
|
||||
switch (c1)
|
||||
{
|
||||
case blue:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return blue;
|
||||
case red:
|
||||
return yellow;
|
||||
case yellow:
|
||||
return red;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
case red:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return yellow;
|
||||
case red:
|
||||
return red;
|
||||
case yellow:
|
||||
return blue;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
case yellow:
|
||||
switch (c2)
|
||||
{
|
||||
case blue:
|
||||
return red;
|
||||
case red:
|
||||
return blue;
|
||||
case yellow:
|
||||
return yellow;
|
||||
default:
|
||||
goto errlb;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
errlb:
|
||||
printf("Invalid colour\n");
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
/* convert integer to number string: 1234 -> "one two three four" */
|
||||
char* formatNumber(int n, char* outbuf)
|
||||
{
|
||||
int ochar = 0, ichar = 0;
|
||||
int i;
|
||||
char tmp[64];
|
||||
|
||||
const char* NUMBERS[] =
|
||||
{
|
||||
"zero", "one", "two", "three", "four", "five",
|
||||
"six", "seven", "eight", "nine"
|
||||
};
|
||||
|
||||
ichar = sprintf(tmp, "%d", n);
|
||||
|
||||
for (i = 0; i < ichar; i++)
|
||||
ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] );
|
||||
|
||||
return outbuf;
|
||||
}
|
||||
|
||||
|
||||
struct MeetingPlace
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
int meetingsLeft;
|
||||
struct Creature* firstCreature;
|
||||
};
|
||||
|
||||
struct Creature
|
||||
{
|
||||
pthread_t ht;
|
||||
pthread_attr_t stack_att;
|
||||
|
||||
struct MeetingPlace* place;
|
||||
int count;
|
||||
int sameCount;
|
||||
|
||||
enum Colour colour;
|
||||
int id;
|
||||
|
||||
BOOL two_met;
|
||||
BOOL sameid;
|
||||
};
|
||||
|
||||
|
||||
void MeetingPlace_Init(struct MeetingPlace* m, int meetings )
|
||||
{
|
||||
pthread_mutex_init( &m->mutex, 0 );
|
||||
m->meetingsLeft = meetings;
|
||||
m->firstCreature = 0;
|
||||
}
|
||||
|
||||
|
||||
BOOL Meet( struct Creature* cr)
|
||||
{
|
||||
BOOL retval = TRUE;
|
||||
|
||||
struct MeetingPlace* mp = cr->place;
|
||||
pthread_mutex_lock( &(mp->mutex) );
|
||||
|
||||
if ( mp->meetingsLeft > 0 )
|
||||
{
|
||||
if ( mp->firstCreature == 0 )
|
||||
{
|
||||
cr->two_met = FALSE;
|
||||
mp->firstCreature = cr;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct Creature* first;
|
||||
enum Colour newColour;
|
||||
|
||||
first = mp->firstCreature;
|
||||
newColour = doCompliment( cr->colour, first->colour );
|
||||
|
||||
cr->sameid = cr->id == first->id;
|
||||
cr->colour = newColour;
|
||||
cr->two_met = TRUE;
|
||||
|
||||
first->sameid = cr->sameid;
|
||||
first->colour = newColour;
|
||||
first->two_met = TRUE;
|
||||
|
||||
mp->firstCreature = 0;
|
||||
mp->meetingsLeft--;
|
||||
}
|
||||
}
|
||||
else
|
||||
retval = FALSE;
|
||||
|
||||
pthread_mutex_unlock( &(mp->mutex) );
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void* CreatureThreadRun(void* param)
|
||||
{
|
||||
struct Creature* cr = (struct Creature*)param;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if ( Meet(cr) )
|
||||
{
|
||||
while (cr->two_met == FALSE)
|
||||
sched_yield();
|
||||
|
||||
if (cr->sameid)
|
||||
cr->sameCount++;
|
||||
cr->count++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour )
|
||||
{
|
||||
cr->place = place;
|
||||
cr->count = cr->sameCount = 0;
|
||||
|
||||
cr->id = ++CreatureID;
|
||||
cr->colour = colour;
|
||||
cr->two_met = FALSE;
|
||||
|
||||
pthread_attr_init( &cr->stack_att );
|
||||
pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE );
|
||||
pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) );
|
||||
}
|
||||
|
||||
/* format meeting times of each creature to string */
|
||||
char* Creature_getResult(struct Creature* cr, char* str)
|
||||
{
|
||||
char numstr[256];
|
||||
formatNumber(cr->sameCount, numstr);
|
||||
|
||||
sprintf( str, "%u%s", cr->count, numstr );
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void runGame( int n_meeting, int ncolor, const enum Colour* colours )
|
||||
{
|
||||
int i;
|
||||
int total = 0;
|
||||
char str[256];
|
||||
|
||||
struct MeetingPlace place;
|
||||
struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) );
|
||||
|
||||
MeetingPlace_Init( &place, n_meeting );
|
||||
|
||||
/* print initial color of each creature */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
{
|
||||
printf( "%s ", ColourName[ colours[i] ] );
|
||||
Creature_Init( &(creatures[i]), &place, colours[i] );
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* wait for them to meet */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
pthread_join( creatures[i].ht, 0 );
|
||||
|
||||
/* print meeting times of each creature */
|
||||
for (i = 0; i < ncolor; i++)
|
||||
{
|
||||
printf( "%s\n", Creature_getResult(&(creatures[i]), str) );
|
||||
total += creatures[i].count;
|
||||
}
|
||||
|
||||
/* print total meeting times, should equal n_meeting */
|
||||
printf( "%s\n\n", formatNumber(total, str) );
|
||||
|
||||
/* cleaup & quit */
|
||||
pthread_mutex_destroy( &place.mutex );
|
||||
free( creatures );
|
||||
}
|
||||
|
||||
|
||||
void printColours( enum Colour c1, enum Colour c2 )
|
||||
{
|
||||
printf( "%s + %s -> %s\n",
|
||||
ColourName[c1],
|
||||
ColourName[c2],
|
||||
ColourName[doCompliment(c1, c2)] );
|
||||
}
|
||||
|
||||
void printColoursTable(void)
|
||||
{
|
||||
printColours(blue, blue);
|
||||
printColours(blue, red);
|
||||
printColours(blue, yellow);
|
||||
printColours(red, blue);
|
||||
printColours(red, red);
|
||||
printColours(red, yellow);
|
||||
printColours(yellow, blue);
|
||||
printColours(yellow, red);
|
||||
printColours(yellow, yellow);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int n = (argc == 2) ? atoi(argv[1]) : 600;
|
||||
|
||||
printColoursTable();
|
||||
printf("\n");
|
||||
|
||||
const enum Colour r1[] = { blue, red, yellow };
|
||||
const enum Colour r2[] = { blue, red, yellow,
|
||||
red, yellow, blue,
|
||||
red, yellow, red, blue };
|
||||
|
||||
runGame( n, sizeof(r1) / sizeof(r1[0]), r1 );
|
||||
runGame( n, sizeof(r2) / sizeof(r2[0]), r2 );
|
||||
|
||||
return 0;
|
||||
}
|
180
gcc/testsuite/go.test/test/bench/chameneosredux.go
Normal file
180
gcc/testsuite/go.test/test/bench/chameneosredux.go
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
blue = iota
|
||||
red
|
||||
yellow
|
||||
ncol
|
||||
)
|
||||
|
||||
var complement = [...]int{
|
||||
red | red<<2: red,
|
||||
red | yellow<<2: blue,
|
||||
red | blue<<2: yellow,
|
||||
yellow | red<<2: blue,
|
||||
yellow | yellow<<2: yellow,
|
||||
yellow | blue<<2: red,
|
||||
blue | red<<2: yellow,
|
||||
blue | yellow<<2: red,
|
||||
blue | blue<<2: blue,
|
||||
}
|
||||
|
||||
var colname = [...]string{
|
||||
blue: "blue",
|
||||
red: "red",
|
||||
yellow: "yellow",
|
||||
}
|
||||
|
||||
// information about the current state of a creature.
|
||||
type info struct {
|
||||
colour int // creature's current colour.
|
||||
name int // creature's name.
|
||||
}
|
||||
|
||||
// exclusive access data-structure kept inside meetingplace.
|
||||
// if mate is nil, it indicates there's no creature currently waiting;
|
||||
// otherwise the creature's info is stored in info, and
|
||||
// it is waiting to receive its mate's information on the mate channel.
|
||||
type rendez struct {
|
||||
n int // current number of encounters.
|
||||
mate chan<- info // creature waiting when non-nil.
|
||||
info info // info about creature waiting.
|
||||
}
|
||||
|
||||
// result sent by each creature at the end of processing.
|
||||
type result struct {
|
||||
met int
|
||||
same int
|
||||
}
|
||||
|
||||
var n = 600
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
if flag.NArg() > 0 {
|
||||
n, _ = strconv.Atoi(flag.Arg(0))
|
||||
}
|
||||
|
||||
for c0 := 0; c0 < ncol; c0++ {
|
||||
for c1 := 0; c1 < ncol; c1++ {
|
||||
fmt.Printf("%s + %s -> %s\n", colname[c0], colname[c1], colname[complement[c0|c1<<2]])
|
||||
}
|
||||
}
|
||||
fmt.Print("\n")
|
||||
|
||||
pallmall([]int{blue, red, yellow})
|
||||
pallmall([]int{blue, red, yellow, red, yellow, blue, red, yellow, red, blue})
|
||||
}
|
||||
|
||||
func pallmall(cols []int) {
|
||||
|
||||
// invariant: meetingplace always contains a value unless a creature
|
||||
// is currently dealing with it (whereupon it must put it back).
|
||||
meetingplace := make(chan rendez, 1)
|
||||
meetingplace <- rendez{n: 0}
|
||||
|
||||
ended := make(chan result)
|
||||
msg := ""
|
||||
for i, col := range cols {
|
||||
go creature(info{col, i}, meetingplace, ended)
|
||||
msg += " " + colname[col]
|
||||
}
|
||||
fmt.Println(msg)
|
||||
tot := 0
|
||||
// wait for all results
|
||||
for _ = range cols {
|
||||
result := <-ended
|
||||
tot += result.met
|
||||
fmt.Printf("%v%v\n", result.met, spell(result.same, true))
|
||||
}
|
||||
fmt.Printf("%v\n\n", spell(tot, true))
|
||||
}
|
||||
|
||||
// in this function, variables ending in 0 refer to the local creature,
|
||||
// variables ending in 1 to the creature we've met.
|
||||
func creature(info0 info, meetingplace chan rendez, ended chan result) {
|
||||
c0 := make(chan info)
|
||||
met := 0
|
||||
same := 0
|
||||
for {
|
||||
var othername int
|
||||
// get access to rendez data and decide what to do.
|
||||
switch r := <-meetingplace; {
|
||||
case r.n >= n:
|
||||
// if no more meetings left, then send our result data and exit.
|
||||
meetingplace <- rendez{n: r.n}
|
||||
ended <- result{met, same}
|
||||
return
|
||||
case r.mate == nil:
|
||||
// no creature waiting; wait for someone to meet us,
|
||||
// get their info and send our info in reply.
|
||||
meetingplace <- rendez{n: r.n, info: info0, mate: c0}
|
||||
info1 := <-c0
|
||||
othername = info1.name
|
||||
info0.colour = complement[info0.colour|info1.colour<<2]
|
||||
default:
|
||||
// another creature is waiting for us with its info;
|
||||
// increment meeting count,
|
||||
// send them our info in reply.
|
||||
r.n++
|
||||
meetingplace <- rendez{n: r.n, mate: nil}
|
||||
r.mate <- info0
|
||||
othername = r.info.name
|
||||
info0.colour = complement[info0.colour|r.info.colour<<2]
|
||||
}
|
||||
if othername == info0.name {
|
||||
same++
|
||||
}
|
||||
met++
|
||||
}
|
||||
}
|
||||
|
||||
var digits = [...]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"}
|
||||
|
||||
func spell(n int, required bool) string {
|
||||
if n == 0 && !required {
|
||||
return ""
|
||||
}
|
||||
return spell(n/10, false) + " " + digits[n%10]
|
||||
}
|
29
gcc/testsuite/go.test/test/bench/chameneosredux.txt
Normal file
29
gcc/testsuite/go.test/test/bench/chameneosredux.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
blue + blue -> blue
|
||||
blue + red -> yellow
|
||||
blue + yellow -> red
|
||||
red + blue -> yellow
|
||||
red + red -> red
|
||||
red + yellow -> blue
|
||||
yellow + blue -> red
|
||||
yellow + red -> blue
|
||||
yellow + yellow -> yellow
|
||||
|
||||
blue red yellow
|
||||
400 zero
|
||||
400 zero
|
||||
400 zero
|
||||
one two zero zero
|
||||
|
||||
blue red yellow red yellow blue red yellow red blue
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
120 zero
|
||||
one two zero zero
|
||||
|
4
gcc/testsuite/go.test/test/bench/clean.bash
Executable file
4
gcc/testsuite/go.test/test/bench/clean.bash
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
OS=568
|
||||
rm -f [$OS].out *.[$OS]
|
224
gcc/testsuite/go.test/test/bench/fannkuch-parallel.go
Normal file
224
gcc/testsuite/go.test/test/bench/fannkuch-parallel.go
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
||||
name of "The Computer Language Shootout Benchmarks" nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The Computer Language Benchmarks Game
|
||||
* http://shootout.alioth.debian.org/
|
||||
*
|
||||
* contributed by The Go Authors.
|
||||
* Based on fannkuch.scala by Rex Kerr
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var n = flag.Int("n", 7, "count")
|
||||
var nCPU = flag.Int("ncpu", 2, "number of cpus")
|
||||
|
||||
type Job struct {
|
||||
start []int
|
||||
n int
|
||||
}
|
||||
|
||||
type Found struct {
|
||||
who *Kucher
|
||||
k int
|
||||
}
|
||||
|
||||
type Kucher struct {
|
||||
perm []int
|
||||
temp []int
|
||||
flip []int
|
||||
in chan Job
|
||||
}
|
||||
|
||||
func NewKucher(length int) *Kucher {
|
||||
return &Kucher{
|
||||
perm: make([]int, length),
|
||||
temp: make([]int, length),
|
||||
flip: make([]int, length),
|
||||
in: make(chan Job),
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Kucher) permute(n int) bool {
|
||||
i := 0
|
||||
for ; i < n-1 && k.flip[i] == 0; i++ {
|
||||
t := k.perm[0]
|
||||
j := 0
|
||||
for ; j <= i; j++ {
|
||||
k.perm[j] = k.perm[j+1]
|
||||
}
|
||||
k.perm[j] = t
|
||||
}
|
||||
k.flip[i]--
|
||||
for i > 0 {
|
||||
i--
|
||||
k.flip[i] = i
|
||||
}
|
||||
return k.flip[n-1] >= 0
|
||||
}
|
||||
|
||||
func (k *Kucher) count() int {
|
||||
K := 0
|
||||
copy(k.temp, k.perm)
|
||||
for k.temp[0] != 0 {
|
||||
m := k.temp[0]
|
||||
for i := 0; i < m; i++ {
|
||||
k.temp[i], k.temp[m] = k.temp[m], k.temp[i]
|
||||
m--
|
||||
}
|
||||
K++
|
||||
}
|
||||
return K
|
||||
}
|
||||
|
||||
func (k *Kucher) Run(foreman chan<- Found) {
|
||||
for job := range k.in {
|
||||
verbose := 30
|
||||
copy(k.perm, job.start)
|
||||
for i, v := range k.perm {
|
||||
if v != i {
|
||||
verbose = 0
|
||||
}
|
||||
k.flip[i] = i
|
||||
}
|
||||
K := 0
|
||||
for {
|
||||
if verbose > 0 {
|
||||
for _, p := range k.perm {
|
||||
fmt.Print(p + 1)
|
||||
}
|
||||
fmt.Println()
|
||||
verbose--
|
||||
}
|
||||
count := k.count()
|
||||
if count > K {
|
||||
K = count
|
||||
}
|
||||
if !k.permute(job.n) {
|
||||
break
|
||||
}
|
||||
}
|
||||
foreman <- Found{k, K}
|
||||
}
|
||||
}
|
||||
|
||||
type Fanner struct {
|
||||
jobind int
|
||||
jobsdone int
|
||||
k int
|
||||
jobs []Job
|
||||
workers []*Kucher
|
||||
in chan Found
|
||||
result chan int
|
||||
}
|
||||
|
||||
func NewFanner(jobs []Job, workers []*Kucher) *Fanner {
|
||||
return &Fanner{
|
||||
jobs: jobs, workers: workers,
|
||||
in: make(chan Found),
|
||||
result: make(chan int),
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Fanner) Run(N int) {
|
||||
for msg := range f.in {
|
||||
if msg.k > f.k {
|
||||
f.k = msg.k
|
||||
}
|
||||
if msg.k >= 0 {
|
||||
f.jobsdone++
|
||||
}
|
||||
if f.jobind < len(f.jobs) {
|
||||
msg.who.in <- f.jobs[f.jobind]
|
||||
f.jobind++
|
||||
} else if f.jobsdone == len(f.jobs) {
|
||||
f.result <- f.k
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func swapped(a []int, i, j int) []int {
|
||||
b := make([]int, len(a))
|
||||
copy(b, a)
|
||||
b[i], b[j] = a[j], a[i]
|
||||
return b
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
runtime.GOMAXPROCS(*nCPU)
|
||||
N := *n
|
||||
base := make([]int, N)
|
||||
for i := range base {
|
||||
base[i] = i
|
||||
}
|
||||
|
||||
njobs := 1
|
||||
if N > 8 {
|
||||
njobs += (N*(N-1))/2 - 28 // njobs = 1 + sum(8..N-1) = 1 + sum(1..N-1) - sum(1..7)
|
||||
}
|
||||
jobs := make([]Job, njobs)
|
||||
jobsind := 0
|
||||
|
||||
firstN := N
|
||||
if firstN > 8 {
|
||||
firstN = 8
|
||||
}
|
||||
jobs[jobsind] = Job{base, firstN}
|
||||
jobsind++
|
||||
for i := N - 1; i >= 8; i-- {
|
||||
for j := 0; j < i; j++ {
|
||||
jobs[jobsind] = Job{swapped(base, i, j), i}
|
||||
jobsind++
|
||||
}
|
||||
}
|
||||
|
||||
nworkers := *nCPU
|
||||
if njobs < nworkers {
|
||||
nworkers = njobs
|
||||
}
|
||||
workers := make([]*Kucher, nworkers)
|
||||
foreman := NewFanner(jobs, workers)
|
||||
go foreman.Run(N)
|
||||
for i := range workers {
|
||||
k := NewKucher(N)
|
||||
workers[i] = k
|
||||
go k.Run(foreman.in)
|
||||
foreman.in <- Found{k, -1}
|
||||
}
|
||||
fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue