├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── bootstrap.sh ├── build ├── build.go ├── build_test.go └── context.go ├── cmd ├── cc-wrapper │ └── main.go ├── gllgo │ └── gllgo.go └── makefilter │ └── main.go ├── debug └── debug.go ├── install.sh ├── irgen ├── annotations.go ├── attribute.go ├── builtins.go ├── cabi.go ├── call.go ├── channels.go ├── closures.go ├── compiler.go ├── errors.go ├── indirect.go ├── interfaces.go ├── maps.go ├── parser.go ├── predicates.go ├── println.go ├── runtime.go ├── slice.go ├── ssa.go ├── strings.go ├── targets.go ├── typemap.go ├── types.go ├── utils.go ├── value.go └── version.go ├── libgo-noext.diff ├── llgo-go.sh ├── ssaopt └── esc.go ├── test ├── debuginfo │ └── emptyname.go ├── execution │ ├── Inputs │ │ └── init2.go │ ├── arrays │ │ ├── compare.go │ │ ├── index.go │ │ ├── range.go │ │ └── slice.go │ ├── assignment │ │ ├── arrays.go │ │ ├── binop.go │ │ ├── dereferencing.go │ │ ├── multi.go │ │ └── namedresult.go │ ├── branching │ │ ├── goto.go │ │ └── labeled.go │ ├── chan │ │ ├── buffered.go │ │ ├── range.go │ │ ├── select.go │ │ └── self.go │ ├── circulartype.go │ ├── closures │ │ ├── basic.go │ │ └── issue176.go │ ├── complex.go │ ├── const.go │ ├── conversions │ │ ├── complex.go │ │ ├── float.go │ │ ├── int.go │ │ └── sameunderlying.go │ ├── defer.go │ ├── errors │ │ └── recover.go │ ├── for │ │ └── branch.go │ ├── fun.go │ ├── functions │ │ ├── compare.go │ │ ├── multivalue.go │ │ └── unreachable.go │ ├── go.go │ ├── if │ │ └── lazy.go │ ├── init.go │ ├── interfaces │ │ ├── assert.go │ │ ├── basic.go │ │ ├── comparei2i.go │ │ ├── comparei2v.go │ │ ├── e2i_conversion.go │ │ ├── embedded.go │ │ ├── error.go │ │ ├── i2i_conversion.go │ │ ├── import.go │ │ ├── methods.go │ │ ├── static_conversion.go │ │ └── wordsize.go │ ├── literals │ │ ├── array.go │ │ ├── func.go │ │ ├── map.go │ │ ├── slice.go │ │ └── struct.go │ ├── maps │ │ ├── delete.go │ │ ├── insert.go │ │ ├── lookup.go │ │ └── range.go │ ├── methods │ │ ├── methodvalues.go │ │ ├── nilrecv.go │ │ └── selectors.go │ ├── new.go │ ├── nil.go │ ├── operators │ │ ├── basics.go │ │ ├── binary_untyped.go │ │ └── shifts.go │ ├── slices │ │ ├── append.go │ │ ├── cap.go │ │ ├── compare.go │ │ ├── copy.go │ │ ├── index.go │ │ ├── literal.go │ │ ├── make.go │ │ └── sliceexpr.go │ ├── strings │ │ ├── add.go │ │ ├── bytes.go │ │ ├── compare.go │ │ ├── index.go │ │ ├── range.go │ │ ├── runetostring.go │ │ └── slice.go │ ├── structs │ │ ├── compare.go │ │ └── embed.go │ ├── switch │ │ ├── branch.go │ │ ├── default.go │ │ ├── empty.go │ │ ├── scope.go │ │ ├── strings.go │ │ └── type.go │ ├── types │ │ ├── named.go │ │ └── recursive.go │ ├── unsafe │ │ ├── const_sizeof.go │ │ ├── offsetof.go │ │ ├── pointer.go │ │ ├── sizeof_array.go │ │ ├── sizeof_basic.go │ │ └── sizeof_struct.go │ ├── var.go │ └── varargs.go ├── gllgo │ └── dead.go ├── irgen │ └── mangling.go └── lit.cfg ├── update_clang.sh ├── update_libgo.sh └── utils └── benchcomp ├── README ├── analyze.R └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.a 4 | *.[68] 5 | _obj 6 | bin 7 | cmd/gllgo/gllgo 8 | test/**/Output 9 | workdir 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - 1.3.1 4 | env: 5 | - APT_GET='apt-get --option=Dpkg::Options::=--force-confold --option=Dpkg::options::=--force-unsafe-io --assume-yes --quiet' 6 | before_install: 7 | - sudo add-apt-repository -y ppa:kalakris/cmake # install newer cmake 8 | - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test # install newer gcc 9 | - sudo $APT_GET update 10 | - sudo $APT_GET install mercurial git subversion cmake gcc-4.8 g++-4.8 11 | - export CXX=g++-4.8 CC=gcc-4.8 12 | install: 13 | - go get -d llvm.org/llvm/bindings/go/llvm 14 | - $(go list -f '{{.Dir}}' llvm.org/llvm/bindings/go/llvm)/../build.sh -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host 15 | - make install prefix=`pwd`/.install 16 | script: 17 | - make check-llgo check-libgo 18 | notifications: 19 | email: 20 | recipients: 21 | - axwalk@gmail.com 22 | on_success: change 23 | on_failure: always 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 The llgo Authors. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | ------------------------------------------------------------------------------- 22 | Portions of llgo's source code has been derived from Go, and are covered by the 23 | following license: 24 | ------------------------------------------------------------------------------- 25 | 26 | Copyright (c) 2009 The Go Authors. All rights reserved. 27 | 28 | Redistribution and use in source and binary forms, with or without 29 | modification, are permitted provided that the following conditions are 30 | met: 31 | 32 | * Redistributions of source code must retain the above copyright 33 | notice, this list of conditions and the following disclaimer. 34 | * Redistributions in binary form must reproduce the above 35 | copyright notice, this list of conditions and the following disclaimer 36 | in the documentation and/or other materials provided with the 37 | distribution. 38 | * Neither the name of Google Inc. nor the names of its 39 | contributors may be used to endorse or promote products derived from 40 | this software without specific prior written permission. 41 | 42 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | j = 1 2 | prefix = /usr/local 3 | bootstrap = quick 4 | gollvmdir = $(shell go list -f '{{.Dir}}' llvm.org/llvm/bindings/go/llvm) 5 | llvmdir = $(gollvmdir)/workdir/llvm_build 6 | 7 | bootstrap: workdir/.bootstrap-stamp 8 | 9 | install: bootstrap 10 | ./install.sh $(prefix) 11 | 12 | check-libgo: bootstrap 13 | $(MAKE) -C workdir/gofrontend_build/libgo-stage1 check 14 | 15 | check-llgo: bootstrap 16 | $(llvmdir)/bin/llvm-lit -s test 17 | 18 | workdir/.bootstrap-stamp: workdir/.build-libgodeps-stamp bootstrap.sh build/*.go cmd/gllgo/*.go cmd/cc-wrapper/*.go debug/*.go irgen/*.go ssaopt/*.go 19 | ./bootstrap.sh $(bootstrap) -j$(j) 20 | 21 | workdir/.build-libgodeps-stamp: workdir/.update-clang-stamp workdir/.update-libgo-stamp bootstrap.sh 22 | ./bootstrap.sh libgodeps -j$(j) 23 | 24 | workdir/.update-clang-stamp: update_clang.sh alwaysrun 25 | ./update_clang.sh 26 | 27 | workdir/.update-libgo-stamp: update_libgo.sh 28 | ./update_libgo.sh 29 | 30 | .SUFFIXES: 31 | 32 | alwaysrun: 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llgo 2 | 3 | **This project has moved to llvm.org. Any contributions or bug reports should be sent there. Please refer to the [llgo readme](http://llvm.org/svn/llvm-project/llgo/trunk/README.TXT) for more information.** 4 | 5 | llgo is a [Go](http://golang.org) frontend for [LLVM](http://llvm.org), written in Go. 6 | 7 | llgo is under active development. It compiles and passes most of the standard library test suite and a substantial portion of the gc test suite, but there are some corner cases that are known not to be handled correctly yet. Nevertheless it can compile modestly substantial programs (including itself; it is self hosting on x86-64 Linux). 8 | 9 | Progress will be reported on the [mailing list](https://groups.google.com/d/forum/llgo-dev). 10 | 11 | # Installation 12 | 13 | llgo requires: 14 | * Go 1.3 or later. 15 | * [CMake](http://cmake.org/) 2.8.8 or later (to build LLVM). 16 | * A [modern C++ toolchain](http://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain) (to build LLVM). 17 | 18 | Note that Ubuntu Precise is one Linux distribution which does not package a sufficiently new CMake or C++ toolchain. 19 | 20 | If you built a newer GCC following the linked instructions above, you will need to set the following environment variables before proceeding: 21 | 22 | export PATH=/path/to/gcc-inst/bin:$PATH 23 | export LD_LIBRARY_PATH=/path/to/gcc-inst/lib64:$LD_LIBRARY_PATH 24 | export CC=`which gcc` 25 | export CXX=`which g++` 26 | export LIBGO_CFLAGS=--gcc-toolchain=/path/to/gcc-inst 27 | 28 | To build and install llgo: 29 | 30 | # Ensure $GOPATH is set. 31 | go get -d github.com/go-llvm/llgo/cmd/gllgo 32 | $GOPATH/src/llvm.org/llvm/bindings/go/build.sh -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host 33 | cd $GOPATH/src/github.com/go-llvm/llgo 34 | make install prefix=/path/to/prefix j=N # where N is the number of cores on your machine. 35 | 36 | # Running 37 | 38 | We install two binaries to `$prefix/bin`: `llgo` and `llgo-go`. 39 | 40 | `llgo` is the compiler binary. It has a command line interface that is intended to be compatible to a large extent with `gccgo`. 41 | 42 | `llgo-go` is a command line wrapper for `go`. It works like the regular `go` command except that it uses llgo to build. 43 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | llgodir=$(dirname "$0") 6 | llgodir=$(cd "$llgodir" && pwd) 7 | 8 | workdir=$llgodir/workdir 9 | gofrontenddir=$workdir/gofrontend 10 | gofrontend_builddir=$workdir/gofrontend_build 11 | 12 | case "$1" in 13 | libgodeps | quick | full) 14 | bootstrap_type="$1" 15 | shift 16 | ;; 17 | 18 | *) 19 | ;; 20 | esac 21 | 22 | if test "$1" == "lto"; then 23 | lto=1 24 | shift 25 | fi 26 | 27 | if test "$1" == "asan"; then 28 | asan=1 29 | shift 30 | fi 31 | 32 | if test "$1" == "tsan"; then 33 | tsan=1 34 | shift 35 | fi 36 | 37 | if test "$1" == "msan"; then 38 | msan=1 39 | shift 40 | fi 41 | 42 | if test "$1" == "dfsan"; then 43 | dfsan=1 44 | shift 45 | fi 46 | 47 | if test "$lto" == "1" -o "$asan" == "1" -o "$tsan" == "1" -o "$msan" == "1" -o "$dfsan" == "1"; then 48 | echo "# WARNING: support for LTO/sanitizer variants is EXPERIMENTAL and unlikely to work correctly!" 49 | fi 50 | 51 | llgo_cc="${LIBGO_CC:-$workdir/clang_build/bin/clang} $LIBGO_CFLAGS" 52 | llgo_cxx="${LIBGO_CXX:-$workdir/clang_build/bin/clang++} $LIBGO_CFLAGS" 53 | 54 | build_libgodeps() { 55 | local cflags="$1" 56 | local destdir="$2" 57 | local variantname="$3" 58 | local makeflags="$4" 59 | 60 | for d in libbacktrace libffi ; do 61 | rm -rf $destdir/$d 62 | mkdir -p $destdir/$d 63 | case $d in 64 | libbacktrace) 65 | config_flags="--enable-host-shared" 66 | ;; 67 | *) 68 | config_flags="" 69 | ;; 70 | esac 71 | 72 | echo "# Configuring $variantname $d." 73 | (cd $destdir/$d && CC="$llgo_cc $cflags" $gofrontenddir/$d/configure --disable-multilib $config_flags > $workdir/${d}-config.log 2>&1 || (echo "# Configure failed, see $workdir/${d}-config.log" && exit 1)) 74 | echo "# Building $variantname $d." 75 | make -C $destdir/$d $makeflags > $workdir/${d}-make.log 2>&1 || (echo "# Build failed, see $workdir/${d}-make.log" && exit 1) 76 | done 77 | } 78 | 79 | build_libgo_stage() { 80 | local goc="$1" 81 | local cflags="$2" 82 | local gocflags="$3" 83 | local destdir="$4" 84 | local variantname="$5" 85 | local makeflags="$6" 86 | 87 | # Wrap Clang in a program that understands -fgo-dump-spec and -fplan9-extensions. 88 | libgo_cc="$llgo_cc $cflags" 89 | libgo_wrapped_cc="env REAL_CC=$(echo $libgo_cc | sed -e 's/ /@SPACE@/g') $workdir/cc-wrapper" 90 | 91 | mkdir -p $destdir 92 | echo "# Configuring $variantname libgo." 93 | (cd $destdir && $gofrontenddir/libgo/configure --disable-multilib --without-libatomic CC="$libgo_wrapped_cc" GOC="$goc -no-prefix $GOCFLAGS $gocflags" > $workdir/${variantname}-config.log 2>&1 || (echo "# Configure failed, see $workdir/${variantname}-config.log" && exit 1)) 94 | echo "# Building $variantname libgo." 95 | make -C $destdir $makeflags 2>&1 | tee $workdir/${variantname}-make.log | $workdir/makefilter 96 | test "${PIPESTATUS[0]}" = "0" || (echo "# Build failed, see $workdir/${variantname}-make.log" && exit 1) 97 | echo 98 | } 99 | 100 | build_libgo_variant() { 101 | local goc="$1" 102 | local cflags="$2" 103 | local gocflags="$3" 104 | local variantname="$4" 105 | local makeflags="$5" 106 | 107 | local destdir="$workdir/gofrontend_build_$variantname" 108 | rm -rf $destdir 109 | build_libgodeps "$cflags" "$destdir" "$variantname" "$makeflags" 110 | build_libgo_stage "$goc" "$cflags" "$gocflags" "$destdir/libgo" "$variantname" "$makeflags" 111 | } 112 | 113 | if [ "$bootstrap_type" = "libgodeps" ]; then 114 | build_libgodeps "$LIBGO_CFLAGS" "$gofrontend_builddir" "normal" "$*" 115 | touch $workdir/.build-libgodeps-stamp 116 | exit 0 117 | fi 118 | 119 | if [ "$bootstrap_type" != "" ]; then 120 | # Clean up any previous libgo stages. 121 | rm -rf $gofrontend_builddir/libgo* $workdir/gofrontend_build_* 122 | 123 | echo "# Building helper programs." 124 | (cd $llgodir/cmd/cc-wrapper && go build -o $workdir/cc-wrapper) 125 | (cd $llgodir/cmd/makefilter && go build -o $workdir/makefilter) 126 | 127 | # Build a stage1 compiler with gc. 128 | echo "# Building stage1 compiler." 129 | (cd $llgodir/cmd/gllgo && go build -o $workdir/gllgo-stage1) 130 | 131 | # Build libgo with the stage1 compiler. 132 | build_libgo_stage $workdir/gllgo-stage1 "" "" $gofrontend_builddir/libgo-stage1 stage1 "$*" 133 | 134 | # Set up a directory which when added to $PATH causes "gccgo" to resolve 135 | # to our stage1 compiler. This is necessary because the logic in "go build" 136 | # for locating the compiler is fixed. 137 | mkdir -p $gofrontend_builddir/stage1-path 138 | ln -sf $workdir/gllgo-stage1 $gofrontend_builddir/stage1-path/gccgo 139 | 140 | # Build a stage2 compiler using the stage1 compiler and libgo. 141 | echo "# Building stage2 compiler." 142 | gllgoflags="-no-prefix -L$gofrontend_builddir/libgo-stage1 -L$gofrontend_builddir/libgo-stage1/.libs -static-libgo $GOCFLAGS" 143 | (cd $llgodir/cmd/gllgo && PATH=$gofrontend_builddir/stage1-path:$PATH CC="$llgo_cc" CXX="$llgo_cxx" go build -compiler gccgo -gccgoflags "$gllgoflags" -o $workdir/gllgo-stage2) 144 | 145 | # If this is a quick bootstrap, do not rebuild libgo with the stage2 compiler. 146 | # Instead, use the stage1 libgo. 147 | 148 | if [ "$bootstrap_type" == "full" ] ; then 149 | # Build libgo with the stage2 compiler. 150 | build_libgo_stage $workdir/gllgo-stage2 "" "" $gofrontent_builddir/libgo-stage2 stage2 "$*" 151 | 152 | # Set up $gllgoflags to use the stage2 libgo. 153 | gllgoflags="-no-prefix -L$gofrontend_builddir/libgo-stage2 -L$gofrontend_builddir/libgo-stage2/.libs -static-libgo $GOCFLAGS" 154 | fi 155 | 156 | # Set up a directory which when added to $PATH causes "gccgo" to resolve 157 | # to our stage2 compiler. 158 | mkdir -p $gofrontend_builddir/stage2-path 159 | ln -sf $workdir/gllgo-stage2 $gofrontend_builddir/stage2-path/gccgo 160 | 161 | # Build the stage3 compiler. 162 | echo "# Building stage3 compiler." 163 | (cd $llgodir/cmd/gllgo && PATH=$gofrontend_builddir/stage2-path:$PATH CC="$llgo_cc" CXX="$llgo_cxx" go build -compiler gccgo -gccgoflags "$gllgoflags" -o $workdir/gllgo-stage3) 164 | 165 | # Strip the compiler binaries. The binaries are currently only 166 | # expected to compare equal modulo debug info. 167 | strip -R .note.gnu.build-id -o $workdir/gllgo-stage2.stripped $workdir/gllgo-stage2 168 | strip -R .note.gnu.build-id -o $workdir/gllgo-stage3.stripped $workdir/gllgo-stage3 169 | 170 | cmp $workdir/gllgo-stage2.stripped $workdir/gllgo-stage3.stripped && \ 171 | echo "# Bootstrap completed successfully." && touch $workdir/.bootstrap-stamp || \ 172 | (echo "# Bootstrap failed, binaries differ." && exit 1) 173 | fi 174 | 175 | if [ "$lto" == "1" ]; then 176 | build_libgo_variant $workdir/gllgo-stage3 "-flto" "-flto" lto "$*" 177 | fi 178 | 179 | if [ "$asan" == "1" ]; then 180 | build_libgo_variant $workdir/gllgo-stage3 "-fsanitize=address" "-fsanitize=address -fcompilerrt-prefix=$workdir/clang_build" asan "$*" 181 | fi 182 | 183 | if [ "$tsan" == "1" ]; then 184 | build_libgo_variant $workdir/gllgo-stage3 "-fsanitize=thread" "-fsanitize=thread -fcompilerrt-prefix=$workdir/clang_build" tsan "$*" 185 | fi 186 | 187 | if [ "$msan" == "1" ]; then 188 | build_libgo_variant $workdir/gllgo-stage3 "-fsanitize=memory" "-fsanitize=memory -fcompilerrt-prefix=$workdir/clang_build" msan "$*" 189 | fi 190 | 191 | if [ "$dfsan" == "1" ]; then 192 | build_libgo_variant $workdir/gllgo-stage3 "-fsanitize=dataflow" "-fsanitize=dataflow -fcompilerrt-prefix=$workdir/clang_build" dfsan "$*" 193 | fi 194 | -------------------------------------------------------------------------------- /build/build.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package build 6 | 7 | import ( 8 | "bytes" 9 | "io" 10 | ) 11 | 12 | // LLVMIRReadCloser wraps an io.ReadCloser, transforming the leading 13 | // comments of the file such that they are preceded with "//" rather 14 | // than standard LLVM IR comments ("; blah"). 15 | // 16 | // This type is intended to be used in the OpenFile field of 17 | // go/build's Context type. 18 | type LLVMIRReadCloser struct { 19 | io.ReadCloser 20 | buf *bytes.Buffer 21 | } 22 | 23 | func NewLLVMIRReader(r io.ReadCloser) *LLVMIRReadCloser { 24 | return &LLVMIRReadCloser{r, nil} 25 | } 26 | 27 | var slashslash = []byte("//") 28 | var semicolon = []byte(";") 29 | 30 | func (r *LLVMIRReadCloser) Read(p []byte) (n int, err error) { 31 | if r.buf != nil { 32 | n, err = r.buf.Read(p) 33 | if err == io.EOF { 34 | if r.ReadCloser != nil { 35 | err = nil 36 | } 37 | r.buf = nil 38 | } 39 | return 40 | } 41 | 42 | n, err = r.ReadCloser.Read(p) 43 | if n > 0 { 44 | // To simplify the translation we'll simply 45 | // replace all instances of ";" in the returned 46 | // data. 47 | p_ := bytes.Replace(p, semicolon, slashslash, -1) 48 | if len(p_) > len(p) { 49 | r.buf = bytes.NewBuffer(p_) 50 | n, err = r.buf.Read(p) 51 | // err should be nil, since n < len(p) 52 | } 53 | } 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /build/build_test.go: -------------------------------------------------------------------------------- 1 | package build_test 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "strings" 7 | "testing" 8 | "testing/iotest" 9 | 10 | "github.com/go-llvm/llgo/build" 11 | ) 12 | 13 | func TestLLVMIRReadCloser(t *testing.T) { 14 | const input = `;abc\n;def\n;xyz` 15 | 16 | var buf bytes.Buffer 17 | buf.WriteString(input) 18 | r := build.NewLLVMIRReader(ioutil.NopCloser(&buf)) 19 | b, err := ioutil.ReadAll(iotest.OneByteReader(r)) 20 | if err != nil { 21 | t.Errorf("unexpected error: %s", err) 22 | } 23 | 24 | str := string(b) 25 | expected := strings.Replace(str, ";", "//", -1) 26 | if str != expected { 27 | t.Errorf("%q != %q", str, expected) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /build/context.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package build 6 | 7 | import ( 8 | "errors" 9 | "go/build" 10 | "regexp" 11 | "strings" 12 | ) 13 | 14 | type Context struct { 15 | build.Context 16 | 17 | // LLVM triple 18 | Triple string 19 | } 20 | 21 | // ContextFromTriple returns a new go/build.Context with GOOS and GOARCH 22 | // configured from the given triple. 23 | func ContextFromTriple(triple string) (*Context, error) { 24 | goos, goarch, err := parseTriple(triple) 25 | if err != nil { 26 | return nil, err 27 | } 28 | ctx := &Context{Context: build.Default, Triple: triple} 29 | ctx.GOOS = goos 30 | ctx.GOARCH = goarch 31 | ctx.BuildTags = append(ctx.BuildTags, "llgo") 32 | if triple == "pnacl" { 33 | ctx.BuildTags = append(ctx.BuildTags, "pnacl") 34 | } 35 | return ctx, nil 36 | } 37 | 38 | func parseTriple(triple string) (goos string, goarch string, err error) { 39 | if strings.ToLower(triple) == "pnacl" { 40 | return "nacl", "le32", nil 41 | } 42 | 43 | type REs struct{ re, out string } 44 | // reference: http://llvm.org/docs/doxygen/html/Triple_8cpp_source.html 45 | goarchREs := []REs{ 46 | {"amd64|x86_64", "amd64"}, 47 | {"i[3-9]86", "386"}, 48 | {"xscale|((arm|thumb)(v.*)?)", "arm"}, 49 | } 50 | goosREs := []REs{ 51 | {"linux.*", "linux"}, 52 | {"(darwin|macosx|ios).*", "darwin"}, 53 | {"k?freebsd.*", "freebsd"}, 54 | {"netbsd.*", "netbsd"}, 55 | {"openbsd.*", "openbsd"}, 56 | } 57 | match := func(list []REs, s string) string { 58 | for _, t := range list { 59 | if matched, _ := regexp.MatchString(t.re, s); matched { 60 | return t.out 61 | } 62 | } 63 | return "" 64 | } 65 | 66 | s := strings.Split(triple, "-") 67 | switch l := len(s); l { 68 | default: 69 | return "", "", errors.New("triple should be made up of 2, 3, or 4 parts.") 70 | case 2, 3: // ARCHITECTURE-(VENDOR-)OPERATING_SYSTEM 71 | goarch = s[0] 72 | goos = s[l-1] 73 | case 4: // ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT 74 | goarch = s[0] 75 | goos = s[2] 76 | } 77 | goarch = match(goarchREs, goarch) 78 | if goarch == "" { 79 | return "", "", errors.New("unknown architecture in triple") 80 | } 81 | goos = match(goosREs, goos) 82 | if goos == "" { 83 | return "", "", errors.New("unknown OS in triple") 84 | } 85 | return goos, goarch, nil 86 | } 87 | -------------------------------------------------------------------------------- /cmd/cc-wrapper/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This is a wrapper for Clang that passes invocations with -fdump-go-spec to 6 | // GCC, and rewrites -fplan9-extensions to -fms-extensions. It is intended to 7 | // go away once libgo's build no longer uses these flags. 8 | 9 | package main 10 | 11 | import ( 12 | "fmt" 13 | "os" 14 | "os/exec" 15 | "strings" 16 | ) 17 | 18 | func runproc(name string, argv []string) { 19 | path, err := exec.LookPath(name) 20 | if err != nil { 21 | fmt.Fprintf(os.Stderr, "cc-wrapper: could not find %s: %v\n", name, err) 22 | os.Exit(1) 23 | } 24 | 25 | proc, err := os.StartProcess(path, append([]string{name}, argv...), &os.ProcAttr{ 26 | Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, 27 | }) 28 | if err != nil { 29 | fmt.Fprintf(os.Stderr, "cc-wrapper: could not start %s: %v\n", name, err) 30 | os.Exit(1) 31 | } 32 | 33 | state, err := proc.Wait() 34 | if err != nil { 35 | fmt.Fprintf(os.Stderr, "cc-wrapper: could not wait for %s: %v\n", name, err) 36 | os.Exit(1) 37 | } 38 | 39 | if state.Success() { 40 | os.Exit(0) 41 | } else { 42 | os.Exit(1) 43 | } 44 | } 45 | 46 | func main() { 47 | newargs := make([]string, len(os.Args)-1) 48 | for i, arg := range os.Args[1:] { 49 | switch { 50 | case strings.HasPrefix(arg, "-fdump-go-spec"): 51 | runproc("gcc", os.Args[1:]) 52 | 53 | case arg == "-fplan9-extensions": 54 | newargs[i] = "-fms-extensions" 55 | newargs = append(newargs, "-Wno-microsoft") 56 | 57 | default: 58 | newargs[i] = arg 59 | } 60 | } 61 | 62 | ccargs := strings.Split(os.Getenv("REAL_CC"), "@SPACE@") 63 | runproc(ccargs[0], append(ccargs[1:], newargs...)) 64 | } 65 | -------------------------------------------------------------------------------- /cmd/makefilter/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // A simple filter program which improves the readability of libgo's build 11 | // output by filtering out everything except the package names. 12 | func main() { 13 | stdin := bufio.NewReader(os.Stdin) 14 | pkgs := make(map[string]struct{}) 15 | for { 16 | line, err := stdin.ReadString('\n') 17 | if err == io.EOF { 18 | return 19 | } else if err != nil { 20 | panic("read error: " + err.Error()) 21 | } 22 | line = line[0 : len(line)-1] 23 | if strings.HasPrefix(line, "libtool: compile:") { 24 | words := strings.Split(line, " ") 25 | for _, word := range words { 26 | if strings.HasPrefix(word, "-fgo-pkgpath=") { 27 | pkg := word[13:] 28 | if _, ok := pkgs[pkg]; !ok { 29 | os.Stdout.WriteString(pkg + "\n") 30 | pkgs[pkg] = struct{}{} 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /debug/debug.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package debug 6 | 7 | import ( 8 | "debug/dwarf" 9 | "fmt" 10 | "go/token" 11 | "os" 12 | "strings" 13 | 14 | "golang.org/x/tools/go/ssa" 15 | "golang.org/x/tools/go/types" 16 | "golang.org/x/tools/go/types/typeutil" 17 | 18 | "llvm.org/llvm/bindings/go/llvm" 19 | ) 20 | 21 | const ( 22 | // non-standard debug metadata tags 23 | tagAutoVariable dwarf.Tag = 0x100 24 | tagArgVariable dwarf.Tag = 0x101 25 | ) 26 | 27 | type PrefixMap struct { 28 | Source, Replacement string 29 | } 30 | 31 | // DIBuilder builds debug metadata for Go programs. 32 | type DIBuilder struct { 33 | // builder is the current builder; there is one per CU. 34 | builder *llvm.DIBuilder 35 | module llvm.Module 36 | files map[*token.File]llvm.Value 37 | cu, fn, lb llvm.Value 38 | fnFile string 39 | debugScope []llvm.Value 40 | sizes types.Sizes 41 | fset *token.FileSet 42 | prefixMaps []PrefixMap 43 | types typeutil.Map 44 | voidType llvm.Value 45 | } 46 | 47 | // NewDIBuilder creates a new debug information builder. 48 | func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap) *DIBuilder { 49 | var d DIBuilder 50 | d.module = module 51 | d.files = make(map[*token.File]llvm.Value) 52 | d.sizes = sizes 53 | d.fset = fset 54 | d.prefixMaps = prefixMaps 55 | d.builder = llvm.NewDIBuilder(d.module) 56 | d.cu = d.createCompileUnit() 57 | return &d 58 | } 59 | 60 | // Destroy destroys the DIBuilder. 61 | func (d *DIBuilder) Destroy() { 62 | d.builder.Destroy() 63 | } 64 | 65 | func (d *DIBuilder) scope() llvm.Value { 66 | if d.lb.C != nil { 67 | return d.lb 68 | } 69 | if d.fn.C != nil { 70 | return d.fn 71 | } 72 | return d.cu 73 | } 74 | 75 | func (d *DIBuilder) remapFilePath(path string) string { 76 | for _, pm := range d.prefixMaps { 77 | if strings.HasPrefix(path, pm.Source) { 78 | return pm.Replacement + path[len(pm.Source):] 79 | } 80 | } 81 | return path 82 | } 83 | 84 | func (d *DIBuilder) getFile(file *token.File) llvm.Value { 85 | if diFile := d.files[file]; !diFile.IsNil() { 86 | return diFile 87 | } 88 | diFile := d.builder.CreateFile(d.remapFilePath(file.Name()), "") 89 | d.files[file] = diFile 90 | return diFile 91 | } 92 | 93 | // createCompileUnit creates and returns debug metadata for the compile 94 | // unit as a whole, using the first file in the file set as a representative 95 | // (the choice of file is arbitrary). 96 | func (d *DIBuilder) createCompileUnit() llvm.Value { 97 | var file *token.File 98 | d.fset.Iterate(func(f *token.File) bool { 99 | file = f 100 | return false 101 | }) 102 | dir, err := os.Getwd() 103 | if err != nil { 104 | panic("could not get current directory: " + err.Error()) 105 | } 106 | return d.builder.CreateCompileUnit(llvm.DICompileUnit{ 107 | Language: llvm.DW_LANG_Go, 108 | File: d.remapFilePath(file.Name()), 109 | Dir: dir, 110 | Producer: "llgo", 111 | }) 112 | } 113 | 114 | // PushFunction creates debug metadata for the specified function, 115 | // and pushes it onto the scope stack. 116 | func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) { 117 | var diFile llvm.Value 118 | var line int 119 | if file := d.fset.File(pos); file != nil { 120 | d.fnFile = file.Name() 121 | diFile = d.getFile(file) 122 | line = file.Line(pos) 123 | } 124 | d.fn = d.builder.CreateFunction(d.scope(), llvm.DIFunction{ 125 | Name: fnptr.Name(), // TODO(axw) unmangled name? 126 | LinkageName: fnptr.Name(), 127 | File: diFile, 128 | Line: line, 129 | Type: d.DIType(sig), 130 | IsDefinition: true, 131 | Function: fnptr, 132 | }) 133 | } 134 | 135 | // PopFunction pops the previously pushed function off the scope stack. 136 | func (d *DIBuilder) PopFunction() { 137 | d.lb = llvm.Value{nil} 138 | d.fn = llvm.Value{nil} 139 | d.fnFile = "" 140 | } 141 | 142 | // Declare creates an llvm.dbg.declare call for the specified function 143 | // parameter or local variable. 144 | func (d *DIBuilder) Declare(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { 145 | tag := tagAutoVariable 146 | if paramIndex >= 0 { 147 | tag = tagArgVariable 148 | } 149 | var diFile llvm.Value 150 | var line int 151 | if file := d.fset.File(v.Pos()); file != nil { 152 | line = file.Line(v.Pos()) 153 | diFile = d.getFile(file) 154 | } 155 | localVar := d.builder.CreateLocalVariable(d.scope(), llvm.DILocalVariable{ 156 | Tag: tag, 157 | Name: llv.Name(), 158 | File: diFile, 159 | Line: line, 160 | ArgNo: paramIndex + 1, 161 | Type: d.DIType(v.Type()), 162 | }) 163 | expr := d.builder.CreateExpression(nil) 164 | d.builder.InsertDeclareAtEnd(llv, localVar, expr, b.GetInsertBlock()) 165 | } 166 | 167 | // Value creates an llvm.dbg.value call for the specified register value. 168 | func (d *DIBuilder) Value(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) { 169 | // TODO(axw) 170 | } 171 | 172 | // SetLocation sets the current debug location. 173 | func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) { 174 | if !pos.IsValid() { 175 | return 176 | } 177 | position := d.fset.Position(pos) 178 | d.lb = llvm.Value{nil} 179 | if position.Filename != d.fnFile && position.Filename != "" { 180 | // This can happen rarely, e.g. in init functions. 181 | diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "") 182 | d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0) 183 | } 184 | b.SetCurrentDebugLocation(llvm.MDNode([]llvm.Value{ 185 | llvm.ConstInt(llvm.Int32Type(), uint64(position.Line), false), 186 | llvm.ConstInt(llvm.Int32Type(), uint64(position.Column), false), 187 | d.scope(), 188 | llvm.Value{}, 189 | })) 190 | } 191 | 192 | // Finalize must be called after all compilation units are translated, 193 | // generating the final debug metadata for the module. 194 | func (d *DIBuilder) Finalize() { 195 | d.module.AddNamedMetadataOperand( 196 | "llvm.module.flags", 197 | llvm.MDNode([]llvm.Value{ 198 | llvm.ConstInt(llvm.Int32Type(), 2, false), // Warn on mismatch 199 | llvm.MDString("Dwarf Version"), 200 | llvm.ConstInt(llvm.Int32Type(), 4, false), 201 | }), 202 | ) 203 | d.module.AddNamedMetadataOperand( 204 | "llvm.module.flags", 205 | llvm.MDNode([]llvm.Value{ 206 | llvm.ConstInt(llvm.Int32Type(), 1, false), // Error on mismatch 207 | llvm.MDString("Debug Info Version"), 208 | llvm.ConstInt(llvm.Int32Type(), 1, false), 209 | }), 210 | ) 211 | d.builder.Finalize() 212 | } 213 | 214 | // DIType maps a Go type to DIType debug metadata value. 215 | func (d *DIBuilder) DIType(t types.Type) llvm.Value { 216 | return d.typeDebugDescriptor(t, types.TypeString(nil, t)) 217 | } 218 | 219 | func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Value { 220 | // Signature needs to be handled specially, to preprocess 221 | // methods, moving the receiver to the parameter list. 222 | if t, ok := t.(*types.Signature); ok { 223 | return d.descriptorSignature(t, name) 224 | } 225 | if t == nil { 226 | if d.voidType.IsNil() { 227 | d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"}) 228 | } 229 | return d.voidType 230 | } 231 | if dt, ok := d.types.At(t).(llvm.Value); ok { 232 | return dt 233 | } 234 | dt := d.descriptor(t, name) 235 | d.types.Set(t, dt) 236 | return dt 237 | } 238 | 239 | func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Value { 240 | switch t := t.(type) { 241 | case *types.Basic: 242 | return d.descriptorBasic(t, name) 243 | case *types.Pointer: 244 | return d.descriptorPointer(t) 245 | case *types.Struct: 246 | return d.descriptorStruct(t, name) 247 | case *types.Named: 248 | return d.descriptorNamed(t) 249 | case *types.Array: 250 | return d.descriptorArray(t, name) 251 | case *types.Slice: 252 | return d.descriptorSlice(t, name) 253 | case *types.Map: 254 | return d.descriptorMap(t, name) 255 | case *types.Chan: 256 | return d.descriptorChan(t, name) 257 | case *types.Interface: 258 | return d.descriptorInterface(t, name) 259 | default: 260 | panic(fmt.Sprintf("unhandled type: %T", t)) 261 | } 262 | } 263 | 264 | func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Value { 265 | switch t.Kind() { 266 | case types.String: 267 | return d.typeDebugDescriptor(types.NewStruct([]*types.Var{ 268 | types.NewVar(0, nil, "ptr", types.NewPointer(types.Typ[types.Uint8])), 269 | types.NewVar(0, nil, "len", types.Typ[types.Int]), 270 | }, nil), name) 271 | case types.UnsafePointer: 272 | return d.builder.CreateBasicType(llvm.DIBasicType{ 273 | Name: name, 274 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 275 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 276 | Encoding: llvm.DW_ATE_unsigned, 277 | }) 278 | default: 279 | bt := llvm.DIBasicType{ 280 | Name: t.String(), 281 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 282 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 283 | } 284 | switch bi := t.Info(); { 285 | case bi&types.IsBoolean != 0: 286 | bt.Encoding = llvm.DW_ATE_boolean 287 | case bi&types.IsUnsigned != 0: 288 | bt.Encoding = llvm.DW_ATE_unsigned 289 | case bi&types.IsInteger != 0: 290 | bt.Encoding = llvm.DW_ATE_signed 291 | case bi&types.IsFloat != 0: 292 | bt.Encoding = llvm.DW_ATE_float 293 | case bi&types.IsComplex != 0: 294 | bt.Encoding = llvm.DW_ATE_imaginary_float 295 | case bi&types.IsUnsigned != 0: 296 | bt.Encoding = llvm.DW_ATE_unsigned 297 | default: 298 | panic(fmt.Sprintf("unhandled: %#v", t)) 299 | } 300 | return d.builder.CreateBasicType(bt) 301 | } 302 | } 303 | 304 | func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Value { 305 | return d.builder.CreatePointerType(llvm.DIPointerType{ 306 | Pointee: d.DIType(t.Elem()), 307 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 308 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 309 | }) 310 | } 311 | 312 | func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Value { 313 | fields := make([]*types.Var, t.NumFields()) 314 | for i := range fields { 315 | fields[i] = t.Field(i) 316 | } 317 | offsets := d.sizes.Offsetsof(fields) 318 | members := make([]llvm.Value, len(fields)) 319 | for i, f := range fields { 320 | // TODO(axw) file/line where member is defined. 321 | t := f.Type() 322 | members[i] = d.builder.CreateMemberType(d.cu, llvm.DIMemberType{ 323 | Name: f.Name(), 324 | Type: d.DIType(t), 325 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 326 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 327 | OffsetInBits: uint64(offsets[i] * 8), 328 | }) 329 | } 330 | // TODO(axw) file/line where struct is defined. 331 | return d.builder.CreateStructType(d.cu, llvm.DIStructType{ 332 | Name: name, 333 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 334 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 335 | Elements: members, 336 | }) 337 | } 338 | 339 | func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Value { 340 | // Create a placeholder for the named type, to terminate cycles. 341 | placeholder := llvm.MDNode(nil) 342 | d.types.Set(t, placeholder) 343 | var diFile llvm.Value 344 | var line int 345 | if file := d.fset.File(t.Obj().Pos()); file != nil { 346 | line = file.Line(t.Obj().Pos()) 347 | diFile = d.getFile(file) 348 | } 349 | typedef := d.builder.CreateTypedef(llvm.DITypedef{ 350 | Type: d.DIType(t.Underlying()), 351 | Name: t.Obj().Name(), 352 | File: diFile, 353 | Line: line, 354 | }) 355 | placeholder.ReplaceAllUsesWith(typedef) 356 | return typedef 357 | } 358 | 359 | func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Value { 360 | return d.builder.CreateArrayType(llvm.DIArrayType{ 361 | SizeInBits: uint64(d.sizes.Sizeof(t) * 8), 362 | AlignInBits: uint64(d.sizes.Alignof(t) * 8), 363 | ElementType: d.DIType(t.Elem()), 364 | Subscripts: []llvm.DISubrange{{Count: t.Len()}}, 365 | }) 366 | } 367 | 368 | func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Value { 369 | sliceStruct := types.NewStruct([]*types.Var{ 370 | types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())), 371 | types.NewVar(0, nil, "len", types.Typ[types.Int]), 372 | types.NewVar(0, nil, "cap", types.Typ[types.Int]), 373 | }, nil) 374 | return d.typeDebugDescriptor(sliceStruct, name) 375 | } 376 | 377 | func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Value { 378 | return d.descriptorBasic(types.Typ[types.Uintptr], name) 379 | } 380 | 381 | func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Value { 382 | return d.descriptorBasic(types.Typ[types.Uintptr], name) 383 | } 384 | 385 | func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Value { 386 | ifaceStruct := types.NewStruct([]*types.Var{ 387 | types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])), 388 | types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])), 389 | }, nil) 390 | return d.typeDebugDescriptor(ifaceStruct, name) 391 | } 392 | 393 | func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Value { 394 | // If there's a receiver change the receiver to an 395 | // additional (first) parameter, and take the value of 396 | // the resulting signature instead. 397 | if recv := t.Recv(); recv != nil { 398 | params := t.Params() 399 | paramvars := make([]*types.Var, int(params.Len()+1)) 400 | paramvars[0] = recv 401 | for i := 0; i < int(params.Len()); i++ { 402 | paramvars[i+1] = params.At(i) 403 | } 404 | params = types.NewTuple(paramvars...) 405 | t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic()) 406 | return d.typeDebugDescriptor(t, name) 407 | } 408 | if dt, ok := d.types.At(t).(llvm.Value); ok { 409 | return dt 410 | } 411 | 412 | var returnType llvm.Value 413 | results := t.Results() 414 | switch n := results.Len(); n { 415 | case 0: 416 | returnType = d.DIType(nil) // void 417 | case 1: 418 | returnType = d.DIType(results.At(0).Type()) 419 | default: 420 | fields := make([]*types.Var, results.Len()) 421 | for i := range fields { 422 | f := results.At(i) 423 | // Structs may not have multiple fields 424 | // with the same name, excepting "_". 425 | if f.Name() == "" { 426 | f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type()) 427 | } 428 | fields[i] = f 429 | } 430 | returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "") 431 | } 432 | 433 | var paramTypes []llvm.Value 434 | params := t.Params() 435 | if params != nil && params.Len() > 0 { 436 | paramTypes = make([]llvm.Value, params.Len()+1) 437 | paramTypes[0] = returnType 438 | for i := range paramTypes[1:] { 439 | paramTypes[i+1] = d.DIType(params.At(i).Type()) 440 | } 441 | } else { 442 | paramTypes = []llvm.Value{returnType} 443 | } 444 | 445 | // TODO(axw) get position of type definition for File field 446 | return d.builder.CreateSubroutineType(llvm.DISubroutineType{ 447 | Parameters: paramTypes, 448 | }) 449 | } 450 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | prefix="$1" 4 | mkdir -p "$prefix" 5 | prefix=$(cd "$prefix" && pwd) 6 | 7 | llgodir=$(dirname "$0") 8 | 9 | workdir=$llgodir/workdir 10 | gofrontend_builddir=$workdir/gofrontend_build 11 | 12 | # Install the compiler binary. 13 | mkdir -p "$prefix/bin" 14 | cp $workdir/gllgo-stage3 "$prefix/bin/llgo" 15 | 16 | # Install llgo-go. 17 | cp $llgodir/llgo-go.sh "$prefix/bin/llgo-go" 18 | chmod +x "$prefix/bin/llgo-go" 19 | 20 | # Install libgo. If we did a quick bootstrap, only the stage1 libgo will exist. 21 | if [ -d "$gofrontend_builddir/libgo-stage2" ] ; then 22 | make -C $gofrontend_builddir/libgo-stage2 install "prefix=$prefix" 23 | else 24 | make -C $gofrontend_builddir/libgo-stage1 install "prefix=$prefix" 25 | fi 26 | 27 | # Install the build variant libraries, but not the export data, which is shared 28 | # between variants. 29 | for i in $workdir/gofrontend_build_*/libgo ; do 30 | if [ -d $i ] ; then 31 | make -C $i install-toolexeclibLIBRARIES install-toolexeclibLTLIBRARIES \ 32 | "prefix=$prefix" 33 | fi 34 | done 35 | 36 | # Set up the symlink required by llgo-go. 37 | mkdir -p "$prefix/lib/llgo/go-path" 38 | ln -sf ../../../bin/llgo "$prefix/lib/llgo/go-path/gccgo" 39 | -------------------------------------------------------------------------------- /irgen/annotations.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "go/ast" 9 | "go/token" 10 | "golang.org/x/tools/go/loader" 11 | "golang.org/x/tools/go/ssa" 12 | "golang.org/x/tools/go/types" 13 | "llvm.org/llvm/bindings/go/llvm" 14 | ) 15 | 16 | // processAnnotations takes an *ssa.Package and a 17 | // *importer.PackageInfo, and processes all of the 18 | // llgo source annotations attached to each top-level 19 | // function and global variable. 20 | func (c *compiler) processAnnotations(u *unit, pkginfo *loader.PackageInfo) { 21 | members := make(map[types.Object]llvm.Value, len(u.globals)) 22 | for k, v := range u.globals { 23 | members[k.(ssa.Member).Object()] = v 24 | } 25 | applyAttributes := func(attrs []Attribute, idents ...*ast.Ident) { 26 | if len(attrs) == 0 { 27 | return 28 | } 29 | for _, ident := range idents { 30 | if v := members[pkginfo.ObjectOf(ident)]; !v.IsNil() { 31 | for _, attr := range attrs { 32 | attr.Apply(v) 33 | } 34 | } 35 | } 36 | } 37 | for _, f := range pkginfo.Files { 38 | for _, decl := range f.Decls { 39 | switch decl := decl.(type) { 40 | case *ast.FuncDecl: 41 | attrs := parseAttributes(decl.Doc) 42 | applyAttributes(attrs, decl.Name) 43 | case *ast.GenDecl: 44 | if decl.Tok != token.VAR { 45 | continue 46 | } 47 | for _, spec := range decl.Specs { 48 | varspec := spec.(*ast.ValueSpec) 49 | attrs := parseAttributes(decl.Doc) 50 | applyAttributes(attrs, varspec.Names...) 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /irgen/attribute.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "llvm.org/llvm/bindings/go/llvm" 11 | "strings" 12 | ) 13 | 14 | const AttributeCommentPrefix = "#llgo " 15 | 16 | // Attribute represents an attribute associated with a 17 | // global variable or function. 18 | type Attribute interface { 19 | Apply(llvm.Value) 20 | } 21 | 22 | // parseAttribute parses zero or more #llgo comment attributes associated with 23 | // a global variable or function. The comment group provided will be processed 24 | // one line at a time using parseAttribute. 25 | func parseAttributes(doc *ast.CommentGroup) []Attribute { 26 | var attributes []Attribute 27 | if doc == nil { 28 | return attributes 29 | } 30 | for _, comment := range doc.List { 31 | if strings.HasPrefix(comment.Text, "//extern ") { 32 | nameattr := nameAttribute(strings.TrimSpace(comment.Text[9:])) 33 | attributes = append(attributes, nameattr) 34 | continue 35 | } 36 | text := comment.Text[2:] 37 | if strings.HasPrefix(comment.Text, "/*") { 38 | text = text[:len(text)-2] 39 | } 40 | attr := parseAttribute(strings.TrimSpace(text)) 41 | if attr != nil { 42 | attributes = append(attributes, attr) 43 | } 44 | } 45 | return attributes 46 | } 47 | 48 | // parseAttribute parses a single #llgo comment attribute associated with 49 | // a global variable or function. The string provided will be parsed 50 | // if it begins with AttributeCommentPrefix, otherwise nil is returned. 51 | func parseAttribute(line string) Attribute { 52 | if !strings.HasPrefix(line, AttributeCommentPrefix) { 53 | return nil 54 | } 55 | line = strings.TrimSpace(line[len(AttributeCommentPrefix):]) 56 | colon := strings.IndexRune(line, ':') 57 | var key, value string 58 | if colon == -1 { 59 | key = line 60 | } else { 61 | key, value = line[:colon], line[colon+1:] 62 | } 63 | switch key { 64 | case "linkage": 65 | return parseLinkageAttribute(value) 66 | case "name": 67 | return nameAttribute(strings.TrimSpace(value)) 68 | case "attr": 69 | return parseLLVMAttribute(strings.TrimSpace(value)) 70 | case "thread_local": 71 | return tlsAttribute{} 72 | default: 73 | // FIXME decide what to do here. return error? log warning? 74 | panic("unknown attribute key: " + key) 75 | } 76 | return nil 77 | } 78 | 79 | type linkageAttribute llvm.Linkage 80 | 81 | func (a linkageAttribute) Apply(v llvm.Value) { 82 | v.SetLinkage(llvm.Linkage(a)) 83 | } 84 | 85 | func parseLinkageAttribute(value string) linkageAttribute { 86 | var result linkageAttribute 87 | value = strings.Replace(value, ",", " ", -1) 88 | for _, field := range strings.Fields(value) { 89 | switch strings.ToLower(field) { 90 | case "private": 91 | result |= linkageAttribute(llvm.PrivateLinkage) 92 | case "internal": 93 | result |= linkageAttribute(llvm.InternalLinkage) 94 | case "available_externally": 95 | result |= linkageAttribute(llvm.AvailableExternallyLinkage) 96 | case "linkonce": 97 | result |= linkageAttribute(llvm.LinkOnceAnyLinkage) 98 | case "common": 99 | result |= linkageAttribute(llvm.CommonLinkage) 100 | case "weak": 101 | result |= linkageAttribute(llvm.WeakAnyLinkage) 102 | case "appending": 103 | result |= linkageAttribute(llvm.AppendingLinkage) 104 | case "extern_weak": 105 | result |= linkageAttribute(llvm.ExternalWeakLinkage) 106 | case "linkonce_odr": 107 | result |= linkageAttribute(llvm.LinkOnceODRLinkage) 108 | case "weak_odr": 109 | result |= linkageAttribute(llvm.WeakODRLinkage) 110 | case "external": 111 | result |= linkageAttribute(llvm.ExternalLinkage) 112 | } 113 | } 114 | return result 115 | } 116 | 117 | type nameAttribute string 118 | 119 | func (a nameAttribute) Apply(v llvm.Value) { 120 | if !v.IsAFunction().IsNil() { 121 | name := string(a) 122 | curr := v.GlobalParent().NamedFunction(name) 123 | if !curr.IsNil() && curr != v { 124 | if curr.BasicBlocksCount() != 0 { 125 | panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name)) 126 | } 127 | curr.SetName(name + "_llgo_replaced") 128 | curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type())) 129 | } 130 | v.SetName(name) 131 | } else { 132 | v.SetName(string(a)) 133 | } 134 | } 135 | 136 | func parseLLVMAttribute(value string) llvmAttribute { 137 | var result llvmAttribute 138 | value = strings.Replace(value, ",", " ", -1) 139 | for _, field := range strings.Fields(value) { 140 | switch strings.ToLower(field) { 141 | case "noreturn": 142 | result |= llvmAttribute(llvm.NoReturnAttribute) 143 | case "nounwind": 144 | result |= llvmAttribute(llvm.NoUnwindAttribute) 145 | case "noinline": 146 | result |= llvmAttribute(llvm.NoInlineAttribute) 147 | case "alwaysinline": 148 | result |= llvmAttribute(llvm.AlwaysInlineAttribute) 149 | } 150 | } 151 | return result 152 | } 153 | 154 | type llvmAttribute llvm.Attribute 155 | 156 | func (a llvmAttribute) Apply(v llvm.Value) { 157 | if !v.IsAFunction().IsNil() { 158 | v.AddFunctionAttr(llvm.Attribute(a)) 159 | } else { 160 | v.AddAttribute(llvm.Attribute(a)) 161 | } 162 | } 163 | 164 | type tlsAttribute struct{} 165 | 166 | func (tlsAttribute) Apply(v llvm.Value) { 167 | v.SetThreadLocal(true) 168 | } 169 | -------------------------------------------------------------------------------- /irgen/builtins.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | func (fr *frame) callCap(arg *govalue) *govalue { 13 | var v llvm.Value 14 | switch typ := arg.Type().Underlying().(type) { 15 | case *types.Array: 16 | v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false) 17 | case *types.Pointer: 18 | atyp := typ.Elem().Underlying().(*types.Array) 19 | v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false) 20 | case *types.Slice: 21 | v = fr.builder.CreateExtractValue(arg.value, 2, "") 22 | case *types.Chan: 23 | v = fr.runtime.chanCap.call(fr, arg.value)[0] 24 | } 25 | return newValue(v, types.Typ[types.Int]) 26 | } 27 | 28 | func (fr *frame) callLen(arg *govalue) *govalue { 29 | var lenvalue llvm.Value 30 | switch typ := arg.Type().Underlying().(type) { 31 | case *types.Array: 32 | lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false) 33 | case *types.Pointer: 34 | atyp := typ.Elem().Underlying().(*types.Array) 35 | lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false) 36 | case *types.Slice: 37 | lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "") 38 | case *types.Map: 39 | lenvalue = fr.runtime.mapLen.call(fr, arg.value)[0] 40 | case *types.Basic: 41 | if isString(typ) { 42 | lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "") 43 | } 44 | case *types.Chan: 45 | lenvalue = fr.runtime.chanLen.call(fr, arg.value)[0] 46 | } 47 | return newValue(lenvalue, types.Typ[types.Int]) 48 | } 49 | 50 | // callAppend takes two slices of the same type, and yields 51 | // the result of appending the second to the first. 52 | func (fr *frame) callAppend(a, b *govalue) *govalue { 53 | bptr := fr.builder.CreateExtractValue(b.value, 0, "") 54 | blen := fr.builder.CreateExtractValue(b.value, 1, "") 55 | elemsizeInt64 := fr.types.Sizeof(a.Type().Underlying().(*types.Slice).Elem()) 56 | elemsize := llvm.ConstInt(fr.target.IntPtrType(), uint64(elemsizeInt64), false) 57 | result := fr.runtime.append.call(fr, a.value, bptr, blen, elemsize)[0] 58 | return newValue(result, a.Type()) 59 | } 60 | 61 | // callCopy takes two slices a and b of the same type, and 62 | // yields the result of calling "copy(a, b)". 63 | func (fr *frame) callCopy(dest, source *govalue) *govalue { 64 | aptr := fr.builder.CreateExtractValue(dest.value, 0, "") 65 | alen := fr.builder.CreateExtractValue(dest.value, 1, "") 66 | bptr := fr.builder.CreateExtractValue(source.value, 0, "") 67 | blen := fr.builder.CreateExtractValue(source.value, 1, "") 68 | aless := fr.builder.CreateICmp(llvm.IntULT, alen, blen, "") 69 | minlen := fr.builder.CreateSelect(aless, alen, blen, "") 70 | elemsizeInt64 := fr.types.Sizeof(dest.Type().Underlying().(*types.Slice).Elem()) 71 | elemsize := llvm.ConstInt(fr.types.inttype, uint64(elemsizeInt64), false) 72 | bytes := fr.builder.CreateMul(minlen, elemsize, "") 73 | fr.runtime.copy.call(fr, aptr, bptr, bytes) 74 | return newValue(minlen, types.Typ[types.Int]) 75 | } 76 | 77 | func (fr *frame) callRecover(isDeferredRecover bool) *govalue { 78 | startbb := fr.builder.GetInsertBlock() 79 | recoverbb := llvm.AddBasicBlock(fr.function, "") 80 | contbb := llvm.AddBasicBlock(fr.function, "") 81 | canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "") 82 | fr.builder.CreateCondBr(canRecover, recoverbb, contbb) 83 | 84 | fr.builder.SetInsertPointAtEnd(recoverbb) 85 | var recovered llvm.Value 86 | if isDeferredRecover { 87 | recovered = fr.runtime.deferredRecover.call(fr)[0] 88 | } else { 89 | recovered = fr.runtime.recover.call(fr)[0] 90 | } 91 | recoverbb = fr.builder.GetInsertBlock() 92 | fr.builder.CreateBr(contbb) 93 | 94 | fr.builder.SetInsertPointAtEnd(contbb) 95 | eface := types.NewInterface(nil, nil) 96 | llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "") 97 | llv.AddIncoming( 98 | []llvm.Value{llvm.ConstNull(llv.Type()), recovered}, 99 | []llvm.BasicBlock{startbb, recoverbb}, 100 | ) 101 | return newValue(llv, eface) 102 | } 103 | 104 | func (fr *frame) callPanic(arg *govalue) { 105 | fr.runtime.panic.call(fr, arg.value) 106 | fr.builder.CreateUnreachable() 107 | } 108 | -------------------------------------------------------------------------------- /irgen/cabi.go: -------------------------------------------------------------------------------- 1 | package irgen 2 | 3 | import ( 4 | "golang.org/x/tools/go/types" 5 | "llvm.org/llvm/bindings/go/llvm" 6 | ) 7 | 8 | type abiArgInfo int 9 | 10 | const ( 11 | AIK_Direct = abiArgInfo(iota) 12 | AIK_Indirect 13 | ) 14 | 15 | type backendType interface { 16 | ToLLVM(llvm.Context) llvm.Type 17 | } 18 | 19 | type ptrBType struct { 20 | } 21 | 22 | func (t ptrBType) ToLLVM(c llvm.Context) llvm.Type { 23 | return llvm.PointerType(c.Int8Type(), 0) 24 | } 25 | 26 | type intBType struct { 27 | width int 28 | signed bool 29 | } 30 | 31 | func (t intBType) ToLLVM(c llvm.Context) llvm.Type { 32 | return c.IntType(t.width * 8) 33 | } 34 | 35 | type floatBType struct { 36 | isDouble bool 37 | } 38 | 39 | func (t floatBType) ToLLVM(c llvm.Context) llvm.Type { 40 | if t.isDouble { 41 | return c.DoubleType() 42 | } else { 43 | return c.FloatType() 44 | } 45 | } 46 | 47 | type structBType struct { 48 | fields []backendType 49 | } 50 | 51 | func (t structBType) ToLLVM(c llvm.Context) llvm.Type { 52 | var lfields []llvm.Type 53 | for _, f := range t.fields { 54 | lfields = append(lfields, f.ToLLVM(c)) 55 | } 56 | return c.StructType(lfields, false) 57 | } 58 | 59 | type arrayBType struct { 60 | length uint64 61 | elem backendType 62 | } 63 | 64 | func (t arrayBType) ToLLVM(c llvm.Context) llvm.Type { 65 | return llvm.ArrayType(t.elem.ToLLVM(c), int(t.length)) 66 | } 67 | 68 | // align returns the smallest y >= x such that y % a == 0. 69 | func align(x, a int64) int64 { 70 | y := x + a - 1 71 | return y - y%a 72 | } 73 | 74 | func (tm *llvmTypeMap) sizeofStruct(fields ...types.Type) int64 { 75 | var o int64 76 | for _, f := range fields { 77 | a := tm.Alignof(f) 78 | o = align(o, a) 79 | o += tm.Sizeof(f) 80 | } 81 | return o 82 | } 83 | 84 | // This decides whether the x86_64 classification algorithm produces MEMORY for 85 | // the given type. Given the subset of types that Go supports, this is exactly 86 | // equivalent to testing the type's size. See in particular the first step of 87 | // the algorithm and its footnote. 88 | func (tm *llvmTypeMap) classify(t ...types.Type) abiArgInfo { 89 | if tm.sizeofStruct(t...) > 16 { 90 | return AIK_Indirect 91 | } 92 | return AIK_Direct 93 | } 94 | 95 | func (tm *llvmTypeMap) sliceBackendType() backendType { 96 | i8ptr := &ptrBType{} 97 | uintptr := &intBType{tm.target.PointerSize(), false} 98 | return &structBType{[]backendType{i8ptr, uintptr, uintptr}} 99 | } 100 | 101 | func (tm *llvmTypeMap) getBackendType(t types.Type) backendType { 102 | switch t := t.(type) { 103 | case *types.Named: 104 | return tm.getBackendType(t.Underlying()) 105 | 106 | case *types.Basic: 107 | switch t.Kind() { 108 | case types.Bool, types.Uint8: 109 | return &intBType{1, false} 110 | case types.Int8: 111 | return &intBType{1, true} 112 | case types.Uint16: 113 | return &intBType{2, false} 114 | case types.Int16: 115 | return &intBType{2, true} 116 | case types.Uint32: 117 | return &intBType{4, false} 118 | case types.Int32: 119 | return &intBType{4, true} 120 | case types.Uint64: 121 | return &intBType{8, false} 122 | case types.Int64: 123 | return &intBType{8, true} 124 | case types.Uint, types.Uintptr: 125 | return &intBType{tm.target.PointerSize(), false} 126 | case types.Int: 127 | return &intBType{tm.target.PointerSize(), true} 128 | case types.Float32: 129 | return &floatBType{false} 130 | case types.Float64: 131 | return &floatBType{true} 132 | case types.UnsafePointer: 133 | return &ptrBType{} 134 | case types.Complex64: 135 | f32 := &floatBType{false} 136 | return &structBType{[]backendType{f32, f32}} 137 | case types.Complex128: 138 | f64 := &floatBType{true} 139 | return &structBType{[]backendType{f64, f64}} 140 | case types.String: 141 | return &structBType{[]backendType{&ptrBType{}, &intBType{tm.target.PointerSize(), false}}} 142 | } 143 | 144 | case *types.Struct: 145 | var fields []backendType 146 | for i := 0; i != t.NumFields(); i++ { 147 | f := t.Field(i) 148 | fields = append(fields, tm.getBackendType(f.Type())) 149 | } 150 | return &structBType{fields} 151 | 152 | case *types.Pointer, *types.Signature, *types.Map, *types.Chan: 153 | return &ptrBType{} 154 | 155 | case *types.Interface: 156 | i8ptr := &ptrBType{} 157 | return &structBType{[]backendType{i8ptr, i8ptr}} 158 | 159 | case *types.Slice: 160 | return tm.sliceBackendType() 161 | 162 | case *types.Array: 163 | return &arrayBType{uint64(t.Len()), tm.getBackendType(t.Elem())} 164 | } 165 | 166 | panic("unhandled type: " + t.String()) 167 | } 168 | 169 | type offsetedType struct { 170 | typ backendType 171 | offset uint64 172 | } 173 | 174 | func (tm *llvmTypeMap) getBackendOffsets(bt backendType) (offsets []offsetedType) { 175 | switch bt := bt.(type) { 176 | case *structBType: 177 | t := bt.ToLLVM(tm.ctx) 178 | for i, f := range bt.fields { 179 | offset := tm.target.ElementOffset(t, i) 180 | fieldOffsets := tm.getBackendOffsets(f) 181 | for _, fo := range fieldOffsets { 182 | offsets = append(offsets, offsetedType{fo.typ, offset + fo.offset}) 183 | } 184 | } 185 | 186 | case *arrayBType: 187 | size := tm.target.TypeAllocSize(bt.elem.ToLLVM(tm.ctx)) 188 | fieldOffsets := tm.getBackendOffsets(bt.elem) 189 | for i := uint64(0); i != bt.length; i++ { 190 | for _, fo := range fieldOffsets { 191 | offsets = append(offsets, offsetedType{fo.typ, i*size + fo.offset}) 192 | } 193 | } 194 | 195 | default: 196 | offsets = []offsetedType{offsetedType{bt, 0}} 197 | } 198 | 199 | return 200 | } 201 | 202 | func (tm *llvmTypeMap) classifyEightbyte(offsets []offsetedType, numInt, numSSE *int) llvm.Type { 203 | if len(offsets) == 1 { 204 | if _, ok := offsets[0].typ.(*floatBType); ok { 205 | *numSSE++ 206 | } else { 207 | *numInt++ 208 | } 209 | return offsets[0].typ.ToLLVM(tm.ctx) 210 | } 211 | // This implements classification for the basic types and step 4 of the 212 | // classification algorithm. At this point, the only two possible 213 | // classifications are SSE (floats) and INTEGER (everything else). 214 | sse := true 215 | for _, ot := range offsets { 216 | if _, ok := ot.typ.(*floatBType); !ok { 217 | sse = false 218 | break 219 | } 220 | } 221 | if sse { 222 | // This can only be (float, float), which uses an SSE vector. 223 | *numSSE++ 224 | return llvm.VectorType(tm.ctx.FloatType(), 2) 225 | } else { 226 | *numInt++ 227 | width := offsets[len(offsets)-1].offset + tm.target.TypeAllocSize(offsets[len(offsets)-1].typ.ToLLVM(tm.ctx)) - offsets[0].offset 228 | return tm.ctx.IntType(int(width) * 8) 229 | } 230 | } 231 | 232 | func (tm *llvmTypeMap) expandType(argTypes []llvm.Type, argAttrs []llvm.Attribute, bt backendType) ([]llvm.Type, []llvm.Attribute, int, int) { 233 | var numInt, numSSE int 234 | 235 | switch bt := bt.(type) { 236 | case *structBType, *arrayBType: 237 | bo := tm.getBackendOffsets(bt) 238 | sp := 0 239 | for sp != len(bo) && bo[sp].offset < 8 { 240 | sp++ 241 | } 242 | eb1 := bo[0:sp] 243 | eb2 := bo[sp:] 244 | if len(eb2) > 0 { 245 | argTypes = append(argTypes, tm.classifyEightbyte(eb1, &numInt, &numSSE), tm.classifyEightbyte(eb2, &numInt, &numSSE)) 246 | argAttrs = append(argAttrs, 0, 0) 247 | } else { 248 | argTypes = append(argTypes, tm.classifyEightbyte(eb1, &numInt, &numSSE)) 249 | argAttrs = append(argAttrs, 0) 250 | } 251 | 252 | default: 253 | argTypes = append(argTypes, tm.classifyEightbyte([]offsetedType{{bt, 0}}, &numInt, &numSSE)) 254 | argAttrs = append(argAttrs, 0) 255 | } 256 | 257 | return argTypes, argAttrs, numInt, numSSE 258 | } 259 | 260 | type argInfo interface { 261 | // Emit instructions to builder to ABI encode val and store result to args. 262 | encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) 263 | 264 | // Emit instructions to builder to ABI decode and return the resulting Value. 265 | decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value 266 | } 267 | 268 | type retInfo interface { 269 | // Prepare args to receive a value. allocaBuilder refers to a builder in the entry block. 270 | prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value) 271 | 272 | // Emit instructions to builder to ABI decode the return value(s), if any. call is the 273 | // call instruction. Must be called after prepare(). 274 | decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value 275 | 276 | // Emit instructions to builder to ABI encode the return value(s), if any, and return. 277 | encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) 278 | } 279 | 280 | type directArgInfo struct { 281 | argOffset int 282 | argTypes []llvm.Type 283 | valType llvm.Type 284 | } 285 | 286 | func directEncode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, argTypes []llvm.Type, args []llvm.Value, val llvm.Value) { 287 | valType := val.Type() 288 | 289 | switch len(argTypes) { 290 | case 0: 291 | // do nothing 292 | 293 | case 1: 294 | if argTypes[0].C == valType.C { 295 | args[0] = val 296 | return 297 | } 298 | alloca := allocaBuilder.CreateAlloca(valType, "") 299 | bitcast := builder.CreateBitCast(alloca, llvm.PointerType(argTypes[0], 0), "") 300 | builder.CreateStore(val, alloca) 301 | args[0] = builder.CreateLoad(bitcast, "") 302 | 303 | case 2: 304 | encodeType := llvm.StructType(argTypes, false) 305 | alloca := allocaBuilder.CreateAlloca(valType, "") 306 | bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "") 307 | builder.CreateStore(val, alloca) 308 | args[0] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 0, ""), "") 309 | args[1] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 1, ""), "") 310 | 311 | default: 312 | panic("unexpected argTypes size") 313 | } 314 | } 315 | 316 | func (ai *directArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) { 317 | directEncode(ctx, allocaBuilder, builder, ai.argTypes, args[ai.argOffset:ai.argOffset+len(ai.argTypes)], val) 318 | } 319 | 320 | func directDecode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, valType llvm.Type, args []llvm.Value) llvm.Value { 321 | var alloca llvm.Value 322 | 323 | switch len(args) { 324 | case 0: 325 | return llvm.ConstNull(ctx.StructType(nil, false)) 326 | 327 | case 1: 328 | if args[0].Type().C == valType.C { 329 | return args[0] 330 | } 331 | alloca = allocaBuilder.CreateAlloca(valType, "") 332 | bitcast := builder.CreateBitCast(alloca, llvm.PointerType(args[0].Type(), 0), "") 333 | builder.CreateStore(args[0], bitcast) 334 | 335 | case 2: 336 | alloca = allocaBuilder.CreateAlloca(valType, "") 337 | var argTypes []llvm.Type 338 | for _, a := range args { 339 | argTypes = append(argTypes, a.Type()) 340 | } 341 | encodeType := ctx.StructType(argTypes, false) 342 | bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "") 343 | builder.CreateStore(args[0], builder.CreateStructGEP(bitcast, 0, "")) 344 | builder.CreateStore(args[1], builder.CreateStructGEP(bitcast, 1, "")) 345 | 346 | default: 347 | panic("unexpected argTypes size") 348 | } 349 | 350 | return builder.CreateLoad(alloca, "") 351 | } 352 | 353 | func (ai *directArgInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value { 354 | var args []llvm.Value 355 | fn := builder.GetInsertBlock().Parent() 356 | for i, _ := range ai.argTypes { 357 | args = append(args, fn.Param(ai.argOffset+i)) 358 | } 359 | return directDecode(ctx, allocaBuilder, builder, ai.valType, args) 360 | } 361 | 362 | type indirectArgInfo struct { 363 | argOffset int 364 | } 365 | 366 | func (ai *indirectArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) { 367 | alloca := allocaBuilder.CreateAlloca(val.Type(), "") 368 | builder.CreateStore(val, alloca) 369 | args[ai.argOffset] = alloca 370 | } 371 | 372 | func (ai *indirectArgInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value { 373 | fn := builder.GetInsertBlock().Parent() 374 | return builder.CreateLoad(fn.Param(ai.argOffset), "") 375 | } 376 | 377 | type directRetInfo struct { 378 | numResults int 379 | retTypes []llvm.Type 380 | resultsType llvm.Type 381 | } 382 | 383 | func (ri *directRetInfo) prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value) { 384 | } 385 | 386 | func (ri *directRetInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value { 387 | var args []llvm.Value 388 | switch len(ri.retTypes) { 389 | case 0: 390 | return nil 391 | case 1: 392 | args = []llvm.Value{call} 393 | default: 394 | args = make([]llvm.Value, len(ri.retTypes)) 395 | for i := 0; i != len(ri.retTypes); i++ { 396 | args[i] = builder.CreateExtractValue(call, i, "") 397 | } 398 | } 399 | 400 | d := directDecode(ctx, allocaBuilder, builder, ri.resultsType, args) 401 | 402 | if ri.numResults == 1 { 403 | return []llvm.Value{d} 404 | } else { 405 | results := make([]llvm.Value, ri.numResults) 406 | for i := 0; i != ri.numResults; i++ { 407 | results[i] = builder.CreateExtractValue(d, i, "") 408 | } 409 | return results 410 | } 411 | } 412 | 413 | func (ri *directRetInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) { 414 | if len(ri.retTypes) == 0 { 415 | builder.CreateRetVoid() 416 | return 417 | } 418 | 419 | var val llvm.Value 420 | switch ri.numResults { 421 | case 1: 422 | val = vals[0] 423 | default: 424 | val = llvm.Undef(ri.resultsType) 425 | for i, v := range vals { 426 | val = builder.CreateInsertValue(val, v, i, "") 427 | } 428 | } 429 | 430 | args := make([]llvm.Value, len(ri.retTypes)) 431 | directEncode(ctx, allocaBuilder, builder, ri.retTypes, args, val) 432 | 433 | var retval llvm.Value 434 | switch len(ri.retTypes) { 435 | case 1: 436 | retval = args[0] 437 | default: 438 | retval = llvm.Undef(ctx.StructType(ri.retTypes, false)) 439 | for i, a := range args { 440 | retval = builder.CreateInsertValue(retval, a, i, "") 441 | } 442 | } 443 | builder.CreateRet(retval) 444 | } 445 | 446 | type indirectRetInfo struct { 447 | numResults int 448 | sretSlot llvm.Value 449 | resultsType llvm.Type 450 | } 451 | 452 | func (ri *indirectRetInfo) prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value) { 453 | ri.sretSlot = allocaBuilder.CreateAlloca(ri.resultsType, "") 454 | args[0] = ri.sretSlot 455 | } 456 | 457 | func (ri *indirectRetInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value { 458 | if ri.numResults == 1 { 459 | return []llvm.Value{builder.CreateLoad(ri.sretSlot, "")} 460 | } else { 461 | vals := make([]llvm.Value, ri.numResults) 462 | for i, _ := range vals { 463 | vals[i] = builder.CreateLoad(builder.CreateStructGEP(ri.sretSlot, i, ""), "") 464 | } 465 | return vals 466 | } 467 | } 468 | 469 | func (ri *indirectRetInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) { 470 | fn := builder.GetInsertBlock().Parent() 471 | sretSlot := fn.Param(0) 472 | 473 | if ri.numResults == 1 { 474 | builder.CreateStore(vals[0], sretSlot) 475 | } else { 476 | for i, v := range vals { 477 | builder.CreateStore(v, builder.CreateStructGEP(sretSlot, i, "")) 478 | } 479 | } 480 | builder.CreateRetVoid() 481 | } 482 | 483 | type functionTypeInfo struct { 484 | functionType llvm.Type 485 | argAttrs []llvm.Attribute 486 | retAttr llvm.Attribute 487 | argInfos []argInfo 488 | retInf retInfo 489 | } 490 | 491 | func (fi *functionTypeInfo) declare(m llvm.Module, name string) llvm.Value { 492 | fn := llvm.AddFunction(m, name, fi.functionType) 493 | fn.AddFunctionAttr(fi.retAttr) 494 | for i, a := range fi.argAttrs { 495 | if a != 0 { 496 | fn.Param(i).AddAttribute(a) 497 | } 498 | } 499 | return fn 500 | } 501 | 502 | func (fi *functionTypeInfo) call(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, args []llvm.Value) []llvm.Value { 503 | callArgs := make([]llvm.Value, len(fi.argAttrs)) 504 | for i, a := range args { 505 | fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a) 506 | } 507 | fi.retInf.prepare(ctx, allocaBuilder, callArgs) 508 | typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "") 509 | call := builder.CreateCall(typedCallee, callArgs, "") 510 | call.AddInstrAttribute(0, fi.retAttr) 511 | for i, a := range fi.argAttrs { 512 | call.AddInstrAttribute(i+1, a) 513 | } 514 | return fi.retInf.decode(ctx, allocaBuilder, builder, call) 515 | } 516 | 517 | func (fi *functionTypeInfo) invoke(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, args []llvm.Value, cont, lpad llvm.BasicBlock) []llvm.Value { 518 | callArgs := make([]llvm.Value, len(fi.argAttrs)) 519 | for i, a := range args { 520 | fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a) 521 | } 522 | fi.retInf.prepare(ctx, allocaBuilder, callArgs) 523 | typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "") 524 | call := builder.CreateInvoke(typedCallee, callArgs, cont, lpad, "") 525 | call.AddInstrAttribute(0, fi.retAttr) 526 | for i, a := range fi.argAttrs { 527 | call.AddInstrAttribute(i+1, a) 528 | } 529 | builder.SetInsertPointAtEnd(cont) 530 | return fi.retInf.decode(ctx, allocaBuilder, builder, call) 531 | } 532 | 533 | func (tm *llvmTypeMap) getFunctionTypeInfo(args []types.Type, results []types.Type) (fi functionTypeInfo) { 534 | var returnType llvm.Type 535 | var argTypes []llvm.Type 536 | if len(results) == 0 { 537 | returnType = llvm.VoidType() 538 | fi.retInf = &directRetInfo{} 539 | } else { 540 | aik := tm.classify(results...) 541 | 542 | var resultsType llvm.Type 543 | if len(results) == 1 { 544 | resultsType = tm.ToLLVM(results[0]) 545 | } else { 546 | elements := make([]llvm.Type, len(results)) 547 | for i := range elements { 548 | elements[i] = tm.ToLLVM(results[i]) 549 | } 550 | resultsType = tm.ctx.StructType(elements, false) 551 | } 552 | 553 | switch aik { 554 | case AIK_Direct: 555 | var retFields []backendType 556 | for _, t := range results { 557 | retFields = append(retFields, tm.getBackendType(t)) 558 | } 559 | bt := &structBType{retFields} 560 | 561 | retTypes, retAttrs, _, _ := tm.expandType(nil, nil, bt) 562 | switch len(retTypes) { 563 | case 0: // e.g., empty struct 564 | returnType = llvm.VoidType() 565 | case 1: 566 | returnType = retTypes[0] 567 | fi.retAttr = retAttrs[0] 568 | case 2: 569 | returnType = llvm.StructType(retTypes, false) 570 | default: 571 | panic("unexpected expandType result") 572 | } 573 | fi.retInf = &directRetInfo{numResults: len(results), retTypes: retTypes, resultsType: resultsType} 574 | 575 | case AIK_Indirect: 576 | returnType = llvm.VoidType() 577 | argTypes = []llvm.Type{llvm.PointerType(resultsType, 0)} 578 | fi.argAttrs = []llvm.Attribute{llvm.StructRetAttribute} 579 | fi.retInf = &indirectRetInfo{numResults: len(results), resultsType: resultsType} 580 | } 581 | } 582 | 583 | // Keep track of the number of INTEGER/SSE class registers remaining. 584 | remainingInt := 6 585 | remainingSSE := 8 586 | 587 | for _, arg := range args { 588 | aik := tm.classify(arg) 589 | 590 | isDirect := aik == AIK_Direct 591 | if isDirect { 592 | bt := tm.getBackendType(arg) 593 | directArgTypes, directArgAttrs, numInt, numSSE := tm.expandType(argTypes, fi.argAttrs, bt) 594 | 595 | // Check if the argument can fit into the remaining registers, or if 596 | // it would just occupy one register (which pushes the whole argument 597 | // onto the stack anyway). 598 | if numInt <= remainingInt && numSSE <= remainingSSE || numInt+numSSE == 1 { 599 | remainingInt -= numInt 600 | remainingSSE -= numSSE 601 | argInfo := &directArgInfo{argOffset: len(argTypes), valType: bt.ToLLVM(tm.ctx)} 602 | fi.argInfos = append(fi.argInfos, argInfo) 603 | argTypes = directArgTypes 604 | fi.argAttrs = directArgAttrs 605 | argInfo.argTypes = argTypes[argInfo.argOffset:len(argTypes)] 606 | } else { 607 | // No remaining registers; pass on the stack. 608 | isDirect = false 609 | } 610 | } 611 | 612 | if !isDirect { 613 | fi.argInfos = append(fi.argInfos, &indirectArgInfo{len(argTypes)}) 614 | argTypes = append(argTypes, llvm.PointerType(tm.ToLLVM(arg), 0)) 615 | fi.argAttrs = append(fi.argAttrs, llvm.ByValAttribute) 616 | } 617 | } 618 | 619 | fi.functionType = llvm.FunctionType(returnType, argTypes, false) 620 | return 621 | } 622 | 623 | func (tm *llvmTypeMap) getSignatureInfo(sig *types.Signature) functionTypeInfo { 624 | var args, results []types.Type 625 | if sig.Recv() != nil { 626 | recvtype := sig.Recv().Type() 627 | if _, ok := recvtype.Underlying().(*types.Pointer); !ok && recvtype != types.Typ[types.UnsafePointer] { 628 | recvtype = types.NewPointer(recvtype) 629 | } 630 | args = []types.Type{recvtype} 631 | } 632 | 633 | for i := 0; i != sig.Params().Len(); i++ { 634 | args = append(args, sig.Params().At(i).Type()) 635 | } 636 | for i := 0; i != sig.Results().Len(); i++ { 637 | results = append(results, sig.Results().At(i).Type()) 638 | } 639 | return tm.getFunctionTypeInfo(args, results) 640 | } 641 | -------------------------------------------------------------------------------- /irgen/call.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | // createCall emits the code for a function call, 13 | // taking into account receivers, and panic/defer. 14 | func (fr *frame) createCall(fn *govalue, argValues []*govalue) []*govalue { 15 | fntyp := fn.Type().Underlying().(*types.Signature) 16 | typinfo := fr.types.getSignatureInfo(fntyp) 17 | 18 | args := make([]llvm.Value, len(argValues)) 19 | for i, arg := range argValues { 20 | args[i] = arg.value 21 | } 22 | var results []llvm.Value 23 | if fr.unwindBlock.IsNil() { 24 | results = typinfo.call(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args) 25 | } else { 26 | contbb := llvm.AddBasicBlock(fr.function, "") 27 | results = typinfo.invoke(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, args, contbb, fr.unwindBlock) 28 | } 29 | 30 | resultValues := make([]*govalue, len(results)) 31 | for i, res := range results { 32 | resultValues[i] = newValue(res, fntyp.Results().At(i).Type()) 33 | } 34 | return resultValues 35 | } 36 | -------------------------------------------------------------------------------- /irgen/channels.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | // makeChan implements make(chantype[, size]) 13 | func (fr *frame) makeChan(chantyp types.Type, size *govalue) *govalue { 14 | // TODO(pcc): call __go_new_channel_big here if needed 15 | dyntyp := fr.types.ToRuntime(chantyp) 16 | size = fr.convert(size, types.Typ[types.Uintptr]) 17 | ch := fr.runtime.newChannel.call(fr, dyntyp, size.value)[0] 18 | return newValue(ch, chantyp) 19 | } 20 | 21 | // chanSend implements ch<- x 22 | func (fr *frame) chanSend(ch *govalue, elem *govalue) { 23 | elemtyp := ch.Type().Underlying().(*types.Chan).Elem() 24 | elem = fr.convert(elem, elemtyp) 25 | elemptr := fr.allocaBuilder.CreateAlloca(elem.value.Type(), "") 26 | fr.builder.CreateStore(elem.value, elemptr) 27 | elemptr = fr.builder.CreateBitCast(elemptr, llvm.PointerType(llvm.Int8Type(), 0), "") 28 | chantyp := fr.types.ToRuntime(ch.Type()) 29 | fr.runtime.sendBig.call(fr, chantyp, ch.value, elemptr) 30 | } 31 | 32 | // chanRecv implements x[, ok] = <-ch 33 | func (fr *frame) chanRecv(ch *govalue, commaOk bool) (x, ok *govalue) { 34 | elemtyp := ch.Type().Underlying().(*types.Chan).Elem() 35 | ptr := fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(elemtyp), "") 36 | ptri8 := fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "") 37 | chantyp := fr.types.ToRuntime(ch.Type()) 38 | 39 | if commaOk { 40 | okval := fr.runtime.chanrecv2.call(fr, chantyp, ch.value, ptri8)[0] 41 | ok = newValue(okval, types.Typ[types.Bool]) 42 | } else { 43 | fr.runtime.receive.call(fr, chantyp, ch.value, ptri8) 44 | } 45 | x = newValue(fr.builder.CreateLoad(ptr, ""), elemtyp) 46 | return 47 | } 48 | 49 | // chanClose implements close(ch) 50 | func (fr *frame) chanClose(ch *govalue) { 51 | fr.runtime.builtinClose.call(fr, ch.value) 52 | } 53 | 54 | // selectState is equivalent to ssa.SelectState 55 | type selectState struct { 56 | Dir types.ChanDir 57 | Chan *govalue 58 | Send *govalue 59 | } 60 | 61 | func (fr *frame) chanSelect(states []selectState, blocking bool) (index, recvOk *govalue, recvElems []*govalue) { 62 | n := uint64(len(states)) 63 | if !blocking { 64 | // non-blocking means there's a default case 65 | n++ 66 | } 67 | size := llvm.ConstInt(llvm.Int32Type(), n, false) 68 | selectp := fr.runtime.newSelect.call(fr, size)[0] 69 | 70 | // Allocate stack for the values to send and receive. 71 | // 72 | // TODO(axw) check if received elements have any users, and 73 | // elide stack allocation if not (pass nil to recv2 instead.) 74 | ptrs := make([]llvm.Value, len(states)) 75 | for i, state := range states { 76 | chantyp := state.Chan.Type().Underlying().(*types.Chan) 77 | elemtyp := fr.types.ToLLVM(chantyp.Elem()) 78 | ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "") 79 | if state.Dir == types.SendOnly { 80 | fr.builder.CreateStore(state.Send.value, ptrs[i]) 81 | } else { 82 | recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem())) 83 | } 84 | } 85 | 86 | // Create select{send,recv2} calls. 87 | var receivedp llvm.Value 88 | if len(recvElems) > 0 { 89 | receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "") 90 | } 91 | if !blocking { 92 | // If the default case is chosen, the index must be -1. 93 | fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type())) 94 | } 95 | for i, state := range states { 96 | ch := state.Chan.value 97 | index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false) 98 | if state.Dir == types.SendOnly { 99 | fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index) 100 | } else { 101 | fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index) 102 | } 103 | } 104 | 105 | // Fire off the select. 106 | index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int]) 107 | if len(recvElems) > 0 { 108 | recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool]) 109 | for _, recvElem := range recvElems { 110 | recvElem.value = fr.builder.CreateLoad(recvElem.value, "") 111 | } 112 | } 113 | return index, recvOk, recvElems 114 | } 115 | -------------------------------------------------------------------------------- /irgen/closures.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | ) 10 | 11 | // makeClosure creates a closure from a function pointer and 12 | // a set of bindings. The bindings are addresses of captured 13 | // variables. 14 | func (fr *frame) makeClosure(fn *govalue, bindings []*govalue) *govalue { 15 | govalues := append([]*govalue{fn}, bindings...) 16 | fields := make([]*types.Var, len(govalues)) 17 | for i, v := range govalues { 18 | field := types.NewField(0, nil, "_", v.Type(), false) 19 | fields[i] = field 20 | } 21 | block := fr.createTypeMalloc(types.NewStruct(fields, nil)) 22 | for i, v := range govalues { 23 | addressPtr := fr.builder.CreateStructGEP(block, i, "") 24 | fr.builder.CreateStore(v.value, addressPtr) 25 | } 26 | closure := fr.builder.CreateBitCast(block, fn.value.Type(), "") 27 | return newValue(closure, fn.Type()) 28 | } 29 | -------------------------------------------------------------------------------- /irgen/compiler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "bytes" 9 | "fmt" 10 | "go/token" 11 | "log" 12 | "sort" 13 | "strconv" 14 | "strings" 15 | 16 | llgobuild "github.com/go-llvm/llgo/build" 17 | "github.com/go-llvm/llgo/debug" 18 | "llvm.org/llvm/bindings/go/llvm" 19 | 20 | "golang.org/x/tools/go/gccgoimporter" 21 | "golang.org/x/tools/go/importer" 22 | "golang.org/x/tools/go/loader" 23 | "golang.org/x/tools/go/ssa" 24 | "golang.org/x/tools/go/types" 25 | ) 26 | 27 | type Module struct { 28 | llvm.Module 29 | Path string 30 | ExportData []byte 31 | disposed bool 32 | } 33 | 34 | func (m *Module) Dispose() { 35 | if m.disposed { 36 | return 37 | } 38 | m.Module.Dispose() 39 | m.disposed = true 40 | } 41 | 42 | /////////////////////////////////////////////////////////////////////////////// 43 | 44 | type CompilerOptions struct { 45 | // TargetTriple is the LLVM triple for the target. 46 | TargetTriple string 47 | 48 | // GenerateDebug decides whether debug data is 49 | // generated in the output module. 50 | GenerateDebug bool 51 | 52 | // DebugPrefixMaps is a list of mappings from source prefixes to 53 | // replacement prefixes, to be applied in debug info. 54 | DebugPrefixMaps []debug.PrefixMap 55 | 56 | // Logger is a logger used for tracing compilation. 57 | Logger *log.Logger 58 | 59 | // DumpSSA is a debugging option that dumps each SSA function 60 | // to stderr before generating code for it. 61 | DumpSSA bool 62 | 63 | // GccgoPath is the path to the gccgo binary whose libgo we read import 64 | // data from. If blank, the caller is expected to supply an import 65 | // path in ImportPaths. 66 | GccgoPath string 67 | 68 | // ImportPaths is the list of additional import paths 69 | ImportPaths []string 70 | 71 | // SanitizerAttribute is an attribute to apply to functions to enable 72 | // dynamic instrumentation using a sanitizer. 73 | SanitizerAttribute llvm.Attribute 74 | } 75 | 76 | type Compiler struct { 77 | opts CompilerOptions 78 | dataLayout string 79 | pnacl bool 80 | } 81 | 82 | func NewCompiler(opts CompilerOptions) (*Compiler, error) { 83 | compiler := &Compiler{opts: opts} 84 | if strings.ToLower(compiler.opts.TargetTriple) == "pnacl" { 85 | compiler.opts.TargetTriple = PNaClTriple 86 | compiler.pnacl = true 87 | } 88 | dataLayout, err := llvmDataLayout(compiler.opts.TargetTriple) 89 | if err != nil { 90 | return nil, err 91 | } 92 | compiler.dataLayout = dataLayout 93 | return compiler, nil 94 | } 95 | 96 | func (c *Compiler) Compile(filenames []string, importpath string) (m *Module, err error) { 97 | target := llvm.NewTargetData(c.dataLayout) 98 | compiler := &compiler{ 99 | CompilerOptions: c.opts, 100 | dataLayout: c.dataLayout, 101 | target: target, 102 | pnacl: c.pnacl, 103 | llvmtypes: NewLLVMTypeMap(llvm.GlobalContext(), target), 104 | } 105 | return compiler.compile(filenames, importpath) 106 | } 107 | 108 | type compiler struct { 109 | CompilerOptions 110 | 111 | module *Module 112 | dataLayout string 113 | target llvm.TargetData 114 | fileset *token.FileSet 115 | 116 | runtime *runtimeInterface 117 | llvmtypes *llvmTypeMap 118 | types *TypeMap 119 | 120 | // runtimetypespkg is the type-checked runtime/types.go file, 121 | // which is used for evaluating the types of runtime functions. 122 | runtimetypespkg *types.Package 123 | 124 | // pnacl is set to true if the target triple was originally 125 | // specified as "pnacl". This is necessary, as the TargetTriple 126 | // field will have been updated to the true triple used to 127 | // compile PNaCl modules. 128 | pnacl bool 129 | 130 | debug *debug.DIBuilder 131 | } 132 | 133 | func (c *compiler) logf(format string, v ...interface{}) { 134 | if c.Logger != nil { 135 | c.Logger.Printf(format, v...) 136 | } 137 | } 138 | 139 | func (c *compiler) addCommonFunctionAttrs(fn llvm.Value) { 140 | fn.AddTargetDependentFunctionAttr("disable-tail-calls", "true") 141 | fn.AddTargetDependentFunctionAttr("split-stack", "") 142 | if attr := c.SanitizerAttribute; attr != 0 { 143 | fn.AddFunctionAttr(attr) 144 | } 145 | } 146 | 147 | func (compiler *compiler) compile(filenames []string, importpath string) (m *Module, err error) { 148 | buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple) 149 | if err != nil { 150 | return nil, err 151 | } 152 | 153 | initmap := make(map[*types.Package]gccgoimporter.InitData) 154 | var importer types.Importer 155 | if compiler.GccgoPath == "" { 156 | paths := append(append([]string{}, compiler.ImportPaths...), ".") 157 | importer = gccgoimporter.GetImporter(paths, initmap) 158 | } else { 159 | var inst gccgoimporter.GccgoInstallation 160 | err = inst.InitFromDriver(compiler.GccgoPath) 161 | if err != nil { 162 | return nil, err 163 | } 164 | importer = inst.GetImporter(compiler.ImportPaths, initmap) 165 | } 166 | 167 | impcfg := &loader.Config{ 168 | Fset: token.NewFileSet(), 169 | TypeChecker: types.Config{ 170 | Import: importer, 171 | Sizes: compiler.llvmtypes, 172 | }, 173 | Build: &buildctx.Context, 174 | } 175 | // Must use parseFiles, so we retain comments; 176 | // this is important for annotation processing. 177 | astFiles, err := parseFiles(impcfg.Fset, filenames) 178 | if err != nil { 179 | return nil, err 180 | } 181 | // If no import path is specified, then set the import 182 | // path to be the same as the package's name. 183 | if importpath == "" { 184 | importpath = astFiles[0].Name.String() 185 | } 186 | impcfg.CreateFromFiles(importpath, astFiles...) 187 | iprog, err := impcfg.Load() 188 | if err != nil { 189 | return nil, err 190 | } 191 | program := ssa.Create(iprog, ssa.BareInits) 192 | mainPkginfo := iprog.InitialPackages()[0] 193 | mainPkg := program.CreatePackage(mainPkginfo) 194 | 195 | // Create a Module, which contains the LLVM module. 196 | modulename := importpath 197 | compiler.module = &Module{Module: llvm.NewModule(modulename), Path: modulename} 198 | compiler.module.SetTarget(compiler.TargetTriple) 199 | compiler.module.SetDataLayout(compiler.dataLayout) 200 | 201 | // Create a new translation unit. 202 | unit := newUnit(compiler, mainPkg) 203 | 204 | // Create the runtime interface. 205 | compiler.runtime, err = newRuntimeInterface(compiler.module.Module, compiler.llvmtypes) 206 | if err != nil { 207 | return nil, err 208 | } 209 | 210 | mainPkg.Build() 211 | 212 | // Create a struct responsible for mapping static types to LLVM types, 213 | // and to runtime/dynamic type values. 214 | compiler.types = NewTypeMap( 215 | mainPkg, 216 | compiler.llvmtypes, 217 | compiler.module.Module, 218 | compiler.runtime, 219 | MethodResolver(unit), 220 | ) 221 | 222 | if compiler.GenerateDebug { 223 | compiler.debug = debug.NewDIBuilder( 224 | types.Sizes(compiler.llvmtypes), 225 | compiler.module.Module, 226 | impcfg.Fset, 227 | compiler.DebugPrefixMaps, 228 | ) 229 | defer compiler.debug.Destroy() 230 | defer compiler.debug.Finalize() 231 | } 232 | 233 | unit.translatePackage(mainPkg) 234 | compiler.processAnnotations(unit, mainPkginfo) 235 | 236 | if importpath == "main" { 237 | if err = compiler.createInitMainFunction(mainPkg, initmap); err != nil { 238 | return nil, fmt.Errorf("failed to create __go_init_main: %v", err) 239 | } 240 | } else { 241 | compiler.module.ExportData = compiler.buildExportData(mainPkg, initmap) 242 | } 243 | 244 | return compiler.module, nil 245 | } 246 | 247 | type byPriorityThenFunc []gccgoimporter.PackageInit 248 | 249 | func (a byPriorityThenFunc) Len() int { return len(a) } 250 | func (a byPriorityThenFunc) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 251 | func (a byPriorityThenFunc) Less(i, j int) bool { 252 | switch { 253 | case a[i].Priority < a[j].Priority: 254 | return true 255 | case a[i].Priority > a[j].Priority: 256 | return false 257 | case a[i].InitFunc < a[j].InitFunc: 258 | return true 259 | default: 260 | return false 261 | } 262 | } 263 | 264 | func (c *compiler) buildPackageInitData(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) gccgoimporter.InitData { 265 | var inits []gccgoimporter.PackageInit 266 | for _, imp := range mainPkg.Object.Imports() { 267 | inits = append(inits, initmap[imp].Inits...) 268 | } 269 | sort.Sort(byPriorityThenFunc(inits)) 270 | 271 | // Deduplicate init entries. We want to preserve the entry with the highest priority. 272 | // Normally a package's priorities will be consistent among its dependencies, but it is 273 | // possible for them to be different. For example, if a standard library test augments a 274 | // package which is a dependency of 'regexp' (which is imported by every test main package) 275 | // with additional dependencies, those dependencies may cause the package under test to 276 | // receive a higher priority than indicated by its init clause in 'regexp'. 277 | uniqinits := make([]gccgoimporter.PackageInit, len(inits)) 278 | uniqinitpos := len(inits) 279 | uniqinitnames := make(map[string]struct{}) 280 | for i, _ := range inits { 281 | init := inits[len(inits)-1-i] 282 | if _, ok := uniqinitnames[init.InitFunc]; !ok { 283 | uniqinitnames[init.InitFunc] = struct{}{} 284 | uniqinitpos-- 285 | uniqinits[uniqinitpos] = init 286 | } 287 | } 288 | uniqinits = uniqinits[uniqinitpos:] 289 | 290 | ourprio := 1 291 | if len(uniqinits) != 0 { 292 | ourprio = uniqinits[len(uniqinits)-1].Priority + 1 293 | } 294 | 295 | if imp := mainPkg.Func("init"); imp != nil { 296 | impname := c.types.mc.mangleFunctionName(imp) 297 | uniqinits = append(uniqinits, gccgoimporter.PackageInit{mainPkg.Object.Name(), impname, ourprio}) 298 | } 299 | 300 | return gccgoimporter.InitData{ourprio, uniqinits} 301 | } 302 | 303 | func (c *compiler) createInitMainFunction(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) error { 304 | initdata := c.buildPackageInitData(mainPkg, initmap) 305 | 306 | ftyp := llvm.FunctionType(llvm.VoidType(), nil, false) 307 | initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp) 308 | c.addCommonFunctionAttrs(initMain) 309 | entry := llvm.AddBasicBlock(initMain, "entry") 310 | 311 | builder := llvm.GlobalContext().NewBuilder() 312 | defer builder.Dispose() 313 | builder.SetInsertPointAtEnd(entry) 314 | 315 | for _, init := range initdata.Inits { 316 | initfn := c.module.Module.NamedFunction(init.InitFunc) 317 | if initfn.IsNil() { 318 | initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp) 319 | } 320 | builder.CreateCall(initfn, nil, "") 321 | } 322 | 323 | builder.CreateRetVoid() 324 | return nil 325 | } 326 | 327 | func (c *compiler) buildExportData(mainPkg *ssa.Package, initmap map[*types.Package]gccgoimporter.InitData) []byte { 328 | exportData := importer.ExportData(mainPkg.Object) 329 | b := bytes.NewBuffer(exportData) 330 | 331 | initdata := c.buildPackageInitData(mainPkg, initmap) 332 | b.WriteString("v1;\npriority ") 333 | b.WriteString(strconv.Itoa(initdata.Priority)) 334 | b.WriteString(";\n") 335 | 336 | if len(initdata.Inits) != 0 { 337 | b.WriteString("init") 338 | for _, init := range initdata.Inits { 339 | b.WriteRune(' ') 340 | b.WriteString(init.Name) 341 | b.WriteRune(' ') 342 | b.WriteString(init.InitFunc) 343 | b.WriteRune(' ') 344 | b.WriteString(strconv.Itoa(init.Priority)) 345 | } 346 | b.WriteString(";\n") 347 | } 348 | 349 | return b.Bytes() 350 | } 351 | 352 | // vim: set ft=go : 353 | -------------------------------------------------------------------------------- /irgen/errors.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "llvm.org/llvm/bindings/go/llvm" 9 | ) 10 | 11 | const ( 12 | // From go-runtime-error.c 13 | gccgoRuntimeErrorSLICE_INDEX_OUT_OF_BOUNDS = 0 14 | gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS = 1 15 | gccgoRuntimeErrorSTRING_INDEX_OUT_OF_BOUNDS = 2 16 | gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS = 3 17 | gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS = 4 18 | gccgoRuntimeErrorSTRING_SLICE_OUT_OF_BOUNDS = 5 19 | gccgoRuntimeErrorNIL_DEREFERENCE = 6 20 | gccgoRuntimeErrorMAKE_SLICE_OUT_OF_BOUNDS = 7 21 | gccgoRuntimeErrorMAKE_MAP_OUT_OF_BOUNDS = 8 22 | gccgoRuntimeErrorMAKE_CHAN_OUT_OF_BOUNDS = 9 23 | gccgoRuntimeErrorDIVISION_BY_ZERO = 10 24 | gccgoRuntimeErrorCount = 11 25 | ) 26 | 27 | func (fr *frame) setBranchWeightMetadata(br llvm.Value, trueweight, falseweight uint64) { 28 | mdprof := llvm.MDKindID("prof") 29 | 30 | mdnode := llvm.MDNode([]llvm.Value{ 31 | llvm.MDString("branch_weights"), 32 | llvm.ConstInt(llvm.Int32Type(), trueweight, false), 33 | llvm.ConstInt(llvm.Int32Type(), falseweight, false), 34 | }) 35 | 36 | br.SetMetadata(mdprof, mdnode) 37 | } 38 | 39 | func (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) { 40 | if cond.IsNull() { 41 | return 42 | } 43 | 44 | errorbb := fr.runtimeErrorBlocks[errcode] 45 | newbb := errorbb.C == nil 46 | if newbb { 47 | errorbb = llvm.AddBasicBlock(fr.function, "") 48 | fr.runtimeErrorBlocks[errcode] = errorbb 49 | } 50 | 51 | contbb := llvm.AddBasicBlock(fr.function, "") 52 | 53 | br := fr.builder.CreateCondBr(cond, errorbb, contbb) 54 | fr.setBranchWeightMetadata(br, 1, 1000) 55 | 56 | if newbb { 57 | fr.builder.SetInsertPointAtEnd(errorbb) 58 | fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false)) 59 | fr.builder.CreateUnreachable() 60 | } 61 | 62 | fr.builder.SetInsertPointAtEnd(contbb) 63 | } 64 | -------------------------------------------------------------------------------- /irgen/indirect.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/ssa" 9 | "golang.org/x/tools/go/types" 10 | "llvm.org/llvm/bindings/go/llvm" 11 | ) 12 | 13 | // createThunk creates a thunk from a 14 | // given function and arguments, suitable for use with 15 | // "defer" and "go". 16 | func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) { 17 | seenarg := make(map[ssa.Value]bool) 18 | var args []ssa.Value 19 | var argtypes []*types.Var 20 | 21 | packArg := func(arg ssa.Value) { 22 | switch arg.(type) { 23 | case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global: 24 | // Do nothing: we can generate these in the thunk 25 | default: 26 | if !seenarg[arg] { 27 | seenarg[arg] = true 28 | args = append(args, arg) 29 | field := types.NewField(0, nil, "_", arg.Type(), true) 30 | argtypes = append(argtypes, field) 31 | } 32 | } 33 | } 34 | 35 | packArg(call.Common().Value) 36 | for _, arg := range call.Common().Args { 37 | packArg(arg) 38 | } 39 | 40 | var isRecoverCall bool 41 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) 42 | var structllptr llvm.Type 43 | if len(args) == 0 { 44 | if builtin, ok := call.Common().Value.(*ssa.Builtin); ok { 45 | isRecoverCall = builtin.Name() == "recover" 46 | } 47 | if isRecoverCall { 48 | // When creating a thunk for recover(), we must pass fr.canRecover. 49 | arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "") 50 | arg = fr.builder.CreateIntToPtr(arg, i8ptr, "") 51 | } else { 52 | arg = llvm.ConstPointerNull(i8ptr) 53 | } 54 | } else { 55 | structtype := types.NewStruct(argtypes, nil) 56 | arg = fr.createTypeMalloc(structtype) 57 | structllptr = arg.Type() 58 | for i, ssaarg := range args { 59 | argptr := fr.builder.CreateStructGEP(arg, i, "") 60 | fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr) 61 | } 62 | arg = fr.builder.CreateBitCast(arg, i8ptr, "") 63 | } 64 | 65 | thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false) 66 | thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype) 67 | thunkfn.SetLinkage(llvm.InternalLinkage) 68 | fr.addCommonFunctionAttrs(thunkfn) 69 | 70 | thunkfr := newFrame(fr.unit, thunkfn) 71 | defer thunkfr.dispose() 72 | 73 | prologuebb := llvm.AddBasicBlock(thunkfn, "prologue") 74 | thunkfr.builder.SetInsertPointAtEnd(prologuebb) 75 | 76 | if isRecoverCall { 77 | thunkarg := thunkfn.Param(0) 78 | thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "") 79 | thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "") 80 | } else if len(args) > 0 { 81 | thunkarg := thunkfn.Param(0) 82 | thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "") 83 | for i, ssaarg := range args { 84 | thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "") 85 | thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "") 86 | thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type()) 87 | } 88 | } 89 | 90 | _, isDefer := call.(*ssa.Defer) 91 | 92 | entrybb := llvm.AddBasicBlock(thunkfn, "entry") 93 | br := thunkfr.builder.CreateBr(entrybb) 94 | thunkfr.allocaBuilder.SetInsertPointBefore(br) 95 | 96 | thunkfr.builder.SetInsertPointAtEnd(entrybb) 97 | var exitbb llvm.BasicBlock 98 | if isDefer { 99 | exitbb = llvm.AddBasicBlock(thunkfn, "exit") 100 | thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb)) 101 | } 102 | if isDefer && isRecoverCall { 103 | thunkfr.callRecover(true) 104 | } else { 105 | thunkfr.callInstruction(call) 106 | } 107 | if isDefer { 108 | thunkfr.builder.CreateBr(exitbb) 109 | thunkfr.builder.SetInsertPointAtEnd(exitbb) 110 | } 111 | thunkfr.builder.CreateRetVoid() 112 | 113 | thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "") 114 | return 115 | } 116 | -------------------------------------------------------------------------------- /irgen/interfaces.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | // interfaceMethod returns a function and receiver pointer for the specified 13 | // interface and method pair. 14 | func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) { 15 | llitab := fr.builder.CreateExtractValue(lliface, 0, "") 16 | recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer]) 17 | methodset := fr.types.MethodSet(ifacety) 18 | // TODO(axw) cache ordered method index 19 | index := -1 20 | for i, m := range orderedMethodSet(methodset) { 21 | if m.Obj() == method { 22 | index = i 23 | break 24 | } 25 | } 26 | if index == -1 { 27 | panic("could not find method index") 28 | } 29 | llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "") 30 | // Skip runtime type pointer. 31 | llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{ 32 | llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false), 33 | }, "") 34 | 35 | llifn := fr.builder.CreateLoad(llifnptr, "") 36 | // Replace receiver type with unsafe.Pointer. 37 | recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer]) 38 | sig := method.Type().(*types.Signature) 39 | sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic()) 40 | fn = newValue(llifn, sig) 41 | return 42 | } 43 | 44 | // compareInterfaces emits code to compare two interfaces for 45 | // equality. 46 | func (fr *frame) compareInterfaces(a, b *govalue) *govalue { 47 | aNull := a.value.IsNull() 48 | bNull := b.value.IsNull() 49 | if aNull && bNull { 50 | return newValue(boolLLVMValue(true), types.Typ[types.Bool]) 51 | } 52 | 53 | compare := fr.runtime.emptyInterfaceCompare 54 | aI := a.Type().Underlying().(*types.Interface).NumMethods() > 0 55 | bI := b.Type().Underlying().(*types.Interface).NumMethods() > 0 56 | switch { 57 | case aI && bI: 58 | compare = fr.runtime.interfaceCompare 59 | case aI: 60 | a = fr.convertI2E(a) 61 | case bI: 62 | b = fr.convertI2E(b) 63 | } 64 | 65 | result := compare.call(fr, a.value, b.value)[0] 66 | result = fr.builder.CreateIsNull(result, "") 67 | result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") 68 | return newValue(result, types.Typ[types.Bool]) 69 | } 70 | 71 | func (fr *frame) makeInterface(llv llvm.Value, vty types.Type, iface types.Type) *govalue { 72 | if _, ok := vty.Underlying().(*types.Pointer); !ok { 73 | ptr := fr.createTypeMalloc(vty) 74 | fr.builder.CreateStore(llv, ptr) 75 | llv = ptr 76 | } 77 | return fr.makeInterfaceFromPointer(llv, vty, iface) 78 | } 79 | 80 | func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue { 81 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) 82 | llv := fr.builder.CreateBitCast(vptr, i8ptr, "") 83 | value := llvm.Undef(fr.types.ToLLVM(iface)) 84 | itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface)) 85 | value = fr.builder.CreateInsertValue(value, itab, 0, "") 86 | value = fr.builder.CreateInsertValue(value, llv, 1, "") 87 | return newValue(value, iface) 88 | } 89 | 90 | // Reads the type descriptor from the given interface type. 91 | func (fr *frame) getInterfaceTypeDescriptor(v *govalue) llvm.Value { 92 | isempty := v.Type().Underlying().(*types.Interface).NumMethods() == 0 93 | itab := fr.builder.CreateExtractValue(v.value, 0, "") 94 | if isempty { 95 | return itab 96 | } else { 97 | itabnonnull := fr.builder.CreateIsNotNull(itab, "") 98 | return fr.loadOrNull(itabnonnull, itab, types.Typ[types.UnsafePointer]).value 99 | } 100 | } 101 | 102 | // Reads the value from the given interface type, assuming that the 103 | // interface holds a value of the correct type. 104 | func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue { 105 | val := fr.builder.CreateExtractValue(v.value, 1, "") 106 | if _, ok := ty.Underlying().(*types.Pointer); !ok { 107 | typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "") 108 | val = fr.builder.CreateLoad(typedval, "") 109 | } 110 | return newValue(val, ty) 111 | } 112 | 113 | // If cond is true, reads the value from the given interface type, otherwise 114 | // returns a nil value. 115 | func (fr *frame) getInterfaceValueOrNull(cond llvm.Value, v *govalue, ty types.Type) *govalue { 116 | val := fr.builder.CreateExtractValue(v.value, 1, "") 117 | if _, ok := ty.Underlying().(*types.Pointer); ok { 118 | val = fr.builder.CreateSelect(cond, val, llvm.ConstNull(val.Type()), "") 119 | } else { 120 | val = fr.loadOrNull(cond, val, ty).value 121 | } 122 | return newValue(val, ty) 123 | } 124 | 125 | func (fr *frame) interfaceTypeCheck(val *govalue, ty types.Type) (v *govalue, okval *govalue) { 126 | tytd := fr.types.ToRuntime(ty) 127 | if _, ok := ty.Underlying().(*types.Interface); ok { 128 | var result []llvm.Value 129 | if val.Type().Underlying().(*types.Interface).NumMethods() > 0 { 130 | result = fr.runtime.ifaceI2I2.call(fr, tytd, val.value) 131 | } else { 132 | result = fr.runtime.ifaceE2I2.call(fr, tytd, val.value) 133 | } 134 | v = newValue(result[0], ty) 135 | okval = newValue(result[1], types.Typ[types.Bool]) 136 | } else { 137 | valtd := fr.getInterfaceTypeDescriptor(val) 138 | tyequal := fr.runtime.typeDescriptorsEqual.call(fr, valtd, tytd)[0] 139 | okval = newValue(tyequal, types.Typ[types.Bool]) 140 | tyequal = fr.builder.CreateTrunc(tyequal, llvm.Int1Type(), "") 141 | 142 | v = fr.getInterfaceValueOrNull(tyequal, val, ty) 143 | } 144 | return 145 | } 146 | 147 | func (fr *frame) interfaceTypeAssert(val *govalue, ty types.Type) *govalue { 148 | if _, ok := ty.Underlying().(*types.Interface); ok { 149 | return fr.changeInterface(val, ty, true) 150 | } else { 151 | valtytd := fr.types.ToRuntime(val.Type()) 152 | valtd := fr.getInterfaceTypeDescriptor(val) 153 | tytd := fr.types.ToRuntime(ty) 154 | fr.runtime.checkInterfaceType.call(fr, valtd, tytd, valtytd) 155 | 156 | return fr.getInterfaceValue(val, ty) 157 | } 158 | } 159 | 160 | // convertI2E converts a non-empty interface value to an empty interface. 161 | func (fr *frame) convertI2E(v *govalue) *govalue { 162 | td := fr.getInterfaceTypeDescriptor(v) 163 | val := fr.builder.CreateExtractValue(v.value, 1, "") 164 | 165 | typ := types.NewInterface(nil, nil) 166 | intf := llvm.Undef(fr.types.ToLLVM(typ)) 167 | intf = fr.builder.CreateInsertValue(intf, td, 0, "") 168 | intf = fr.builder.CreateInsertValue(intf, val, 1, "") 169 | return newValue(intf, typ) 170 | } 171 | 172 | func (fr *frame) changeInterface(v *govalue, ty types.Type, assert bool) *govalue { 173 | td := fr.getInterfaceTypeDescriptor(v) 174 | tytd := fr.types.ToRuntime(ty) 175 | var itab llvm.Value 176 | if assert { 177 | itab = fr.runtime.assertInterface.call(fr, tytd, td)[0] 178 | } else { 179 | itab = fr.runtime.convertInterface.call(fr, tytd, td)[0] 180 | } 181 | val := fr.builder.CreateExtractValue(v.value, 1, "") 182 | 183 | intf := llvm.Undef(fr.types.ToLLVM(ty)) 184 | intf = fr.builder.CreateInsertValue(intf, itab, 0, "") 185 | intf = fr.builder.CreateInsertValue(intf, val, 1, "") 186 | return newValue(intf, ty) 187 | } 188 | -------------------------------------------------------------------------------- /irgen/maps.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | // makeMap implements make(maptype[, initial space]) 13 | func (fr *frame) makeMap(typ types.Type, cap_ *govalue) *govalue { 14 | // TODO(pcc): call __go_new_map_big here if needed 15 | dyntyp := fr.types.getMapDescriptorPointer(typ) 16 | dyntyp = fr.builder.CreateBitCast(dyntyp, llvm.PointerType(llvm.Int8Type(), 0), "") 17 | var cap llvm.Value 18 | if cap_ != nil { 19 | cap = fr.convert(cap_, types.Typ[types.Uintptr]).value 20 | } else { 21 | cap = llvm.ConstNull(fr.types.inttype) 22 | } 23 | m := fr.runtime.newMap.call(fr, dyntyp, cap) 24 | return newValue(m[0], typ) 25 | } 26 | 27 | // mapLookup implements v[, ok] = m[k] 28 | func (fr *frame) mapLookup(m, k *govalue) (v *govalue, ok *govalue) { 29 | llk := k.value 30 | pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") 31 | fr.builder.CreateStore(llk, pk) 32 | valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(false))[0] 33 | valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute) 34 | valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute) 35 | okbit := fr.builder.CreateIsNotNull(valptr, "") 36 | 37 | elemtyp := m.Type().Underlying().(*types.Map).Elem() 38 | ok = newValue(fr.builder.CreateZExt(okbit, llvm.Int8Type(), ""), types.Typ[types.Bool]) 39 | v = fr.loadOrNull(okbit, valptr, elemtyp) 40 | return 41 | } 42 | 43 | // mapUpdate implements m[k] = v 44 | func (fr *frame) mapUpdate(m, k, v *govalue) { 45 | llk := k.value 46 | pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") 47 | fr.builder.CreateStore(llk, pk) 48 | valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(true))[0] 49 | valptr.AddInstrAttribute(2, llvm.NoCaptureAttribute) 50 | valptr.AddInstrAttribute(2, llvm.ReadOnlyAttribute) 51 | 52 | elemtyp := m.Type().Underlying().(*types.Map).Elem() 53 | llelemtyp := fr.types.ToLLVM(elemtyp) 54 | typedvalptr := fr.builder.CreateBitCast(valptr, llvm.PointerType(llelemtyp, 0), "") 55 | fr.builder.CreateStore(v.value, typedvalptr) 56 | } 57 | 58 | // mapDelete implements delete(m, k) 59 | func (fr *frame) mapDelete(m, k *govalue) { 60 | llk := k.value 61 | pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "") 62 | fr.builder.CreateStore(llk, pk) 63 | fr.runtime.mapdelete.call(fr, m.value, pk) 64 | } 65 | 66 | // mapIterInit creates a map iterator 67 | func (fr *frame) mapIterInit(m *govalue) []*govalue { 68 | // We represent an iterator as a tuple (map, *bool). The second element 69 | // controls whether the code we generate for "next" (below) calls the 70 | // runtime function for the first or the next element. We let the 71 | // optimizer reorganize this into something more sensible. 72 | isinit := fr.allocaBuilder.CreateAlloca(llvm.Int1Type(), "") 73 | fr.builder.CreateStore(llvm.ConstNull(llvm.Int1Type()), isinit) 74 | 75 | return []*govalue{m, newValue(isinit, types.NewPointer(types.Typ[types.Bool]))} 76 | } 77 | 78 | // mapIterNext advances the iterator, and returns the tuple (ok, k, v). 79 | func (fr *frame) mapIterNext(iter []*govalue) []*govalue { 80 | maptyp := iter[0].Type().Underlying().(*types.Map) 81 | ktyp := maptyp.Key() 82 | klltyp := fr.types.ToLLVM(ktyp) 83 | vtyp := maptyp.Elem() 84 | vlltyp := fr.types.ToLLVM(vtyp) 85 | 86 | m, isinitptr := iter[0], iter[1] 87 | 88 | i8ptr := llvm.PointerType(llvm.Int8Type(), 0) 89 | mapiterbufty := llvm.ArrayType(i8ptr, 4) 90 | mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "") 91 | mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "") 92 | 93 | keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "") 94 | keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "") 95 | valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "") 96 | valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "") 97 | 98 | isinit := fr.builder.CreateLoad(isinitptr.value, "") 99 | 100 | initbb := llvm.AddBasicBlock(fr.function, "") 101 | nextbb := llvm.AddBasicBlock(fr.function, "") 102 | contbb := llvm.AddBasicBlock(fr.function, "") 103 | 104 | fr.builder.CreateCondBr(isinit, nextbb, initbb) 105 | 106 | fr.builder.SetInsertPointAtEnd(initbb) 107 | fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value) 108 | fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr) 109 | fr.builder.CreateBr(contbb) 110 | 111 | fr.builder.SetInsertPointAtEnd(nextbb) 112 | fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr) 113 | fr.builder.CreateBr(contbb) 114 | 115 | fr.builder.SetInsertPointAtEnd(contbb) 116 | mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "") 117 | okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "") 118 | ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "") 119 | 120 | loadbb := llvm.AddBasicBlock(fr.function, "") 121 | cont2bb := llvm.AddBasicBlock(fr.function, "") 122 | fr.builder.CreateCondBr(okbit, loadbb, cont2bb) 123 | 124 | fr.builder.SetInsertPointAtEnd(loadbb) 125 | fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr) 126 | loadbb = fr.builder.GetInsertBlock() 127 | loadedkey := fr.builder.CreateLoad(keybuf, "") 128 | loadedval := fr.builder.CreateLoad(valbuf, "") 129 | fr.builder.CreateBr(cont2bb) 130 | 131 | fr.builder.SetInsertPointAtEnd(cont2bb) 132 | k := fr.builder.CreatePHI(klltyp, "") 133 | k.AddIncoming( 134 | []llvm.Value{llvm.ConstNull(klltyp), loadedkey}, 135 | []llvm.BasicBlock{contbb, loadbb}, 136 | ) 137 | v := fr.builder.CreatePHI(vlltyp, "") 138 | v.AddIncoming( 139 | []llvm.Value{llvm.ConstNull(vlltyp), loadedval}, 140 | []llvm.BasicBlock{contbb, loadbb}, 141 | ) 142 | 143 | return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)} 144 | } 145 | -------------------------------------------------------------------------------- /irgen/parser.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "fmt" 9 | "go/ast" 10 | "go/parser" 11 | "go/scanner" 12 | "go/token" 13 | ) 14 | 15 | func parseFile(fset *token.FileSet, filename string) (*ast.File, error) { 16 | mode := parser.DeclarationErrors | parser.ParseComments 17 | return parser.ParseFile(fset, filename, nil, mode) 18 | } 19 | 20 | func parseFiles(fset *token.FileSet, filenames []string) ([]*ast.File, error) { 21 | files := make([]*ast.File, len(filenames)) 22 | for i, filename := range filenames { 23 | file, err := parseFile(fset, filename) 24 | if _, ok := err.(scanner.ErrorList); ok { 25 | return nil, err 26 | } else if err != nil { 27 | return nil, fmt.Errorf("%q: %v", filename, err) 28 | } 29 | files[i] = file 30 | } 31 | return files, nil 32 | } 33 | -------------------------------------------------------------------------------- /irgen/predicates.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // This file implements commonly used type predicates. 6 | 7 | package irgen 8 | 9 | import ( 10 | "golang.org/x/tools/go/types" 11 | ) 12 | 13 | func isBoolean(typ types.Type) bool { 14 | t, ok := typ.Underlying().(*types.Basic) 15 | return ok && t.Info()&types.IsBoolean != 0 16 | } 17 | 18 | func isInteger(typ types.Type) bool { 19 | t, ok := typ.Underlying().(*types.Basic) 20 | return ok && t.Info()&types.IsInteger != 0 21 | } 22 | 23 | func isUnsigned(typ types.Type) bool { 24 | t, ok := typ.Underlying().(*types.Basic) 25 | return ok && t.Info()&types.IsUnsigned != 0 26 | } 27 | 28 | func isFloat(typ types.Type) bool { 29 | t, ok := typ.Underlying().(*types.Basic) 30 | return ok && t.Info()&types.IsFloat != 0 31 | } 32 | 33 | func isComplex(typ types.Type) bool { 34 | t, ok := typ.Underlying().(*types.Basic) 35 | return ok && t.Info()&types.IsComplex != 0 36 | } 37 | 38 | func isString(typ types.Type) bool { 39 | t, ok := typ.Underlying().(*types.Basic) 40 | return ok && t.Info()&types.IsString != 0 41 | } 42 | 43 | func isUntyped(typ types.Type) bool { 44 | t, ok := typ.Underlying().(*types.Basic) 45 | return ok && t.Info()&types.IsUntyped != 0 46 | } 47 | 48 | func isSlice(typ types.Type, bkind types.BasicKind) bool { 49 | t, ok := typ.Underlying().(*types.Slice) 50 | return ok && types.Identical(t.Elem().Underlying(), types.Typ[bkind]) 51 | } 52 | -------------------------------------------------------------------------------- /irgen/println.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "fmt" 9 | 10 | "golang.org/x/tools/go/types" 11 | ) 12 | 13 | func (fr *frame) printValues(println_ bool, values ...*govalue) { 14 | for i, value := range values { 15 | llvm_value := value.value 16 | 17 | typ := value.Type().Underlying() 18 | if name, isname := typ.(*types.Named); isname { 19 | typ = name.Underlying() 20 | } 21 | 22 | if println_ && i > 0 { 23 | fr.runtime.printSpace.call(fr) 24 | } 25 | switch typ := typ.(type) { 26 | case *types.Basic: 27 | switch typ.Kind() { 28 | case types.Uint8, types.Uint16, types.Uint32, types.Uintptr, types.Uint, types.Uint64: 29 | i64 := fr.llvmtypes.ctx.Int64Type() 30 | zext := fr.builder.CreateZExt(llvm_value, i64, "") 31 | fr.runtime.printUint64.call(fr, zext) 32 | 33 | case types.Int, types.Int8, types.Int16, types.Int32, types.Int64: 34 | i64 := fr.llvmtypes.ctx.Int64Type() 35 | sext := fr.builder.CreateSExt(llvm_value, i64, "") 36 | fr.runtime.printInt64.call(fr, sext) 37 | 38 | case types.Float32: 39 | llvm_value = fr.builder.CreateFPExt(llvm_value, fr.llvmtypes.ctx.DoubleType(), "") 40 | fallthrough 41 | case types.Float64: 42 | fr.runtime.printDouble.call(fr, llvm_value) 43 | 44 | case types.Complex64: 45 | llvm_value = fr.convert(value, types.Typ[types.Complex128]).value 46 | fallthrough 47 | case types.Complex128: 48 | fr.runtime.printComplex.call(fr, llvm_value) 49 | 50 | case types.String, types.UntypedString: 51 | fr.runtime.printString.call(fr, llvm_value) 52 | 53 | case types.Bool: 54 | fr.runtime.printBool.call(fr, llvm_value) 55 | 56 | case types.UnsafePointer: 57 | fr.runtime.printPointer.call(fr, llvm_value) 58 | 59 | default: 60 | panic(fmt.Sprint("Unhandled Basic Kind: ", typ.Kind)) 61 | } 62 | 63 | case *types.Interface: 64 | if typ.Empty() { 65 | fr.runtime.printEmptyInterface.call(fr, llvm_value) 66 | } else { 67 | fr.runtime.printInterface.call(fr, llvm_value) 68 | } 69 | 70 | case *types.Slice: 71 | fr.runtime.printSlice.call(fr, llvm_value) 72 | 73 | case *types.Pointer, *types.Map, *types.Chan, *types.Signature: 74 | fr.runtime.printPointer.call(fr, llvm_value) 75 | 76 | default: 77 | panic(fmt.Sprintf("Unhandled type kind: %s (%T)", typ, typ)) 78 | } 79 | } 80 | if println_ { 81 | fr.runtime.printNl.call(fr) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /irgen/runtime.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "strconv" 9 | 10 | "golang.org/x/tools/go/types" 11 | 12 | "llvm.org/llvm/bindings/go/llvm" 13 | ) 14 | 15 | type runtimeFnInfo struct { 16 | fi *functionTypeInfo 17 | fn llvm.Value 18 | } 19 | 20 | func (rfi *runtimeFnInfo) init(tm *llvmTypeMap, m llvm.Module, name string, args []types.Type, results []types.Type) { 21 | rfi.fi = new(functionTypeInfo) 22 | *rfi.fi = tm.getFunctionTypeInfo(args, results) 23 | rfi.fn = rfi.fi.declare(m, name) 24 | } 25 | 26 | func (rfi *runtimeFnInfo) call(f *frame, args ...llvm.Value) []llvm.Value { 27 | if f.unwindBlock.IsNil() { 28 | return rfi.callOnly(f, args...) 29 | } else { 30 | return rfi.invoke(f, f.unwindBlock, args...) 31 | } 32 | } 33 | 34 | func (rfi *runtimeFnInfo) callOnly(f *frame, args ...llvm.Value) []llvm.Value { 35 | return rfi.fi.call(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, args) 36 | } 37 | 38 | func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value { 39 | contbb := llvm.AddBasicBlock(f.function, "") 40 | return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, args, contbb, lpad) 41 | } 42 | 43 | // runtimeInterface is a struct containing references to 44 | // runtime types and intrinsic function declarations. 45 | type runtimeInterface struct { 46 | // LLVM intrinsics 47 | memcpy, 48 | memset, 49 | returnaddress llvm.Value 50 | 51 | // Exception handling support 52 | gccgoPersonality llvm.Value 53 | gccgoExceptionType llvm.Type 54 | 55 | // Runtime intrinsics 56 | append, 57 | assertInterface, 58 | canRecover, 59 | chanCap, 60 | chanLen, 61 | chanrecv2, 62 | checkDefer, 63 | checkInterfaceType, 64 | builtinClose, 65 | convertInterface, 66 | copy, 67 | Defer, 68 | deferredRecover, 69 | emptyInterfaceCompare, 70 | getClosure, 71 | Go, 72 | ifaceE2I2, 73 | ifaceI2I2, 74 | intArrayToString, 75 | interfaceCompare, 76 | intToString, 77 | makeSlice, 78 | mapdelete, 79 | mapiter2, 80 | mapiterinit, 81 | mapiternext, 82 | mapIndex, 83 | mapLen, 84 | New, 85 | newChannel, 86 | newMap, 87 | NewNopointers, 88 | newSelect, 89 | panic, 90 | printBool, 91 | printComplex, 92 | printDouble, 93 | printEmptyInterface, 94 | printInterface, 95 | printInt64, 96 | printNl, 97 | printPointer, 98 | printSlice, 99 | printSpace, 100 | printString, 101 | printUint64, 102 | receive, 103 | recover, 104 | registerGcRoots, 105 | runtimeError, 106 | selectdefault, 107 | selectrecv2, 108 | selectsend, 109 | selectgo, 110 | sendBig, 111 | setClosure, 112 | setDeferRetaddr, 113 | strcmp, 114 | stringiter2, 115 | stringPlus, 116 | stringSlice, 117 | stringToIntArray, 118 | typeDescriptorsEqual, 119 | undefer runtimeFnInfo 120 | } 121 | 122 | func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) { 123 | var ri runtimeInterface 124 | 125 | Bool := types.Typ[types.Bool] 126 | Complex128 := types.Typ[types.Complex128] 127 | Float64 := types.Typ[types.Float64] 128 | Int32 := types.Typ[types.Int32] 129 | Int64 := types.Typ[types.Int64] 130 | Int := types.Typ[types.Int] 131 | Rune := types.Typ[types.Rune] 132 | String := types.Typ[types.String] 133 | Uintptr := types.Typ[types.Uintptr] 134 | UnsafePointer := types.Typ[types.UnsafePointer] 135 | 136 | EmptyInterface := types.NewInterface(nil, nil) 137 | IntSlice := types.NewSlice(types.Typ[types.Int]) 138 | 139 | for _, rt := range [...]struct { 140 | name string 141 | rfi *runtimeFnInfo 142 | args, res []types.Type 143 | attrs []llvm.Attribute 144 | }{ 145 | { 146 | name: "__go_append", 147 | rfi: &ri.append, 148 | args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr}, 149 | res: []types.Type{IntSlice}, 150 | }, 151 | { 152 | name: "__go_assert_interface", 153 | rfi: &ri.assertInterface, 154 | args: []types.Type{UnsafePointer, UnsafePointer}, 155 | res: []types.Type{UnsafePointer}, 156 | }, 157 | { 158 | name: "__go_can_recover", 159 | rfi: &ri.canRecover, 160 | args: []types.Type{UnsafePointer}, 161 | res: []types.Type{Bool}, 162 | }, 163 | { 164 | name: "__go_chan_cap", 165 | rfi: &ri.chanCap, 166 | args: []types.Type{UnsafePointer}, 167 | res: []types.Type{Int}, 168 | }, 169 | { 170 | name: "__go_chan_len", 171 | rfi: &ri.chanLen, 172 | args: []types.Type{UnsafePointer}, 173 | res: []types.Type{Int}, 174 | }, 175 | { 176 | name: "runtime.chanrecv2", 177 | rfi: &ri.chanrecv2, 178 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 179 | res: []types.Type{Bool}, 180 | }, 181 | { 182 | name: "__go_check_defer", 183 | rfi: &ri.checkDefer, 184 | args: []types.Type{UnsafePointer}, 185 | }, 186 | { 187 | name: "__go_check_interface_type", 188 | rfi: &ri.checkInterfaceType, 189 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 190 | }, 191 | { 192 | name: "__go_builtin_close", 193 | rfi: &ri.builtinClose, 194 | args: []types.Type{UnsafePointer}, 195 | }, 196 | { 197 | name: "__go_convert_interface", 198 | rfi: &ri.convertInterface, 199 | args: []types.Type{UnsafePointer, UnsafePointer}, 200 | res: []types.Type{UnsafePointer}, 201 | }, 202 | { 203 | name: "__go_copy", 204 | rfi: &ri.copy, 205 | args: []types.Type{UnsafePointer, UnsafePointer, Uintptr}, 206 | }, 207 | { 208 | name: "__go_defer", 209 | rfi: &ri.Defer, 210 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 211 | }, 212 | { 213 | name: "__go_deferred_recover", 214 | rfi: &ri.deferredRecover, 215 | res: []types.Type{EmptyInterface}, 216 | }, 217 | { 218 | name: "__go_empty_interface_compare", 219 | rfi: &ri.emptyInterfaceCompare, 220 | args: []types.Type{EmptyInterface, EmptyInterface}, 221 | res: []types.Type{Int}, 222 | }, 223 | { 224 | name: "__go_get_closure", 225 | rfi: &ri.getClosure, 226 | res: []types.Type{UnsafePointer}, 227 | }, 228 | { 229 | name: "__go_go", 230 | rfi: &ri.Go, 231 | args: []types.Type{UnsafePointer, UnsafePointer}, 232 | }, 233 | { 234 | name: "runtime.ifaceE2I2", 235 | rfi: &ri.ifaceE2I2, 236 | args: []types.Type{UnsafePointer, EmptyInterface}, 237 | res: []types.Type{EmptyInterface, Bool}, 238 | }, 239 | { 240 | name: "runtime.ifaceI2I2", 241 | rfi: &ri.ifaceI2I2, 242 | args: []types.Type{UnsafePointer, EmptyInterface}, 243 | res: []types.Type{EmptyInterface, Bool}, 244 | }, 245 | { 246 | name: "__go_int_array_to_string", 247 | rfi: &ri.intArrayToString, 248 | args: []types.Type{UnsafePointer, Int}, 249 | res: []types.Type{String}, 250 | }, 251 | { 252 | name: "__go_int_to_string", 253 | rfi: &ri.intToString, 254 | args: []types.Type{Int}, 255 | res: []types.Type{String}, 256 | }, 257 | { 258 | name: "__go_interface_compare", 259 | rfi: &ri.interfaceCompare, 260 | args: []types.Type{EmptyInterface, EmptyInterface}, 261 | res: []types.Type{Int}, 262 | }, 263 | { 264 | name: "__go_make_slice2", 265 | rfi: &ri.makeSlice, 266 | args: []types.Type{UnsafePointer, Uintptr, Uintptr}, 267 | res: []types.Type{IntSlice}, 268 | }, 269 | { 270 | name: "runtime.mapdelete", 271 | rfi: &ri.mapdelete, 272 | args: []types.Type{UnsafePointer, UnsafePointer}, 273 | }, 274 | { 275 | name: "runtime.mapiter2", 276 | rfi: &ri.mapiter2, 277 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 278 | }, 279 | { 280 | name: "runtime.mapiterinit", 281 | rfi: &ri.mapiterinit, 282 | args: []types.Type{UnsafePointer, UnsafePointer}, 283 | }, 284 | { 285 | name: "runtime.mapiternext", 286 | rfi: &ri.mapiternext, 287 | args: []types.Type{UnsafePointer}, 288 | }, 289 | { 290 | name: "__go_map_index", 291 | rfi: &ri.mapIndex, 292 | args: []types.Type{UnsafePointer, UnsafePointer, Bool}, 293 | res: []types.Type{UnsafePointer}, 294 | }, 295 | { 296 | name: "__go_map_len", 297 | rfi: &ri.mapLen, 298 | args: []types.Type{UnsafePointer}, 299 | res: []types.Type{Int}, 300 | }, 301 | { 302 | name: "__go_new", 303 | rfi: &ri.New, 304 | args: []types.Type{Uintptr}, 305 | res: []types.Type{UnsafePointer}, 306 | }, 307 | { 308 | name: "__go_new_channel", 309 | rfi: &ri.newChannel, 310 | args: []types.Type{UnsafePointer, Uintptr}, 311 | res: []types.Type{UnsafePointer}, 312 | }, 313 | { 314 | name: "__go_new_map", 315 | rfi: &ri.newMap, 316 | args: []types.Type{UnsafePointer, Uintptr}, 317 | res: []types.Type{UnsafePointer}, 318 | }, 319 | { 320 | name: "__go_new_nopointers", 321 | rfi: &ri.NewNopointers, 322 | args: []types.Type{Uintptr}, 323 | res: []types.Type{UnsafePointer}, 324 | }, 325 | { 326 | name: "runtime.newselect", 327 | rfi: &ri.newSelect, 328 | args: []types.Type{Int32}, 329 | res: []types.Type{UnsafePointer}, 330 | }, 331 | { 332 | name: "__go_panic", 333 | rfi: &ri.panic, 334 | args: []types.Type{EmptyInterface}, 335 | attrs: []llvm.Attribute{llvm.NoReturnAttribute}, 336 | }, 337 | { 338 | name: "__go_print_bool", 339 | rfi: &ri.printBool, 340 | args: []types.Type{Bool}, 341 | }, 342 | { 343 | name: "__go_print_complex", 344 | rfi: &ri.printComplex, 345 | args: []types.Type{Complex128}, 346 | }, 347 | { 348 | name: "__go_print_double", 349 | rfi: &ri.printDouble, 350 | args: []types.Type{Float64}, 351 | }, 352 | { 353 | name: "__go_print_empty_interface", 354 | rfi: &ri.printEmptyInterface, 355 | args: []types.Type{EmptyInterface}, 356 | }, 357 | { 358 | name: "__go_print_interface", 359 | rfi: &ri.printInterface, 360 | args: []types.Type{EmptyInterface}, 361 | }, 362 | { 363 | name: "__go_print_int64", 364 | rfi: &ri.printInt64, 365 | args: []types.Type{Int64}, 366 | }, 367 | { 368 | name: "__go_print_nl", 369 | rfi: &ri.printNl, 370 | }, 371 | { 372 | name: "__go_print_pointer", 373 | rfi: &ri.printPointer, 374 | args: []types.Type{UnsafePointer}, 375 | }, 376 | { 377 | name: "__go_print_slice", 378 | rfi: &ri.printSlice, 379 | args: []types.Type{IntSlice}, 380 | }, 381 | { 382 | name: "__go_print_space", 383 | rfi: &ri.printSpace, 384 | }, 385 | { 386 | name: "__go_print_string", 387 | rfi: &ri.printString, 388 | args: []types.Type{String}, 389 | }, 390 | { 391 | name: "__go_print_uint64", 392 | rfi: &ri.printUint64, 393 | args: []types.Type{Int64}, 394 | }, 395 | { 396 | name: "__go_receive", 397 | rfi: &ri.receive, 398 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 399 | }, 400 | { 401 | name: "__go_recover", 402 | rfi: &ri.recover, 403 | res: []types.Type{EmptyInterface}, 404 | }, 405 | { 406 | name: "__go_register_gc_roots", 407 | rfi: &ri.registerGcRoots, 408 | args: []types.Type{UnsafePointer}, 409 | }, 410 | { 411 | name: "__go_runtime_error", 412 | rfi: &ri.runtimeError, 413 | args: []types.Type{Int32}, 414 | attrs: []llvm.Attribute{llvm.NoReturnAttribute}, 415 | }, 416 | { 417 | name: "runtime.selectdefault", 418 | rfi: &ri.selectdefault, 419 | args: []types.Type{UnsafePointer, Int32}, 420 | }, 421 | { 422 | name: "runtime.selectgo", 423 | rfi: &ri.selectgo, 424 | args: []types.Type{UnsafePointer}, 425 | res: []types.Type{Int}, 426 | }, 427 | { 428 | name: "runtime.selectrecv2", 429 | rfi: &ri.selectrecv2, 430 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32}, 431 | }, 432 | { 433 | name: "runtime.selectsend", 434 | rfi: &ri.selectsend, 435 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32}, 436 | }, 437 | { 438 | name: "__go_send_big", 439 | rfi: &ri.sendBig, 440 | args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer}, 441 | }, 442 | { 443 | name: "__go_set_closure", 444 | rfi: &ri.setClosure, 445 | args: []types.Type{UnsafePointer}, 446 | }, 447 | { 448 | name: "__go_set_defer_retaddr", 449 | rfi: &ri.setDeferRetaddr, 450 | args: []types.Type{UnsafePointer}, 451 | res: []types.Type{Bool}, 452 | }, 453 | { 454 | name: "__go_strcmp", 455 | rfi: &ri.strcmp, 456 | args: []types.Type{String, String}, 457 | res: []types.Type{Int}, 458 | }, 459 | { 460 | name: "__go_string_plus", 461 | rfi: &ri.stringPlus, 462 | args: []types.Type{String, String}, 463 | res: []types.Type{String}, 464 | }, 465 | { 466 | name: "__go_string_slice", 467 | rfi: &ri.stringSlice, 468 | args: []types.Type{String, Int, Int}, 469 | res: []types.Type{String}, 470 | }, 471 | { 472 | name: "__go_string_to_int_array", 473 | rfi: &ri.stringToIntArray, 474 | args: []types.Type{String}, 475 | res: []types.Type{IntSlice}, 476 | }, 477 | { 478 | name: "runtime.stringiter2", 479 | rfi: &ri.stringiter2, 480 | args: []types.Type{String, Int}, 481 | res: []types.Type{Int, Rune}, 482 | }, 483 | { 484 | name: "__go_type_descriptors_equal", 485 | rfi: &ri.typeDescriptorsEqual, 486 | args: []types.Type{UnsafePointer, UnsafePointer}, 487 | res: []types.Type{Bool}, 488 | }, 489 | { 490 | name: "__go_undefer", 491 | rfi: &ri.undefer, 492 | args: []types.Type{UnsafePointer}, 493 | }, 494 | } { 495 | rt.rfi.init(tm, module, rt.name, rt.args, rt.res) 496 | for _, attr := range rt.attrs { 497 | rt.rfi.fn.AddFunctionAttr(attr) 498 | } 499 | } 500 | 501 | memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth()) 502 | memsetType := llvm.FunctionType( 503 | llvm.VoidType(), 504 | []llvm.Type{ 505 | llvm.PointerType(llvm.Int8Type(), 0), 506 | llvm.Int8Type(), 507 | tm.target.IntPtrType(), 508 | llvm.Int32Type(), 509 | llvm.Int1Type(), 510 | }, 511 | false, 512 | ) 513 | ri.memset = llvm.AddFunction(module, memsetName, memsetType) 514 | 515 | memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth()) 516 | memcpyType := llvm.FunctionType( 517 | llvm.VoidType(), 518 | []llvm.Type{ 519 | llvm.PointerType(llvm.Int8Type(), 0), 520 | llvm.PointerType(llvm.Int8Type(), 0), 521 | tm.target.IntPtrType(), 522 | llvm.Int32Type(), 523 | llvm.Int1Type(), 524 | }, 525 | false, 526 | ) 527 | ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType) 528 | 529 | returnaddressType := llvm.FunctionType( 530 | llvm.PointerType(llvm.Int8Type(), 0), 531 | []llvm.Type{llvm.Int32Type()}, 532 | false, 533 | ) 534 | ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType) 535 | 536 | gccgoPersonalityType := llvm.FunctionType( 537 | llvm.Int32Type(), 538 | []llvm.Type{ 539 | llvm.Int32Type(), 540 | llvm.Int64Type(), 541 | llvm.PointerType(llvm.Int8Type(), 0), 542 | llvm.PointerType(llvm.Int8Type(), 0), 543 | }, 544 | false, 545 | ) 546 | ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType) 547 | 548 | ri.gccgoExceptionType = llvm.StructType( 549 | []llvm.Type{ 550 | llvm.PointerType(llvm.Int8Type(), 0), 551 | llvm.Int32Type(), 552 | }, 553 | false, 554 | ) 555 | 556 | return &ri, nil 557 | } 558 | 559 | func (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value { 560 | switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); { 561 | case n < 0: 562 | v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name) 563 | case n > 0: 564 | v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name) 565 | } 566 | return v 567 | } 568 | 569 | func (fr *frame) createMalloc(size llvm.Value, hasPointers bool) llvm.Value { 570 | var allocator *runtimeFnInfo 571 | if hasPointers { 572 | allocator = &fr.runtime.New 573 | } else { 574 | allocator = &fr.runtime.NewNopointers 575 | } 576 | 577 | return allocator.callOnly(fr, fr.createZExtOrTrunc(size, fr.target.IntPtrType(), ""))[0] 578 | } 579 | 580 | func (fr *frame) createTypeMalloc(t types.Type) llvm.Value { 581 | size := llvm.ConstInt(fr.target.IntPtrType(), uint64(fr.llvmtypes.Sizeof(t)), false) 582 | malloc := fr.createMalloc(size, hasPointers(t)) 583 | return fr.builder.CreateBitCast(malloc, llvm.PointerType(fr.types.ToLLVM(t), 0), "") 584 | } 585 | 586 | func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) { 587 | memset := fr.runtime.memset 588 | ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "") 589 | fill := llvm.ConstNull(llvm.Int8Type()) 590 | size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") 591 | align := llvm.ConstInt(llvm.Int32Type(), 1, false) 592 | isvolatile := llvm.ConstNull(llvm.Int1Type()) 593 | fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, align, isvolatile}, "") 594 | } 595 | 596 | func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) { 597 | memcpy := fr.runtime.memcpy 598 | dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "") 599 | src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "") 600 | size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "") 601 | align := llvm.ConstInt(llvm.Int32Type(), 1, false) 602 | isvolatile := llvm.ConstNull(llvm.Int1Type()) 603 | fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, align, isvolatile}, "") 604 | } 605 | 606 | func (fr *frame) returnAddress(level uint64) llvm.Value { 607 | returnaddress := fr.runtime.returnaddress 608 | levelValue := llvm.ConstInt(llvm.Int32Type(), level, false) 609 | return fr.builder.CreateCall(returnaddress, []llvm.Value{levelValue}, "") 610 | } 611 | -------------------------------------------------------------------------------- /irgen/slice.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | "llvm.org/llvm/bindings/go/llvm" 10 | ) 11 | 12 | // makeSlice allocates a new slice with the optional length and capacity, 13 | // initialising its contents to their zero values. 14 | func (fr *frame) makeSlice(sliceType types.Type, length, capacity *govalue) *govalue { 15 | length = fr.convert(length, types.Typ[types.Uintptr]) 16 | capacity = fr.convert(capacity, types.Typ[types.Uintptr]) 17 | runtimeType := fr.types.ToRuntime(sliceType) 18 | llslice := fr.runtime.makeSlice.call(fr, runtimeType, length.value, capacity.value) 19 | return newValue(llslice[0], sliceType) 20 | } 21 | 22 | func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value { 23 | if !low.IsNil() { 24 | low = fr.createZExtOrTrunc(low, fr.types.inttype, "") 25 | } else { 26 | low = llvm.ConstNull(fr.types.inttype) 27 | } 28 | if !high.IsNil() { 29 | high = fr.createZExtOrTrunc(high, fr.types.inttype, "") 30 | } 31 | if !max.IsNil() { 32 | max = fr.createZExtOrTrunc(max, fr.types.inttype, "") 33 | } 34 | 35 | var arrayptr, arraylen, arraycap llvm.Value 36 | var elemtyp types.Type 37 | var errcode uint64 38 | switch typ := xtyp.Underlying().(type) { 39 | case *types.Pointer: // *array 40 | errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS 41 | arraytyp := typ.Elem().Underlying().(*types.Array) 42 | elemtyp = arraytyp.Elem() 43 | arrayptr = x 44 | arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "") 45 | arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) 46 | arraycap = arraylen 47 | case *types.Slice: 48 | errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS 49 | elemtyp = typ.Elem() 50 | arrayptr = fr.builder.CreateExtractValue(x, 0, "") 51 | arraylen = fr.builder.CreateExtractValue(x, 1, "") 52 | arraycap = fr.builder.CreateExtractValue(x, 2, "") 53 | case *types.Basic: 54 | if high.IsNil() { 55 | high = llvm.ConstAllOnes(fr.types.inttype) // -1 56 | } 57 | result := fr.runtime.stringSlice.call(fr, x, low, high) 58 | return result[0] 59 | default: 60 | panic("unimplemented") 61 | } 62 | if high.IsNil() { 63 | high = arraylen 64 | } 65 | if max.IsNil() { 66 | max = arraycap 67 | } 68 | 69 | // Bounds checking: 0 <= low <= high <= max <= cap 70 | zero := llvm.ConstNull(fr.types.inttype) 71 | l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "") 72 | hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "") 73 | mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "") 74 | cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "") 75 | 76 | cond := fr.builder.CreateOr(l0, hl, "") 77 | cond = fr.builder.CreateOr(cond, mh, "") 78 | cond = fr.builder.CreateOr(cond, cm, "") 79 | 80 | fr.condBrRuntimeError(cond, errcode) 81 | 82 | slicelen := fr.builder.CreateSub(high, low, "") 83 | slicecap := fr.builder.CreateSub(max, low, "") 84 | 85 | elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false) 86 | offset := fr.builder.CreateMul(low, elemsize, "") 87 | 88 | sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "") 89 | 90 | llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx) 91 | sliceValue := llvm.Undef(llslicetyp) 92 | sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "") 93 | sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "") 94 | sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "") 95 | 96 | return sliceValue 97 | } 98 | -------------------------------------------------------------------------------- /irgen/strings.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "go/token" 9 | "golang.org/x/tools/go/types" 10 | "llvm.org/llvm/bindings/go/llvm" 11 | ) 12 | 13 | func (fr *frame) concatenateStrings(lhs, rhs *govalue) *govalue { 14 | result := fr.runtime.stringPlus.call(fr, lhs.value, rhs.value) 15 | return newValue(result[0], types.Typ[types.String]) 16 | } 17 | 18 | func (fr *frame) compareStrings(lhs, rhs *govalue, op token.Token) *govalue { 19 | result := fr.runtime.strcmp.call(fr, lhs.value, rhs.value)[0] 20 | zero := llvm.ConstNull(fr.types.inttype) 21 | var pred llvm.IntPredicate 22 | switch op { 23 | case token.EQL: 24 | pred = llvm.IntEQ 25 | case token.LSS: 26 | pred = llvm.IntSLT 27 | case token.GTR: 28 | pred = llvm.IntSGT 29 | case token.LEQ: 30 | pred = llvm.IntSLE 31 | case token.GEQ: 32 | pred = llvm.IntSGE 33 | case token.NEQ: 34 | panic("NEQ is handled in govalue.BinaryOp") 35 | default: 36 | panic("unreachable") 37 | } 38 | result = fr.builder.CreateICmp(pred, result, zero, "") 39 | result = fr.builder.CreateZExt(result, llvm.Int8Type(), "") 40 | return newValue(result, types.Typ[types.Bool]) 41 | } 42 | 43 | // stringIndex implements v = m[i] 44 | func (fr *frame) stringIndex(s, i *govalue) *govalue { 45 | ptr := fr.builder.CreateExtractValue(s.value, 0, "") 46 | ptr = fr.builder.CreateGEP(ptr, []llvm.Value{i.value}, "") 47 | return newValue(fr.builder.CreateLoad(ptr, ""), types.Typ[types.Byte]) 48 | } 49 | 50 | func (fr *frame) stringIterInit(str *govalue) []*govalue { 51 | indexptr := fr.allocaBuilder.CreateAlloca(fr.types.inttype, "") 52 | fr.builder.CreateStore(llvm.ConstNull(fr.types.inttype), indexptr) 53 | return []*govalue{str, newValue(indexptr, types.Typ[types.Int])} 54 | } 55 | 56 | // stringIterNext advances the iterator, and returns the tuple (ok, k, v). 57 | func (fr *frame) stringIterNext(iter []*govalue) []*govalue { 58 | str, indexptr := iter[0], iter[1] 59 | k := fr.builder.CreateLoad(indexptr.value, "") 60 | 61 | result := fr.runtime.stringiter2.call(fr, str.value, k) 62 | fr.builder.CreateStore(result[0], indexptr.value) 63 | ok := fr.builder.CreateIsNotNull(result[0], "") 64 | ok = fr.builder.CreateZExt(ok, llvm.Int8Type(), "") 65 | v := result[1] 66 | 67 | return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, types.Typ[types.Int]), newValue(v, types.Typ[types.Rune])} 68 | } 69 | 70 | func (fr *frame) runeToString(v *govalue) *govalue { 71 | v = fr.convert(v, types.Typ[types.Int]) 72 | result := fr.runtime.intToString.call(fr, v.value) 73 | return newValue(result[0], types.Typ[types.String]) 74 | } 75 | 76 | func (fr *frame) stringToRuneSlice(v *govalue) *govalue { 77 | result := fr.runtime.stringToIntArray.call(fr, v.value) 78 | runeslice := types.NewSlice(types.Typ[types.Rune]) 79 | return newValue(result[0], runeslice) 80 | } 81 | 82 | func (fr *frame) runeSliceToString(v *govalue) *govalue { 83 | llv := v.value 84 | ptr := fr.builder.CreateExtractValue(llv, 0, "") 85 | len := fr.builder.CreateExtractValue(llv, 1, "") 86 | result := fr.runtime.intArrayToString.call(fr, ptr, len) 87 | return newValue(result[0], types.Typ[types.String]) 88 | } 89 | -------------------------------------------------------------------------------- /irgen/targets.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "fmt" 9 | "strings" 10 | 11 | "llvm.org/llvm/bindings/go/llvm" 12 | ) 13 | 14 | // PNaClTriple is the LLVM target triple that should be used to compile 15 | // modules to be compatible with PNaCl (Portable Native Client). 16 | const PNaClTriple = "armv7-none-linux-gnueabi" 17 | 18 | // Below are the target data representation constants generated by clang. 19 | // For unknown targets, we enumerate all targets known to LLVM and use 20 | // the first one with a matching architecture. 21 | const ( 22 | x86TargetData = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" 23 | ) 24 | 25 | // llvmDataLayout returns the data layout string 26 | // representation for the specified LLVM triple. 27 | func llvmDataLayout(triple string) (string, error) { 28 | // Triples are several fields separated by '-' characters. 29 | // The first field is the architecture. The architecture's 30 | // canonical form may include a '-' character, which would 31 | // have been translated to '_' for inclusion in a triple. 32 | arch := parseArch(triple[:strings.IndexRune(triple, '-')]) 33 | switch arch { 34 | case "x86-64": 35 | return x86TargetData, nil 36 | } 37 | for target := llvm.FirstTarget(); target.C != nil; target = target.NextTarget() { 38 | if arch == target.Name() { 39 | machine := target.CreateTargetMachine( 40 | triple, "", "", 41 | llvm.CodeGenLevelDefault, 42 | llvm.RelocDefault, 43 | llvm.CodeModelDefault, 44 | ) 45 | target := machine.TargetData().String() 46 | machine.Dispose() 47 | return target, nil 48 | } 49 | } 50 | return "", fmt.Errorf("Invalid target triple: %s", triple) 51 | } 52 | 53 | // Based on parseArch from LLVM's lib/Support/Triple.cpp. 54 | // This is used to match the target machine type. 55 | func parseArch(arch string) string { 56 | switch arch { 57 | case "i386", "i486", "i586", "i686", "i786", "i886", "i986": 58 | return "x86" 59 | case "amd64", "x86_64": 60 | return "x86-64" 61 | case "powerpc": 62 | return "ppc" 63 | case "powerpc64", "ppu": 64 | return "ppc64" 65 | case "mblaze": 66 | return "mblaze" 67 | case "arm", "xscale": 68 | return "arm" 69 | case "thumb": 70 | return "thumb" 71 | case "spu", "cellspu": 72 | return "cellspu" 73 | case "msp430": 74 | return "msp430" 75 | case "mips", "mipseb", "mipsallegrex": 76 | return "mips" 77 | case "mipsel", "mipsallegrexel": 78 | return "mipsel" 79 | case "mips64", "mips64eb": 80 | return "mips64" 81 | case "mipsel64": 82 | return "mipsel64" 83 | case "r600", "hexagon", "sparc", "sparcv9", "tce", 84 | "xcore", "nvptx", "nvptx64", "le32", "amdil": 85 | return arch 86 | } 87 | if strings.HasPrefix(arch, "armv") { 88 | return "arm" 89 | } else if strings.HasPrefix(arch, "thumbv") { 90 | return "thumb" 91 | } 92 | return "unknown" 93 | } 94 | -------------------------------------------------------------------------------- /irgen/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | import ( 8 | "golang.org/x/tools/go/types" 9 | ) 10 | 11 | func deref(t types.Type) types.Type { 12 | return t.Underlying().(*types.Pointer).Elem() 13 | } 14 | -------------------------------------------------------------------------------- /irgen/utils.go: -------------------------------------------------------------------------------- 1 | package irgen 2 | 3 | import ( 4 | "golang.org/x/tools/go/types" 5 | "llvm.org/llvm/bindings/go/llvm" 6 | ) 7 | 8 | func (fr *frame) loadOrNull(cond, ptr llvm.Value, ty types.Type) *govalue { 9 | startbb := fr.builder.GetInsertBlock() 10 | loadbb := llvm.AddBasicBlock(fr.function, "") 11 | contbb := llvm.AddBasicBlock(fr.function, "") 12 | fr.builder.CreateCondBr(cond, loadbb, contbb) 13 | 14 | fr.builder.SetInsertPointAtEnd(loadbb) 15 | llty := fr.types.ToLLVM(ty) 16 | typedptr := fr.builder.CreateBitCast(ptr, llvm.PointerType(llty, 0), "") 17 | loadedval := fr.builder.CreateLoad(typedptr, "") 18 | fr.builder.CreateBr(contbb) 19 | 20 | fr.builder.SetInsertPointAtEnd(contbb) 21 | llv := fr.builder.CreatePHI(llty, "") 22 | llv.AddIncoming( 23 | []llvm.Value{llvm.ConstNull(llty), loadedval}, 24 | []llvm.BasicBlock{startbb, loadbb}, 25 | ) 26 | return newValue(llv, ty) 27 | } 28 | -------------------------------------------------------------------------------- /irgen/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package irgen 6 | 7 | const ( 8 | goVersion = "go1.3" 9 | version = "0.1" 10 | ) 11 | 12 | // GoVersion returns the version of Go that we are targeting. 13 | func GoVersion() string { 14 | return goVersion 15 | } 16 | 17 | // Version returns the version of the llgo compiler. 18 | func Version() string { 19 | return version 20 | } 21 | -------------------------------------------------------------------------------- /llgo-go.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | scriptpath=$(which "$0") 4 | scriptpath=$(readlink -f "$scriptpath") 5 | bindir=$(dirname "$scriptpath") 6 | prefix=$(dirname "$bindir") 7 | 8 | cmd="$1" 9 | 10 | case "$cmd" in 11 | build | get | install | run | test) 12 | shift 13 | PATH="$prefix/lib/llgo/go-path:$PATH" exec go "$cmd" -compiler gccgo "$@" 14 | ;; 15 | 16 | *) 17 | exec go "$@" 18 | ;; 19 | esac 20 | -------------------------------------------------------------------------------- /ssaopt/esc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The llgo Authors. 2 | // Use of this source code is governed by an MIT-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ssaopt 6 | 7 | import ( 8 | "go/token" 9 | 10 | "golang.org/x/tools/go/ssa" 11 | ) 12 | 13 | func escapes(val ssa.Value, bb *ssa.BasicBlock, pending []ssa.Value) bool { 14 | for _, p := range pending { 15 | if val == p { 16 | return false 17 | } 18 | } 19 | 20 | for _, ref := range *val.Referrers() { 21 | switch ref := ref.(type) { 22 | case *ssa.Phi: 23 | // We must consider the variable to have escaped if it is 24 | // possible for the program to see more than one "version" 25 | // of the variable at once, as this requires the program 26 | // to use heap allocation for the multiple versions. 27 | // 28 | // I (pcc) think that this is only possible (without stores) 29 | // in the case where a phi node that (directly or indirectly) 30 | // refers to the allocation dominates the allocation. 31 | if ref.Block().Dominates(bb) { 32 | return true 33 | } 34 | if escapes(ref, bb, append(pending, val)) { 35 | return true 36 | } 37 | 38 | case *ssa.BinOp, *ssa.ChangeType, *ssa.Convert, *ssa.ChangeInterface, *ssa.MakeInterface, *ssa.Slice, *ssa.FieldAddr, *ssa.IndexAddr, *ssa.TypeAssert, *ssa.Extract: 39 | if escapes(ref.(ssa.Value), bb, append(pending, val)) { 40 | return true 41 | } 42 | 43 | case *ssa.Range, *ssa.DebugRef: 44 | continue 45 | 46 | case *ssa.UnOp: 47 | if ref.Op == token.MUL || ref.Op == token.ARROW { 48 | continue 49 | } 50 | if escapes(ref, bb, append(pending, val)) { 51 | return true 52 | } 53 | 54 | case *ssa.Store: 55 | if val == ref.Val { 56 | return true 57 | } 58 | 59 | case *ssa.Call: 60 | if builtin, ok := ref.Call.Value.(*ssa.Builtin); ok { 61 | switch builtin.Name() { 62 | case "cap", "len", "copy", "ssa:wrapnilchk": 63 | continue 64 | case "append": 65 | if ref.Call.Args[0] == val && escapes(ref, bb, append(pending, val)) { 66 | return true 67 | } 68 | default: 69 | return true 70 | } 71 | } else { 72 | return true 73 | } 74 | 75 | default: 76 | return true 77 | } 78 | } 79 | 80 | return false 81 | } 82 | 83 | func LowerAllocsToStack(f *ssa.Function) { 84 | pending := make([]ssa.Value, 0, 10) 85 | 86 | for _, b := range f.Blocks { 87 | for _, instr := range b.Instrs { 88 | if alloc, ok := instr.(*ssa.Alloc); ok && alloc.Heap && !escapes(alloc, alloc.Block(), pending) { 89 | alloc.Heap = false 90 | f.Locals = append(f.Locals, alloc) 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /test/debuginfo/emptyname.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -c -o /dev/null -g %s 2 | 3 | package main 4 | 5 | //line :1 6 | func main() { 7 | } 8 | -------------------------------------------------------------------------------- /test/execution/Inputs/init2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func init() { 4 | println("do some other stuff before main") 5 | } 6 | -------------------------------------------------------------------------------- /test/execution/arrays/compare.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | a := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 10 | b := [...]int{10, 1, 2, 3, 4, 5, 6, 7, 8, 9} 11 | c := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 12 | 13 | println(a == b) 14 | println(a == c) 15 | println(b == c) 16 | } 17 | -------------------------------------------------------------------------------- /test/execution/arrays/index.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func testBasics() { 9 | var i [2]int 10 | j := &i 11 | i[0] = 123 12 | i[1] = 456 13 | println(i[0], i[1]) 14 | println(j[0], j[1]) 15 | i[0]++ 16 | i[1]-- 17 | println(i[0], i[1]) 18 | println(j[0], j[1]) 19 | } 20 | 21 | func testByteIndex() { 22 | var a [255]int 23 | for i := 0; i < len(a); i++ { 24 | a[i] = i 25 | } 26 | for i := byte(0); i < byte(len(a)); i++ { 27 | println(a[i]) 28 | } 29 | } 30 | 31 | func main() { 32 | //testBasics() 33 | testByteIndex() 34 | } 35 | -------------------------------------------------------------------------------- /test/execution/arrays/range.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | a := [...]int{1: 1, 2: 2, 4: 4} 10 | for i, val := range a { 11 | println(i, val, a[i]) 12 | } 13 | for i, val := range [...]int{10, 20, 30} { 14 | println(i, val) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/execution/arrays/slice.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var a [10]int 10 | b := a[1:] 11 | println(len(a)) 12 | println(len(b)) 13 | } 14 | -------------------------------------------------------------------------------- /test/execution/assignment/arrays.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | var a1 = [...]float32{1.0, 2.0, 3.0} 9 | 10 | func main() { 11 | var a2 [3]float32 12 | a2 = a1 13 | println(a2[0]) 14 | println(a2[1]) 15 | println(a2[2]) 16 | 17 | // broken due to lack of promotion of 18 | // stack to heap. 19 | //println(a2[0], a2[1], a2[2]) 20 | } 21 | -------------------------------------------------------------------------------- /test/execution/assignment/binop.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := 123 10 | x *= 2 11 | println(x) 12 | x /= 2 13 | println(x) 14 | x += 1 15 | println(x) 16 | x -= 1 17 | println(x) 18 | } 19 | -------------------------------------------------------------------------------- /test/execution/assignment/dereferencing.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var x int 10 | px := &x 11 | *px = 123 12 | println(x) 13 | } 14 | -------------------------------------------------------------------------------- /test/execution/assignment/multi.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func xyz() (int, int) { 9 | return 123, 456 10 | } 11 | 12 | func abc() (int, int) { 13 | var a, b = xyz() 14 | return a, b 15 | } 16 | 17 | type S struct { 18 | a int 19 | b int 20 | } 21 | 22 | func main() { 23 | a, b := xyz() 24 | println(a, b) 25 | b, a = abc() 26 | println(a, b) 27 | 28 | // swap 29 | println(a, b) 30 | a, b = b, a 31 | println(a, b) 32 | 33 | var s S 34 | s.a, s.b = a, b 35 | println(s.a, s.b) 36 | } 37 | -------------------------------------------------------------------------------- /test/execution/assignment/namedresult.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f1() (x int) { 9 | x = 123 10 | return 11 | } 12 | 13 | func f2() (x int) { 14 | return 456 15 | } 16 | 17 | func f3() (x, y int) { 18 | y, x = 2, 1 19 | return 20 | } 21 | 22 | func f4() (x, _ int) { 23 | x = 666 24 | return 25 | } 26 | 27 | func main() { 28 | x := f1() 29 | println(x) 30 | x = f2() 31 | println(x) 32 | 33 | var y int 34 | x, y = f3() 35 | println(x, y) 36 | 37 | x, y = f4() 38 | println(x, y) 39 | } 40 | -------------------------------------------------------------------------------- /test/execution/branching/goto.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f1() { 9 | goto labeled 10 | labeled: 11 | goto done 12 | return 13 | done: 14 | println("!") 15 | } 16 | 17 | func main() { 18 | i := 0 19 | start: 20 | if i < 10 { 21 | println(i) 22 | i++ 23 | goto start 24 | } else { 25 | goto end 26 | } 27 | return 28 | end: 29 | println("done") 30 | f1() 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /test/execution/branching/labeled.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func labeledBreak() { 9 | var i int 10 | L: 11 | for ; i < 10; i++ { 12 | switch { 13 | default: 14 | break L 15 | } 16 | } 17 | println(i) 18 | } 19 | 20 | func main() { 21 | labeledBreak() 22 | } 23 | -------------------------------------------------------------------------------- /test/execution/chan/buffered.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | c := make(chan int) 10 | println(len(c), cap(c)) 11 | c1 := make(chan int, 1) 12 | println(len(c1), cap(c1)) 13 | f := func() { 14 | n, ok := <-c 15 | if ok { 16 | c1 <- n * 10 17 | } else { 18 | c1 <- -1 19 | } 20 | } 21 | for i := 0; i < 10; i++ { 22 | go f() 23 | c <- i + 1 24 | println(<-c1) 25 | } 26 | go f() 27 | close(c) 28 | println(<-c1) 29 | } 30 | -------------------------------------------------------------------------------- /test/execution/chan/range.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | ch := make(chan int) 10 | go func() { 11 | for i := 0; i < 10; i++ { 12 | ch <- i 13 | } 14 | close(ch) 15 | }() 16 | for n := range ch { 17 | println(n) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/chan/select.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f1() { 9 | c := make(chan int, 1) 10 | for i := 0; i < 3; i++ { 11 | select { 12 | case n, _ := <-c: 13 | println("received", n) 14 | c = nil 15 | case c <- 123: 16 | println("sent a value") 17 | default: 18 | println("default") 19 | } 20 | } 21 | } 22 | 23 | func main() { 24 | f1() 25 | } 26 | -------------------------------------------------------------------------------- /test/execution/chan/self.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | ch := make(chan int, uint8(1)) 10 | 11 | ch <- 1 12 | println(<-ch) 13 | 14 | ch <- 2 15 | x, ok := <-ch 16 | println(x) 17 | println(ok) 18 | } 19 | -------------------------------------------------------------------------------- /test/execution/circulartype.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type A struct { 9 | b1, b2 B 10 | } 11 | 12 | type B struct { 13 | a1, a2 *A 14 | } 15 | 16 | func main() { 17 | var a A 18 | _ = a 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/closures/basic.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func cat(a, b string) func(string) string { 9 | return func(c string) string { return a + b + c } 10 | } 11 | 12 | func main() { 13 | f := cat("a", "b") 14 | println(f("c")) 15 | } 16 | -------------------------------------------------------------------------------- /test/execution/closures/issue176.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | a := false 10 | f := func() { 11 | make(chan *bool, 1) <- &a 12 | } 13 | f() 14 | println(a) 15 | } 16 | -------------------------------------------------------------------------------- /test/execution/complex.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var f32 float32 = 1 10 | var f64 float64 = 1 11 | c64 := complex(f32, f32+1) 12 | println(c64) 13 | println(-c64) 14 | println(c64 == c64) 15 | c128 := complex(f64, f64+1) 16 | println(c128) 17 | println(-c128) 18 | println(c128 == c128) 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/const.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "runtime" 9 | 10 | const ( 11 | a = iota * 2 12 | A = 1 13 | B 14 | C 15 | D = Z + iota 16 | ) 17 | 18 | const ( 19 | Z = iota 20 | Big = 1<<31 - 1 21 | Big2 = -2147483648 22 | Big3 = 2147483647 23 | ) 24 | 25 | const ( 26 | expbits32 uint = 8 27 | bias32 = -1<<(expbits32-1) + 1 28 | darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" 29 | ) 30 | 31 | func f1() float32 { 32 | return 0 33 | } 34 | 35 | func constArrayLen() { 36 | a := [...]int{1, 2, 3} 37 | const x = len(a) 38 | println(x) 39 | } 40 | 41 | func main() { 42 | println(a) 43 | println(B) 44 | println(A, A) 45 | println(A, B, C, D) 46 | println(Big) 47 | println(Big2) 48 | println(Big3) 49 | println(bias32) 50 | 51 | // Currently fails, due to difference in C printf and Go's println 52 | // formatting of the exponent. 53 | //println(10 * 1e9) 54 | println(darwinAMD64) 55 | 56 | // Test conversion. 57 | println(int64(10) * 1e9) 58 | 59 | // Ensure consts work just as well when declared inside a function. 60 | const ( 61 | x_ = iota 62 | y_ 63 | ) 64 | println(y_) 65 | 66 | constArrayLen() 67 | } 68 | -------------------------------------------------------------------------------- /test/execution/conversions/complex.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func constIntToComplex() complex128 { 9 | return 0 10 | } 11 | 12 | func main() { 13 | var c64 complex64 14 | var c128 complex128 15 | c128 = complex128(c64) 16 | c64 = complex64(c128) 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/conversions/float.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | // float to int 10 | for _, f32 := range []float32{123.456, -123.456} { 11 | println(int8(f32)) 12 | println(int16(f32)) 13 | println(int32(f32)) 14 | println(int64(f32)) 15 | println(uint8(f32)) 16 | println(uint16(f32)) 17 | println(uint32(f32)) 18 | println(uint64(f32)) 19 | } 20 | for _, f64 := range []float64{123.456, -123.456} { 21 | println(int8(f64)) 22 | println(int16(f64)) 23 | println(int32(f64)) 24 | println(int64(f64)) 25 | println(uint8(f64)) 26 | println(uint16(f64)) 27 | println(uint32(f64)) 28 | println(uint64(f64)) 29 | } 30 | 31 | // int to float 32 | var i8 int8 = 123 33 | println(float32(i8)) 34 | println(float64(i8)) 35 | var ui8 uint8 = 123 36 | println(float32(ui8)) 37 | println(float64(ui8)) 38 | var i16 int32 = 12345 39 | println(float32(i16)) 40 | println(float64(i16)) 41 | var ui16 uint32 = 12345 42 | println(float32(ui16)) 43 | println(float64(ui16)) 44 | var i32 int32 = 123456 45 | println(float32(i32)) 46 | println(float64(i32)) 47 | var ui32 uint32 = 123456 48 | println(float32(ui32)) 49 | println(float64(ui32)) 50 | var i64 int64 = 12345678910 51 | println(float32(i64)) 52 | println(float64(i64)) 53 | var ui64 uint64 = 12345678910 54 | println(float32(ui64)) 55 | println(float64(ui64)) 56 | } 57 | -------------------------------------------------------------------------------- /test/execution/conversions/int.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func signed(i32 int32) { 9 | println(uint32(i32)) 10 | println(int64(i32)) 11 | println(uint64(i32)) 12 | } 13 | 14 | func unsigned(u32 uint32) { 15 | println(int32(u32)) 16 | println(int64(u32)) 17 | println(uint64(u32)) 18 | } 19 | 20 | func main() { 21 | signed(1<<31 - 1) 22 | signed(-1 << 31) 23 | signed(0) 24 | unsigned(1<<32 - 1) 25 | unsigned(0) 26 | unsigned(1) 27 | } 28 | -------------------------------------------------------------------------------- /test/execution/conversions/sameunderlying.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type X struct{} 9 | type Y X 10 | 11 | func main() { 12 | var x X 13 | px := &x 14 | py := (*Y)(&x) 15 | py = (*Y)(px) 16 | _ = py 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/defer.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type T struct { 9 | value int 10 | } 11 | 12 | type T1 struct { 13 | T 14 | } 15 | 16 | func (t T) abc() { 17 | println(t.value) 18 | } 19 | 20 | func (t *T) def() { 21 | println(t.value) 22 | } 23 | 24 | func (t *T) ghi(v int) { 25 | println(v) 26 | } 27 | 28 | func printerr(err interface{}) { 29 | if err != nil { 30 | println("recovered:", err.(string)) 31 | } else { 32 | println("recovered no error") 33 | } 34 | } 35 | 36 | func f6() { 37 | defer func() { printerr(recover()) }() 38 | defer func() { panic("second") }() 39 | panic("first") 40 | } 41 | 42 | func f5(panic_ bool) { 43 | var t1 T1 44 | t1.T.value = 888 45 | defer t1.abc() 46 | var f func(int) 47 | f = func(recursion int) { 48 | if recursion > 0 { 49 | f(recursion - 1) 50 | return 51 | } 52 | println("f5") 53 | printerr(recover()) 54 | } 55 | defer f(0) // will recover (after f(1)) 56 | defer f(1) // won't recover 57 | if panic_ { 58 | panic("meep meep") 59 | } 60 | } 61 | 62 | func f4() { 63 | var a T = T{999} 64 | var b *T = &a 65 | defer a.abc() 66 | defer a.def() 67 | defer a.ghi(123) 68 | defer b.abc() 69 | defer b.def() 70 | defer b.ghi(456) 71 | f5(true) 72 | f5(false) // verify the recover in f5 works 73 | } 74 | 75 | func f3() (a int) { 76 | defer func() { a *= 2 }() 77 | f4() 78 | return 123 79 | } 80 | 81 | func f2() { 82 | defer func() { println("f2.3") }() 83 | defer func(s string) { println(s) }("f2.2") 84 | println("f2.1") 85 | println(f3()) 86 | } 87 | 88 | func f1() { 89 | defer func() { println("f1.2") }() 90 | defer func() { println("f1.1") }() 91 | f2() 92 | } 93 | 94 | func builtins() { 95 | defer println("ahoy") 96 | } 97 | 98 | func main() { 99 | f1() 100 | f6() 101 | builtins() 102 | } 103 | -------------------------------------------------------------------------------- /test/execution/errors/recover.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | err := recover() 10 | println(err) 11 | } 12 | -------------------------------------------------------------------------------- /test/execution/for/branch.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | for i := 0; true; i++ { 10 | println(i) 11 | if i == 2 { 12 | println(3) 13 | break 14 | } 15 | println(1) 16 | i++ 17 | continue 18 | println("unreachable") 19 | } 20 | 21 | nums := [...]int{0, 1, 2, 3, 4, 5} 22 | for n := range nums { 23 | if n == 1 { 24 | continue 25 | } 26 | println(n) 27 | if n == 4 { 28 | { 29 | break 30 | } 31 | println("!") 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/execution/fun.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | // vim: set ft=go : 7 | 8 | package main 9 | 10 | func test() func() int { 11 | return blah 12 | } 13 | 14 | func blah() int { 15 | return 123 16 | } 17 | 18 | func sret() (int, bool, bool) { 19 | return 123, true, false 20 | } 21 | 22 | func main() { 23 | f := test() 24 | println(2 * f()) 25 | a, b, c := sret() 26 | println(a, b, c) 27 | } 28 | -------------------------------------------------------------------------------- /test/execution/functions/compare.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var f func() 10 | println(f == nil) 11 | println(f != nil) 12 | println(nil == f) 13 | println(nil != f) 14 | f = func() {} 15 | println(f == nil) 16 | println(f != nil) 17 | println(nil == f) 18 | println(nil != f) 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/functions/multivalue.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func swap(a, b int) (int, int) { 9 | return b, a 10 | } 11 | 12 | func sub(a, b int) int { 13 | return a - b 14 | } 15 | 16 | func printint(a int, extra ...int) { 17 | println(a) 18 | for _, b := range extra { 19 | println("extra:", b) 20 | } 21 | } 22 | 23 | func main() { 24 | println(sub(swap(1, 2))) 25 | printint(swap(10, 20)) 26 | } 27 | -------------------------------------------------------------------------------- /test/execution/functions/unreachable.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f1() { 9 | if true { 10 | println("f1") 11 | return 12 | } 13 | for { 14 | } 15 | } 16 | 17 | func f2() { 18 | defer func() { println("f2") }() 19 | if true { 20 | return 21 | } 22 | for { 23 | } 24 | } 25 | 26 | func f3() int { 27 | if true { 28 | println("f3") 29 | return 123 30 | } 31 | for { 32 | } 33 | } 34 | 35 | func f4() int { 36 | defer func() { println("f4") }() 37 | if true { 38 | return 123 39 | } 40 | for { 41 | } 42 | } 43 | 44 | func main() { 45 | f1() 46 | f2() 47 | f3() 48 | println(f4()) 49 | } 50 | -------------------------------------------------------------------------------- /test/execution/go.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type T struct { 9 | val int 10 | } 11 | 12 | func (t T) Hello(done chan bool) { 13 | println("hello from T", t.val) 14 | done <- true 15 | } 16 | 17 | type I interface { 18 | Hello(chan bool) 19 | } 20 | 21 | func main() { 22 | done := make(chan bool) 23 | 24 | t := T{1} 25 | go t.Hello(done) 26 | <-done 27 | 28 | var i I = T{2} 29 | go i.Hello(done) 30 | <-done 31 | 32 | go println("hello builtin") 33 | } 34 | -------------------------------------------------------------------------------- /test/execution/if/lazy.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func False() bool { 9 | println("False()") 10 | return false 11 | } 12 | 13 | func True() bool { 14 | println("True()") 15 | return true 16 | } 17 | 18 | func main() { 19 | println(False() || False()) 20 | println(False() || True()) 21 | println(True() || False()) 22 | println(True() || True()) 23 | println(False() && False()) 24 | println(False() && True()) 25 | println(True() && False()) 26 | println(True() && True()) 27 | } 28 | -------------------------------------------------------------------------------- /test/execution/init.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s %p/Inputs/init2.go 2 | // RUN: %t 2>&1 | FileCheck %s 3 | 4 | package main 5 | 6 | // CHECK-DAG: do some other stuff before main 7 | //func init() 8 | 9 | // CHECK-DAG: do some stuff before main 10 | func init() { 11 | println("do some stuff before main") 12 | } 13 | 14 | // CHECK: main has been called 15 | func main() { 16 | println("main has been called") 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/interfaces/assert.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type X struct{ x int } 9 | 10 | func (x *X) F1() { println("(*X).F1:", x.x) } 11 | func (x *X) F2() { println("(*X).F2") } 12 | 13 | type I interface { 14 | F1() 15 | F2() 16 | } 17 | 18 | func main() { 19 | var x interface{} 20 | 21 | // x is nil. Let's make sure an assertion on it 22 | // won't cause a panic. 23 | if x, ok := x.(int32); ok { 24 | println("i2v:", x) 25 | } 26 | if x == nil { 27 | println("x is nil") 28 | } 29 | 30 | x = int32(123456) 31 | 32 | // Let's try an interface-to-value assertion. 33 | if x, ok := x.(int32); ok { 34 | println("i2v:", x) 35 | } 36 | if x, ok := x.(int64); ok { 37 | println("i2v:", x) 38 | } 39 | 40 | // This will fail the assertion. 41 | if i, ok := x.(I); ok { 42 | i.F1() 43 | _ = i 44 | } else { 45 | println("!") 46 | } 47 | 48 | // Assign an *X, which should pass the assertion. 49 | x_ := new(X) 50 | x_.x = 123456 51 | x = x_ //&X{x: 123456} 52 | if i, ok := x.(I); ok { 53 | i.F1() 54 | _ = i 55 | } else { 56 | println("!") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/execution/interfaces/basic.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type any interface{} 9 | 10 | type Stringer interface { 11 | String() string 12 | } 13 | 14 | type lessThanAWord struct { 15 | a byte 16 | } 17 | 18 | func (l lessThanAWord) String() string { 19 | return "!" 20 | } 21 | 22 | func makeAStringer() Stringer { 23 | return lessThanAWord{} 24 | } 25 | 26 | func main() { 27 | var x1, x2 int = 1, 2 28 | var y any = x1 29 | var z any = x2 30 | if y != z { 31 | println("expected: y != z") 32 | } else { 33 | println("unexpected: y == z") 34 | } 35 | /* 36 | if y == x1 { 37 | println("expected: y == x1") 38 | } else { 39 | println("unexpected: y == x1") 40 | } 41 | */ 42 | //println(y.(int)) 43 | } 44 | -------------------------------------------------------------------------------- /test/execution/interfaces/comparei2i.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | type I interface { 11 | X() 12 | } 13 | 14 | type T int 15 | 16 | func (t T) X() { 17 | } 18 | 19 | func main() { 20 | var highbit uint32 = 1 << 31 21 | var pos0 float32 = 0 22 | var neg0 float32 = *(*float32)(unsafe.Pointer(&highbit)) 23 | var i1 interface{} = pos0 24 | var i2 interface{} = neg0 25 | println(i1 == i2) 26 | var i3 interface{} = T(123) 27 | var i4 I = T(123) 28 | println(i3 == i4) 29 | } 30 | -------------------------------------------------------------------------------- /test/execution/interfaces/comparei2v.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var x interface{} = 123 10 | println(x == 123) 11 | println(x != 123) 12 | } 13 | -------------------------------------------------------------------------------- /test/execution/interfaces/e2i_conversion.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "io" 9 | 10 | type rdr struct{} 11 | 12 | func (r rdr) Read(b []byte) (int, error) { 13 | return 0, nil 14 | } 15 | 16 | func F(i interface{}) { 17 | _ = i.(io.Reader) 18 | } 19 | 20 | func main() { 21 | var r rdr 22 | F(r) 23 | F(&r) 24 | } 25 | -------------------------------------------------------------------------------- /test/execution/interfaces/embedded.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type BI interface { 9 | B() 10 | } 11 | 12 | type AI interface { 13 | A() 14 | BI 15 | } 16 | 17 | type S struct{} 18 | 19 | func (s S) A() { 20 | println("A") 21 | } 22 | 23 | func (s S) B() { 24 | println("B") 25 | } 26 | 27 | func main() { 28 | var ai AI = S{} 29 | ai.A() 30 | ai.B() 31 | } 32 | -------------------------------------------------------------------------------- /test/execution/interfaces/error.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | var errors = [...]string{} 9 | 10 | func itoa(val int) string { // do it here rather than with fmt to avoid dependency 11 | if val < 0 { 12 | return "-" + itoa(-val) 13 | } 14 | var buf [32]byte // big enough for int64 15 | i := len(buf) - 1 16 | for val >= 10 { 17 | buf[i] = byte(val%10 + '0') 18 | i-- 19 | val /= 10 20 | } 21 | buf[i] = byte(val + '0') 22 | return string(buf[i:]) 23 | } 24 | 25 | type Errno uintptr 26 | 27 | func (e Errno) Error() string { 28 | println("!!!!", uintptr(e)) 29 | if 0 <= int(e) && int(e) < len(errors) { 30 | s := errors[e] 31 | if s != "" { 32 | return s 33 | } 34 | } 35 | return "errno " + itoa(int(e)) 36 | } 37 | 38 | func main() { 39 | e := Errno(123) 40 | i := (interface{})(e) 41 | println(i.(error).Error()) 42 | } 43 | -------------------------------------------------------------------------------- /test/execution/interfaces/i2i_conversion.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type Numbered interface { 9 | Number() int 10 | } 11 | 12 | type Named interface { 13 | Name() string 14 | } 15 | 16 | type Beast struct{} 17 | 18 | func (b *Beast) Number() int { 19 | return 666 20 | } 21 | 22 | func (b *Beast) Name() string { 23 | return "The Beast" 24 | } 25 | 26 | func main() { 27 | var b Beast 28 | var numbered Numbered = &b 29 | var named Named = numbered.(Named) 30 | println(numbered.Number()) 31 | println(named.Name()) 32 | } 33 | -------------------------------------------------------------------------------- /test/execution/interfaces/import.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t 2>&1 | FileCheck %s 3 | 4 | package main 5 | 6 | import "syscall" 7 | 8 | type Signal interface { 9 | Signal() 10 | } 11 | 12 | func main() { 13 | var s Signal = syscall.SIGINT 14 | // CHECK: ({{.*}},{{.*}}) 15 | println(s) 16 | } 17 | -------------------------------------------------------------------------------- /test/execution/interfaces/methods.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type Stringer interface { 9 | String() string 10 | } 11 | 12 | type X int 13 | type Y int 14 | 15 | type Z1 struct { 16 | X 17 | } 18 | 19 | type Z2 struct { 20 | Stringer 21 | } 22 | 23 | func (x X) String() string { 24 | return "X()" 25 | } 26 | 27 | func (y *Y) String() string { 28 | return "Y()" 29 | } 30 | 31 | func makeX() X { 32 | return X(0) 33 | } 34 | 35 | func main() { 36 | var z Stringer = X(0) 37 | println(z.String()) 38 | 39 | z = new(Y) 40 | println(z.String()) 41 | 42 | z = Z1{} 43 | println(z.String()) 44 | 45 | z = Z2{new(Y)} 46 | println(z.String()) 47 | 48 | println(makeX().String()) 49 | } 50 | -------------------------------------------------------------------------------- /test/execution/interfaces/static_conversion.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type Blah interface{} 9 | type Numbered interface { 10 | Blah 11 | Number() int 12 | } 13 | 14 | type Beast struct{} 15 | 16 | func (b *Beast) Number() int { 17 | return 666 18 | } 19 | 20 | type MagicNumber int 21 | 22 | func (m MagicNumber) Number() int { 23 | return int(m) 24 | } 25 | 26 | func main() { 27 | var b Beast 28 | var m MagicNumber = 3 29 | var n Numbered = &b 30 | println(n.Number()) 31 | 32 | n = m 33 | println(n.Number()) 34 | } 35 | -------------------------------------------------------------------------------- /test/execution/interfaces/wordsize.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type Stringer interface { 9 | String() string 10 | } 11 | 12 | type StringStringer string 13 | 14 | func (s StringStringer) String() string { 15 | return "StringStringer(" + string(s) + ")" 16 | } 17 | 18 | func (s StringStringer) MethodWithArgs(a, b, c int) { 19 | println(s, a, b, c) 20 | } 21 | 22 | type I interface { 23 | MethodWithArgs(a, b, c int) 24 | } 25 | 26 | func testLargerThanWord() { 27 | // string is larger than a word. Make sure it works 28 | // well as a method receiver when using interfaces. 29 | var s Stringer = StringStringer("abc") 30 | println(s.String()) 31 | 32 | // Test calling a method which takes parameters 33 | // beyond the receiver. 34 | s.(I).MethodWithArgs(1, 2, 3) 35 | } 36 | 37 | func main() { 38 | testLargerThanWord() 39 | } 40 | -------------------------------------------------------------------------------- /test/execution/literals/array.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | // An extFloat represents an extended floating-point number, with more 9 | // precision than a float64. It does not try to save bits: the 10 | // number represented by the structure is mant*(2^exp), with a negative 11 | // sign if neg is true. 12 | type extFloat struct { 13 | mant uint64 14 | exp int 15 | neg bool 16 | } 17 | 18 | var smallPowersOfTen = [...]extFloat{ 19 | {1 << 63, -63, false}, // 1 20 | {0xa << 60, -60, false}, // 1e1 21 | {0x64 << 57, -57, false}, // 1e2 22 | {0x3e8 << 54, -54, false}, // 1e3 23 | {0x2710 << 50, -50, false}, // 1e4 24 | {0x186a0 << 47, -47, false}, // 1e5 25 | {0xf4240 << 44, -44, false}, // 1e6 26 | {0x989680 << 40, -40, false}, // 1e7 27 | } 28 | 29 | var arrayWithHoles = [10]int{ 30 | 2: 1, 31 | 4: 2, 32 | 6: 3, 33 | 8: 4, 34 | } 35 | 36 | type namedInt int32 37 | 38 | const N0 namedInt = 0 39 | const N1 namedInt = 1 40 | 41 | var arrayWithNamedIndices = [...]int{ 42 | N0: 1, 43 | N1: 2, 44 | } 45 | 46 | func main() { 47 | for i := range smallPowersOfTen { 48 | s := smallPowersOfTen[i] 49 | println(s.mant, s.exp, s.neg) 50 | } 51 | 52 | for i, value := range arrayWithHoles { 53 | println(i, value) 54 | } 55 | 56 | for i, value := range arrayWithNamedIndices { 57 | println(i, value) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/execution/literals/func.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | f := func(x bool) { 10 | println(x) 11 | } 12 | f(true) 13 | f(false) 14 | } 15 | -------------------------------------------------------------------------------- /test/execution/literals/map.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | type IntMap map[int]int 10 | m := IntMap{0: 1, 2: 3} 11 | println(m == nil) 12 | println(len(m)) 13 | println(m[0], m[1], m[2]) 14 | 15 | f32tostr := map[float32]string{0.1: "0.1", 0.2: "0.2", 0.3: "0.3"} 16 | println(f32tostr[0.1]) 17 | println(f32tostr[0.2]) 18 | println(f32tostr[0.3]) 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/literals/slice.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := []string{"abc", "123"} 10 | println(x[0]) 11 | println(x[1]) 12 | 13 | // Elements are composite literals, so the '&' can be elided. 14 | type S struct{ string } 15 | y := []*S{{"abc"}, {"123"}} 16 | println(y[0].string) 17 | println(y[1].string) 18 | } 19 | -------------------------------------------------------------------------------- /test/execution/literals/struct.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type E struct { 9 | e *E 10 | } 11 | 12 | type S struct { 13 | *E 14 | a, b int 15 | } 16 | 17 | type File struct { 18 | } 19 | 20 | type Reader struct { 21 | } 22 | 23 | type Response struct { 24 | } 25 | 26 | type reader struct { 27 | *Reader 28 | fd *File 29 | resp *Response 30 | } 31 | 32 | type Range32 struct { 33 | Lo uint32 34 | Hi uint32 35 | Stride uint32 36 | } 37 | 38 | func main() { 39 | s := &S{nil, 1, 2} 40 | println(s.a, s.b) 41 | s = &S{a: 1, b: 2} 42 | println(s.a, s.b) 43 | 44 | _ = &reader{} 45 | 46 | r := Range32{ 47 | Lo: 0, 48 | Stride: 2, 49 | Hi: 1, 50 | } 51 | println(r.Lo, r.Hi, r.Stride) 52 | 53 | // slice of structs 54 | ss := []S{{nil, 1, 2}, {nil, 3, 4}} 55 | for _, s := range ss { 56 | println(s.a, s.b) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/execution/maps/delete.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | m := make(map[int]int) 10 | delete(m, 0) // no-op 11 | m[0] = 1 12 | println(len(m)) 13 | delete(m, 1) // no-op 14 | println(len(m), m[0]) 15 | delete(m, 0) // delete element in map 16 | println(len(m), m[0]) 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/maps/insert.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | { 10 | var m map[int]int 11 | println(len(m)) // 0 12 | println(m[123]) // 0, despite map being nil 13 | } 14 | 15 | { 16 | m := make(map[int]int) 17 | m[123] = 456 18 | println(len(m)) // 1 19 | println(m[123]) 20 | m[123] = 789 21 | println(len(m)) // 1 22 | println(m[123]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/execution/maps/lookup.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | m := make(map[int]int) 10 | v, ok := m[8] 11 | println(v, ok) 12 | m[8] = 1 13 | v, ok = m[8] 14 | println(v, ok) 15 | 16 | type S struct{ s1, s2 string } 17 | sm := make(map[S]int) 18 | sm[S{"ABC", "DEF"}] = 1 19 | sv, ok := sm[S{string([]byte{65, 66, 67}), string([]byte{68, 69, 70})}] 20 | println(sv, ok) 21 | 22 | type A [2]string 23 | am := make(map[A]int) 24 | am[A{"ABC", "DEF"}] = 1 25 | av, ok := am[A{string([]byte{65, 66, 67}), string([]byte{68, 69, 70})}] 26 | println(av, ok) 27 | } 28 | -------------------------------------------------------------------------------- /test/execution/maps/range.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t 2>&1 | sort > %t1 3 | // RUN: go run %s 2>&1 | sort > %t2 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | defer println("done") 10 | m := make(map[int]int) 11 | m[0] = 3 12 | m[1] = 4 13 | m[2] = 5 14 | for k := range m { 15 | println(k) 16 | } 17 | for k, _ := range m { 18 | println(k) 19 | } 20 | for _, v := range m { 21 | println(v) 22 | } 23 | for k, v := range m { 24 | println(k, v) 25 | } 26 | 27 | // test deletion. 28 | i := 0 29 | for k, _ := range m { 30 | i++ 31 | delete(m, (k+1)%3) 32 | delete(m, (k+2)%3) 33 | } 34 | println(i) 35 | } 36 | -------------------------------------------------------------------------------- /test/execution/methods/methodvalues.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type T1 struct { 9 | value int 10 | } 11 | 12 | func (t *T1) f(m int) int { 13 | return m * t.value 14 | } 15 | 16 | func f1() { 17 | var t T1 18 | var f func(int) int = t.f 19 | t.value = 2 20 | println(f(123)) 21 | } 22 | 23 | type T2 struct{} 24 | 25 | func (T2) f() { 26 | println("T2.f()") 27 | } 28 | 29 | func f2() { 30 | var f func() = T2{}.f 31 | f() 32 | } 33 | 34 | type T3 complex128 35 | 36 | func (t T3) f() int { 37 | return int(real(t)) 38 | } 39 | 40 | func f3() { 41 | var f func() int = T3(10).f 42 | println(f()) 43 | } 44 | 45 | type T4 string 46 | 47 | func (t T4) f() string { 48 | return string(t) 49 | } 50 | 51 | func f4() { 52 | var f func() string = T4("abc").f 53 | println(f()) 54 | } 55 | 56 | func main() { 57 | f1() 58 | f2() 59 | f3() 60 | f4() 61 | } 62 | -------------------------------------------------------------------------------- /test/execution/methods/nilrecv.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type T1 int 9 | 10 | func (t *T1) t1() { println(t == nil) } 11 | 12 | func constNilRecv() { 13 | (*T1)(nil).t1() 14 | } 15 | 16 | func nonConstNilRecv() { 17 | var v1 T1 18 | v1.t1() 19 | var v2 *T1 20 | v2.t1() 21 | v2 = &v1 22 | v2.t1() 23 | } 24 | 25 | func main() { 26 | constNilRecv() 27 | nonConstNilRecv() 28 | } 29 | -------------------------------------------------------------------------------- /test/execution/methods/selectors.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type S1 struct{} 9 | type S2 struct { 10 | S1 11 | } 12 | 13 | func (s S1) F1() { 14 | println("F1") 15 | } 16 | 17 | func (s *S2) F2() { 18 | println("F2") 19 | } 20 | 21 | func testUnnamedStructMethods() { 22 | // Test method lookup on an unnamed struct type. 23 | var x struct { 24 | S1 25 | S2 26 | } 27 | x.F1() 28 | x.F2() 29 | } 30 | 31 | func main() { 32 | var s S2 33 | 34 | // Derive pointer-receiver function. 35 | f1 := (*S2).F1 36 | f1(&s) 37 | 38 | f2 := (*S2).F2 39 | f2(&s) 40 | 41 | testUnnamedStructMethods() 42 | } 43 | -------------------------------------------------------------------------------- /test/execution/new.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := new(int) 10 | println(*x) 11 | *x = 2 12 | println(*x) 13 | *x = *x * *x 14 | println(*x) 15 | } 16 | -------------------------------------------------------------------------------- /test/execution/nil.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var x *int = nil 10 | println(x) 11 | 12 | if x == nil { 13 | println("x is nil") 14 | } 15 | 16 | var y interface{} 17 | var z interface{} = y 18 | if y == nil { 19 | println("y is nil") 20 | } else { 21 | println("y is not nil") 22 | } 23 | 24 | if z == nil { 25 | println("z is nil") 26 | } else { 27 | println("z is not nil") 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/execution/operators/basics.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | var global string 11 | 12 | var hi = 0xFF00 13 | var lo = 0xFF00 14 | 15 | // borrowed from math package to avoid dependency on standard library 16 | func float32bits(f float32) uint32 { return *(*uint32)(unsafe.Pointer(&f)) } 17 | func float64bits(f float64) uint64 { return *(*uint64)(unsafe.Pointer(&f)) } 18 | 19 | func main() { 20 | println(hi & 0x1000) 21 | println(hi & 0x0100) 22 | println(hi & 0x0010) 23 | println(hi & 0x0001) 24 | println(lo & 0x1000) 25 | println(lo & 0x0100) 26 | println(lo & 0x0010) 27 | println(lo & 0x0001) 28 | println(hi | lo) 29 | println(hi ^ hi) 30 | println(hi ^ lo) 31 | println(lo ^ lo) 32 | println(hi ^ 0x1000) 33 | println(hi ^ 0x0100) 34 | println(hi ^ 0x0010) 35 | println(hi ^ 0x0001) 36 | println(lo ^ 0x1000) 37 | println(lo ^ 0x0100) 38 | println(lo ^ 0x0010) 39 | println(lo ^ 0x0001) 40 | println(-123 >> 1) 41 | println(-123 << 1) 42 | 43 | var f float64 = 123.456 44 | f-- 45 | println(f) 46 | 47 | // context of '&' op is used to type the untyped lhs 48 | // operand of the shift expression. 49 | shift := uint(2) 50 | println(uint64(0xFFFFFFFF) & (1<> (63 - _uint) 59 | if x == 2<<_uint { 60 | println("!") 61 | } 62 | } 63 | 64 | // There was a bug related to compound expressions involving 65 | // multiple binary logical operators. 66 | var a, b, c int 67 | if a == 0 && (b != 0 || c != 0) { 68 | println("!") 69 | } 70 | 71 | var si int = -123 72 | var ui int = 123 73 | println(^si) 74 | println(^ui) 75 | println(ui &^ 3) 76 | 77 | // test case from math/modf.go 78 | var x uint64 = 0xFFFFFFFFFFFFFFFF 79 | var e uint = 40 80 | x &^= 1<<(64-12-e) - 1 81 | println(x) 82 | 83 | // compare global to non-global 84 | println(new(string) == &global) 85 | 86 | // negative zero 87 | var f32 float32 88 | var f64 float64 89 | var c64 complex64 90 | var c128 complex128 91 | f32 = -f32 92 | f64 = -f64 93 | c64 = -c64 94 | c128 = -c128 95 | println(float32bits(f32)) 96 | println(float64bits(f64)) 97 | println(float32bits(real(c64)), float32bits(imag(c64))) 98 | println(float64bits(real(c128)), float64bits(imag(c128))) 99 | } 100 | -------------------------------------------------------------------------------- /test/execution/operators/binary_untyped.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f1(b bool) bool { 9 | return b 10 | } 11 | 12 | func main() { 13 | x := false 14 | y := x 15 | x = !y 16 | println(x || y) 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/operators/shifts.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func testShrUint32(v uint32) { 9 | for i := uint(0); i <= 32; i++ { 10 | println(v >> i) 11 | println(v << i) 12 | } 13 | } 14 | 15 | func testShrInt32(v int32) { 16 | for i := uint(0); i <= 32; i++ { 17 | println(v >> i) 18 | println(v << i) 19 | } 20 | } 21 | 22 | func main() { 23 | testShrUint32(0xFFFFFFFF) 24 | testShrUint32(0xEFFFFFFF) 25 | testShrInt32(-1) 26 | testShrInt32(1) 27 | } 28 | -------------------------------------------------------------------------------- /test/execution/slices/append.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func stringtobytes() { 9 | var b []byte 10 | b = append(b, "abc"...) 11 | b = append(b, "def"...) 12 | println(string(b)) 13 | } 14 | 15 | func appendnothing() { 16 | var x []string 17 | println(append(x) == nil) 18 | x = append(x, "!") 19 | println(len(append(x)) == 1) 20 | } 21 | 22 | func appendmulti() { 23 | a := append([]bool{}, []bool{false, true, false}...) 24 | b := append([]bool{}, false, true, false) 25 | for i := range a { 26 | println(a[i], b[i]) 27 | } 28 | } 29 | 30 | func main() { 31 | x := []int{} 32 | for i := 0; i < 100; i++ { 33 | x = append(x, i) 34 | } 35 | for i := 0; i < len(x); i++ { 36 | println(x[i]) 37 | } 38 | y := []int{1, 2, 3} 39 | x = append(x, y...) 40 | for i := 0; i < len(x); i++ { 41 | println(x[i]) 42 | } 43 | stringtobytes() 44 | appendnothing() 45 | appendmulti() 46 | } 47 | -------------------------------------------------------------------------------- /test/execution/slices/cap.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func test(l, c int) { 9 | var s []int 10 | if l != -1 { 11 | if c == -1 { 12 | s = make([]int, l) 13 | } else { 14 | s = make([]int, l, c) 15 | } 16 | } 17 | println(len(s), cap(s)) 18 | } 19 | 20 | func main() { 21 | test(-1, -1) 22 | test(0, -1) 23 | test(0, 0) 24 | test(1, -1) 25 | test(1, 1) 26 | test(1, 2) 27 | 28 | // make sure capacity is transferred to slice 29 | s := make([]int, 5, 10) 30 | s1 := s[1:3] 31 | println(len(s1), cap(s1)) 32 | 33 | s2 := append(s1, 999) 34 | println(len(s2), cap(s2)) 35 | println(s2[2]) 36 | println(s[3]) 37 | 38 | s3 := s1[0:1:2] 39 | println(len(s3), cap(s3)) 40 | } 41 | -------------------------------------------------------------------------------- /test/execution/slices/compare.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | var s []int 10 | println(s == nil) 11 | println(s != nil) 12 | println(nil == s) 13 | println(nil != s) 14 | s = make([]int, 0) 15 | println(s == nil) 16 | println(s != nil) 17 | println(nil == s) 18 | println(nil != s) 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/slices/copy.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | a := make([]int, 10) 10 | b := make([]int, 10) 11 | for i, _ := range b { 12 | b[i] = 1 13 | } 14 | println(copy(a[:5], b)) // expect 5 15 | println(a[5]) // expect 0 16 | } 17 | -------------------------------------------------------------------------------- /test/execution/slices/index.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func blah() []int { 9 | return make([]int, 1) 10 | } 11 | 12 | func main() { 13 | println(blah()[0]) 14 | } 15 | -------------------------------------------------------------------------------- /test/execution/slices/literal.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := []int{1, 2, 3} 10 | for i := 0; i < len(x); i++ { 11 | println(x[i]) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/execution/slices/make.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := make([]int, 10) 10 | x[5] = 666 11 | for i, val := range x { 12 | println(i, val) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/execution/slices/sliceexpr.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := []int{1, 2, 3, 4} 10 | for i, val := range x[1:3] { 11 | println(i, val) 12 | } 13 | println("") 14 | for i, val := range x[2:] { 15 | println(i, val) 16 | } 17 | println("") 18 | for i, val := range x[:2] { 19 | println(i, val) 20 | } 21 | println("") 22 | for i, val := range x[:] { 23 | println(i, val) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/execution/strings/add.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | a := "abc" 10 | b := "123" 11 | c := a + b 12 | println(len(a), len(b), len(c)) 13 | println(c) 14 | } 15 | -------------------------------------------------------------------------------- /test/execution/strings/bytes.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type namedByte byte 9 | 10 | func testBytesConversion() { 11 | s := "abc" 12 | b := []byte(s) 13 | println("testBytesConversion:", s == string(b)) 14 | nb := []namedByte(s) 15 | for _, v := range nb { 16 | println(v) 17 | } 18 | b[0] = '!' 19 | println(s) 20 | s = string(b) 21 | b[0] = 'a' 22 | println(s) 23 | } 24 | 25 | func testBytesCopy() { 26 | s := "abc" 27 | b := make([]byte, len(s)) 28 | copy(b, s) 29 | println("testBytesCopy:", string(b) == s) 30 | } 31 | 32 | func main() { 33 | testBytesConversion() 34 | testBytesCopy() 35 | } 36 | -------------------------------------------------------------------------------- /test/execution/strings/compare.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | x := "abc" 10 | y := "def" 11 | z := "abcd" 12 | 13 | println(x == x) // true 14 | println(x == y) // false 15 | println(x != x) // false 16 | println(x != y) // true 17 | println(x < x) // false 18 | println(x < y) // true 19 | println(y < x) // false 20 | println(x > x) // false 21 | println(x > y) // false 22 | println(y > x) // true 23 | 24 | println(x == z) // false 25 | println(z == x) // false 26 | println(x < z) // true 27 | println(x > z) // false 28 | println(z < x) // false 29 | println(z > x) // true 30 | 31 | println(x <= x) // true 32 | println(x <= y) // true 33 | println(x >= x) // true 34 | println(y >= x) // true 35 | } 36 | -------------------------------------------------------------------------------- /test/execution/strings/index.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | s := "abc" 10 | println(s[0], s[1], s[2]) 11 | } 12 | -------------------------------------------------------------------------------- /test/execution/strings/range.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func printchars(s string) { 9 | var x int 10 | for i, c := range s { 11 | // test loop-carried dependence (x++), introducing a Phi node 12 | x++ 13 | println(i, c, x) 14 | } 15 | 16 | // now test with plain old assignment 17 | var i int 18 | var c rune 19 | for i, c = range s { 20 | println(i, c) 21 | if i == len(s)-1 { 22 | // test multiple branches to loop header 23 | continue 24 | } 25 | } 26 | } 27 | 28 | func main() { 29 | // 1 bytes 30 | printchars(".") 31 | 32 | // 2 bytes 33 | printchars("©") 34 | 35 | // 3 bytes 36 | printchars("€") 37 | 38 | // 4 bytes 39 | printchars("𐐀") 40 | 41 | // mixed 42 | printchars("Sale price: €0.99") 43 | 44 | // TODO add test cases for invalid sequences 45 | } 46 | -------------------------------------------------------------------------------- /test/execution/strings/runetostring.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func test(r rune) { 9 | println("test(", r, ")") 10 | s := string(r) 11 | println(s) 12 | for i := 0; i < len(s); i++ { 13 | println(s[i]) 14 | } 15 | for i, r := range s { 16 | println(i, r) 17 | } 18 | } 19 | 20 | type namedRune rune 21 | 22 | func testslice(r1 []rune) { 23 | s := string(r1) 24 | println(s) 25 | r2 := []rune(s) 26 | r3 := []namedRune(s) 27 | println(len(r1), len(r2), len(r3)) 28 | if len(r2) == len(r1) && len(r3) == len(r1) { 29 | for i := range r2 { 30 | println(r1[i] == r2[i]) 31 | println(r1[i] == rune(r3[i])) 32 | } 33 | } 34 | } 35 | 36 | func main() { 37 | var runes = []rune{'.', '©', '€', '𐐀'} 38 | test(runes[0]) 39 | test(runes[1]) 40 | test(runes[2]) 41 | test(runes[3]) 42 | testslice(runes) 43 | } 44 | -------------------------------------------------------------------------------- /test/execution/strings/slice.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | s := "abcdef" 10 | println(s[:]) 11 | println(s[1:]) 12 | println(s[:3]) 13 | println(s[1:4]) 14 | } 15 | -------------------------------------------------------------------------------- /test/execution/structs/compare.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type S0 struct{} 9 | 10 | type S1 struct { 11 | a int 12 | } 13 | 14 | type S2 struct { 15 | a, b int 16 | } 17 | 18 | func testS0() { 19 | println(S0{} == S0{}) 20 | println(S0{} != S0{}) 21 | } 22 | 23 | func testS1() { 24 | println(S1{1} == S1{1}) 25 | println(S1{1} != S1{1}) 26 | println(S1{1} == S1{2}) 27 | println(S1{1} != S1{2}) 28 | } 29 | 30 | func testS2() { 31 | s1 := S2{1, 2} 32 | s2 := S2{1, 3} 33 | println(s1 == s1) 34 | println(s1 == s2) 35 | println(s1 != s1) 36 | println(s1 != s2) 37 | } 38 | 39 | func main() { 40 | testS0() 41 | testS1() 42 | testS2() 43 | } 44 | -------------------------------------------------------------------------------- /test/execution/structs/embed.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type A struct{ aval int } 9 | 10 | func (a *A) test() { 11 | println("A.test", a.aval) 12 | } 13 | 14 | func (a *A) testA() { 15 | println("A.testA") 16 | } 17 | 18 | func (a A) testA2() { 19 | println("A.testA2") 20 | } 21 | 22 | type B struct { 23 | A 24 | bval int 25 | } 26 | 27 | func (b B) test() { 28 | println("B.test", b.bval) 29 | } 30 | 31 | type C struct { 32 | *B 33 | cval int 34 | } 35 | 36 | func main() { 37 | var b B 38 | b.aval = 1 39 | b.bval = 2 40 | b.A.test() 41 | b.A.testA() 42 | b.A.testA2() 43 | b.test() 44 | b.testA() 45 | b.testA2() 46 | 47 | var c C 48 | c.B = &b 49 | c.cval = 3 50 | c.testA() 51 | //c.testA2() 52 | } 53 | -------------------------------------------------------------------------------- /test/execution/switch/branch.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | switch true { 10 | default: 11 | break 12 | println("default") 13 | } 14 | 15 | switch true { 16 | case true: 17 | println("true") 18 | fallthrough 19 | case false: 20 | println("false") 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/execution/switch/default.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | switch true { 10 | default: 11 | println("default") 12 | } 13 | 14 | switch { 15 | default: 16 | println("default") 17 | case true: 18 | println("true") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/execution/switch/empty.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func f() int { 9 | println("f was called") 10 | return 123 11 | } 12 | 13 | func main() { 14 | switch f() { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/execution/switch/scope.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | // case clauses have their own scope. 10 | switch { 11 | case true, false: 12 | x := 1 13 | println(x) 14 | fallthrough 15 | default: 16 | x := 2 17 | println(x) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/switch/strings.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func main() { 9 | switch "abc" { 10 | case "def": 11 | println("def") 12 | case "abc": 13 | println("abc") 14 | } 15 | 16 | switch "abc" { 17 | case "def", "abc": 18 | println("def, abc") 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/execution/switch/type.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func test(i interface{}) { 9 | switch x := i.(type) { 10 | case int64: 11 | println("int64", x) 12 | // FIXME 13 | //case string: 14 | // println("string", x) 15 | default: 16 | println("default") 17 | } 18 | } 19 | 20 | type stringer interface { 21 | String() string 22 | } 23 | 24 | func printany(i interface{}) { 25 | switch v := i.(type) { 26 | case nil: 27 | print("nil", v) 28 | case stringer: 29 | print(v.String()) 30 | case error: 31 | print(v.Error()) 32 | case int: 33 | print(v) 34 | case string: 35 | print(v) 36 | } 37 | } 38 | 39 | func multi(i interface{}) { 40 | switch i.(type) { 41 | case uint8, int8: 42 | println("uint8 or int8") 43 | default: 44 | println("something else") 45 | } 46 | } 47 | 48 | type N int 49 | 50 | func (n N) String() string { return "N" } 51 | 52 | func named() { 53 | var x interface{} = N(123) 54 | switch x := x.(type) { 55 | case N: 56 | // Test for bug: previously, type switch was 57 | // assigning underlying type of N (int). 58 | println(x.String()) 59 | } 60 | } 61 | 62 | func main() { 63 | test(int64(123)) 64 | test("abc") 65 | multi(uint8(123)) 66 | multi(int8(123)) 67 | named() 68 | } 69 | -------------------------------------------------------------------------------- /test/execution/types/named.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | func f1() { 11 | type T struct { 12 | a, b, c int 13 | } 14 | var t T 15 | println(unsafe.Sizeof(t)) 16 | } 17 | 18 | func f2() { 19 | type T interface{} 20 | var t T 21 | t = 1 22 | println(unsafe.Sizeof(t)) 23 | } 24 | 25 | func f3() { 26 | type T struct{} 27 | var t T 28 | println(unsafe.Sizeof(t)) 29 | } 30 | 31 | func main() { 32 | f1() 33 | f2() 34 | f3() 35 | } 36 | -------------------------------------------------------------------------------- /test/execution/types/recursive.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | type T1 *T1 9 | 10 | func count(t T1) int { 11 | if t == nil { 12 | return 1 13 | } 14 | return 1 + count(*t) 15 | } 16 | 17 | func testSelfPointer() { 18 | var a T1 19 | var b T1 20 | var c T1 = &b 21 | *c = &a 22 | println(count(c)) 23 | println(count(&c)) 24 | } 25 | 26 | func main() { 27 | testSelfPointer() 28 | } 29 | -------------------------------------------------------------------------------- /test/execution/unsafe/const_sizeof.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | const ptrSize = unsafe.Sizeof((*byte)(nil)) 11 | 12 | var x [ptrSize]int 13 | 14 | func main() { 15 | println(ptrSize) 16 | println(len(x)) 17 | } 18 | -------------------------------------------------------------------------------- /test/execution/unsafe/offsetof.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | type S struct { 11 | a int16 12 | b int32 13 | c int8 14 | d int64 15 | } 16 | 17 | func main() { 18 | var s S 19 | println(unsafe.Offsetof(s.a)) 20 | println(unsafe.Offsetof(s.b)) 21 | println(unsafe.Offsetof(s.c)) 22 | println(unsafe.Offsetof(s.d)) 23 | } 24 | -------------------------------------------------------------------------------- /test/execution/unsafe/pointer.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | func main() { 11 | var i [2]int 12 | i[0] = 123 13 | i[1] = 456 14 | ptr := &i[0] 15 | println(*ptr) 16 | ptr_i := unsafe.Pointer(ptr) 17 | ptr_i = unsafe.Pointer(uintptr(ptr_i) + unsafe.Sizeof(i[0])) 18 | ptr = (*int)(ptr_i) 19 | println(*ptr) 20 | } 21 | -------------------------------------------------------------------------------- /test/execution/unsafe/sizeof_array.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | type uint24 struct { 11 | a uint16 12 | b uint8 13 | } 14 | 15 | func main() { 16 | var a [3]uint24 17 | println(unsafe.Sizeof(a)) 18 | } 19 | -------------------------------------------------------------------------------- /test/execution/unsafe/sizeof_basic.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | func main() { 11 | var b bool 12 | var i int 13 | var i8 int8 14 | var i16 int16 15 | var i32 int32 16 | var i64 int64 17 | var u uint 18 | var u8 uint8 19 | var u16 uint16 20 | var u32 uint32 21 | var u64 uint64 22 | var f32 float32 23 | var f64 float64 24 | var c64 complex64 25 | var c128 complex128 26 | var s string 27 | var p unsafe.Pointer 28 | var up uintptr 29 | 30 | println(unsafe.Sizeof(b)) 31 | println(unsafe.Sizeof(i)) 32 | println(unsafe.Sizeof(i8)) 33 | println(unsafe.Sizeof(i16)) 34 | println(unsafe.Sizeof(i32)) 35 | println(unsafe.Sizeof(i64)) 36 | println(unsafe.Sizeof(u)) 37 | println(unsafe.Sizeof(u8)) 38 | println(unsafe.Sizeof(u16)) 39 | println(unsafe.Sizeof(u32)) 40 | println(unsafe.Sizeof(u64)) 41 | println(unsafe.Sizeof(f32)) 42 | println(unsafe.Sizeof(f64)) 43 | println(unsafe.Sizeof(c64)) 44 | println(unsafe.Sizeof(c128)) 45 | println(unsafe.Sizeof(s)) 46 | println(unsafe.Sizeof(p)) 47 | println(unsafe.Sizeof(up)) 48 | 49 | println(unsafe.Alignof(b)) 50 | println(unsafe.Alignof(i)) 51 | println(unsafe.Alignof(i8)) 52 | println(unsafe.Alignof(i16)) 53 | println(unsafe.Alignof(i32)) 54 | println(unsafe.Alignof(i64)) 55 | println(unsafe.Alignof(u)) 56 | println(unsafe.Alignof(u8)) 57 | println(unsafe.Alignof(u16)) 58 | println(unsafe.Alignof(u32)) 59 | println(unsafe.Alignof(u64)) 60 | println(unsafe.Alignof(f32)) 61 | println(unsafe.Alignof(f64)) 62 | println(unsafe.Alignof(c64)) 63 | println(unsafe.Alignof(c128)) 64 | println(unsafe.Alignof(s)) 65 | println(unsafe.Alignof(p)) 66 | println(unsafe.Alignof(up)) 67 | } 68 | -------------------------------------------------------------------------------- /test/execution/unsafe/sizeof_struct.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | import "unsafe" 9 | 10 | type a struct { 11 | a int16 12 | b int32 13 | c int8 14 | d int64 15 | } 16 | 17 | func main() { 18 | println(unsafe.Sizeof(a{})) 19 | } 20 | -------------------------------------------------------------------------------- /test/execution/var.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func Blah() int { 9 | println("woobie") 10 | return 123 11 | } 12 | 13 | func F1() (int, float64) { 14 | return 12, 3.45 15 | } 16 | 17 | var X = Y + Blah() // == 579 18 | var Y = 123 + Z // == 456 19 | 20 | var X1, Y1 = F1() 21 | 22 | const ( 23 | _ = 333 * iota 24 | Z 25 | ) 26 | 27 | var I interface{} = -1 28 | var I1 = I.(int) 29 | 30 | func main() { 31 | println(X, Y) 32 | println(X1, Y1) 33 | println(I1) 34 | } 35 | -------------------------------------------------------------------------------- /test/execution/varargs.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -o %t %s 2 | // RUN: %t > %t1 2>&1 3 | // RUN: go run %s > %t2 2>&1 4 | // RUN: diff -u %t1 %t2 5 | 6 | package main 7 | 8 | func p(i ...int) { 9 | println(len(i)) 10 | for j := 0; j < len(i); j++ { 11 | println(i[j]) 12 | } 13 | } 14 | 15 | func main() { 16 | p(123, 456, 789) 17 | p(123, 456, 789, 101112) 18 | p([]int{1, 2, 3}...) 19 | } 20 | -------------------------------------------------------------------------------- /test/gllgo/dead.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -O0 -S -o - %s | FileCheck %s 2 | 3 | package gotest 4 | 5 | // CHECK-NOT: deadfunc 6 | func deadfunc() 7 | -------------------------------------------------------------------------------- /test/irgen/mangling.go: -------------------------------------------------------------------------------- 1 | // RUN: llgo -fgo-pkgpath=llvm.org/llvm -S -emit-llvm -o - %s | FileCheck %s 2 | 3 | package llvm 4 | 5 | // CHECK: @llvm_org_llvm.F 6 | func F() { 7 | } 8 | -------------------------------------------------------------------------------- /test/lit.cfg: -------------------------------------------------------------------------------- 1 | import lit.formats 2 | import os 3 | import sys 4 | 5 | config.name = 'llgo' 6 | config.suffixes = ['.go'] 7 | config.test_format = lit.formats.ShTest() 8 | config.test_source_root = None 9 | config.test_exec_root = None 10 | config.excludes = ['Inputs'] 11 | 12 | workdir = os.path.dirname(__file__) + '/../workdir' 13 | llvm_bindir = os.path.dirname(sys.argv[0]) 14 | 15 | config.substitutions.append((r"\bllgo\b", workdir + '/gllgo-stage3 -no-prefix -L' + workdir + '/gofrontend_build/libgo-stage1 -L' + workdir + '/gofrontend_build/libgo-stage1/.libs -static-libgo')) 16 | config.substitutions.append((r"\bFileCheck\b", llvm_bindir + '/FileCheck')) 17 | -------------------------------------------------------------------------------- /update_clang.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Build a version of Clang that matches the version we use in gollvm. 4 | # This will ensure that the bitcode files that we produce are compatible with 5 | # those that Clang produces. 6 | 7 | llgodir=$(dirname "$0") 8 | llgodir=$(cd "$llgodir" && pwd) 9 | gollvmdir=$(go list -f '{{.Dir}}' llvm.org/llvm/bindings/go/llvm) 10 | 11 | llvmrev=$(cd $gollvmdir && (svn info || git svn info) | grep '^Revision:' | cut -d' ' -f2) 12 | 13 | workdir=$llgodir/workdir 14 | clangdir=$workdir/clang 15 | clang_builddir=$workdir/clang_build 16 | 17 | if [ "$llvmrev" = "$(cat $workdir/.update-clang-stamp 2>/dev/null)" ] ; then 18 | exit 0 19 | fi 20 | 21 | mkdir -p $workdir 22 | svn co -r $llvmrev https://llvm.org/svn/llvm-project/cfe/trunk $clangdir 23 | mkdir -p $clang_builddir 24 | 25 | cmake_flags="../clang -DCMAKE_PREFIX_PATH=$gollvmdir/workdir/llvm_build/bin -DLLVM_INCLUDE_TESTS=NO $@" 26 | 27 | if test -n "`which ninja`" ; then 28 | (cd $clang_builddir && cmake -G Ninja $cmake_flags) 29 | ninja -C $clang_builddir clang 30 | else 31 | (cd $clang_builddir && cmake $cmake_flags) 32 | make -C $clang_builddir -j4 clang 33 | fi 34 | 35 | echo $llvmrev > $workdir/.update-clang-stamp 36 | -------------------------------------------------------------------------------- /update_libgo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # Fetch libgo and its dependencies. 4 | 5 | llgodir=$(dirname "$0") 6 | llgodir=$(cd "$llgodir" && pwd) 7 | 8 | gofrontendrepo=https://code.google.com/p/gofrontend/ 9 | gofrontendrev=225a208260a6 10 | 11 | gccrepo=svn://gcc.gnu.org/svn/gcc/trunk 12 | gccrev=210256 13 | 14 | workdir=$llgodir/workdir 15 | gofrontenddir=$workdir/gofrontend 16 | 17 | mkdir -p $workdir 18 | if [ -d $gofrontenddir/.hg ] ; then 19 | (cd $gofrontenddir && hg pull) 20 | else 21 | hg clone $gofrontendrepo $gofrontenddir 22 | fi 23 | 24 | # Revert the previous version of the noext diff (see below). 25 | if [ -e $workdir/libgo-noext.diff ] ; then 26 | (cd $gofrontenddir && patch -R -p1 < $workdir/libgo-noext.diff) 27 | rm $workdir/libgo-noext.diff 28 | fi 29 | 30 | (cd $gofrontenddir && hg update -r $gofrontendrev) 31 | 32 | # Apply a diff that eliminates use of the unnamed struct extension beyond what 33 | # -fms-extensions supports. We keep a copy of the diff in the work directory so 34 | # we know what to revert when we update. This is a temporary measure until a 35 | # similar change can be made upstream. 36 | (cd $gofrontenddir && patch -p1 < $llgodir/libgo-noext.diff) 37 | cp $llgodir/libgo-noext.diff $workdir/ 38 | 39 | # Some dependencies are stored in the gcc repository. 40 | # TODO(pcc): Ask iant about mirroring these dependencies into gofrontend. 41 | 42 | mkdir -p $gofrontenddir/include 43 | mkdir -p $gofrontenddir/libgcc 44 | for f in config.guess config-ml.in config.sub depcomp \ 45 | install-sh ltmain.sh missing move-if-change \ 46 | include/dwarf2.def include/dwarf2.h libgcc/unwind-pe.h ; do 47 | svn cat -r $gccrev $gccrepo/$f > $gofrontenddir/$f 48 | done 49 | 50 | # Avoid pulling in a bunch of unneeded gcc headers. 51 | echo "#define IS_ABSOLUTE_PATH(path) ((path)[0] == '/')" > $gofrontenddir/include/filenames.h 52 | 53 | for d in libbacktrace libffi ; do 54 | svn co -r $gccrev $gccrepo/$d $gofrontenddir/$d 55 | done 56 | 57 | touch $workdir/.update-libgo-stamp 58 | -------------------------------------------------------------------------------- /utils/benchcomp/README: -------------------------------------------------------------------------------- 1 | These are some quick and dirty tools for measuring the performance impact 2 | of a change to llgo by sampling the results of running the libgo benchmark 3 | suite. They can be used to calculate the geo-mean and 95% confidence interval 4 | using the Student's t-test. The benchcomp program massages the output of the 5 | Go benchmark tools into a form that can be read by the R program analyze.R 6 | which runs the statistics. 7 | 8 | To use, clpatch this into gofrontend: 9 | https://codereview.appspot.com/103550047/ 10 | 11 | then run: 12 | 13 | make 14 | make -C workdir/gofrontend_build/libgo-stage1 bench 2>&1 | tee before.out 15 | # make changes 16 | make 17 | make -C workdir/gofrontend_build/libgo-stage1 bench 2>&1 | tee after.out 18 | utils/benchcomp/benchcomp benchns before.out after.out | R -f utils/benchcomp/analyze.R 19 | 20 | The results should be displayed on stdout. 21 | -------------------------------------------------------------------------------- /utils/benchcomp/analyze.R: -------------------------------------------------------------------------------- 1 | sc <- read.table(file('stdin')) 2 | scratio <- sc$V2 / sc$V3 3 | scratio <- scratio[scratio > 0] 4 | 5 | # Take the log of the ratio. Our null hypothesis is a normal distribution 6 | # around zero. 7 | tt <- t.test(log(scratio)) 8 | tt 9 | 10 | # This gives us the geo-mean as we are taking the exponent of the linear mean 11 | # of logarithms. 12 | 1 - 1/exp(tt$estimate) 13 | 14 | # Likewise for the confidence interval. 15 | 1 - 1/exp(tt$conf.int) 16 | -------------------------------------------------------------------------------- /utils/benchcomp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "debug/elf" 6 | "fmt" 7 | "os" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func symsizes(path string) map[string]float64 { 13 | m := make(map[string]float64) 14 | f, err := elf.Open(path) 15 | if err != nil { 16 | panic(err.Error()) 17 | } 18 | syms, err := f.Symbols() 19 | if err != nil { 20 | panic(err.Error()) 21 | } 22 | for _, sym := range syms { 23 | if sym.Section < elf.SectionIndex(len(f.Sections)) && f.Sections[sym.Section].Name == ".text" { 24 | m[sym.Name] = float64(sym.Size) 25 | } 26 | } 27 | return m 28 | } 29 | 30 | func benchnums(path, stat string) map[string]float64 { 31 | m := make(map[string]float64) 32 | 33 | fh, err := os.Open(path) 34 | if err != nil { 35 | panic(err.Error()) 36 | } 37 | 38 | scanner := bufio.NewScanner(fh) 39 | for scanner.Scan() { 40 | elems := strings.Split(scanner.Text(), "\t") 41 | if !strings.HasPrefix(elems[0], "Benchmark") || len(elems) < 3 { 42 | continue 43 | } 44 | var s string 45 | for _, elem := range elems[2:] { 46 | selems := strings.Split(strings.TrimSpace(elem), " ") 47 | if selems[1] == stat { 48 | s = selems[0] 49 | } 50 | } 51 | if s != "" { 52 | ns, err := strconv.ParseFloat(s, 64) 53 | if err != nil { 54 | panic(scanner.Text() + " ---- " + err.Error()) 55 | } 56 | m[elems[0]] = ns 57 | } 58 | } 59 | 60 | if err := scanner.Err(); err != nil { 61 | panic(err) 62 | } 63 | 64 | return m 65 | } 66 | 67 | func main() { 68 | var cmp func(string) map[string]float64 69 | switch os.Args[1] { 70 | case "symsizes": 71 | cmp = symsizes 72 | 73 | case "benchns": 74 | cmp = func(path string) map[string]float64 { 75 | return benchnums(path, "ns/op") 76 | } 77 | 78 | case "benchallocs": 79 | cmp = func(path string) map[string]float64 { 80 | return benchnums(path, "allocs/op") 81 | } 82 | } 83 | 84 | syms1 := cmp(os.Args[2]) 85 | syms2 := cmp(os.Args[3]) 86 | 87 | for n, z1 := range syms1 { 88 | if z2, ok := syms2[n]; ok && z2 != 0 { 89 | fmt.Printf("%s %f %f %f\n", n, z1, z2, z1/z2) 90 | } 91 | } 92 | } 93 | --------------------------------------------------------------------------------