Remove llgo per discussion on llvm-dev:

http://lists.llvm.org/pipermail/llvm-dev/2020-February/139058.html

Approved by dblaikie, pcc.
This commit is contained in:
Eric Christopher 2020-02-10 10:07:37 -08:00
parent 936d1427da
commit 372bfc65de
2872 changed files with 0 additions and 729809 deletions

View File

@ -1,4 +0,0 @@
{
"project_id" : "llgo",
"conduit_uri" : "https://reviews.llvm.org/"
}

View File

@ -1,265 +0,0 @@
include(ExternalProject)
include(ProcessorCount)
# Provide a config.h which exposes build system information.
configure_file(
cmd/gllgo/config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/cmd/gllgo/config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/cmd/gllgo)
list(APPEND LLVM_GO_PACKAGES "llvm.org/llgo=${CMAKE_CURRENT_SOURCE_DIR}")
llvm_add_go_executable(llgo llvm.org/llgo/cmd/gllgo ALL DEPENDS
build/context.go
cmd/gllgo/gllgo.go
debug/debug.go
driver/parser.go
irgen/annotations.go
irgen/attribute.go
irgen/builtins.go
irgen/cabi.go
irgen/call.go
irgen/channels.go
irgen/closures.go
irgen/compiler.go
irgen/errors.go
irgen/indirect.go
irgen/interfaces.go
irgen/maps.go
irgen/predicates.go
irgen/println.go
irgen/runtime.go
irgen/slice.go
irgen/ssa.go
irgen/strings.go
irgen/switches.go
irgen/targets.go
irgen/typemap.go
irgen/types.go
irgen/utils.go
irgen/value.go
irgen/version.go
ssaopt/esc.go
)
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLGO_VERSION
${PACKAGE_VERSION})
configure_file(
cmd/go/zdefaultcc.go.in
${CMAKE_CURRENT_BINARY_DIR}/cmd/go/zdefaultcc.go)
set(LLGO_GO_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/build.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/clean.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/context.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/discovery.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/doc.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/env.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fix.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/fmt.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/generate.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/get.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/go11.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/help.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/http.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/list.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/main.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/note.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/pkg.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/run.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/signal.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/signal_unix.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/testflag.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/test.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/tool.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/vcs.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/version.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/vet.go
${CMAKE_CURRENT_BINARY_DIR}/cmd/go/zdefaultcc.go
)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
COMMAND ${CMAKE_BINARY_DIR}/bin/llgo -static-libgo
-I ${CMAKE_CURRENT_BINARY_DIR}/libgo
-o ${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
${LLGO_GO_SOURCES}
${CMAKE_CURRENT_BINARY_DIR}/libgo/zstdpkglist.go
DEPENDS llgo libgo ${LLGO_GO_SOURCES}
COMMENT "Building Go executable llgo-go"
VERBATIM)
add_custom_target(llgo-go ALL DEPENDS ${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX})
set(LLGO_CGO_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/ast.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/doc.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/gcc.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/godefs.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/main.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/out.go
${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/cgo/util.go
${CMAKE_CURRENT_SOURCE_DIR}/cmd/cgo/zdefaultcc.go
)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/lib/go/llgo-${LLGO_VERSION}/cgo
COMMAND ${CMAKE_BINARY_DIR}/bin/llgo -static-libgo
-o ${CMAKE_BINARY_DIR}/lib/go/llgo-${LLGO_VERSION}/cgo
${LLGO_CGO_SOURCES}
DEPENDS llgo libgo ${LLGO_CGO_SOURCES}
COMMENT "Building Go executable cgo"
VERBATIM)
add_custom_target(cgo ALL DEPENDS ${CMAKE_BINARY_DIR}/lib/go/llgo-${LLGO_VERSION}/cgo)
llvm_add_go_executable(llgo-stage2 llvm.org/llgo/cmd/gllgo
DEPENDS libgo ${CMAKE_BINARY_DIR}/bin/llgo${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_BINARY_DIR}/lib/go/llgo-${LLGO_VERSION}/cgo
${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
GOFLAGS "cc=${CMAKE_BINARY_DIR}/bin/clang"
"cxx=${CMAKE_BINARY_DIR}/bin/clang++"
"go=${CMAKE_BINARY_DIR}/bin/llgo-go"
)
llvm_add_go_executable(llgo-stage3 llvm.org/llgo/cmd/gllgo
DEPENDS libgo ${CMAKE_BINARY_DIR}/bin/llgo-stage2${CMAKE_EXECUTABLE_SUFFIX}
GOFLAGS "cc=${CMAKE_BINARY_DIR}/bin/clang"
"cxx=${CMAKE_BINARY_DIR}/bin/clang++"
"go=${CMAKE_BINARY_DIR}/bin/llgo-go"
"llgo=${CMAKE_BINARY_DIR}/bin/llgo-stage2${CMAKE_EXECUTABLE_SUFFIX}"
)
llvm_add_go_executable(cc-wrapper llvm.org/llgo/cmd/cc-wrapper DEPENDS
cmd/cc-wrapper/main.go
)
llvm_add_go_executable(llgoi llvm.org/llgo/cmd/llgoi ALL
DEPENDS libgo ${CMAKE_BINARY_DIR}/bin/llgo${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_BINARY_DIR}/lib/go/llgo-${LLGO_VERSION}/cgo
${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
cmd/llgoi/llgoi.go
GOFLAGS "cc=${CMAKE_BINARY_DIR}/bin/clang"
"cxx=${CMAKE_BINARY_DIR}/bin/clang++"
"go=${CMAKE_BINARY_DIR}/bin/llgo-go"
)
install(FILES ${CMAKE_BINARY_DIR}/bin/llgo${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_BINARY_DIR}/bin/llgoi${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
DESTINATION bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)
function(add_clobber_steps name)
ExternalProject_Add_Step(${name} force-reconfigure
DEPENDERS configure
ALWAYS 1
)
ExternalProject_Add_Step(${name} clobber
COMMAND ${CMAKE_COMMAND} -E remove_directory <BINARY_DIR>
COMMAND ${CMAKE_COMMAND} -E make_directory <BINARY_DIR>
COMMENT "Clobbering ${name} build directory..."
DEPENDERS configure
DEPENDS ${ARGN}
)
endfunction()
processorcount(PROCESSOR_COUNT)
function(add_libgo_variant suffix cflags gocflags deps exclude_from_all)
externalproject_add(libbacktrace${suffix}
DEPENDS clang ${deps}
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libbacktrace
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${suffix}/libbacktrace
CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-multilib --enable-host-shared "CC=${CMAKE_BINARY_DIR}/bin/clang ${cflags}"
BUILD_COMMAND make -j${PROCESSOR_COUNT}
INSTALL_COMMAND ""
LOG_CONFIGURE 1
LOG_BUILD 1
)
set_property(TARGET libbacktrace${suffix}
PROPERTY EXCLUDE_FROM_ALL ${exclude_from_all})
add_clobber_steps(libbacktrace${suffix} clang ${deps})
externalproject_add(libffi${suffix}
DEPENDS clang ${deps}
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libffi
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${suffix}/libffi
CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-multilib "CC=${CMAKE_BINARY_DIR}/bin/clang ${cflags}"
BUILD_COMMAND make -j${PROCESSOR_COUNT}
INSTALL_COMMAND ""
LOG_CONFIGURE 1
LOG_BUILD 1
)
set_property(TARGET libffi${suffix}
PROPERTY EXCLUDE_FROM_ALL ${exclude_from_all})
add_clobber_steps(libffi${suffix} clang ${deps})
externalproject_add(libgo${suffix}
DEPENDS clang llgo cc-wrapper libbacktrace${suffix} libffi${suffix} ${deps}
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${suffix}/libgo
INSTALL_DIR ${CMAKE_BINARY_DIR}
CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-multilib --without-libatomic --prefix=<INSTALL_DIR> "CC=env REAL_CC=${CMAKE_BINARY_DIR}/bin/clang@SPACE@${cflags} ${CMAKE_BINARY_DIR}/bin/cc-wrapper" "GOC=${CMAKE_BINARY_DIR}/bin/llgo -no-prefix -fcompilerrt-prefix=${CMAKE_BINARY_DIR} ${gocflags}"
BUILD_COMMAND make -j${PROCESSOR_COUNT}
LOG_CONFIGURE 1
LOG_BUILD 1
LOG_INSTALL 1
)
set_property(TARGET libgo${suffix}
PROPERTY EXCLUDE_FROM_ALL ${exclude_from_all})
add_clobber_steps(libgo${suffix} clang
${CMAKE_BINARY_DIR}/bin/llgo${CMAKE_EXECUTABLE_SUFFIX}
${CMAKE_BINARY_DIR}/bin/cc-wrapper${CMAKE_EXECUTABLE_SUFFIX})
endfunction()
add_libgo_variant("" "" "" "" FALSE)
if(TARGET asan)
add_libgo_variant("_asan" "-fsanitize=address" "-fsanitize=address" asan TRUE)
endif()
if(TARGET tsan)
add_libgo_variant("_tsan" "-fsanitize=thread" "-fsanitize=thread" tsan TRUE)
endif()
if(TARGET msan)
add_libgo_variant("_msan" "-fsanitize=memory" "-fsanitize=memory" msan TRUE)
endif()
if(TARGET dfsan)
add_libgo_variant("_dfsan" "-fsanitize=dataflow" "-fsanitize=dataflow" dfsan TRUE)
endif()
set(LLGO_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})
install(FILES ${LLGO_LIBRARY_DIR}/libgo-llgo.a
${LLGO_LIBRARY_DIR}/libgo-llgo.so
${LLGO_LIBRARY_DIR}/libgo-llgo.so.8
${LLGO_LIBRARY_DIR}/libgo-llgo.so.8.0.0
${LLGO_LIBRARY_DIR}/libgobegin-llgo.a
DESTINATION lib${LLVM_LIBDIR_SUFFIX})
install(DIRECTORY ${LLGO_LIBRARY_DIR}/go
DESTINATION lib${LLVM_LIBDIR_SUFFIX})
add_custom_target(check-libgo
COMMAND make -C ${CMAKE_CURRENT_BINARY_DIR}/libgo -j${PROCESSOR_COUNT} check
DEPENDS libgo
${cmake_3_2_USES_TERMINAL}
COMMENT "Running libgo tests")
add_custom_target(check-llgo-bootstrap
COMMAND strip -R .note.gnu.build-id -o ${CMAKE_CURRENT_BINARY_DIR}/llgo-stage2.stripped
${CMAKE_BINARY_DIR}/bin/llgo-stage2${CMAKE_EXECUTABLE_SUFFIX}
COMMAND strip -R .note.gnu.build-id -o ${CMAKE_CURRENT_BINARY_DIR}/llgo-stage3.stripped
${CMAKE_BINARY_DIR}/bin/llgo-stage3${CMAKE_EXECUTABLE_SUFFIX}
COMMAND cmp ${CMAKE_CURRENT_BINARY_DIR}/llgo-stage2.stripped
${CMAKE_CURRENT_BINARY_DIR}/llgo-stage3.stripped
DEPENDS llgo-stage2 llgo-stage3
COMMENT "Checking llgo bootstrap")
add_subdirectory(test)

View File

@ -1,308 +0,0 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
The llgo distribution, excluding the contents of the 'include' and any third
party software is licensed under the University of Illinois "BSD-Like" license.
The contents of the 'include' directory are dual licensed under both the
University of Illinois "BSD-Like" license and the MIT license. As a user of
this code you may choose to use it under either license. As a contributor,
you agree to allow your code to be used under both.
Full text of the relevant licenses is included below.
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
LLVM Team
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,74 +0,0 @@
llgo
====
llgo is a Go (http://golang.org) frontend for LLVM, written in Go.
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).
Mailing list: https://groups.google.com/d/forum/llgo-dev
Supported platforms
-------------------
llgo is currently only supported on the x86-64 Linux platform. Contributions
that add support for other platforms are welcome.
There are two components which would need to be ported to new platforms: the
compiler and the runtime library. The compiler has little platform-specific
code; the most significant is in irgen/cabi.go. The main limiting factor
for new platforms is the runtime library in third_party/gofrontend/libgo,
which inherits some support for other platforms from the gc compiler's
runtime library, but this support tends to be incomplete.
Installation
------------
llgo requires:
* Go 1.3 or later.
* CMake 2.8.8 or later (to build LLVM).
* A modern C++ toolchain (to build LLVM).
http://llvm.org/docs/GettingStarted.html#getting-a-modern-host-c-toolchain
Note that Ubuntu Precise is one Linux distribution which does not package
a sufficiently new CMake or C++ toolchain.
To build and install llgo:
# Checkout llvm project.
git clone https://github.com/llvm/llvm-project.git
# Build LLVM, Clang and llgo: (see also http://llvm.org/docs/CMake.html)
cd llvm-project
mkdir build
cd build
cmake ../llvm -DLLVM_ENABLE_PROJECTS='clang;llgo' -DCMAKE_INSTALL_PREFIX=/path/to/llvm-inst
make install
Running
-------
llgo-go is llgo's version of the "go" command. It has the same command line
interface as go, and works the same way, but it uses llgo to compile.
llgoi is an interactive REPL for Go. It supports expressions, statements, most
declarations and imports, including binary imports from the standard library
and source imports from $GOPATH. See docs/llgoi.rst for more information.
llgo is the compiler binary. It has a command line interface that is intended
to be compatible to a large extent with gccgo.
Contributing
------------
Changes to code outside the third_party directory should be contributed in
the normal way by sending patches to <llvm-commits@lists.llvm.org>.
Changes to code in the third_party directory must first be made in the
respective upstream project, from which they will be mirrored into the llgo
repository. See the script update_third_party.sh for the locations of the
upstream projects and details of how the mirroring works.

1770
llgo/autoconf/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
//===- context.go - Build context utilities for llgo ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Build context utilities for llgo.
//
//===----------------------------------------------------------------------===//
package build
import (
"errors"
"go/build"
"regexp"
"strings"
)
type Context struct {
build.Context
// LLVM triple
Triple string
}
// ContextFromTriple returns a new go/build.Context with GOOS and GOARCH
// configured from the given triple.
func ContextFromTriple(triple string) (*Context, error) {
goos, goarch, err := parseTriple(triple)
if err != nil {
return nil, err
}
ctx := &Context{Context: build.Default, Triple: triple}
ctx.GOOS = goos
ctx.GOARCH = goarch
ctx.BuildTags = append(ctx.BuildTags, "llgo")
if triple == "pnacl" {
ctx.BuildTags = append(ctx.BuildTags, "pnacl")
}
return ctx, nil
}
func parseTriple(triple string) (goos string, goarch string, err error) {
if strings.ToLower(triple) == "pnacl" {
return "nacl", "le32", nil
}
type REs struct{ re, out string }
// reference: http://llvm.org/docs/doxygen/html/Triple_8cpp_source.html
goarchREs := []REs{
{"amd64|x86_64", "amd64"},
{"i[3-9]86", "386"},
{"xscale|((arm|thumb)(v.*)?)", "arm"},
}
goosREs := []REs{
{"linux.*", "linux"},
{"(darwin|macosx|ios).*", "darwin"},
{"k?freebsd.*", "freebsd"},
{"netbsd.*", "netbsd"},
{"openbsd.*", "openbsd"},
}
match := func(list []REs, s string) string {
for _, t := range list {
if matched, _ := regexp.MatchString(t.re, s); matched {
return t.out
}
}
return ""
}
s := strings.Split(triple, "-")
switch l := len(s); l {
default:
return "", "", errors.New("triple should be made up of 2, 3, or 4 parts.")
case 2, 3: // ARCHITECTURE-(VENDOR-)OPERATING_SYSTEM
goarch = s[0]
goos = s[l-1]
case 4: // ARCHITECTURE-VENDOR-OPERATING_SYSTEM-ENVIRONMENT
goarch = s[0]
goos = s[2]
}
goarch = match(goarchREs, goarch)
if goarch == "" {
return "", "", errors.New("unknown architecture in triple")
}
goos = match(goosREs, goos)
if goos == "" {
return "", "", errors.New("unknown OS in triple")
}
return goos, goarch, nil
}

View File

@ -1,31 +0,0 @@
# This file contains llgo's configuration for the buildbot-slave Juju charm.
#
# The slave is deployed with the following command in a Juju environment:
# juju deploy cs:~axwalk/buildbot-slave --config buildslave-config.yaml
#
# The charm generates a random password on first run, in the file
# /srv/buildbot/password. If the password is regenerated, it must
# be updated in the buildbot master.
#
buildbot-slave:
name: llgo-builder
master: lab.llvm.org:9990
admin-info: Andrew Wilkins <axwalk@gmail.com>
apt-packages: subversion git cmake gcc g++ gccgo python-dev
pip-versions: sqlalchemy==0.7.9 buildbot==0.8.5 buildbot_slave==0.8.5 twisted==12.0.0
post-install: |
#!/bin/bash
#
# Fetch, build and install Ninja.
rm -fr /tmp/ninja
cd /tmp && git clone git://github.com/martine/ninja.git
cd /tmp/ninja && ./configure.py --bootstrap
cp /tmp/ninja/ninja /usr/local/bin
# Fetch and unpack Go.
cd /tmp && wget https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz
sha1sum <<EOF
5020af94b52b65cc9b6f11d50a67e4bae07b0aff go1.4.2.linux-amd64.tar.gz
EOF
cd /usr/local && tar xzf /tmp/go1.4.2.linux-amd64.tar.gz
ln -f -s /usr/local/go/bin/go /usr/local/bin/go

View File

@ -1,70 +0,0 @@
//===- main.go - Clang compiler wrapper for building libgo ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is a wrapper for Clang that passes invocations with -fdump-go-spec to
// GCC, and rewrites -fplan9-extensions to -fms-extensions. It is intended to
// go away once libgo's build no longer uses these flags.
//
//===----------------------------------------------------------------------===//
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
func runproc(name string, argv []string) {
path, err := exec.LookPath(name)
if err != nil {
fmt.Fprintf(os.Stderr, "cc-wrapper: could not find %s: %v\n", name, err)
os.Exit(1)
}
proc, err := os.StartProcess(path, append([]string{name}, argv...), &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
})
if err != nil {
fmt.Fprintf(os.Stderr, "cc-wrapper: could not start %s: %v\n", name, err)
os.Exit(1)
}
state, err := proc.Wait()
if err != nil {
fmt.Fprintf(os.Stderr, "cc-wrapper: could not wait for %s: %v\n", name, err)
os.Exit(1)
}
if state.Success() {
os.Exit(0)
} else {
os.Exit(1)
}
}
func main() {
newargs := make([]string, len(os.Args)-1)
for i, arg := range os.Args[1:] {
switch {
case strings.HasPrefix(arg, "-fdump-go-spec"):
runproc("gcc", os.Args[1:])
case arg == "-fplan9-extensions":
newargs[i] = "-fms-extensions"
newargs = append(newargs, "-Wno-microsoft")
default:
newargs[i] = arg
}
}
ccargs := strings.Split(os.Getenv("REAL_CC"), "@SPACE@")
runproc(ccargs[0], append(ccargs[1:], newargs...))
}

View File

@ -1,45 +0,0 @@
//===- zdefaultcc.go - default compiler locations -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides a default location for cc.
//
//===----------------------------------------------------------------------===//
package main
import (
"path/filepath"
"os"
"os/exec"
)
var defaultCC string
func getInstPrefix() (string, error) {
path, err := exec.LookPath(os.Args[0])
if err != nil {
return "", err
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
return "", err
}
prefix := filepath.Join(path, "..", "..", "..", "..")
return prefix, nil
}
func init() {
prefix, err := getInstPrefix()
if err != nil {
panic(err.Error())
}
defaultCC = filepath.Join(prefix, "bin", "clang")
}

View File

@ -1,11 +0,0 @@
/* This generated file is for internal use. Do not include it from headers. */
#ifdef CONFIG_H
#error config.h can only be included once
#else
#define CONFIG_H
/* Multilib suffix for libdir. */
#define LLVM_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}"
#endif

View File

@ -1,837 +0,0 @@
//===- gllgo.go - gccgo-like driver for llgo ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is llgo's driver. It has a gccgo-like interface in order to easily
// interoperate with the "go" command and the libgo build system.
//
//===----------------------------------------------------------------------===//
package main
/*
#include "config.h"
*/
import "C"
import (
"errors"
"fmt"
"go/scanner"
"go/token"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"llvm.org/llgo/debug"
"llvm.org/llgo/driver"
"llvm.org/llgo/irgen"
"llvm.org/llvm/bindings/go/llvm"
)
const LibDirSuffix = C.LLVM_LIBDIR_SUFFIX
func report(err error) {
if list, ok := err.(scanner.ErrorList); ok {
for _, e := range list {
fmt.Fprintf(os.Stderr, "%s\n", e)
}
} else if err != nil {
fmt.Fprintf(os.Stderr, "gllgo: error: %s\n", err)
}
}
func llvmVersion() string {
return strings.Replace(llvm.Version, "svn", "", 1)
}
func displayVersion() {
fmt.Printf("llgo version %s (%s)\n\n", llvmVersion(), irgen.GoVersion())
os.Exit(0)
}
func initCompiler(opts *driverOptions) (*irgen.Compiler, error) {
importPaths := make([]string, len(opts.importPaths)+len(opts.libPaths))
copy(importPaths, opts.importPaths)
copy(importPaths[len(opts.importPaths):], opts.libPaths)
if opts.prefix != "" {
importPaths = append(importPaths, filepath.Join(opts.prefix, "lib"+LibDirSuffix, "go", "llgo-"+llvmVersion()))
}
copts := irgen.CompilerOptions{
TargetTriple: opts.triple,
GenerateDebug: opts.generateDebug,
DebugPrefixMaps: opts.debugPrefixMaps,
DumpSSA: opts.dumpSSA,
GccgoPath: opts.gccgoPath,
GccgoABI: opts.gccgoPath != "",
ImportPaths: importPaths,
SanitizerAttribute: opts.sanitizer.getAttribute(),
}
if opts.dumpTrace {
copts.Logger = log.New(os.Stderr, "", 0)
}
return irgen.NewCompiler(copts)
}
type actionKind int
const (
actionAssemble = actionKind(iota)
actionCompile
actionLink
actionPrint
)
type action struct {
kind actionKind
inputs []string
}
type sanitizerOptions struct {
blacklist string
crtPrefix string
address, thread, memory, dataflow bool
}
func (san *sanitizerOptions) resourcePath() string {
return filepath.Join(san.crtPrefix, "lib"+LibDirSuffix, "clang", llvmVersion())
}
func (san *sanitizerOptions) isPIEDefault() bool {
return san.thread || san.memory || san.dataflow
}
func (san *sanitizerOptions) addPasses(mpm, fpm llvm.PassManager) {
switch {
case san.address:
mpm.AddAddressSanitizerModulePass()
fpm.AddAddressSanitizerFunctionPass()
case san.thread:
mpm.AddThreadSanitizerPass()
case san.memory:
mpm.AddMemorySanitizerLegacyPassPass()
case san.dataflow:
blacklist := san.blacklist
if blacklist == "" {
blacklist = filepath.Join(san.resourcePath(), "dfsan_abilist.txt")
}
mpm.AddDataFlowSanitizerPass([]string{blacklist})
}
}
func (san *sanitizerOptions) libPath(triple, sanitizerName string) string {
s := strings.Split(triple, "-")
return filepath.Join(san.resourcePath(), "lib", s[2], "libclang_rt."+sanitizerName+"-"+s[0]+".a")
}
func (san *sanitizerOptions) addLibsForSanitizer(flags []string, triple, sanitizerName string) []string {
return append(flags, san.libPath(triple, sanitizerName),
"-Wl,--no-as-needed", "-lpthread", "-lrt", "-lm", "-ldl")
}
func (san *sanitizerOptions) addLibs(triple string, flags []string) []string {
switch {
case san.address:
flags = san.addLibsForSanitizer(flags, triple, "asan")
case san.thread:
flags = san.addLibsForSanitizer(flags, triple, "tsan")
case san.memory:
flags = san.addLibsForSanitizer(flags, triple, "msan")
case san.dataflow:
flags = san.addLibsForSanitizer(flags, triple, "dfsan")
}
return flags
}
func (san *sanitizerOptions) getAttribute() llvm.Attribute {
var attrKind uint
switch {
case san.address:
attrKind = llvm.AttributeKindID("sanitize_address")
case san.thread:
attrKind = llvm.AttributeKindID("sanitize_thread")
case san.memory:
attrKind = llvm.AttributeKindID("sanitize_memory")
default:
attrKind = 0
}
ctx := llvm.GlobalContext()
return ctx.CreateEnumAttribute(attrKind, 0)
}
type driverOptions struct {
actions []action
output string
bprefix string
debugPrefixMaps []debug.PrefixMap
dumpSSA bool
dumpTrace bool
emitIR bool
gccgoPath string
generateDebug bool
importPaths []string
libPaths []string
llvmArgs []string
lto bool
optLevel int
pic bool
pieLink bool
pkgpath string
plugins []string
prefix string
sanitizer sanitizerOptions
sizeLevel int
staticLibgcc bool
staticLibgo bool
staticLink bool
triple string
}
func getInstPrefix() (string, error) {
path, err := exec.LookPath(os.Args[0])
if err != nil {
return "", err
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
return "", err
}
prefix := filepath.Join(path, "..", "..")
return prefix, nil
}
func parseArguments(args []string) (opts driverOptions, err error) {
var goInputs, otherInputs []string
hasOtherNonFlagInputs := false
noPrefix := false
actionKind := actionLink
opts.triple = llvm.DefaultTargetTriple()
for len(args) > 0 {
consumedArgs := 1
switch {
case !strings.HasPrefix(args[0], "-"):
if strings.HasSuffix(args[0], ".go") {
goInputs = append(goInputs, args[0])
} else {
hasOtherNonFlagInputs = true
otherInputs = append(otherInputs, args[0])
}
case strings.HasPrefix(args[0], "-Wl,"), strings.HasPrefix(args[0], "-l"), strings.HasPrefix(args[0], "--sysroot="):
// TODO(pcc): Handle these correctly.
otherInputs = append(otherInputs, args[0])
case args[0] == "-B":
if len(args) == 1 {
return opts, errors.New("missing argument after '-B'")
}
opts.bprefix = args[1]
consumedArgs = 2
case args[0] == "-D":
if len(args) == 1 {
return opts, errors.New("missing argument after '-D'")
}
otherInputs = append(otherInputs, args[0], args[1])
consumedArgs = 2
case strings.HasPrefix(args[0], "-D"):
otherInputs = append(otherInputs, args[0])
case args[0] == "-I":
if len(args) == 1 {
return opts, errors.New("missing argument after '-I'")
}
opts.importPaths = append(opts.importPaths, args[1])
consumedArgs = 2
case strings.HasPrefix(args[0], "-I"):
opts.importPaths = append(opts.importPaths, args[0][2:])
case args[0] == "-isystem":
if len(args) == 1 {
return opts, errors.New("missing argument after '-isystem'")
}
otherInputs = append(otherInputs, args[0], args[1])
consumedArgs = 2
case args[0] == "-L":
if len(args) == 1 {
return opts, errors.New("missing argument after '-L'")
}
opts.libPaths = append(opts.libPaths, args[1])
consumedArgs = 2
case strings.HasPrefix(args[0], "-L"):
opts.libPaths = append(opts.libPaths, args[0][2:])
case args[0] == "-O0":
opts.optLevel = 0
case args[0] == "-O1", args[0] == "-O":
opts.optLevel = 1
case args[0] == "-O2":
opts.optLevel = 2
case args[0] == "-Os":
opts.optLevel = 2
opts.sizeLevel = 1
case args[0] == "-O3":
opts.optLevel = 3
case args[0] == "-S":
actionKind = actionAssemble
case args[0] == "-c":
actionKind = actionCompile
case strings.HasPrefix(args[0], "-fcompilerrt-prefix="):
opts.sanitizer.crtPrefix = args[0][20:]
case strings.HasPrefix(args[0], "-fdebug-prefix-map="):
split := strings.SplitN(args[0][19:], "=", 2)
if len(split) < 2 {
return opts, fmt.Errorf("argument '%s' must be of form '-fdebug-prefix-map=SOURCE=REPLACEMENT'", args[0])
}
opts.debugPrefixMaps = append(opts.debugPrefixMaps, debug.PrefixMap{split[0], split[1]})
case args[0] == "-fdump-ssa":
opts.dumpSSA = true
case args[0] == "-fdump-trace":
opts.dumpTrace = true
case strings.HasPrefix(args[0], "-fgccgo-path="):
opts.gccgoPath = args[0][13:]
case strings.HasPrefix(args[0], "-fgo-pkgpath="):
opts.pkgpath = args[0][13:]
case strings.HasPrefix(args[0], "-fgo-relative-import-path="):
// TODO(pcc): Handle this.
case strings.HasPrefix(args[0], "-fstack-protector"):
// TODO(axw) set ssp function attributes. This can be useful
// even for Go, if it interfaces with code written in a non-
// memory safe language (e.g. via cgo).
case strings.HasPrefix(args[0], "-W"):
// Go doesn't do warnings. Ignore.
case args[0] == "-fload-plugin":
if len(args) == 1 {
return opts, errors.New("missing argument after '-fload-plugin'")
}
opts.plugins = append(opts.plugins, args[1])
consumedArgs = 2
case args[0] == "-fno-toplevel-reorder":
// This is a GCC-specific code generation option. Ignore.
case args[0] == "-emit-llvm":
opts.emitIR = true
case args[0] == "-flto":
opts.lto = true
case args[0] == "-fPIC":
opts.pic = true
case strings.HasPrefix(args[0], "-fsanitize-blacklist="):
opts.sanitizer.blacklist = args[0][21:]
// TODO(pcc): Enforce mutual exclusion between sanitizers.
case args[0] == "-fsanitize=address":
opts.sanitizer.address = true
case args[0] == "-fsanitize=thread":
opts.sanitizer.thread = true
case args[0] == "-fsanitize=memory":
opts.sanitizer.memory = true
case args[0] == "-fsanitize=dataflow":
opts.sanitizer.dataflow = true
case args[0] == "-g":
opts.generateDebug = true
case args[0] == "-mllvm":
if len(args) == 1 {
return opts, errors.New("missing argument after '-mllvm'")
}
opts.llvmArgs = append(opts.llvmArgs, args[1])
consumedArgs = 2
case strings.HasPrefix(args[0], "-m"), args[0] == "-funsafe-math-optimizations", args[0] == "-ffp-contract=off":
// TODO(pcc): Handle code generation options.
case args[0] == "-no-prefix":
noPrefix = true
case args[0] == "-o":
if len(args) == 1 {
return opts, errors.New("missing argument after '-o'")
}
opts.output = args[1]
consumedArgs = 2
case args[0] == "-pie":
opts.pieLink = true
case args[0] == "-dumpversion",
args[0] == "-print-libgcc-file-name",
args[0] == "-print-multi-os-directory",
args[0] == "--version":
actionKind = actionPrint
opts.output = args[0]
case args[0] == "-static":
opts.staticLink = true
case args[0] == "-static-libgcc":
opts.staticLibgcc = true
case args[0] == "-static-libgo":
opts.staticLibgo = true
default:
return opts, fmt.Errorf("unrecognized command line option '%s'", args[0])
}
args = args[consumedArgs:]
}
if actionKind != actionPrint && len(goInputs) == 0 && !hasOtherNonFlagInputs {
return opts, errors.New("no input files")
}
if !noPrefix {
opts.prefix, err = getInstPrefix()
if err != nil {
return opts, err
}
}
if opts.sanitizer.crtPrefix == "" {
opts.sanitizer.crtPrefix = opts.prefix
}
if opts.sanitizer.isPIEDefault() {
// This should really only be turning on -fPIE, but this isn't
// easy to do from Go, and -fPIC is a superset of it anyway.
opts.pic = true
opts.pieLink = true
}
switch actionKind {
case actionLink:
if len(goInputs) != 0 {
opts.actions = []action{action{actionCompile, goInputs}}
}
opts.actions = append(opts.actions, action{actionLink, otherInputs})
case actionCompile, actionAssemble:
if len(goInputs) != 0 {
opts.actions = []action{action{actionKind, goInputs}}
}
case actionPrint:
opts.actions = []action{action{actionKind, nil}}
}
if opts.output == "" && len(opts.actions) != 0 {
switch actionKind {
case actionCompile, actionAssemble:
base := filepath.Base(goInputs[0])
base = base[0 : len(base)-3]
if actionKind == actionCompile {
opts.output = base + ".o"
} else {
opts.output = base + ".s"
}
case actionLink:
opts.output = "a.out"
}
}
return opts, nil
}
func runPasses(opts *driverOptions, tm llvm.TargetMachine, m llvm.Module) {
fpm := llvm.NewFunctionPassManagerForModule(m)
defer fpm.Dispose()
mpm := llvm.NewPassManager()
defer mpm.Dispose()
pmb := llvm.NewPassManagerBuilder()
defer pmb.Dispose()
pmb.SetOptLevel(opts.optLevel)
pmb.SetSizeLevel(opts.sizeLevel)
tm.AddAnalysisPasses(mpm)
tm.AddAnalysisPasses(fpm)
mpm.AddVerifierPass()
fpm.AddVerifierPass()
pmb.Populate(mpm)
pmb.PopulateFunc(fpm)
if opts.optLevel == 0 {
// Remove references (via the descriptor) to dead functions,
// for compatibility with other compilers.
mpm.AddGlobalDCEPass()
}
opts.sanitizer.addPasses(mpm, fpm)
fpm.InitializeFunc()
for fn := m.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
fpm.RunFunc(fn)
}
fpm.FinalizeFunc()
mpm.Run(m)
}
func getMetadataSectionInlineAsm(name string) string {
// ELF: creates a non-allocated excluded section.
return ".section \"" + name + "\", \"e\"\n"
}
func getDataInlineAsm(data []byte) string {
edata := make([]byte, 0, len(data)*4+10)
edata = append(edata, ".ascii \""...)
for i := range data {
switch data[i] {
case '\000':
edata = append(edata, "\\000"...)
continue
case '\n':
edata = append(edata, "\\n"...)
continue
case '"', '\\':
edata = append(edata, '\\')
}
edata = append(edata, data[i])
}
edata = append(edata, "\"\n"...)
return string(edata)
}
// Get the lib path to the standard libraries for the given driver options.
// This is normally 'lib' but can vary for cross compilation, LTO, sanitizers
// etc.
func getLibDir(opts *driverOptions) string {
lib := "lib" + LibDirSuffix
switch {
case opts.lto:
return filepath.Join(lib, "llvm-lto.0")
case opts.sanitizer.address:
return filepath.Join(lib, "llvm-asan.0")
case opts.sanitizer.thread:
return filepath.Join(lib, "llvm-tsan.0")
case opts.sanitizer.memory:
return filepath.Join(lib, "llvm-msan.0")
case opts.sanitizer.dataflow:
return filepath.Join(lib, "llvm-dfsan.0")
default:
return lib
}
}
func performAction(opts *driverOptions, kind actionKind, inputs []string, output string) error {
switch kind {
case actionPrint:
switch opts.output {
case "-dumpversion":
fmt.Println("llgo-" + llvmVersion())
return nil
case "-print-libgcc-file-name":
cmd := exec.Command(opts.bprefix+"gcc", "-print-libgcc-file-name")
out, err := cmd.CombinedOutput()
os.Stdout.Write(out)
return err
case "-print-multi-os-directory":
fmt.Println(filepath.Join("..", getLibDir(opts)))
return nil
case "--version":
displayVersion()
return nil
default:
panic("unexpected print command")
}
case actionCompile, actionAssemble:
compiler, err := initCompiler(opts)
if err != nil {
return err
}
fset := token.NewFileSet()
files, err := driver.ParseFiles(fset, inputs)
if err != nil {
return err
}
module, err := compiler.Compile(fset, files, opts.pkgpath)
if err != nil {
return err
}
defer module.Dispose()
target, err := llvm.GetTargetFromTriple(opts.triple)
if err != nil {
return err
}
optLevel := [...]llvm.CodeGenOptLevel{
llvm.CodeGenLevelNone,
llvm.CodeGenLevelLess,
llvm.CodeGenLevelDefault,
llvm.CodeGenLevelAggressive,
}[opts.optLevel]
relocMode := llvm.RelocStatic
if opts.pic {
relocMode = llvm.RelocPIC
}
tm := target.CreateTargetMachine(opts.triple, "", "", optLevel,
relocMode, llvm.CodeModelDefault)
defer tm.Dispose()
runPasses(opts, tm, module.Module)
var file *os.File
if output == "-" {
file = os.Stdout
} else {
file, err = os.Create(output)
if err != nil {
return err
}
defer file.Close()
}
switch {
case !opts.lto && !opts.emitIR:
if module.ExportData != nil {
asm := getMetadataSectionInlineAsm(".go_export")
asm += getDataInlineAsm(module.ExportData)
module.Module.SetInlineAsm(asm)
}
fileType := llvm.AssemblyFile
if kind == actionCompile {
fileType = llvm.ObjectFile
}
mb, err := tm.EmitToMemoryBuffer(module.Module, fileType)
if err != nil {
return err
}
defer mb.Dispose()
bytes := mb.Bytes()
_, err = file.Write(bytes)
return err
case opts.lto:
bcmb := llvm.WriteBitcodeToMemoryBuffer(module.Module)
defer bcmb.Dispose()
// This is a bit of a hack. We just want an object file
// containing some metadata sections. This might be simpler
// if we had bindings for the MC library, but for now we create
// a fresh module containing only inline asm that creates the
// sections.
outmodule := llvm.NewModule("")
defer outmodule.Dispose()
asm := getMetadataSectionInlineAsm(".llvmbc")
asm += getDataInlineAsm(bcmb.Bytes())
if module.ExportData != nil {
asm += getMetadataSectionInlineAsm(".go_export")
asm += getDataInlineAsm(module.ExportData)
}
outmodule.SetInlineAsm(asm)
fileType := llvm.AssemblyFile
if kind == actionCompile {
fileType = llvm.ObjectFile
}
mb, err := tm.EmitToMemoryBuffer(outmodule, fileType)
if err != nil {
return err
}
defer mb.Dispose()
bytes := mb.Bytes()
_, err = file.Write(bytes)
return err
case kind == actionCompile:
err := llvm.WriteBitcodeToFile(module.Module, file)
return err
case kind == actionAssemble:
_, err := file.WriteString(module.Module.String())
return err
default:
panic("unexpected action kind")
}
case actionLink:
// TODO(pcc): Teach this to do LTO.
args := []string{"-o", output}
if opts.pic {
args = append(args, "-fPIC")
}
if opts.pieLink {
args = append(args, "-pie")
}
if opts.staticLink {
args = append(args, "-static")
}
if opts.staticLibgcc {
args = append(args, "-static-libgcc")
}
for _, p := range opts.libPaths {
args = append(args, "-L", p)
}
for _, p := range opts.importPaths {
args = append(args, "-I", p)
}
args = append(args, inputs...)
var linkerPath string
if opts.gccgoPath == "" {
// TODO(pcc): See if we can avoid calling gcc here.
// We currently rely on it to find crt*.o and compile
// any C source files passed as arguments.
linkerPath = opts.bprefix + "gcc"
if opts.prefix != "" {
libdir := filepath.Join(opts.prefix, getLibDir(opts))
args = append(args, "-L", libdir)
if !opts.staticLibgo {
args = append(args, "-Wl,-rpath,"+libdir)
}
}
args = append(args, "-lgobegin-llgo")
if opts.staticLibgo {
args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm")
} else {
args = append(args, "-lgo-llgo", "-lm")
}
} else {
linkerPath = opts.gccgoPath
if opts.staticLibgo {
args = append(args, "-static-libgo")
}
}
args = opts.sanitizer.addLibs(opts.triple, args)
cmd := exec.Command(linkerPath, args...)
out, err := cmd.CombinedOutput()
if err != nil {
os.Stderr.Write(out)
}
return err
default:
panic("unexpected action kind")
}
}
func performActions(opts *driverOptions) error {
var extraInput string
for _, plugin := range opts.plugins {
err := llvm.LoadLibraryPermanently(plugin)
if err != nil {
return err
}
}
llvm.ParseCommandLineOptions(append([]string{"llgo"}, opts.llvmArgs...), "llgo (LLVM option parsing)\n")
for i, action := range opts.actions {
var output string
if i == len(opts.actions)-1 {
output = opts.output
} else {
tmpfile, err := ioutil.TempFile("", "llgo")
if err != nil {
return err
}
output = tmpfile.Name() + ".o"
tmpfile.Close()
err = os.Remove(tmpfile.Name())
if err != nil {
return err
}
defer os.Remove(output)
}
inputs := action.inputs
if extraInput != "" {
inputs = append([]string{extraInput}, inputs...)
}
err := performAction(opts, action.kind, inputs, output)
if err != nil {
return err
}
extraInput = output
}
return nil
}
func main() {
llvm.InitializeAllTargets()
llvm.InitializeAllTargetMCs()
llvm.InitializeAllTargetInfos()
llvm.InitializeAllAsmParsers()
llvm.InitializeAllAsmPrinters()
opts, err := parseArguments(os.Args[1:])
if err != nil {
report(err)
os.Exit(1)
}
err = performActions(&opts)
if err != nil {
report(err)
os.Exit(1)
}
}

View File

@ -1,54 +0,0 @@
//===- zdefaultcc.go - default compiler locations -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides default locations for cc, cxx and llgo.
//
//===----------------------------------------------------------------------===//
package main
import (
"path/filepath"
"os"
"os/exec"
)
var defaultGCCGO, defaultCC, defaultCXX string
func getInstPrefix() (string, error) {
path, err := exec.LookPath(os.Args[0])
if err != nil {
return "", err
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
return "", err
}
prefix := filepath.Join(path, "..", "..")
return prefix, nil
}
func init() {
prefix, err := getInstPrefix()
if err != nil {
panic(err.Error())
}
defaultCC = filepath.Join(prefix, "bin", "clang")
defaultCXX = filepath.Join(prefix, "bin", "clang++")
defaultGCCGO = filepath.Join(prefix, "bin", "llgo")
toolDir = filepath.Join(prefix, "lib", "go", "llgo-@LLGO_VERSION@")
gccgoName = os.Getenv("GCCGO")
if gccgoName == "" {
gccgoName = defaultGCCGO
}
gccgoBin, _ = exec.LookPath(gccgoName)
}

View File

@ -1,596 +0,0 @@
//===- llgoi.go - llgo-based Go REPL --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This is llgoi, a Go REPL based on llgo and the LLVM JIT.
//
//===----------------------------------------------------------------------===//
package main
import (
"bytes"
"errors"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/scanner"
"go/token"
"io"
"os"
"os/exec"
"path/filepath"
"runtime/debug"
"strconv"
"strings"
"unsafe"
"llvm.org/llgo/driver"
"llvm.org/llgo/irgen"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llgo/third_party/liner"
"llvm.org/llvm/bindings/go/llvm"
)
// /* Force exporting __morestack if it's available, so that it is
// available to the engine when linking with libLLVM.so. */
//
// void *__morestack __attribute__((weak));
import "C"
func getInstPrefix() (string, error) {
path, err := exec.LookPath(os.Args[0])
if err != nil {
return "", err
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
return "", err
}
prefix := filepath.Join(path, "..", "..")
return prefix, nil
}
func llvmVersion() string {
return strings.Replace(llvm.Version, "svn", "", 1)
}
type line struct {
line string
isStmt bool
declName string
assigns []string
parens, bracks, braces int
}
type interp struct {
engine llvm.ExecutionEngine
liner *liner.State
pendingLine line
copts irgen.CompilerOptions
imports []*types.Package
scope map[string]types.Object
modules map[string]llvm.Module
pkgmap map[string]*types.Package
pkgnum int
}
func (in *interp) makeCompilerOptions() error {
prefix, err := getInstPrefix()
if err != nil {
return err
}
importPaths := []string{filepath.Join(prefix, "lib", "go", "llgo-"+llvmVersion())}
in.copts = irgen.CompilerOptions{
TargetTriple: llvm.DefaultTargetTriple(),
ImportPaths: importPaths,
GenerateDebug: true,
Packages: in.pkgmap,
}
err = in.copts.MakeImporter()
if err != nil {
return err
}
origImporter := in.copts.Importer
in.copts.Importer = func(pkgmap map[string]*types.Package, pkgpath string) (*types.Package, error) {
if pkg, ok := pkgmap[pkgpath]; ok && pkg.Complete() {
return pkg, nil
}
return origImporter(pkgmap, pkgpath)
}
return nil
}
func (in *interp) init() error {
in.liner = liner.NewLiner()
in.scope = make(map[string]types.Object)
in.pkgmap = make(map[string]*types.Package)
in.modules = make(map[string]llvm.Module)
err := in.makeCompilerOptions()
if err != nil {
return err
}
return nil
}
func (in *interp) dispose() {
in.liner.Close()
in.engine.Dispose()
}
func (in *interp) loadSourcePackageFromCode(pkgcode, pkgpath string, copts irgen.CompilerOptions) (*types.Package, error) {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "<input>", pkgcode, parser.DeclarationErrors|parser.ParseComments)
if err != nil {
return nil, err
}
files := []*ast.File{file}
return in.loadSourcePackage(fset, files, pkgpath, copts)
}
func (in *interp) loadSourcePackage(fset *token.FileSet, files []*ast.File, pkgpath string, copts irgen.CompilerOptions) (_ *types.Package, resultErr error) {
compiler, err := irgen.NewCompiler(copts)
if err != nil {
return nil, err
}
module, err := compiler.Compile(fset, files, pkgpath)
if err != nil {
return nil, err
}
in.modules[pkgpath] = module.Module
if in.engine.C != nil {
in.engine.AddModule(module.Module)
} else {
options := llvm.NewMCJITCompilerOptions()
in.engine, err = llvm.NewMCJITCompiler(module.Module, options)
if err != nil {
return nil, err
}
}
var importFunc func()
importAddress := in.getPackageSymbol(pkgpath, ".import$descriptor")
*(*unsafe.Pointer)(unsafe.Pointer(&importFunc)) = importAddress
defer func() {
p := recover()
if p != nil {
resultErr = fmt.Errorf("panic: %v\n%v", p, string(debug.Stack()))
}
}()
importFunc()
in.pkgmap[pkgpath] = module.Package
return module.Package, nil
}
func (in *interp) getPackageSymbol(pkgpath, name string) unsafe.Pointer {
symbolName := irgen.ManglePackagePath(pkgpath) + "." + name
global := in.modules[pkgpath].NamedGlobal(symbolName)
if global.IsNil() {
return nil
}
return in.engine.PointerToGlobal(global)
}
func (in *interp) augmentPackageScope(pkg *types.Package) {
for _, obj := range in.scope {
pkg.Scope().Insert(obj)
}
}
func (l *line) append(str string, assigns []string) {
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(str))
s.Init(file, []byte(str), nil, 0)
_, tok, _ := s.Scan()
if l.line == "" {
switch tok {
case token.FOR, token.GO, token.IF, token.LBRACE, token.SELECT, token.SWITCH:
l.isStmt = true
case token.CONST, token.FUNC, token.TYPE, token.VAR:
var lit string
_, tok, lit = s.Scan()
if tok == token.IDENT {
l.declName = lit
}
}
}
for tok != token.EOF {
switch tok {
case token.LPAREN:
l.parens++
case token.RPAREN:
l.parens--
case token.LBRACE:
l.braces++
case token.RBRACE:
l.braces--
case token.LBRACK:
l.bracks++
case token.RBRACK:
l.bracks--
case token.DEC, token.INC,
token.ASSIGN, token.ADD_ASSIGN, token.SUB_ASSIGN,
token.MUL_ASSIGN, token.QUO_ASSIGN, token.REM_ASSIGN,
token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN,
token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN:
if l.parens == 0 && l.bracks == 0 && l.braces == 0 {
l.isStmt = true
}
}
_, tok, _ = s.Scan()
}
if l.line == "" {
l.assigns = assigns
}
l.line += str
}
func (l *line) ready() bool {
return l.parens <= 0 && l.bracks <= 0 && l.braces <= 0
}
func (in *interp) readExprLine(str string, assigns []string) ([]interface{}, error) {
in.pendingLine.append(str, assigns)
if !in.pendingLine.ready() {
return nil, nil
}
results, err := in.interpretLine(in.pendingLine)
in.pendingLine = line{}
return results, err
}
func (in *interp) interpretLine(l line) ([]interface{}, error) {
pkgname := fmt.Sprintf("input%05d", in.pkgnum)
in.pkgnum++
pkg := types.NewPackage(pkgname, pkgname)
scope := pkg.Scope()
for _, imppkg := range in.imports {
obj := types.NewPkgName(token.NoPos, pkg, imppkg.Name(), imppkg)
scope.Insert(obj)
}
in.augmentPackageScope(pkg)
var tv types.TypeAndValue
if l.declName == "" && !l.isStmt {
var err error
tv, err = types.Eval(l.line, pkg, scope)
if err != nil {
return nil, err
}
}
var code bytes.Buffer
fmt.Fprintf(&code, "package %s\n", pkgname)
for _, pkg := range in.imports {
fmt.Fprintf(&code, "import %q\n", pkg.Path())
}
if l.declName != "" {
code.WriteString(l.line)
} else if !l.isStmt && tv.IsValue() {
var typs []types.Type
if tuple, ok := tv.Type.(*types.Tuple); ok {
typs = make([]types.Type, tuple.Len())
for i := range typs {
typs[i] = tuple.At(i).Type()
}
} else {
typs = []types.Type{tv.Type}
}
if len(l.assigns) == 2 && tv.HasOk() {
typs = append(typs, types.Typ[types.Bool])
}
if len(l.assigns) != 0 && len(l.assigns) != len(typs) {
return nil, errors.New("return value mismatch")
}
code.WriteString("var ")
for i := range typs {
if i != 0 {
code.WriteString(", ")
}
if len(l.assigns) != 0 && l.assigns[i] != "" {
if _, ok := in.scope[l.assigns[i]]; ok {
fmt.Fprintf(&code, "__llgoiV%d", i)
} else {
code.WriteString(l.assigns[i])
}
} else {
fmt.Fprintf(&code, "__llgoiV%d", i)
}
}
fmt.Fprintf(&code, " = %s\n", l.line)
code.WriteString("func init() {\n")
varnames := make([]string, len(typs))
for i := range typs {
var varname string
if len(l.assigns) != 0 && l.assigns[i] != "" {
if _, ok := in.scope[l.assigns[i]]; ok {
fmt.Fprintf(&code, "\t%s = __llgoiV%d\n", l.assigns[i], i)
}
varname = l.assigns[i]
} else {
varname = fmt.Sprintf("__llgoiV%d", i)
}
varnames[i] = varname
}
code.WriteString("}\n\n")
code.WriteString("func __llgoiResults() []interface{} {\n")
code.WriteString("\treturn []interface{}{\n")
for _, varname := range varnames {
fmt.Fprintf(&code, "\t\t%s,\n", varname)
}
code.WriteString("\t}\n")
code.WriteString("}\n")
} else {
if len(l.assigns) != 0 {
return nil, errors.New("return value mismatch")
}
fmt.Fprintf(&code, "func init() {\n\t%s}", l.line)
}
copts := in.copts
copts.PackageCreated = in.augmentPackageScope
copts.DisableUnusedImportCheck = true
pkg, err := in.loadSourcePackageFromCode(code.String(), pkgname, copts)
if err != nil {
return nil, err
}
in.imports = append(in.imports, pkg)
var results []interface{}
llgoiResultsAddress := in.getPackageSymbol(pkgname, "__llgoiResults$descriptor")
if llgoiResultsAddress != nil {
var resultsFunc func() []interface{}
*(*unsafe.Pointer)(unsafe.Pointer(&resultsFunc)) = llgoiResultsAddress
results = resultsFunc()
}
for _, assign := range l.assigns {
if assign != "" {
if _, ok := in.scope[assign]; !ok {
in.scope[assign] = pkg.Scope().Lookup(assign)
}
}
}
if l.declName != "" {
in.scope[l.declName] = pkg.Scope().Lookup(l.declName)
}
return results, nil
}
func (in *interp) maybeReadAssignment(line string, s *scanner.Scanner, initial string, base int) (bool, error) {
if initial == "_" {
initial = ""
}
assigns := []string{initial}
pos, tok, lit := s.Scan()
for tok == token.COMMA {
pos, tok, lit = s.Scan()
if tok != token.IDENT {
return false, nil
}
if lit == "_" {
lit = ""
}
assigns = append(assigns, lit)
pos, tok, lit = s.Scan()
}
if tok != token.DEFINE {
return false, nil
}
// It's an assignment statement, there are no results.
_, err := in.readExprLine(line[int(pos)-base+2:], assigns)
return true, err
}
func (in *interp) loadPackage(pkgpath string) (*types.Package, error) {
pkg, err := in.copts.Importer(in.pkgmap, pkgpath)
if err == nil {
return pkg, nil
}
buildpkg, err := build.Import(pkgpath, ".", 0)
if err != nil {
return nil, err
}
if len(buildpkg.CgoFiles) != 0 {
return nil, fmt.Errorf("%s: cannot load cgo package", pkgpath)
}
for _, imp := range buildpkg.Imports {
_, err := in.loadPackage(imp)
if err != nil {
return nil, err
}
}
inputs := make([]string, len(buildpkg.GoFiles))
for i, file := range buildpkg.GoFiles {
inputs[i] = filepath.Join(buildpkg.Dir, file)
}
fset := token.NewFileSet()
files, err := driver.ParseFiles(fset, inputs)
if err != nil {
return nil, err
}
return in.loadSourcePackage(fset, files, pkgpath, in.copts)
}
// readLine accumulates lines of input, including trailing newlines,
// executing statements as they are completed.
func (in *interp) readLine(line string) ([]interface{}, error) {
if !in.pendingLine.ready() {
return in.readExprLine(line, nil)
}
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(line))
s.Init(file, []byte(line), nil, 0)
_, tok, lit := s.Scan()
switch tok {
case token.EOF:
return nil, nil
case token.IMPORT:
_, tok, lit = s.Scan()
if tok != token.STRING {
return nil, errors.New("expected string literal")
}
pkgpath, err := strconv.Unquote(lit)
if err != nil {
return nil, err
}
pkg, err := in.loadPackage(pkgpath)
if err != nil {
return nil, err
}
in.imports = append(in.imports, pkg)
return nil, nil
case token.IDENT:
ok, err := in.maybeReadAssignment(line, &s, lit, file.Base())
if err != nil {
return nil, err
}
if ok {
return nil, nil
}
fallthrough
default:
return in.readExprLine(line, nil)
}
}
// printResult prints a value that was the result of an expression evaluated
// by the interpreter.
func printResult(w io.Writer, v interface{}) {
// TODO the result should be formatted in Go syntax, without
// package qualifiers for types defined within the interpreter.
fmt.Fprintf(w, "%+v", v)
}
// formatHistory reformats the provided Go source by collapsing all lines
// and adding semicolons where required, suitable for adding to line history.
func formatHistory(input []byte) string {
var buf bytes.Buffer
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(input))
s.Init(file, input, nil, 0)
pos, tok, lit := s.Scan()
for tok != token.EOF {
if int(pos)-1 > buf.Len() {
n := int(pos) - 1 - buf.Len()
buf.WriteString(strings.Repeat(" ", n))
}
var semicolon bool
if tok == token.SEMICOLON {
semicolon = true
} else if lit != "" {
buf.WriteString(lit)
} else {
buf.WriteString(tok.String())
}
pos, tok, lit = s.Scan()
if semicolon {
switch tok {
case token.RBRACE, token.RPAREN, token.EOF:
default:
buf.WriteRune(';')
}
}
}
return buf.String()
}
func main() {
llvm.LinkInMCJIT()
llvm.InitializeNativeTarget()
llvm.InitializeNativeAsmPrinter()
var in interp
err := in.init()
if err != nil {
panic(err)
}
defer in.dispose()
var buf bytes.Buffer
for {
if in.pendingLine.ready() && buf.Len() > 0 {
history := formatHistory(buf.Bytes())
in.liner.AppendHistory(history)
buf.Reset()
}
prompt := "(llgo) "
if !in.pendingLine.ready() {
prompt = strings.Repeat(" ", len(prompt))
}
line, err := in.liner.Prompt(prompt)
if err == io.EOF {
break
} else if err != nil {
panic(err)
}
if line == "" {
continue
}
buf.WriteString(line + "\n")
results, err := in.readLine(line + "\n")
if err != nil {
fmt.Println(err)
}
for _, result := range results {
printResult(os.Stdout, result)
fmt.Println()
}
}
if liner.TerminalSupported() {
fmt.Println()
}
}

View File

@ -1,431 +0,0 @@
//===- debug.go - debug info builder --------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This package builds LLVM debug info from go/* data structures.
//
//===----------------------------------------------------------------------===//
package debug
import (
"debug/dwarf"
"fmt"
"go/token"
"os"
"strings"
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llgo/third_party/gotools/go/types/typeutil"
"llvm.org/llvm/bindings/go/llvm"
)
const (
// non-standard debug metadata tags
tagAutoVariable dwarf.Tag = 0x100
tagArgVariable dwarf.Tag = 0x101
)
type PrefixMap struct {
Source, Replacement string
}
// DIBuilder builds debug metadata for Go programs.
type DIBuilder struct {
// builder is the current builder; there is one per CU.
builder *llvm.DIBuilder
module llvm.Module
files map[*token.File]llvm.Metadata
cu, fn, lb llvm.Metadata
fnFile string
sizes types.Sizes
fset *token.FileSet
prefixMaps []PrefixMap
types typeutil.Map
voidType llvm.Metadata
}
// NewDIBuilder creates a new debug information builder.
func NewDIBuilder(sizes types.Sizes, module llvm.Module, fset *token.FileSet, prefixMaps []PrefixMap) *DIBuilder {
var d DIBuilder
d.module = module
d.files = make(map[*token.File]llvm.Metadata)
d.sizes = sizes
d.fset = fset
d.prefixMaps = prefixMaps
d.builder = llvm.NewDIBuilder(d.module)
d.cu = d.createCompileUnit()
return &d
}
// Destroy destroys the DIBuilder.
func (d *DIBuilder) Destroy() {
d.builder.Destroy()
}
func (d *DIBuilder) scope() llvm.Metadata {
if d.lb.C != nil {
return d.lb
}
if d.fn.C != nil {
return d.fn
}
return d.cu
}
func (d *DIBuilder) remapFilePath(path string) string {
for _, pm := range d.prefixMaps {
if strings.HasPrefix(path, pm.Source) {
return pm.Replacement + path[len(pm.Source):]
}
}
return path
}
func (d *DIBuilder) getFile(file *token.File) llvm.Metadata {
if diFile := d.files[file]; diFile.C != nil {
return diFile
}
diFile := d.builder.CreateFile(d.remapFilePath(file.Name()), "")
d.files[file] = diFile
return diFile
}
// createCompileUnit creates and returns debug metadata for the compile
// unit as a whole, using the first file in the file set as a representative
// (the choice of file is arbitrary).
func (d *DIBuilder) createCompileUnit() llvm.Metadata {
var file *token.File
d.fset.Iterate(func(f *token.File) bool {
file = f
return false
})
dir, err := os.Getwd()
if err != nil {
panic("could not get current directory: " + err.Error())
}
return d.builder.CreateCompileUnit(llvm.DICompileUnit{
Language: llvm.DW_LANG_Go,
File: d.remapFilePath(file.Name()),
Dir: dir,
Producer: "llgo",
})
}
// PushFunction creates debug metadata for the specified function,
// and pushes it onto the scope stack.
func (d *DIBuilder) PushFunction(fnptr llvm.Value, sig *types.Signature, pos token.Pos) {
var diFile llvm.Metadata
var line int
if file := d.fset.File(pos); file != nil {
d.fnFile = file.Name()
diFile = d.getFile(file)
line = file.Line(pos)
}
d.fn = d.builder.CreateFunction(d.scope(), llvm.DIFunction{
Name: fnptr.Name(), // TODO(axw) unmangled name?
LinkageName: fnptr.Name(),
File: diFile,
Line: line,
Type: d.DIType(sig),
IsDefinition: true,
})
fnptr.SetSubprogram(d.fn)
}
// PopFunction pops the previously pushed function off the scope stack.
func (d *DIBuilder) PopFunction() {
d.lb = llvm.Metadata{}
d.fn = llvm.Metadata{}
d.fnFile = ""
}
// Value creates an llvm.dbg.value call for the specified register value.
func (d *DIBuilder) Value(b llvm.Builder, v ssa.Value, llv llvm.Value, paramIndex int) {
// TODO(axw)
}
// SetLocation sets the current debug location.
func (d *DIBuilder) SetLocation(b llvm.Builder, pos token.Pos) {
position := d.fset.Position(pos)
d.lb = llvm.Metadata{}
if position.Filename != d.fnFile && position.Filename != "" {
// This can happen rarely, e.g. in init functions.
diFile := d.builder.CreateFile(d.remapFilePath(position.Filename), "")
d.lb = d.builder.CreateLexicalBlockFile(d.scope(), diFile, 0)
}
b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), d.scope(), llvm.Metadata{})
}
// Finalize must be called after all compilation units are translated,
// generating the final debug metadata for the module.
func (d *DIBuilder) Finalize() {
d.module.AddNamedMetadataOperand(
"llvm.module.flags",
llvm.GlobalContext().MDNode([]llvm.Metadata{
llvm.ConstInt(llvm.Int32Type(), 2, false).ConstantAsMetadata(), // Warn on mismatch
llvm.GlobalContext().MDString("Dwarf Version"),
llvm.ConstInt(llvm.Int32Type(), 4, false).ConstantAsMetadata(),
}),
)
d.module.AddNamedMetadataOperand(
"llvm.module.flags",
llvm.GlobalContext().MDNode([]llvm.Metadata{
llvm.ConstInt(llvm.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch
llvm.GlobalContext().MDString("Debug Info Version"),
llvm.ConstInt(llvm.Int32Type(), 3, false).ConstantAsMetadata(),
}),
)
d.builder.Finalize()
}
// DIType maps a Go type to DIType debug metadata value.
func (d *DIBuilder) DIType(t types.Type) llvm.Metadata {
return d.typeDebugDescriptor(t, types.TypeString(nil, t))
}
func (d *DIBuilder) typeDebugDescriptor(t types.Type, name string) llvm.Metadata {
// Signature needs to be handled specially, to preprocess
// methods, moving the receiver to the parameter list.
if t, ok := t.(*types.Signature); ok {
return d.descriptorSignature(t, name)
}
if t == nil {
if d.voidType.C == nil {
d.voidType = d.builder.CreateBasicType(llvm.DIBasicType{Name: "void"})
}
return d.voidType
}
if dt, ok := d.types.At(t).(llvm.Metadata); ok {
return dt
}
dt := d.descriptor(t, name)
d.types.Set(t, dt)
return dt
}
func (d *DIBuilder) descriptor(t types.Type, name string) llvm.Metadata {
switch t := t.(type) {
case *types.Basic:
return d.descriptorBasic(t, name)
case *types.Pointer:
return d.descriptorPointer(t)
case *types.Struct:
return d.descriptorStruct(t, name)
case *types.Named:
return d.descriptorNamed(t)
case *types.Array:
return d.descriptorArray(t, name)
case *types.Slice:
return d.descriptorSlice(t, name)
case *types.Map:
return d.descriptorMap(t, name)
case *types.Chan:
return d.descriptorChan(t, name)
case *types.Interface:
return d.descriptorInterface(t, name)
default:
panic(fmt.Sprintf("unhandled type: %T", t))
}
}
func (d *DIBuilder) descriptorBasic(t *types.Basic, name string) llvm.Metadata {
switch t.Kind() {
case types.String:
return d.typeDebugDescriptor(types.NewStruct([]*types.Var{
types.NewVar(0, nil, "ptr", types.NewPointer(types.Typ[types.Uint8])),
types.NewVar(0, nil, "len", types.Typ[types.Int]),
}, nil), name)
case types.UnsafePointer:
return d.builder.CreateBasicType(llvm.DIBasicType{
Name: name,
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
Encoding: llvm.DW_ATE_unsigned,
})
default:
bt := llvm.DIBasicType{
Name: t.String(),
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
}
switch bi := t.Info(); {
case bi&types.IsBoolean != 0:
bt.Encoding = llvm.DW_ATE_boolean
case bi&types.IsUnsigned != 0:
bt.Encoding = llvm.DW_ATE_unsigned
case bi&types.IsInteger != 0:
bt.Encoding = llvm.DW_ATE_signed
case bi&types.IsFloat != 0:
bt.Encoding = llvm.DW_ATE_float
case bi&types.IsComplex != 0:
bt.Encoding = llvm.DW_ATE_imaginary_float
case bi&types.IsUnsigned != 0:
bt.Encoding = llvm.DW_ATE_unsigned
default:
panic(fmt.Sprintf("unhandled: %#v", t))
}
return d.builder.CreateBasicType(bt)
}
}
func (d *DIBuilder) descriptorPointer(t *types.Pointer) llvm.Metadata {
return d.builder.CreatePointerType(llvm.DIPointerType{
Pointee: d.DIType(t.Elem()),
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
AlignInBits: uint32(d.sizes.Alignof(t) * 8),
})
}
func (d *DIBuilder) descriptorStruct(t *types.Struct, name string) llvm.Metadata {
fields := make([]*types.Var, t.NumFields())
for i := range fields {
fields[i] = t.Field(i)
}
offsets := d.sizes.Offsetsof(fields)
members := make([]llvm.Metadata, len(fields))
for i, f := range fields {
// TODO(axw) file/line where member is defined.
t := f.Type()
members[i] = d.builder.CreateMemberType(d.cu, llvm.DIMemberType{
Name: f.Name(),
Type: d.DIType(t),
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
AlignInBits: uint32(d.sizes.Alignof(t) * 8),
OffsetInBits: uint64(offsets[i] * 8),
})
}
// TODO(axw) file/line where struct is defined.
return d.builder.CreateStructType(d.cu, llvm.DIStructType{
Name: name,
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
AlignInBits: uint32(d.sizes.Alignof(t) * 8),
Elements: members,
})
}
func (d *DIBuilder) descriptorNamed(t *types.Named) llvm.Metadata {
var diFile llvm.Metadata
var line int
if file := d.fset.File(t.Obj().Pos()); file != nil {
line = file.Line(t.Obj().Pos())
diFile = d.getFile(file)
}
// Create a placeholder for the named type, to terminate cycles.
name := t.Obj().Name()
placeholder := d.builder.CreateReplaceableCompositeType(d.scope(), llvm.DIReplaceableCompositeType{
Tag: dwarf.TagStructType,
Name: name,
File: diFile,
Line: line,
})
d.types.Set(t, placeholder)
typedef := d.builder.CreateTypedef(llvm.DITypedef{
Type: d.DIType(t.Underlying()),
Name: name,
File: diFile,
Line: line,
})
placeholder.ReplaceAllUsesWith(typedef)
return typedef
}
func (d *DIBuilder) descriptorArray(t *types.Array, name string) llvm.Metadata {
return d.builder.CreateArrayType(llvm.DIArrayType{
SizeInBits: uint64(d.sizes.Sizeof(t) * 8),
AlignInBits: uint32(d.sizes.Alignof(t) * 8),
ElementType: d.DIType(t.Elem()),
Subscripts: []llvm.DISubrange{{Count: t.Len()}},
})
}
func (d *DIBuilder) descriptorSlice(t *types.Slice, name string) llvm.Metadata {
sliceStruct := types.NewStruct([]*types.Var{
types.NewVar(0, nil, "ptr", types.NewPointer(t.Elem())),
types.NewVar(0, nil, "len", types.Typ[types.Int]),
types.NewVar(0, nil, "cap", types.Typ[types.Int]),
}, nil)
return d.typeDebugDescriptor(sliceStruct, name)
}
func (d *DIBuilder) descriptorMap(t *types.Map, name string) llvm.Metadata {
// FIXME: This should be DW_TAG_pointer_type to __go_map.
return d.descriptorBasic(types.Typ[types.Uintptr], name)
}
func (d *DIBuilder) descriptorChan(t *types.Chan, name string) llvm.Metadata {
// FIXME: This should be DW_TAG_pointer_type to __go_channel.
return d.descriptorBasic(types.Typ[types.Uintptr], name)
}
func (d *DIBuilder) descriptorInterface(t *types.Interface, name string) llvm.Metadata {
ifaceStruct := types.NewStruct([]*types.Var{
types.NewVar(0, nil, "type", types.NewPointer(types.Typ[types.Uint8])),
types.NewVar(0, nil, "data", types.NewPointer(types.Typ[types.Uint8])),
}, nil)
return d.typeDebugDescriptor(ifaceStruct, name)
}
func (d *DIBuilder) descriptorSignature(t *types.Signature, name string) llvm.Metadata {
// If there's a receiver change the receiver to an
// additional (first) parameter, and take the value of
// the resulting signature instead.
if recv := t.Recv(); recv != nil {
params := t.Params()
paramvars := make([]*types.Var, int(params.Len()+1))
paramvars[0] = recv
for i := 0; i < int(params.Len()); i++ {
paramvars[i+1] = params.At(i)
}
params = types.NewTuple(paramvars...)
t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic())
return d.typeDebugDescriptor(t, name)
}
if dt, ok := d.types.At(t).(llvm.Metadata); ok {
return dt
}
var returnType llvm.Metadata
results := t.Results()
switch n := results.Len(); n {
case 0:
returnType = d.DIType(nil) // void
case 1:
returnType = d.DIType(results.At(0).Type())
default:
fields := make([]*types.Var, results.Len())
for i := range fields {
f := results.At(i)
// Structs may not have multiple fields
// with the same name, excepting "_".
if f.Name() == "" {
f = types.NewVar(f.Pos(), f.Pkg(), "_", f.Type())
}
fields[i] = f
}
returnType = d.typeDebugDescriptor(types.NewStruct(fields, nil), "")
}
var paramTypes []llvm.Metadata
params := t.Params()
if params != nil && params.Len() > 0 {
paramTypes = make([]llvm.Metadata, params.Len()+1)
paramTypes[0] = returnType
for i := range paramTypes[1:] {
paramTypes[i+1] = d.DIType(params.At(i).Type())
}
} else {
paramTypes = []llvm.Metadata{returnType}
}
// TODO(axw) get position of type definition for File field
return d.builder.CreateSubroutineType(llvm.DISubroutineType{
Parameters: paramTypes,
})
}

View File

@ -1,177 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/llgo.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/llgo.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/llgo"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/llgo"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

View File

@ -1,258 +0,0 @@
# -*- coding: utf-8 -*-
#
# llgo documentation build configuration file, created by
# sphinx-quickstart on Sun Apr 5 16:02:16 2015.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'llgo'
copyright = u'2015, LLVM Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.7'
# The full version, including alpha/beta/rc tags.
release = '3.7'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'llgodoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'llgo.tex', u'llgo Documentation',
u'LLVM Team', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'llgo', u'llgo Documentation',
[u'LLVM Team'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'llgo', u'llgo Documentation',
u'LLVM Team', 'llgo', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False

View File

@ -1,23 +0,0 @@
.. llgo documentation master file, created by
sphinx-quickstart on Sun Apr 5 16:02:16 2015.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to llgo's documentation!
================================
Contents:
.. toctree::
:maxdepth: 2
llgoi
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -1,80 +0,0 @@
=====
llgoi
=====
Introduction
============
llgoi is an interactive REPL for Go. It supports expressions, statements,
most declarations and imports, including binary imports from the standard
library and source imports from ``$GOPATH``.
Example usage
=============
.. code-block:: none
(llgo) 1+1
#0 untyped int = 2
(llgo) x := 1
x untyped int = 1
(llgo) x++
(llgo) x
#0 int = 2
(llgo) import "fmt"
(llgo) fmt.Println("hello world")
hello world
#0 int = 12
#1 error (<nil>) = <nil>
(llgo) for i := 0; i != 3; i++ {
fmt.Println(i)
}
0
1
2
(llgo) func foo() {
fmt.Println("hello decl")
}
(llgo) foo()
hello decl
(llgo) import "golang.org/x/tools/go/types"
# golang.org/x/tools/go/ast/astutil
# golang.org/x/tools/go/exact
# golang.org/x/tools/go/types
(llgo) types.Eval("1+1", nil, nil)
#0 golang.org/x/tools/go/types.TypeAndValue = {mode:4 Type:untyped int Value:2}
#1 error (<nil>) = <nil>
Expressions
===========
Expressions can be evaluated by entering them at the llgoi prompt. The
result of evaluating the expression is displayed as if printed with the
format string ``"%+v"``. If the expression has multiple values (e.g. calls),
each value is displayed separately.
Declarations
============
Declarations introduce new entities into llgoi's scope. For example, entering
``x := 1`` introduces into the scope a variable named ``x`` with an initial
value of 1. In addition to short variable declarations (i.e. variables declared
with ``:=``), llgoi supports constant declarations, function declarations,
variable declarations and type declarations.
Imports
=======
To import a package, enter ``import`` followed by the name of a package
surrounded by quotes. This introduces the package name into llgoi's
scope. The package may be a standard library package, or a source package on
``$GOPATH``. In the latter case, llgoi will first compile the package and
its dependencies.
Statements
==========
Aside from declarations and expressions, the following kinds of statements
can be evaluated by entering them at the llgoi prompt: IncDec statements,
assignments, go statements, blocks, if statements, switch statements, select
statements and for statements.

View File

@ -1,242 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\llgo.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\llgo.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %BUILDDIR%/..
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

View File

@ -1,42 +0,0 @@
//===- parser.go - parser wrapper -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains functions for calling the parser in an appropriate way for
// llgo.
//
//===----------------------------------------------------------------------===//
package driver
import (
"fmt"
"go/ast"
"go/parser"
"go/scanner"
"go/token"
)
func parseFile(fset *token.FileSet, filename string) (*ast.File, error) {
// Retain comments; this is important for annotation processing.
mode := parser.DeclarationErrors | parser.ParseComments
return parser.ParseFile(fset, filename, nil, mode)
}
func ParseFiles(fset *token.FileSet, filenames []string) ([]*ast.File, error) {
files := make([]*ast.File, len(filenames))
for i, filename := range filenames {
file, err := parseFile(fset, filename)
if _, ok := err.(scanner.ErrorList); ok {
return nil, err
} else if err != nil {
return nil, fmt.Errorf("%q: %v", filename, err)
}
files[i] = file
}
return files, nil
}

View File

@ -1,93 +0,0 @@
//===----------------------------- dwarf2.h -------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// DWARF constants. Derived from:
// - libcxxabi/src/Unwind/dwarf2.h
// - DWARF 4 specification
//
//===----------------------------------------------------------------------===//
#ifndef DWARF2_H
#define DWARF2_H
enum dwarf_attribute {
DW_AT_name = 0x03,
DW_AT_stmt_list = 0x10,
DW_AT_low_pc = 0x11,
DW_AT_high_pc = 0x12,
DW_AT_comp_dir = 0x1b,
DW_AT_abstract_origin = 0x31,
DW_AT_specification = 0x47,
DW_AT_ranges = 0x55,
DW_AT_call_file = 0x58,
DW_AT_call_line = 0x59,
DW_AT_linkage_name = 0x6e,
DW_AT_MIPS_linkage_name = 0x2007
};
enum dwarf_form {
DW_FORM_addr = 0x01,
DW_FORM_block2 = 0x03,
DW_FORM_block4 = 0x04,
DW_FORM_data2 = 0x05,
DW_FORM_data4 = 0x06,
DW_FORM_data8 = 0x07,
DW_FORM_string = 0x08,
DW_FORM_block = 0x09,
DW_FORM_block1 = 0x0a,
DW_FORM_data1 = 0x0b,
DW_FORM_flag = 0x0c,
DW_FORM_sdata = 0x0d,
DW_FORM_strp = 0x0e,
DW_FORM_udata = 0x0f,
DW_FORM_ref_addr = 0x10,
DW_FORM_ref1 = 0x11,
DW_FORM_ref2 = 0x12,
DW_FORM_ref4 = 0x13,
DW_FORM_ref8 = 0x14,
DW_FORM_ref_udata = 0x15,
DW_FORM_indirect = 0x16,
DW_FORM_sec_offset = 0x17,
DW_FORM_exprloc = 0x18,
DW_FORM_flag_present = 0x19,
DW_FORM_ref_sig8 = 0x20,
DW_FORM_GNU_addr_index = 0x1f01,
DW_FORM_GNU_str_index = 0x1f02,
DW_FORM_GNU_ref_alt = 0x1f20,
DW_FORM_GNU_strp_alt = 0x1f21
};
enum dwarf_tag {
DW_TAG_entry_point = 0x03,
DW_TAG_compile_unit = 0x11,
DW_TAG_inlined_subroutine = 0x1d,
DW_TAG_subprogram = 0x2e
};
enum dwarf_lns {
DW_LNS_extended_op = 0x00,
DW_LNS_copy = 0x01,
DW_LNS_advance_pc = 0x02,
DW_LNS_advance_line = 0x03,
DW_LNS_set_file = 0x04,
DW_LNS_set_column = 0x05,
DW_LNS_negate_stmt = 0x06,
DW_LNS_set_basic_block = 0x07,
DW_LNS_const_add_pc = 0x08,
DW_LNS_fixed_advance_pc = 0x09,
DW_LNS_set_prologue_end = 0x0a,
DW_LNS_set_epilogue_begin = 0x0b,
DW_LNS_set_isa = 0x0c
};
enum dwarf_lne {
DW_LNE_end_sequence = 0x01,
DW_LNE_set_address = 0x02,
DW_LNE_define_file = 0x03,
DW_LNE_set_discriminator = 0x04
};
#endif // DWARF2_H

View File

@ -1,14 +0,0 @@
//===----------------------------- filenames.h ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef FILENAMES_H
#define FILENAMES_H
#define IS_ABSOLUTE_PATH(path) ((path)[0] == '/')
#endif

View File

@ -1,200 +0,0 @@
//===----------------------------- unwind-pe.h ----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Pointer-Encoding decoder. Derived from:
// - libcxxabi/src/Unwind/dwarf2.h
// - libcxxabi/src/Unwind/AddressSpace.h
//
//===----------------------------------------------------------------------===//
#ifndef UNWIND_PE_H
#define UNWIND_PE_H
#include <assert.h>
#include <stdint.h>
#include <string.h>
// FSF exception handling Pointer-Encoding constants
// Used in CFI augmentation by GCC
enum {
DW_EH_PE_ptr = 0x00,
DW_EH_PE_uleb128 = 0x01,
DW_EH_PE_udata2 = 0x02,
DW_EH_PE_udata4 = 0x03,
DW_EH_PE_udata8 = 0x04,
DW_EH_PE_signed = 0x08,
DW_EH_PE_sleb128 = 0x09,
DW_EH_PE_sdata2 = 0x0A,
DW_EH_PE_sdata4 = 0x0B,
DW_EH_PE_sdata8 = 0x0C,
DW_EH_PE_absptr = 0x00,
DW_EH_PE_pcrel = 0x10,
DW_EH_PE_textrel = 0x20,
DW_EH_PE_datarel = 0x30,
DW_EH_PE_funcrel = 0x40,
DW_EH_PE_aligned = 0x50,
DW_EH_PE_indirect = 0x80,
DW_EH_PE_omit = 0xFF
};
/// Read a ULEB128 into a 64-bit word.
static uint64_t unw_getULEB128(uintptr_t *addr) {
const uint8_t *p = (uint8_t *)*addr;
uint64_t result = 0;
int bit = 0;
do {
uint64_t b;
b = *p & 0x7f;
if (bit >= 64 || b << bit >> bit != b) {
assert(!"malformed uleb128 expression");
} else {
result |= b << bit;
bit += 7;
}
} while (*p++ >= 0x80);
*addr = (uintptr_t) p;
return result;
}
/// Read a SLEB128 into a 64-bit word.
static int64_t unw_getSLEB128(uintptr_t *addr) {
const uint8_t *p = (uint8_t *)addr;
int64_t result = 0;
int bit = 0;
uint8_t byte;
do {
byte = *p++;
result |= ((byte & 0x7f) << bit);
bit += 7;
} while (byte & 0x80);
// sign extend negative numbers
if ((byte & 0x40) != 0)
result |= (-1LL) << bit;
*addr = (uintptr_t) p;
return result;
}
static uint16_t unw_get16(uintptr_t addr) {
uint16_t val;
memcpy(&val, (void *)addr, sizeof(val));
return val;
}
static uint32_t unw_get32(uintptr_t addr) {
uint32_t val;
memcpy(&val, (void *)addr, sizeof(val));
return val;
}
static uint64_t unw_get64(uintptr_t addr) {
uint64_t val;
memcpy(&val, (void *)addr, sizeof(val));
return val;
}
static uintptr_t unw_getP(uintptr_t addr) {
if (sizeof(uintptr_t) == 8)
return unw_get64(addr);
else
return unw_get32(addr);
}
static const unsigned char *read_uleb128(const unsigned char *p,
_uleb128_t *ret) {
uintptr_t addr = (uintptr_t)p;
*ret = unw_getULEB128(&addr);
return (unsigned char *)addr;
}
static const unsigned char *read_encoded_value(struct _Unwind_Context *ctx,
unsigned char encoding,
const unsigned char *p,
_Unwind_Ptr *ret) {
uintptr_t addr = (uintptr_t)p;
uintptr_t startAddr = addr;
uintptr_t result;
(void)ctx;
// first get value
switch (encoding & 0x0F) {
case DW_EH_PE_ptr:
result = unw_getP(addr);
p += sizeof(uintptr_t);
break;
case DW_EH_PE_uleb128:
result = (uintptr_t)unw_getULEB128(&addr);
p = (const unsigned char *)addr;
break;
case DW_EH_PE_udata2:
result = unw_get16(addr);
p += 2;
break;
case DW_EH_PE_udata4:
result = unw_get32(addr);
p += 4;
break;
case DW_EH_PE_udata8:
result = (uintptr_t)unw_get64(addr);
p += 8;
break;
case DW_EH_PE_sleb128:
result = (uintptr_t)unw_getSLEB128(&addr);
p = (const unsigned char *)addr;
break;
case DW_EH_PE_sdata2:
// Sign extend from signed 16-bit value.
result = (uintptr_t)(int16_t)unw_get16(addr);
p += 2;
break;
case DW_EH_PE_sdata4:
// Sign extend from signed 32-bit value.
result = (uintptr_t)(int32_t)unw_get32(addr);
p += 4;
break;
case DW_EH_PE_sdata8:
result = (uintptr_t)unw_get64(addr);
p += 8;
break;
default:
assert(!"unknown pointer encoding");
}
// then add relative offset
switch (encoding & 0x70) {
case DW_EH_PE_absptr:
// do nothing
break;
case DW_EH_PE_pcrel:
result += startAddr;
break;
case DW_EH_PE_textrel:
assert(!"DW_EH_PE_textrel pointer encoding not supported");
break;
case DW_EH_PE_datarel:
assert(!"DW_EH_PE_datarel pointer encoding not supported");
break;
case DW_EH_PE_funcrel:
assert(!"DW_EH_PE_funcrel pointer encoding not supported");
break;
case DW_EH_PE_aligned:
assert(!"DW_EH_PE_aligned pointer encoding not supported");
break;
default:
assert(!"unknown pointer encoding");
break;
}
if (encoding & DW_EH_PE_indirect)
result = unw_getP(result);
*ret = result;
return p;
}
#endif // UNWIND_PE_H

View File

@ -1,63 +0,0 @@
//===- annotations.go - annotation processor ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file converts llgo annotations into attributes.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"go/ast"
"go/token"
"llvm.org/llgo/third_party/gotools/go/loader"
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// processAnnotations takes an *ssa.Package and a
// *importer.PackageInfo, and processes all of the
// llgo source annotations attached to each top-level
// function and global variable.
func (c *compiler) processAnnotations(u *unit, pkginfo *loader.PackageInfo) {
members := make(map[types.Object]llvm.Value, len(u.globals))
for k, v := range u.globals {
members[k.(ssa.Member).Object()] = v
}
applyAttributes := func(attrs []Attribute, idents ...*ast.Ident) {
if len(attrs) == 0 {
return
}
for _, ident := range idents {
if v := members[pkginfo.ObjectOf(ident)]; !v.IsNil() {
for _, attr := range attrs {
attr.Apply(v)
}
}
}
}
for _, f := range pkginfo.Files {
for _, decl := range f.Decls {
switch decl := decl.(type) {
case *ast.FuncDecl:
attrs := parseAttributes(decl.Doc)
applyAttributes(attrs, decl.Name)
case *ast.GenDecl:
if decl.Tok != token.VAR {
continue
}
for _, spec := range decl.Specs {
varspec := spec.(*ast.ValueSpec)
attrs := parseAttributes(decl.Doc)
applyAttributes(attrs, varspec.Names...)
}
}
}
}
}

View File

@ -1,146 +0,0 @@
//===- attribute.go - attribute processor ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file processes llgo and //extern attributes.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"fmt"
"go/ast"
"llvm.org/llvm/bindings/go/llvm"
"strings"
)
const AttributeCommentPrefix = "#llgo "
// Attribute represents an attribute associated with a
// global variable or function.
type Attribute interface {
Apply(llvm.Value)
}
// parseAttribute parses zero or more #llgo comment attributes associated with
// a global variable or function. The comment group provided will be processed
// one line at a time using parseAttribute.
func parseAttributes(doc *ast.CommentGroup) []Attribute {
var attributes []Attribute
if doc == nil {
return attributes
}
for _, comment := range doc.List {
if strings.HasPrefix(comment.Text, "//extern ") {
nameattr := nameAttribute(strings.TrimSpace(comment.Text[9:]))
attributes = append(attributes, nameattr)
continue
}
text := comment.Text[2:]
if strings.HasPrefix(comment.Text, "/*") {
text = text[:len(text)-2]
}
attr := parseAttribute(strings.TrimSpace(text))
if attr != nil {
attributes = append(attributes, attr)
}
}
return attributes
}
// parseAttribute parses a single #llgo comment attribute associated with
// a global variable or function. The string provided will be parsed
// if it begins with AttributeCommentPrefix, otherwise nil is returned.
func parseAttribute(line string) Attribute {
if !strings.HasPrefix(line, AttributeCommentPrefix) {
return nil
}
line = strings.TrimSpace(line[len(AttributeCommentPrefix):])
colon := strings.IndexRune(line, ':')
var key, value string
if colon == -1 {
key = line
} else {
key, value = line[:colon], line[colon+1:]
}
switch key {
case "linkage":
return parseLinkageAttribute(value)
case "name":
return nameAttribute(strings.TrimSpace(value))
case "thread_local":
return tlsAttribute{}
default:
// FIXME decide what to do here. return error? log warning?
panic("unknown attribute key: " + key)
}
return nil
}
type linkageAttribute llvm.Linkage
func (a linkageAttribute) Apply(v llvm.Value) {
v.SetLinkage(llvm.Linkage(a))
}
func parseLinkageAttribute(value string) linkageAttribute {
var result linkageAttribute
value = strings.Replace(value, ",", " ", -1)
for _, field := range strings.Fields(value) {
switch strings.ToLower(field) {
case "private":
result |= linkageAttribute(llvm.PrivateLinkage)
case "internal":
result |= linkageAttribute(llvm.InternalLinkage)
case "available_externally":
result |= linkageAttribute(llvm.AvailableExternallyLinkage)
case "linkonce":
result |= linkageAttribute(llvm.LinkOnceAnyLinkage)
case "common":
result |= linkageAttribute(llvm.CommonLinkage)
case "weak":
result |= linkageAttribute(llvm.WeakAnyLinkage)
case "appending":
result |= linkageAttribute(llvm.AppendingLinkage)
case "extern_weak":
result |= linkageAttribute(llvm.ExternalWeakLinkage)
case "linkonce_odr":
result |= linkageAttribute(llvm.LinkOnceODRLinkage)
case "weak_odr":
result |= linkageAttribute(llvm.WeakODRLinkage)
case "external":
result |= linkageAttribute(llvm.ExternalLinkage)
}
}
return result
}
type nameAttribute string
func (a nameAttribute) Apply(v llvm.Value) {
if !v.IsAFunction().IsNil() {
name := string(a)
curr := v.GlobalParent().NamedFunction(name)
if !curr.IsNil() && curr != v {
if curr.BasicBlocksCount() != 0 {
panic(fmt.Errorf("Want to take the name %s from a function that has a body!", name))
}
curr.SetName(name + "_llgo_replaced")
curr.ReplaceAllUsesWith(llvm.ConstBitCast(v, curr.Type()))
}
v.SetName(name)
} else {
v.SetName(string(a))
}
}
type tlsAttribute struct{}
func (tlsAttribute) Apply(v llvm.Value) {
v.SetThreadLocal(true)
}

View File

@ -1,117 +0,0 @@
//===- builtins.go - IR generation for builtins ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for the built-in functions.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
func (fr *frame) callCap(arg *govalue) *govalue {
var v llvm.Value
switch typ := arg.Type().Underlying().(type) {
case *types.Array:
v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false)
case *types.Pointer:
atyp := typ.Elem().Underlying().(*types.Array)
v = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false)
case *types.Slice:
v = fr.builder.CreateExtractValue(arg.value, 2, "")
case *types.Chan:
v = fr.runtime.chanCap.call(fr, arg.value)[0]
}
return newValue(v, types.Typ[types.Int])
}
func (fr *frame) callLen(arg *govalue) *govalue {
var lenvalue llvm.Value
switch typ := arg.Type().Underlying().(type) {
case *types.Array:
lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(typ.Len()), false)
case *types.Pointer:
atyp := typ.Elem().Underlying().(*types.Array)
lenvalue = llvm.ConstInt(fr.llvmtypes.inttype, uint64(atyp.Len()), false)
case *types.Slice:
lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "")
case *types.Map:
lenvalue = fr.runtime.mapLen.call(fr, arg.value)[0]
case *types.Basic:
if isString(typ) {
lenvalue = fr.builder.CreateExtractValue(arg.value, 1, "")
}
case *types.Chan:
lenvalue = fr.runtime.chanLen.call(fr, arg.value)[0]
}
return newValue(lenvalue, types.Typ[types.Int])
}
// callAppend takes two slices of the same type, and yields
// the result of appending the second to the first.
func (fr *frame) callAppend(a, b *govalue) *govalue {
bptr := fr.builder.CreateExtractValue(b.value, 0, "")
blen := fr.builder.CreateExtractValue(b.value, 1, "")
elemsizeInt64 := fr.types.Sizeof(a.Type().Underlying().(*types.Slice).Elem())
elemsize := llvm.ConstInt(fr.target.IntPtrType(), uint64(elemsizeInt64), false)
result := fr.runtime.append.call(fr, a.value, bptr, blen, elemsize)[0]
return newValue(result, a.Type())
}
// callCopy takes two slices a and b of the same type, and
// yields the result of calling "copy(a, b)".
func (fr *frame) callCopy(dest, source *govalue) *govalue {
aptr := fr.builder.CreateExtractValue(dest.value, 0, "")
alen := fr.builder.CreateExtractValue(dest.value, 1, "")
bptr := fr.builder.CreateExtractValue(source.value, 0, "")
blen := fr.builder.CreateExtractValue(source.value, 1, "")
aless := fr.builder.CreateICmp(llvm.IntULT, alen, blen, "")
minlen := fr.builder.CreateSelect(aless, alen, blen, "")
elemsizeInt64 := fr.types.Sizeof(dest.Type().Underlying().(*types.Slice).Elem())
elemsize := llvm.ConstInt(fr.types.inttype, uint64(elemsizeInt64), false)
bytes := fr.builder.CreateMul(minlen, elemsize, "")
fr.runtime.copy.call(fr, aptr, bptr, bytes)
return newValue(minlen, types.Typ[types.Int])
}
func (fr *frame) callRecover(isDeferredRecover bool) *govalue {
startbb := fr.builder.GetInsertBlock()
recoverbb := llvm.AddBasicBlock(fr.function, "")
contbb := llvm.AddBasicBlock(fr.function, "")
canRecover := fr.builder.CreateTrunc(fr.canRecover, llvm.Int1Type(), "")
fr.builder.CreateCondBr(canRecover, recoverbb, contbb)
fr.builder.SetInsertPointAtEnd(recoverbb)
var recovered llvm.Value
if isDeferredRecover {
recovered = fr.runtime.deferredRecover.call(fr)[0]
} else {
recovered = fr.runtime.recover.call(fr)[0]
}
recoverbb = fr.builder.GetInsertBlock()
fr.builder.CreateBr(contbb)
fr.builder.SetInsertPointAtEnd(contbb)
eface := types.NewInterface(nil, nil)
llv := fr.builder.CreatePHI(fr.types.ToLLVM(eface), "")
llv.AddIncoming(
[]llvm.Value{llvm.ConstNull(llv.Type()), recovered},
[]llvm.BasicBlock{startbb, recoverbb},
)
return newValue(llv, eface)
}
func (fr *frame) callPanic(arg *govalue, term bool) {
fr.runtime.panic.call(fr, arg.value)
if term {
fr.builder.CreateUnreachable()
}
}

View File

@ -1,695 +0,0 @@
//===- cabi.go - C ABI abstraction layer ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements an abstraction layer for the platform's C ABI (currently
// supports only Linux/x86_64).
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
type abiArgInfo int
const (
AIK_Direct = abiArgInfo(iota)
AIK_Indirect
)
type backendType interface {
ToLLVM(llvm.Context) llvm.Type
}
type ptrBType struct {
}
func (t ptrBType) ToLLVM(c llvm.Context) llvm.Type {
return llvm.PointerType(c.Int8Type(), 0)
}
type intBType struct {
width int
signed bool
}
func (t intBType) ToLLVM(c llvm.Context) llvm.Type {
return c.IntType(t.width * 8)
}
type floatBType struct {
isDouble bool
}
func (t floatBType) ToLLVM(c llvm.Context) llvm.Type {
if t.isDouble {
return c.DoubleType()
} else {
return c.FloatType()
}
}
type structBType struct {
fields []backendType
}
func (t structBType) ToLLVM(c llvm.Context) llvm.Type {
var lfields []llvm.Type
for _, f := range t.fields {
lfields = append(lfields, f.ToLLVM(c))
}
return c.StructType(lfields, false)
}
type arrayBType struct {
length uint64
elem backendType
}
func (t arrayBType) ToLLVM(c llvm.Context) llvm.Type {
return llvm.ArrayType(t.elem.ToLLVM(c), int(t.length))
}
// align returns the smallest y >= x such that y % a == 0.
func align(x, a int64) int64 {
y := x + a - 1
return y - y%a
}
func (tm *llvmTypeMap) sizeofStruct(fields ...types.Type) int64 {
var o int64
for _, f := range fields {
a := tm.Alignof(f)
o = align(o, a)
o += tm.Sizeof(f)
}
return o
}
// This decides whether the x86_64 classification algorithm produces MEMORY for
// the given type. Given the subset of types that Go supports, this is exactly
// equivalent to testing the type's size. See in particular the first step of
// the algorithm and its footnote.
func (tm *llvmTypeMap) classify(t ...types.Type) abiArgInfo {
if tm.sizeofStruct(t...) > 16 {
return AIK_Indirect
}
return AIK_Direct
}
func (tm *llvmTypeMap) sliceBackendType() backendType {
i8ptr := &ptrBType{}
uintptr := &intBType{tm.target.PointerSize(), false}
return &structBType{[]backendType{i8ptr, uintptr, uintptr}}
}
func (tm *llvmTypeMap) getBackendType(t types.Type) backendType {
switch t := t.(type) {
case *types.Named:
return tm.getBackendType(t.Underlying())
case *types.Basic:
switch t.Kind() {
case types.Bool, types.Uint8:
return &intBType{1, false}
case types.Int8:
return &intBType{1, true}
case types.Uint16:
return &intBType{2, false}
case types.Int16:
return &intBType{2, true}
case types.Uint32:
return &intBType{4, false}
case types.Int32:
return &intBType{4, true}
case types.Uint64:
return &intBType{8, false}
case types.Int64:
return &intBType{8, true}
case types.Uint, types.Uintptr:
return &intBType{tm.target.PointerSize(), false}
case types.Int:
return &intBType{tm.target.PointerSize(), true}
case types.Float32:
return &floatBType{false}
case types.Float64:
return &floatBType{true}
case types.UnsafePointer:
return &ptrBType{}
case types.Complex64:
f32 := &floatBType{false}
return &structBType{[]backendType{f32, f32}}
case types.Complex128:
f64 := &floatBType{true}
return &structBType{[]backendType{f64, f64}}
case types.String:
return &structBType{[]backendType{&ptrBType{}, &intBType{tm.target.PointerSize(), false}}}
}
case *types.Struct:
var fields []backendType
for i := 0; i != t.NumFields(); i++ {
f := t.Field(i)
fields = append(fields, tm.getBackendType(f.Type()))
}
return &structBType{fields}
case *types.Pointer, *types.Signature, *types.Map, *types.Chan:
return &ptrBType{}
case *types.Interface:
i8ptr := &ptrBType{}
return &structBType{[]backendType{i8ptr, i8ptr}}
case *types.Slice:
return tm.sliceBackendType()
case *types.Array:
return &arrayBType{uint64(t.Len()), tm.getBackendType(t.Elem())}
}
panic("unhandled type: " + t.String())
}
type offsetedType struct {
typ backendType
offset uint64
}
func (tm *llvmTypeMap) getBackendOffsets(bt backendType) (offsets []offsetedType) {
switch bt := bt.(type) {
case *structBType:
t := bt.ToLLVM(tm.ctx)
for i, f := range bt.fields {
offset := tm.target.ElementOffset(t, i)
fieldOffsets := tm.getBackendOffsets(f)
for _, fo := range fieldOffsets {
offsets = append(offsets, offsetedType{fo.typ, offset + fo.offset})
}
}
case *arrayBType:
size := tm.target.TypeAllocSize(bt.elem.ToLLVM(tm.ctx))
fieldOffsets := tm.getBackendOffsets(bt.elem)
for i := uint64(0); i != bt.length; i++ {
for _, fo := range fieldOffsets {
offsets = append(offsets, offsetedType{fo.typ, i*size + fo.offset})
}
}
default:
offsets = []offsetedType{offsetedType{bt, 0}}
}
return
}
func (tm *llvmTypeMap) classifyEightbyte(offsets []offsetedType, numInt, numSSE *int) llvm.Type {
if len(offsets) == 1 {
if _, ok := offsets[0].typ.(*floatBType); ok {
*numSSE++
} else {
*numInt++
}
return offsets[0].typ.ToLLVM(tm.ctx)
}
// This implements classification for the basic types and step 4 of the
// classification algorithm. At this point, the only two possible
// classifications are SSE (floats) and INTEGER (everything else).
sse := true
for _, ot := range offsets {
if _, ok := ot.typ.(*floatBType); !ok {
sse = false
break
}
}
if sse {
// This can only be (float, float), which uses an SSE vector.
*numSSE++
return llvm.VectorType(tm.ctx.FloatType(), 2)
} else {
*numInt++
width := offsets[len(offsets)-1].offset + tm.target.TypeAllocSize(offsets[len(offsets)-1].typ.ToLLVM(tm.ctx)) - offsets[0].offset
return tm.ctx.IntType(int(width) * 8)
}
}
func (tm *llvmTypeMap) expandType(argTypes []llvm.Type, argAttrs []llvm.Attribute, bt backendType) ([]llvm.Type, []llvm.Attribute, int, int) {
var numInt, numSSE int
var argAttr llvm.Attribute
switch bt := bt.(type) {
case *structBType, *arrayBType:
noneAttr := tm.ctx.CreateEnumAttribute(0, 0)
bo := tm.getBackendOffsets(bt)
sp := 0
for sp != len(bo) && bo[sp].offset < 8 {
sp++
}
eb1 := bo[0:sp]
eb2 := bo[sp:]
if len(eb2) > 0 {
argTypes = append(argTypes, tm.classifyEightbyte(eb1, &numInt, &numSSE), tm.classifyEightbyte(eb2, &numInt, &numSSE))
argAttrs = append(argAttrs, noneAttr, noneAttr)
} else {
argTypes = append(argTypes, tm.classifyEightbyte(eb1, &numInt, &numSSE))
argAttrs = append(argAttrs, noneAttr)
}
return argTypes, argAttrs, numInt, numSSE
case *intBType:
if bt.width < 4 {
var argAttrKind uint
if bt.signed {
argAttrKind = llvm.AttributeKindID("signext")
} else {
argAttrKind = llvm.AttributeKindID("zeroext")
}
argAttr = tm.ctx.CreateEnumAttribute(argAttrKind, 0)
}
}
argTypes = append(argTypes, tm.classifyEightbyte([]offsetedType{{bt, 0}}, &numInt, &numSSE))
argAttrs = append(argAttrs, argAttr)
return argTypes, argAttrs, numInt, numSSE
}
type argInfo interface {
// Emit instructions to builder to ABI encode val and store result to args.
encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value)
// Emit instructions to builder to ABI decode and return the resulting Value.
decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value
}
type retInfo interface {
// Prepare args to receive a value. allocaBuilder refers to a builder in the entry block.
prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value)
// Emit instructions to builder to ABI decode the return value(s), if any. call is the
// call instruction. Must be called after prepare().
decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value
// Emit instructions to builder to ABI encode the return value(s), if any, and return.
encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value)
}
type directArgInfo struct {
argOffset int
argTypes []llvm.Type
valType llvm.Type
}
func directEncode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, argTypes []llvm.Type, args []llvm.Value, val llvm.Value) {
valType := val.Type()
switch len(argTypes) {
case 0:
// do nothing
case 1:
if argTypes[0].C == valType.C {
args[0] = val
return
}
alloca := allocaBuilder.CreateAlloca(valType, "")
bitcast := builder.CreateBitCast(alloca, llvm.PointerType(argTypes[0], 0), "")
builder.CreateStore(val, alloca)
args[0] = builder.CreateLoad(bitcast, "")
case 2:
encodeType := llvm.StructType(argTypes, false)
alloca := allocaBuilder.CreateAlloca(valType, "")
bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "")
builder.CreateStore(val, alloca)
args[0] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 0, ""), "")
args[1] = builder.CreateLoad(builder.CreateStructGEP(bitcast, 1, ""), "")
default:
panic("unexpected argTypes size")
}
}
func (ai *directArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) {
directEncode(ctx, allocaBuilder, builder, ai.argTypes, args[ai.argOffset:ai.argOffset+len(ai.argTypes)], val)
}
func directDecode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, valType llvm.Type, args []llvm.Value) llvm.Value {
var alloca llvm.Value
switch len(args) {
case 0:
return llvm.ConstNull(ctx.StructType(nil, false))
case 1:
if args[0].Type().C == valType.C {
return args[0]
}
alloca = allocaBuilder.CreateAlloca(valType, "")
bitcast := builder.CreateBitCast(alloca, llvm.PointerType(args[0].Type(), 0), "")
builder.CreateStore(args[0], bitcast)
case 2:
alloca = allocaBuilder.CreateAlloca(valType, "")
var argTypes []llvm.Type
for _, a := range args {
argTypes = append(argTypes, a.Type())
}
encodeType := ctx.StructType(argTypes, false)
bitcast := builder.CreateBitCast(alloca, llvm.PointerType(encodeType, 0), "")
builder.CreateStore(args[0], builder.CreateStructGEP(bitcast, 0, ""))
builder.CreateStore(args[1], builder.CreateStructGEP(bitcast, 1, ""))
default:
panic("unexpected argTypes size")
}
return builder.CreateLoad(alloca, "")
}
func (ai *directArgInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value {
var args []llvm.Value
fn := builder.GetInsertBlock().Parent()
for i, _ := range ai.argTypes {
args = append(args, fn.Param(ai.argOffset+i))
}
return directDecode(ctx, allocaBuilder, builder, ai.valType, args)
}
type indirectArgInfo struct {
argOffset int
}
func (ai *indirectArgInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, args []llvm.Value, val llvm.Value) {
alloca := allocaBuilder.CreateAlloca(val.Type(), "")
builder.CreateStore(val, alloca)
args[ai.argOffset] = alloca
}
func (ai *indirectArgInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder) llvm.Value {
fn := builder.GetInsertBlock().Parent()
return builder.CreateLoad(fn.Param(ai.argOffset), "")
}
type directRetInfo struct {
numResults int
retTypes []llvm.Type
resultsType llvm.Type
}
func (ri *directRetInfo) prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value) {
}
func (ri *directRetInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value {
var args []llvm.Value
switch len(ri.retTypes) {
case 0:
return nil
case 1:
args = []llvm.Value{call}
default:
args = make([]llvm.Value, len(ri.retTypes))
for i := 0; i != len(ri.retTypes); i++ {
args[i] = builder.CreateExtractValue(call, i, "")
}
}
d := directDecode(ctx, allocaBuilder, builder, ri.resultsType, args)
if ri.numResults == 1 {
return []llvm.Value{d}
} else {
results := make([]llvm.Value, ri.numResults)
for i := 0; i != ri.numResults; i++ {
results[i] = builder.CreateExtractValue(d, i, "")
}
return results
}
}
func (ri *directRetInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) {
if len(ri.retTypes) == 0 {
builder.CreateRetVoid()
return
}
var val llvm.Value
switch ri.numResults {
case 1:
val = vals[0]
default:
val = llvm.Undef(ri.resultsType)
for i, v := range vals {
val = builder.CreateInsertValue(val, v, i, "")
}
}
args := make([]llvm.Value, len(ri.retTypes))
directEncode(ctx, allocaBuilder, builder, ri.retTypes, args, val)
var retval llvm.Value
switch len(ri.retTypes) {
case 1:
retval = args[0]
default:
retval = llvm.Undef(ctx.StructType(ri.retTypes, false))
for i, a := range args {
retval = builder.CreateInsertValue(retval, a, i, "")
}
}
builder.CreateRet(retval)
}
type indirectRetInfo struct {
numResults int
sretSlot llvm.Value
resultsType llvm.Type
}
func (ri *indirectRetInfo) prepare(ctx llvm.Context, allocaBuilder llvm.Builder, args []llvm.Value) {
ri.sretSlot = allocaBuilder.CreateAlloca(ri.resultsType, "")
args[0] = ri.sretSlot
}
func (ri *indirectRetInfo) decode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, call llvm.Value) []llvm.Value {
if ri.numResults == 1 {
return []llvm.Value{builder.CreateLoad(ri.sretSlot, "")}
} else {
vals := make([]llvm.Value, ri.numResults)
for i, _ := range vals {
vals[i] = builder.CreateLoad(builder.CreateStructGEP(ri.sretSlot, i, ""), "")
}
return vals
}
}
func (ri *indirectRetInfo) encode(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, vals []llvm.Value) {
fn := builder.GetInsertBlock().Parent()
sretSlot := fn.Param(0)
if ri.numResults == 1 {
builder.CreateStore(vals[0], sretSlot)
} else {
for i, v := range vals {
builder.CreateStore(v, builder.CreateStructGEP(sretSlot, i, ""))
}
}
builder.CreateRetVoid()
}
type functionTypeInfo struct {
functionType llvm.Type
argAttrs []llvm.Attribute
retAttr llvm.Attribute
argInfos []argInfo
retInf retInfo
chainIndex int
}
func (fi *functionTypeInfo) declare(m llvm.Module, name string) llvm.Value {
fn := llvm.AddFunction(m, name, fi.functionType)
if fi.retAttr.GetEnumKind() != 0 {
fn.AddAttributeAtIndex(0, fi.retAttr)
}
for i, a := range fi.argAttrs {
if a.GetEnumKind() != 0 {
fn.AddAttributeAtIndex(i + 1, a)
}
}
return fn
}
func (fi *functionTypeInfo) call(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, chain llvm.Value, args []llvm.Value) []llvm.Value {
callArgs := make([]llvm.Value, len(fi.argAttrs))
if chain.C == nil {
chain = llvm.Undef(llvm.PointerType(ctx.Int8Type(), 0))
}
callArgs[fi.chainIndex] = chain
for i, a := range args {
fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a)
}
fi.retInf.prepare(ctx, allocaBuilder, callArgs)
typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "")
call := builder.CreateCall(typedCallee, callArgs, "")
if fi.retAttr.GetEnumKind() != 0 {
call.AddCallSiteAttribute(0, fi.retAttr)
}
for i, a := range fi.argAttrs {
if a.GetEnumKind() != 0 {
call.AddCallSiteAttribute(i + 1, a)
}
}
return fi.retInf.decode(ctx, allocaBuilder, builder, call)
}
func (fi *functionTypeInfo) invoke(ctx llvm.Context, allocaBuilder llvm.Builder, builder llvm.Builder, callee llvm.Value, chain llvm.Value, args []llvm.Value, cont, lpad llvm.BasicBlock) []llvm.Value {
callArgs := make([]llvm.Value, len(fi.argAttrs))
if chain.C == nil {
chain = llvm.Undef(llvm.PointerType(ctx.Int8Type(), 0))
}
callArgs[fi.chainIndex] = chain
for i, a := range args {
fi.argInfos[i].encode(ctx, allocaBuilder, builder, callArgs, a)
}
fi.retInf.prepare(ctx, allocaBuilder, callArgs)
typedCallee := builder.CreateBitCast(callee, llvm.PointerType(fi.functionType, 0), "")
call := builder.CreateInvoke(typedCallee, callArgs, cont, lpad, "")
if fi.retAttr.GetEnumKind() != 0 {
call.AddCallSiteAttribute(0, fi.retAttr)
}
for i, a := range fi.argAttrs {
if a.GetEnumKind() != 0 {
call.AddCallSiteAttribute(i + 1, a)
}
}
builder.SetInsertPointAtEnd(cont)
return fi.retInf.decode(ctx, allocaBuilder, builder, call)
}
func (tm *llvmTypeMap) getFunctionTypeInfo(args []types.Type, results []types.Type) (fi functionTypeInfo) {
var returnType llvm.Type
var argTypes []llvm.Type
var argAttrKind uint
if len(results) == 0 {
returnType = llvm.VoidType()
fi.retInf = &directRetInfo{}
} else {
aik := tm.classify(results...)
var resultsType llvm.Type
if len(results) == 1 {
resultsType = tm.ToLLVM(results[0])
} else {
elements := make([]llvm.Type, len(results))
for i := range elements {
elements[i] = tm.ToLLVM(results[i])
}
resultsType = tm.ctx.StructType(elements, false)
}
switch aik {
case AIK_Direct:
var retFields []backendType
for _, t := range results {
retFields = append(retFields, tm.getBackendType(t))
}
bt := &structBType{retFields}
retTypes, retAttrs, _, _ := tm.expandType(nil, nil, bt)
switch len(retTypes) {
case 0: // e.g., empty struct
returnType = llvm.VoidType()
case 1:
returnType = retTypes[0]
fi.retAttr = retAttrs[0]
case 2:
returnType = llvm.StructType(retTypes, false)
default:
panic("unexpected expandType result")
}
fi.retInf = &directRetInfo{numResults: len(results), retTypes: retTypes, resultsType: resultsType}
case AIK_Indirect:
returnType = llvm.VoidType()
argTypes = []llvm.Type{llvm.PointerType(resultsType, 0)}
argAttrKind = llvm.AttributeKindID("sret")
fi.argAttrs = []llvm.Attribute{tm.ctx.CreateEnumAttribute(argAttrKind, 0)}
fi.retInf = &indirectRetInfo{numResults: len(results), resultsType: resultsType}
}
}
// Allocate an argument for the call chain.
fi.chainIndex = len(argTypes)
argTypes = append(argTypes, llvm.PointerType(tm.ctx.Int8Type(), 0))
argAttrKind = llvm.AttributeKindID("nest")
fi.argAttrs = append(fi.argAttrs, tm.ctx.CreateEnumAttribute(argAttrKind, 0))
// Keep track of the number of INTEGER/SSE class registers remaining.
remainingInt := 6
remainingSSE := 8
for _, arg := range args {
aik := tm.classify(arg)
isDirect := aik == AIK_Direct
if isDirect {
bt := tm.getBackendType(arg)
directArgTypes, directArgAttrs, numInt, numSSE := tm.expandType(argTypes, fi.argAttrs, bt)
// Check if the argument can fit into the remaining registers, or if
// it would just occupy one register (which pushes the whole argument
// onto the stack anyway).
if numInt <= remainingInt && numSSE <= remainingSSE || numInt+numSSE == 1 {
remainingInt -= numInt
remainingSSE -= numSSE
argInfo := &directArgInfo{argOffset: len(argTypes), valType: bt.ToLLVM(tm.ctx)}
fi.argInfos = append(fi.argInfos, argInfo)
argTypes = directArgTypes
fi.argAttrs = directArgAttrs
argInfo.argTypes = argTypes[argInfo.argOffset:len(argTypes)]
} else {
// No remaining registers; pass on the stack.
isDirect = false
}
}
if !isDirect {
fi.argInfos = append(fi.argInfos, &indirectArgInfo{len(argTypes)})
argTypes = append(argTypes, llvm.PointerType(tm.ToLLVM(arg), 0))
argAttrKind = llvm.AttributeKindID("byval")
fi.argAttrs = append(fi.argAttrs, tm.ctx.CreateEnumAttribute(argAttrKind, 0))
}
}
fi.functionType = llvm.FunctionType(returnType, argTypes, false)
return
}
func (tm *llvmTypeMap) getSignatureInfo(sig *types.Signature) functionTypeInfo {
var args, results []types.Type
if sig.Recv() != nil {
recvtype := sig.Recv().Type()
if _, ok := recvtype.Underlying().(*types.Pointer); !ok && recvtype != types.Typ[types.UnsafePointer] {
recvtype = types.NewPointer(recvtype)
}
args = []types.Type{recvtype}
}
for i := 0; i != sig.Params().Len(); i++ {
args = append(args, sig.Params().At(i).Type())
}
for i := 0; i != sig.Results().Len(); i++ {
results = append(results, sig.Results().At(i).Type())
}
return tm.getFunctionTypeInfo(args, results)
}

View File

@ -1,43 +0,0 @@
//===- call.go - IR generation for calls ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for calls.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// createCall emits the code for a function call,
// taking into account receivers, and panic/defer.
func (fr *frame) createCall(fn *govalue, chain llvm.Value, argValues []*govalue) []*govalue {
fntyp := fn.Type().Underlying().(*types.Signature)
typinfo := fr.types.getSignatureInfo(fntyp)
args := make([]llvm.Value, len(argValues))
for i, arg := range argValues {
args[i] = arg.value
}
var results []llvm.Value
if fr.unwindBlock.IsNil() {
results = typinfo.call(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, chain, args)
} else {
contbb := llvm.AddBasicBlock(fr.function, "")
results = typinfo.invoke(fr.types.ctx, fr.allocaBuilder, fr.builder, fn.value, chain, args, contbb, fr.unwindBlock)
}
resultValues := make([]*govalue, len(results))
for i, res := range results {
resultValues[i] = newValue(res, fntyp.Results().At(i).Type())
}
return resultValues
}

View File

@ -1,133 +0,0 @@
//===- channels.go - IR generation for channels ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for channels.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// makeChan implements make(chantype[, size])
func (fr *frame) makeChan(chantyp types.Type, size *govalue) *govalue {
// TODO(pcc): call __go_new_channel_big here if needed
dyntyp := fr.types.ToRuntime(chantyp)
size = fr.convert(size, types.Typ[types.Uintptr])
ch := fr.runtime.newChannel.call(fr, dyntyp, size.value)[0]
return newValue(ch, chantyp)
}
// chanSend implements ch<- x
func (fr *frame) chanSend(ch *govalue, elem *govalue) {
elemtyp := ch.Type().Underlying().(*types.Chan).Elem()
elem = fr.convert(elem, elemtyp)
elemptr := fr.allocaBuilder.CreateAlloca(elem.value.Type(), "")
fr.builder.CreateStore(elem.value, elemptr)
elemptr = fr.builder.CreateBitCast(elemptr, llvm.PointerType(llvm.Int8Type(), 0), "")
chantyp := fr.types.ToRuntime(ch.Type())
fr.runtime.sendBig.call(fr, chantyp, ch.value, elemptr)
}
// chanRecv implements x[, ok] = <-ch
func (fr *frame) chanRecv(ch *govalue, commaOk bool) (x, ok *govalue) {
elemtyp := ch.Type().Underlying().(*types.Chan).Elem()
ptr := fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(elemtyp), "")
ptri8 := fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
chantyp := fr.types.ToRuntime(ch.Type())
if commaOk {
okval := fr.runtime.chanrecv2.call(fr, chantyp, ch.value, ptri8)[0]
ok = newValue(okval, types.Typ[types.Bool])
} else {
fr.runtime.receive.call(fr, chantyp, ch.value, ptri8)
}
x = newValue(fr.builder.CreateLoad(ptr, ""), elemtyp)
return
}
// chanClose implements close(ch)
func (fr *frame) chanClose(ch *govalue) {
fr.runtime.builtinClose.call(fr, ch.value)
}
func (fr *frame) chanSelect(sel *ssa.Select) (index, recvOk *govalue, recvElems []*govalue) {
n := uint64(len(sel.States))
if !sel.Blocking {
// non-blocking means there's a default case
n++
}
size := llvm.ConstInt(llvm.Int32Type(), n, false)
selectp := fr.runtime.newSelect.call(fr, size)[0]
// Allocate stack for the values to send and receive.
ptrs := make([]llvm.Value, len(sel.States))
for i, state := range sel.States {
chantyp := state.Chan.Type().Underlying().(*types.Chan)
elemtyp := fr.types.ToLLVM(chantyp.Elem())
if state.Dir == types.SendOnly {
ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
fr.builder.CreateStore(fr.llvmvalue(state.Send), ptrs[i])
} else {
// Only allocate stack space if the received value is used.
used := chanSelectStateUsed(sel, len(recvElems))
if used {
ptrs[i] = fr.allocaBuilder.CreateAlloca(elemtyp, "")
} else {
ptrs[i] = llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))
}
recvElems = append(recvElems, newValue(ptrs[i], chantyp.Elem()))
}
}
// Create select{send,recv2} calls.
var receivedp llvm.Value
if len(recvElems) > 0 {
receivedp = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(types.Typ[types.Bool]), "")
}
if !sel.Blocking {
// If the default case is chosen, the index must be -1.
fr.runtime.selectdefault.call(fr, selectp, llvm.ConstAllOnes(llvm.Int32Type()))
}
for i, state := range sel.States {
ch := fr.llvmvalue(state.Chan)
index := llvm.ConstInt(llvm.Int32Type(), uint64(i), false)
if state.Dir == types.SendOnly {
fr.runtime.selectsend.call(fr, selectp, ch, ptrs[i], index)
} else {
fr.runtime.selectrecv2.call(fr, selectp, ch, ptrs[i], receivedp, index)
}
}
// Fire off the select.
index = newValue(fr.runtime.selectgo.call(fr, selectp)[0], types.Typ[types.Int])
if len(recvElems) > 0 {
recvOk = newValue(fr.builder.CreateLoad(receivedp, ""), types.Typ[types.Bool])
for _, recvElem := range recvElems {
recvElem.value = fr.builder.CreateLoad(recvElem.value, "")
}
}
return index, recvOk, recvElems
}
func chanSelectStateUsed(sel *ssa.Select, recvIndex int) bool {
for _, instr := range *sel.Referrers() {
extract, ok := instr.(*ssa.Extract)
if !ok || extract.Index != (recvIndex+2) {
continue
}
if len(*extract.Referrers()) > 0 {
return true
}
}
return false
}

View File

@ -1,36 +0,0 @@
//===- closures.go - IR generation for closures ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for closures.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
)
// makeClosure creates a closure from a function pointer and
// a set of bindings. The bindings are addresses of captured
// variables.
func (fr *frame) makeClosure(fn *govalue, bindings []*govalue) *govalue {
govalues := append([]*govalue{fn}, bindings...)
fields := make([]*types.Var, len(govalues))
for i, v := range govalues {
field := types.NewField(0, nil, "_", v.Type(), false)
fields[i] = field
}
block := fr.createTypeMalloc(types.NewStruct(fields, nil))
for i, v := range govalues {
addressPtr := fr.builder.CreateStructGEP(block, i, "")
fr.builder.CreateStore(v.value, addressPtr)
}
closure := fr.builder.CreateBitCast(block, fn.value.Type(), "")
return newValue(closure, fn.Type())
}

View File

@ -1,394 +0,0 @@
//===- compiler.go - IR generator entry point -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the main IR generator entry point, (*Compiler).Compile.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"bytes"
"go/ast"
"go/token"
"log"
"sort"
"strconv"
llgobuild "llvm.org/llgo/build"
"llvm.org/llgo/debug"
"llvm.org/llvm/bindings/go/llvm"
"llvm.org/llgo/third_party/gotools/go/gccgoimporter"
"llvm.org/llgo/third_party/gotools/go/importer"
"llvm.org/llgo/third_party/gotools/go/loader"
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/types"
)
type Module struct {
llvm.Module
Path string
ExportData []byte
Package *types.Package
disposed bool
}
func (m *Module) Dispose() {
if m.disposed {
return
}
m.Module.Dispose()
m.disposed = true
}
///////////////////////////////////////////////////////////////////////////////
type CompilerOptions struct {
// TargetTriple is the LLVM triple for the target.
TargetTriple string
// GenerateDebug decides whether debug data is
// generated in the output module.
GenerateDebug bool
// DebugPrefixMaps is a list of mappings from source prefixes to
// replacement prefixes, to be applied in debug info.
DebugPrefixMaps []debug.PrefixMap
// Logger is a logger used for tracing compilation.
Logger *log.Logger
// DumpSSA is a debugging option that dumps each SSA function
// to stderr before generating code for it.
DumpSSA bool
// GccgoPath is the path to the gccgo binary whose libgo we read import
// data from. If blank, the caller is expected to supply an import
// path in ImportPaths.
GccgoPath string
// Whether to use the gccgo ABI.
GccgoABI bool
// ImportPaths is the list of additional import paths
ImportPaths []string
// SanitizerAttribute is an attribute to apply to functions to enable
// dynamic instrumentation using a sanitizer.
SanitizerAttribute llvm.Attribute
// Importer is the importer. If nil, the compiler will set this field
// automatically using MakeImporter().
Importer types.Importer
// InitMap is the init map used by Importer. If Importer is nil, the
// compiler will set this field automatically using MakeImporter().
// If Importer is non-nil, InitMap must be non-nil also.
InitMap map[*types.Package]gccgoimporter.InitData
// PackageCreated is a hook passed to the go/loader package via
// loader.Config, see the documentation for that package for more
// information.
PackageCreated func(*types.Package)
// DisableUnusedImportCheck disables the unused import check performed
// by go/types if set to true.
DisableUnusedImportCheck bool
// Packages is used by go/types as the imported package map if non-nil.
Packages map[string]*types.Package
}
type Compiler struct {
opts CompilerOptions
dataLayout string
}
func NewCompiler(opts CompilerOptions) (*Compiler, error) {
compiler := &Compiler{opts: opts}
dataLayout, err := llvmDataLayout(compiler.opts.TargetTriple)
if err != nil {
return nil, err
}
compiler.dataLayout = dataLayout
return compiler, nil
}
func (c *Compiler) Compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
target := llvm.NewTargetData(c.dataLayout)
compiler := &compiler{
CompilerOptions: c.opts,
dataLayout: c.dataLayout,
target: target,
llvmtypes: NewLLVMTypeMap(llvm.GlobalContext(), target),
}
return compiler.compile(fset, astFiles, importpath)
}
type compiler struct {
CompilerOptions
module *Module
dataLayout string
target llvm.TargetData
fileset *token.FileSet
runtime *runtimeInterface
llvmtypes *llvmTypeMap
types *TypeMap
debug *debug.DIBuilder
}
func (c *compiler) logf(format string, v ...interface{}) {
if c.Logger != nil {
c.Logger.Printf(format, v...)
}
}
func (c *compiler) addCommonFunctionAttrs(fn llvm.Value) {
fn.AddTargetDependentFunctionAttr("disable-tail-calls", "true")
fn.AddTargetDependentFunctionAttr("split-stack", "")
if c.SanitizerAttribute.GetEnumKind() != 0 {
fn.AddFunctionAttr(c.SanitizerAttribute)
}
}
// MakeImporter sets CompilerOptions.Importer to an appropriate importer
// for the search paths given in CompilerOptions.ImportPaths, and sets
// CompilerOptions.InitMap to an init map belonging to that importer.
// If CompilerOptions.GccgoPath is non-empty, the importer will also use
// the search paths for that gccgo installation.
func (opts *CompilerOptions) MakeImporter() error {
opts.InitMap = make(map[*types.Package]gccgoimporter.InitData)
if opts.GccgoPath == "" {
paths := append(append([]string{}, opts.ImportPaths...), ".")
opts.Importer = gccgoimporter.GetImporter(paths, opts.InitMap)
} else {
var inst gccgoimporter.GccgoInstallation
err := inst.InitFromDriver(opts.GccgoPath)
if err != nil {
return err
}
opts.Importer = inst.GetImporter(opts.ImportPaths, opts.InitMap)
}
return nil
}
func (compiler *compiler) compile(fset *token.FileSet, astFiles []*ast.File, importpath string) (m *Module, err error) {
buildctx, err := llgobuild.ContextFromTriple(compiler.TargetTriple)
if err != nil {
return nil, err
}
if compiler.Importer == nil {
err = compiler.MakeImporter()
if err != nil {
return nil, err
}
}
impcfg := &loader.Config{
Fset: fset,
TypeChecker: types.Config{
Packages: compiler.Packages,
Import: compiler.Importer,
Sizes: compiler.llvmtypes,
DisableUnusedImportCheck: compiler.DisableUnusedImportCheck,
},
ImportFromBinary: true,
Build: &buildctx.Context,
PackageCreated: compiler.PackageCreated,
}
// If no import path is specified, then set the import
// path to be the same as the package's name.
if importpath == "" {
importpath = astFiles[0].Name.String()
}
impcfg.CreateFromFiles(importpath, astFiles...)
iprog, err := impcfg.Load()
if err != nil {
return nil, err
}
program := ssa.Create(iprog, ssa.BareInits)
mainPkginfo := iprog.InitialPackages()[0]
mainPkg := program.CreatePackage(mainPkginfo)
// Create a Module, which contains the LLVM module.
modulename := importpath
compiler.module = &Module{Module: llvm.NewModule(modulename), Path: modulename, Package: mainPkg.Object}
compiler.module.SetTarget(compiler.TargetTriple)
compiler.module.SetDataLayout(compiler.dataLayout)
// Create a new translation unit.
unit := newUnit(compiler, mainPkg)
// Create the runtime interface.
compiler.runtime, err = newRuntimeInterface(compiler.module.Module, compiler.llvmtypes)
if err != nil {
return nil, err
}
mainPkg.Build()
// Create a struct responsible for mapping static types to LLVM types,
// and to runtime/dynamic type values.
compiler.types = NewTypeMap(
mainPkg,
compiler.llvmtypes,
compiler.module.Module,
compiler.runtime,
MethodResolver(unit),
)
if compiler.GenerateDebug {
compiler.debug = debug.NewDIBuilder(
types.Sizes(compiler.llvmtypes),
compiler.module.Module,
impcfg.Fset,
compiler.DebugPrefixMaps,
)
defer compiler.debug.Destroy()
defer compiler.debug.Finalize()
}
unit.translatePackage(mainPkg)
compiler.processAnnotations(unit, mainPkginfo)
if importpath == "main" {
compiler.createInitMainFunction(mainPkg)
} else {
compiler.module.ExportData = compiler.buildExportData(mainPkg)
}
return compiler.module, nil
}
type byPriorityThenFunc []gccgoimporter.PackageInit
func (a byPriorityThenFunc) Len() int { return len(a) }
func (a byPriorityThenFunc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byPriorityThenFunc) Less(i, j int) bool {
switch {
case a[i].Priority < a[j].Priority:
return true
case a[i].Priority > a[j].Priority:
return false
case a[i].InitFunc < a[j].InitFunc:
return true
default:
return false
}
}
func (c *compiler) buildPackageInitData(mainPkg *ssa.Package) gccgoimporter.InitData {
var inits []gccgoimporter.PackageInit
for _, imp := range mainPkg.Object.Imports() {
inits = append(inits, c.InitMap[imp].Inits...)
}
sort.Sort(byPriorityThenFunc(inits))
// Deduplicate init entries. We want to preserve the entry with the highest priority.
// Normally a package's priorities will be consistent among its dependencies, but it is
// possible for them to be different. For example, if a standard library test augments a
// package which is a dependency of 'regexp' (which is imported by every test main package)
// with additional dependencies, those dependencies may cause the package under test to
// receive a higher priority than indicated by its init clause in 'regexp'.
uniqinits := make([]gccgoimporter.PackageInit, len(inits))
uniqinitpos := len(inits)
uniqinitnames := make(map[string]struct{})
for i, _ := range inits {
init := inits[len(inits)-1-i]
if _, ok := uniqinitnames[init.InitFunc]; !ok {
uniqinitnames[init.InitFunc] = struct{}{}
uniqinitpos--
uniqinits[uniqinitpos] = init
}
}
uniqinits = uniqinits[uniqinitpos:]
ourprio := 1
if len(uniqinits) != 0 {
ourprio = uniqinits[len(uniqinits)-1].Priority + 1
}
if imp := mainPkg.Func("init"); imp != nil {
impname := c.types.mc.mangleFunctionName(imp)
uniqinits = append(uniqinits, gccgoimporter.PackageInit{mainPkg.Object.Name(), impname, ourprio})
}
return gccgoimporter.InitData{ourprio, uniqinits}
}
func (c *compiler) createInitMainFunction(mainPkg *ssa.Package) {
int8ptr := llvm.PointerType(c.types.ctx.Int8Type(), 0)
ftyp := llvm.FunctionType(llvm.VoidType(), []llvm.Type{int8ptr}, false)
initMain := llvm.AddFunction(c.module.Module, "__go_init_main", ftyp)
c.addCommonFunctionAttrs(initMain)
entry := llvm.AddBasicBlock(initMain, "entry")
builder := llvm.GlobalContext().NewBuilder()
defer builder.Dispose()
builder.SetInsertPointAtEnd(entry)
args := []llvm.Value{llvm.Undef(int8ptr)}
if !c.GccgoABI {
initfn := c.module.Module.NamedFunction("main..import")
if !initfn.IsNil() {
builder.CreateCall(initfn, args, "")
}
builder.CreateRetVoid()
return
}
initdata := c.buildPackageInitData(mainPkg)
for _, init := range initdata.Inits {
initfn := c.module.Module.NamedFunction(init.InitFunc)
if initfn.IsNil() {
initfn = llvm.AddFunction(c.module.Module, init.InitFunc, ftyp)
}
builder.CreateCall(initfn, args, "")
}
builder.CreateRetVoid()
}
func (c *compiler) buildExportData(mainPkg *ssa.Package) []byte {
exportData := importer.ExportData(mainPkg.Object)
b := bytes.NewBuffer(exportData)
b.WriteString("v1;\n")
if !c.GccgoABI {
return b.Bytes()
}
initdata := c.buildPackageInitData(mainPkg)
b.WriteString("priority ")
b.WriteString(strconv.Itoa(initdata.Priority))
b.WriteString(";\n")
if len(initdata.Inits) != 0 {
b.WriteString("init")
for _, init := range initdata.Inits {
b.WriteRune(' ')
b.WriteString(init.Name)
b.WriteRune(' ')
b.WriteString(init.InitFunc)
b.WriteRune(' ')
b.WriteString(strconv.Itoa(init.Priority))
}
b.WriteString(";\n")
}
return b.Bytes()
}
// vim: set ft=go :

View File

@ -1,71 +0,0 @@
//===- errors.go - IR generation for run-time panics ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for triggering run-time panics.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llvm/bindings/go/llvm"
)
const (
// From go-runtime-error.c
gccgoRuntimeErrorSLICE_INDEX_OUT_OF_BOUNDS = 0
gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS = 1
gccgoRuntimeErrorSTRING_INDEX_OUT_OF_BOUNDS = 2
gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS = 3
gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS = 4
gccgoRuntimeErrorSTRING_SLICE_OUT_OF_BOUNDS = 5
gccgoRuntimeErrorNIL_DEREFERENCE = 6
gccgoRuntimeErrorMAKE_SLICE_OUT_OF_BOUNDS = 7
gccgoRuntimeErrorMAKE_MAP_OUT_OF_BOUNDS = 8
gccgoRuntimeErrorMAKE_CHAN_OUT_OF_BOUNDS = 9
gccgoRuntimeErrorDIVISION_BY_ZERO = 10
gccgoRuntimeErrorCount = 11
)
func (fr *frame) setBranchWeightMetadata(br llvm.Value, trueweight, falseweight uint64) {
mdprof := llvm.MDKindID("prof")
mdnode := llvm.GlobalContext().MDNode([]llvm.Metadata{
llvm.GlobalContext().MDString("branch_weights"),
llvm.ConstInt(llvm.Int32Type(), trueweight, false).ConstantAsMetadata(),
llvm.ConstInt(llvm.Int32Type(), falseweight, false).ConstantAsMetadata(),
})
br.SetMetadata(mdprof, mdnode)
}
func (fr *frame) condBrRuntimeError(cond llvm.Value, errcode uint64) {
if cond.IsNull() {
return
}
errorbb := fr.runtimeErrorBlocks[errcode]
newbb := errorbb.C == nil
if newbb {
errorbb = llvm.AddBasicBlock(fr.function, "")
fr.runtimeErrorBlocks[errcode] = errorbb
}
contbb := llvm.AddBasicBlock(fr.function, "")
br := fr.builder.CreateCondBr(cond, errorbb, contbb)
fr.setBranchWeightMetadata(br, 1, 1000)
if newbb {
fr.builder.SetInsertPointAtEnd(errorbb)
fr.runtime.runtimeError.call(fr, llvm.ConstInt(llvm.Int32Type(), errcode, false))
fr.builder.CreateUnreachable()
}
fr.builder.SetInsertPointAtEnd(contbb)
}

View File

@ -1,124 +0,0 @@
//===- indirect.go - IR generation for thunks -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for thunks required by the "defer" and
// "go" builtins.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// createThunk creates a thunk from a
// given function and arguments, suitable for use with
// "defer" and "go".
func (fr *frame) createThunk(call ssa.CallInstruction) (thunk llvm.Value, arg llvm.Value) {
seenarg := make(map[ssa.Value]bool)
var args []ssa.Value
var argtypes []*types.Var
packArg := func(arg ssa.Value) {
switch arg.(type) {
case *ssa.Builtin, *ssa.Function, *ssa.Const, *ssa.Global:
// Do nothing: we can generate these in the thunk
default:
if !seenarg[arg] {
seenarg[arg] = true
args = append(args, arg)
field := types.NewField(0, nil, "_", arg.Type(), true)
argtypes = append(argtypes, field)
}
}
}
packArg(call.Common().Value)
for _, arg := range call.Common().Args {
packArg(arg)
}
var isRecoverCall bool
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
var structllptr llvm.Type
if len(args) == 0 {
if builtin, ok := call.Common().Value.(*ssa.Builtin); ok {
isRecoverCall = builtin.Name() == "recover"
}
if isRecoverCall {
// When creating a thunk for recover(), we must pass fr.canRecover.
arg = fr.builder.CreateZExt(fr.canRecover, fr.target.IntPtrType(), "")
arg = fr.builder.CreateIntToPtr(arg, i8ptr, "")
} else {
arg = llvm.ConstPointerNull(i8ptr)
}
} else {
structtype := types.NewStruct(argtypes, nil)
arg = fr.createTypeMalloc(structtype)
structllptr = arg.Type()
for i, ssaarg := range args {
argptr := fr.builder.CreateStructGEP(arg, i, "")
fr.builder.CreateStore(fr.llvmvalue(ssaarg), argptr)
}
arg = fr.builder.CreateBitCast(arg, i8ptr, "")
}
thunkfntype := llvm.FunctionType(llvm.VoidType(), []llvm.Type{i8ptr}, false)
thunkfn := llvm.AddFunction(fr.module.Module, "", thunkfntype)
thunkfn.SetLinkage(llvm.InternalLinkage)
fr.addCommonFunctionAttrs(thunkfn)
thunkfr := newFrame(fr.unit, thunkfn)
defer thunkfr.dispose()
prologuebb := llvm.AddBasicBlock(thunkfn, "prologue")
thunkfr.builder.SetInsertPointAtEnd(prologuebb)
if isRecoverCall {
thunkarg := thunkfn.Param(0)
thunkarg = thunkfr.builder.CreatePtrToInt(thunkarg, fr.target.IntPtrType(), "")
thunkfr.canRecover = thunkfr.builder.CreateTrunc(thunkarg, llvm.Int1Type(), "")
} else if len(args) > 0 {
thunkarg := thunkfn.Param(0)
thunkarg = thunkfr.builder.CreateBitCast(thunkarg, structllptr, "")
for i, ssaarg := range args {
thunkargptr := thunkfr.builder.CreateStructGEP(thunkarg, i, "")
thunkarg := thunkfr.builder.CreateLoad(thunkargptr, "")
thunkfr.env[ssaarg] = newValue(thunkarg, ssaarg.Type())
}
}
_, isDefer := call.(*ssa.Defer)
entrybb := llvm.AddBasicBlock(thunkfn, "entry")
br := thunkfr.builder.CreateBr(entrybb)
thunkfr.allocaBuilder.SetInsertPointBefore(br)
thunkfr.builder.SetInsertPointAtEnd(entrybb)
var exitbb llvm.BasicBlock
if isDefer {
exitbb = llvm.AddBasicBlock(thunkfn, "exit")
thunkfr.runtime.setDeferRetaddr.call(thunkfr, llvm.BlockAddress(thunkfn, exitbb))
}
if isDefer && isRecoverCall {
thunkfr.callRecover(true)
} else {
thunkfr.callInstruction(call)
}
if isDefer {
thunkfr.builder.CreateBr(exitbb)
thunkfr.builder.SetInsertPointAtEnd(exitbb)
}
thunkfr.builder.CreateRetVoid()
thunk = fr.builder.CreateBitCast(thunkfn, i8ptr, "")
return
}

View File

@ -1,195 +0,0 @@
//===- interfaces.go - IR generation for interfaces -----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for dealing with interface values.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// interfaceMethod returns a function and receiver pointer for the specified
// interface and method pair.
func (fr *frame) interfaceMethod(lliface llvm.Value, ifacety types.Type, method *types.Func) (fn, recv *govalue) {
llitab := fr.builder.CreateExtractValue(lliface, 0, "")
recv = newValue(fr.builder.CreateExtractValue(lliface, 1, ""), types.Typ[types.UnsafePointer])
methodset := fr.types.MethodSet(ifacety)
// TODO(axw) cache ordered method index
index := -1
for i, m := range orderedMethodSet(methodset) {
if m.Obj() == method {
index = i
break
}
}
if index == -1 {
panic("could not find method index")
}
llitab = fr.builder.CreateBitCast(llitab, llvm.PointerType(llvm.PointerType(llvm.Int8Type(), 0), 0), "")
// Skip runtime type pointer.
llifnptr := fr.builder.CreateGEP(llitab, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), uint64(index+1), false),
}, "")
llifn := fr.builder.CreateLoad(llifnptr, "")
// Replace receiver type with unsafe.Pointer.
recvparam := types.NewParam(0, nil, "", types.Typ[types.UnsafePointer])
sig := method.Type().(*types.Signature)
sig = types.NewSignature(nil, recvparam, sig.Params(), sig.Results(), sig.Variadic())
fn = newValue(llifn, sig)
return
}
// compareInterfaces emits code to compare two interfaces for
// equality.
func (fr *frame) compareInterfaces(a, b *govalue) *govalue {
aNull := a.value.IsNull()
bNull := b.value.IsNull()
if aNull && bNull {
return newValue(boolLLVMValue(true), types.Typ[types.Bool])
}
compare := fr.runtime.emptyInterfaceCompare
aI := a.Type().Underlying().(*types.Interface).NumMethods() > 0
bI := b.Type().Underlying().(*types.Interface).NumMethods() > 0
switch {
case aI && bI:
compare = fr.runtime.interfaceCompare
case aI:
a = fr.convertI2E(a)
case bI:
b = fr.convertI2E(b)
}
result := compare.call(fr, a.value, b.value)[0]
result = fr.builder.CreateIsNull(result, "")
result = fr.builder.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
}
func (fr *frame) makeInterface(llv llvm.Value, vty types.Type, iface types.Type) *govalue {
if _, ok := vty.Underlying().(*types.Pointer); !ok {
ptr := fr.createTypeMalloc(vty)
fr.builder.CreateStore(llv, ptr)
llv = ptr
}
return fr.makeInterfaceFromPointer(llv, vty, iface)
}
func (fr *frame) makeInterfaceFromPointer(vptr llvm.Value, vty types.Type, iface types.Type) *govalue {
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
llv := fr.builder.CreateBitCast(vptr, i8ptr, "")
value := llvm.Undef(fr.types.ToLLVM(iface))
itab := fr.types.getItabPointer(vty, iface.Underlying().(*types.Interface))
value = fr.builder.CreateInsertValue(value, itab, 0, "")
value = fr.builder.CreateInsertValue(value, llv, 1, "")
return newValue(value, iface)
}
// Reads the type descriptor from the given interface type.
func (fr *frame) getInterfaceTypeDescriptor(v *govalue) llvm.Value {
isempty := v.Type().Underlying().(*types.Interface).NumMethods() == 0
itab := fr.builder.CreateExtractValue(v.value, 0, "")
if isempty {
return itab
} else {
itabnonnull := fr.builder.CreateIsNotNull(itab, "")
return fr.loadOrNull(itabnonnull, itab, types.Typ[types.UnsafePointer]).value
}
}
// Reads the value from the given interface type, assuming that the
// interface holds a value of the correct type.
func (fr *frame) getInterfaceValue(v *govalue, ty types.Type) *govalue {
val := fr.builder.CreateExtractValue(v.value, 1, "")
if _, ok := ty.Underlying().(*types.Pointer); !ok {
typedval := fr.builder.CreateBitCast(val, llvm.PointerType(fr.types.ToLLVM(ty), 0), "")
val = fr.builder.CreateLoad(typedval, "")
}
return newValue(val, ty)
}
// If cond is true, reads the value from the given interface type, otherwise
// returns a nil value.
func (fr *frame) getInterfaceValueOrNull(cond llvm.Value, v *govalue, ty types.Type) *govalue {
val := fr.builder.CreateExtractValue(v.value, 1, "")
if _, ok := ty.Underlying().(*types.Pointer); ok {
val = fr.builder.CreateSelect(cond, val, llvm.ConstNull(val.Type()), "")
} else {
val = fr.loadOrNull(cond, val, ty).value
}
return newValue(val, ty)
}
func (fr *frame) interfaceTypeCheck(val *govalue, ty types.Type) (v *govalue, okval *govalue) {
tytd := fr.types.ToRuntime(ty)
if _, ok := ty.Underlying().(*types.Interface); ok {
var result []llvm.Value
if val.Type().Underlying().(*types.Interface).NumMethods() > 0 {
result = fr.runtime.ifaceI2I2.call(fr, tytd, val.value)
} else {
result = fr.runtime.ifaceE2I2.call(fr, tytd, val.value)
}
v = newValue(result[0], ty)
okval = newValue(result[1], types.Typ[types.Bool])
} else {
valtd := fr.getInterfaceTypeDescriptor(val)
tyequal := fr.runtime.typeDescriptorsEqual.call(fr, valtd, tytd)[0]
okval = newValue(tyequal, types.Typ[types.Bool])
tyequal = fr.builder.CreateTrunc(tyequal, llvm.Int1Type(), "")
v = fr.getInterfaceValueOrNull(tyequal, val, ty)
}
return
}
func (fr *frame) interfaceTypeAssert(val *govalue, ty types.Type) *govalue {
if _, ok := ty.Underlying().(*types.Interface); ok {
return fr.changeInterface(val, ty, true)
} else {
valtytd := fr.types.ToRuntime(val.Type())
valtd := fr.getInterfaceTypeDescriptor(val)
tytd := fr.types.ToRuntime(ty)
fr.runtime.checkInterfaceType.call(fr, valtd, tytd, valtytd)
return fr.getInterfaceValue(val, ty)
}
}
// convertI2E converts a non-empty interface value to an empty interface.
func (fr *frame) convertI2E(v *govalue) *govalue {
td := fr.getInterfaceTypeDescriptor(v)
val := fr.builder.CreateExtractValue(v.value, 1, "")
typ := types.NewInterface(nil, nil)
intf := llvm.Undef(fr.types.ToLLVM(typ))
intf = fr.builder.CreateInsertValue(intf, td, 0, "")
intf = fr.builder.CreateInsertValue(intf, val, 1, "")
return newValue(intf, typ)
}
func (fr *frame) changeInterface(v *govalue, ty types.Type, assert bool) *govalue {
td := fr.getInterfaceTypeDescriptor(v)
tytd := fr.types.ToRuntime(ty)
var itab llvm.Value
if assert {
itab = fr.runtime.assertInterface.call(fr, tytd, td)[0]
} else {
itab = fr.runtime.convertInterface.call(fr, tytd, td)[0]
}
val := fr.builder.CreateExtractValue(v.value, 1, "")
intf := llvm.Undef(fr.types.ToLLVM(ty))
intf = fr.builder.CreateInsertValue(intf, itab, 0, "")
intf = fr.builder.CreateInsertValue(intf, val, 1, "")
return newValue(intf, ty)
}

View File

@ -1,156 +0,0 @@
//===- maps.go - IR generation for maps -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for maps.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// makeMap implements make(maptype[, initial space])
func (fr *frame) makeMap(typ types.Type, cap_ *govalue) *govalue {
// TODO(pcc): call __go_new_map_big here if needed
dyntyp := fr.types.getMapDescriptorPointer(typ)
dyntyp = fr.builder.CreateBitCast(dyntyp, llvm.PointerType(llvm.Int8Type(), 0), "")
var cap llvm.Value
if cap_ != nil {
cap = fr.convert(cap_, types.Typ[types.Uintptr]).value
} else {
cap = llvm.ConstNull(fr.types.inttype)
}
m := fr.runtime.newMap.call(fr, dyntyp, cap)
return newValue(m[0], typ)
}
// mapLookup implements v[, ok] = m[k]
func (fr *frame) mapLookup(m, k *govalue) (v *govalue, ok *govalue) {
llk := k.value
pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
fr.builder.CreateStore(llk, pk)
valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(false))[0]
attrkind := llvm.AttributeKindID("nocapture")
valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0))
attrkind = llvm.AttributeKindID("readonly")
valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0))
okbit := fr.builder.CreateIsNotNull(valptr, "")
elemtyp := m.Type().Underlying().(*types.Map).Elem()
ok = newValue(fr.builder.CreateZExt(okbit, llvm.Int8Type(), ""), types.Typ[types.Bool])
v = fr.loadOrNull(okbit, valptr, elemtyp)
return
}
// mapUpdate implements m[k] = v
func (fr *frame) mapUpdate(m, k, v *govalue) {
llk := k.value
pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
fr.builder.CreateStore(llk, pk)
valptr := fr.runtime.mapIndex.call(fr, m.value, pk, boolLLVMValue(true))[0]
attrkind := llvm.AttributeKindID("nocapture")
valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0))
attrkind = llvm.AttributeKindID("readonly")
valptr.AddCallSiteAttribute(2, fr.types.ctx.CreateEnumAttribute(attrkind, 0))
elemtyp := m.Type().Underlying().(*types.Map).Elem()
llelemtyp := fr.types.ToLLVM(elemtyp)
typedvalptr := fr.builder.CreateBitCast(valptr, llvm.PointerType(llelemtyp, 0), "")
fr.builder.CreateStore(v.value, typedvalptr)
}
// mapDelete implements delete(m, k)
func (fr *frame) mapDelete(m, k *govalue) {
llk := k.value
pk := fr.allocaBuilder.CreateAlloca(llk.Type(), "")
fr.builder.CreateStore(llk, pk)
fr.runtime.mapdelete.call(fr, m.value, pk)
}
// mapIterInit creates a map iterator
func (fr *frame) mapIterInit(m *govalue) []*govalue {
// We represent an iterator as a tuple (map, *bool). The second element
// controls whether the code we generate for "next" (below) calls the
// runtime function for the first or the next element. We let the
// optimizer reorganize this into something more sensible.
isinit := fr.allocaBuilder.CreateAlloca(llvm.Int1Type(), "")
fr.builder.CreateStore(llvm.ConstNull(llvm.Int1Type()), isinit)
return []*govalue{m, newValue(isinit, types.NewPointer(types.Typ[types.Bool]))}
}
// mapIterNext advances the iterator, and returns the tuple (ok, k, v).
func (fr *frame) mapIterNext(iter []*govalue) []*govalue {
maptyp := iter[0].Type().Underlying().(*types.Map)
ktyp := maptyp.Key()
klltyp := fr.types.ToLLVM(ktyp)
vtyp := maptyp.Elem()
vlltyp := fr.types.ToLLVM(vtyp)
m, isinitptr := iter[0], iter[1]
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
mapiterbufty := llvm.ArrayType(i8ptr, 4)
mapiterbuf := fr.allocaBuilder.CreateAlloca(mapiterbufty, "")
mapiterbufelem0ptr := fr.builder.CreateStructGEP(mapiterbuf, 0, "")
keybuf := fr.allocaBuilder.CreateAlloca(klltyp, "")
keyptr := fr.builder.CreateBitCast(keybuf, i8ptr, "")
valbuf := fr.allocaBuilder.CreateAlloca(vlltyp, "")
valptr := fr.builder.CreateBitCast(valbuf, i8ptr, "")
isinit := fr.builder.CreateLoad(isinitptr.value, "")
initbb := llvm.AddBasicBlock(fr.function, "")
nextbb := llvm.AddBasicBlock(fr.function, "")
contbb := llvm.AddBasicBlock(fr.function, "")
fr.builder.CreateCondBr(isinit, nextbb, initbb)
fr.builder.SetInsertPointAtEnd(initbb)
fr.builder.CreateStore(llvm.ConstAllOnes(llvm.Int1Type()), isinitptr.value)
fr.runtime.mapiterinit.call(fr, m.value, mapiterbufelem0ptr)
fr.builder.CreateBr(contbb)
fr.builder.SetInsertPointAtEnd(nextbb)
fr.runtime.mapiternext.call(fr, mapiterbufelem0ptr)
fr.builder.CreateBr(contbb)
fr.builder.SetInsertPointAtEnd(contbb)
mapiterbufelem0 := fr.builder.CreateLoad(mapiterbufelem0ptr, "")
okbit := fr.builder.CreateIsNotNull(mapiterbufelem0, "")
ok := fr.builder.CreateZExt(okbit, llvm.Int8Type(), "")
loadbb := llvm.AddBasicBlock(fr.function, "")
cont2bb := llvm.AddBasicBlock(fr.function, "")
fr.builder.CreateCondBr(okbit, loadbb, cont2bb)
fr.builder.SetInsertPointAtEnd(loadbb)
fr.runtime.mapiter2.call(fr, mapiterbufelem0ptr, keyptr, valptr)
loadbb = fr.builder.GetInsertBlock()
loadedkey := fr.builder.CreateLoad(keybuf, "")
loadedval := fr.builder.CreateLoad(valbuf, "")
fr.builder.CreateBr(cont2bb)
fr.builder.SetInsertPointAtEnd(cont2bb)
k := fr.builder.CreatePHI(klltyp, "")
k.AddIncoming(
[]llvm.Value{llvm.ConstNull(klltyp), loadedkey},
[]llvm.BasicBlock{contbb, loadbb},
)
v := fr.builder.CreatePHI(vlltyp, "")
v.AddIncoming(
[]llvm.Value{llvm.ConstNull(vlltyp), loadedval},
[]llvm.BasicBlock{contbb, loadbb},
)
return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, ktyp), newValue(v, vtyp)}
}

View File

@ -1,57 +0,0 @@
//===- predicates.go - type predicates ------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements commonly used type predicates.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
)
func isBoolean(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsBoolean != 0
}
func isInteger(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsInteger != 0
}
func isUnsigned(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsUnsigned != 0
}
func isFloat(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsFloat != 0
}
func isComplex(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsComplex != 0
}
func isString(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsString != 0
}
func isUntyped(typ types.Type) bool {
t, ok := typ.Underlying().(*types.Basic)
return ok && t.Info()&types.IsUntyped != 0
}
func isSlice(typ types.Type, bkind types.BasicKind) bool {
t, ok := typ.Underlying().(*types.Slice)
return ok && types.Identical(t.Elem().Underlying(), types.Typ[bkind])
}

View File

@ -1,92 +0,0 @@
//===- println.go - IR generation for print and println -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for the print and println built-in
// functions.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"fmt"
"llvm.org/llgo/third_party/gotools/go/types"
)
func (fr *frame) printValues(println_ bool, values ...*govalue) {
for i, value := range values {
llvm_value := value.value
typ := value.Type().Underlying()
if name, isname := typ.(*types.Named); isname {
typ = name.Underlying()
}
if println_ && i > 0 {
fr.runtime.printSpace.call(fr)
}
switch typ := typ.(type) {
case *types.Basic:
switch typ.Kind() {
case types.Uint8, types.Uint16, types.Uint32, types.Uintptr, types.Uint, types.Uint64:
i64 := fr.llvmtypes.ctx.Int64Type()
zext := fr.builder.CreateZExt(llvm_value, i64, "")
fr.runtime.printUint64.call(fr, zext)
case types.Int, types.Int8, types.Int16, types.Int32, types.Int64:
i64 := fr.llvmtypes.ctx.Int64Type()
sext := fr.builder.CreateSExt(llvm_value, i64, "")
fr.runtime.printInt64.call(fr, sext)
case types.Float32:
llvm_value = fr.builder.CreateFPExt(llvm_value, fr.llvmtypes.ctx.DoubleType(), "")
fallthrough
case types.Float64:
fr.runtime.printDouble.call(fr, llvm_value)
case types.Complex64:
llvm_value = fr.convert(value, types.Typ[types.Complex128]).value
fallthrough
case types.Complex128:
fr.runtime.printComplex.call(fr, llvm_value)
case types.String, types.UntypedString:
fr.runtime.printString.call(fr, llvm_value)
case types.Bool:
fr.runtime.printBool.call(fr, llvm_value)
case types.UnsafePointer:
fr.runtime.printPointer.call(fr, llvm_value)
default:
panic(fmt.Sprint("Unhandled Basic Kind: ", typ.Kind))
}
case *types.Interface:
if typ.Empty() {
fr.runtime.printEmptyInterface.call(fr, llvm_value)
} else {
fr.runtime.printInterface.call(fr, llvm_value)
}
case *types.Slice:
fr.runtime.printSlice.call(fr, llvm_value)
case *types.Pointer, *types.Map, *types.Chan, *types.Signature:
fr.runtime.printPointer.call(fr, llvm_value)
default:
panic(fmt.Sprintf("Unhandled type kind: %s (%T)", typ, typ))
}
}
if println_ {
fr.runtime.printNl.call(fr)
}
}

View File

@ -1,607 +0,0 @@
//===- runtime.go - IR generation for runtime calls -----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for calls to the runtime library.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"strconv"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
type runtimeFnInfo struct {
fi *functionTypeInfo
fn llvm.Value
}
func (rfi *runtimeFnInfo) init(tm *llvmTypeMap, m llvm.Module, name string, args []types.Type, results []types.Type) {
rfi.fi = new(functionTypeInfo)
*rfi.fi = tm.getFunctionTypeInfo(args, results)
rfi.fn = rfi.fi.declare(m, name)
}
func (rfi *runtimeFnInfo) call(f *frame, args ...llvm.Value) []llvm.Value {
if f.unwindBlock.IsNil() {
return rfi.callOnly(f, args...)
} else {
return rfi.invoke(f, f.unwindBlock, args...)
}
}
func (rfi *runtimeFnInfo) callOnly(f *frame, args ...llvm.Value) []llvm.Value {
return rfi.fi.call(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args)
}
func (rfi *runtimeFnInfo) invoke(f *frame, lpad llvm.BasicBlock, args ...llvm.Value) []llvm.Value {
contbb := llvm.AddBasicBlock(f.function, "")
return rfi.fi.invoke(f.llvmtypes.ctx, f.allocaBuilder, f.builder, rfi.fn, llvm.Value{nil}, args, contbb, lpad)
}
// runtimeInterface is a struct containing references to
// runtime types and intrinsic function declarations.
type runtimeInterface struct {
// LLVM intrinsics
memcpy,
memset,
returnaddress llvm.Value
// Exception handling support
gccgoPersonality llvm.Value
gccgoExceptionType llvm.Type
// Runtime intrinsics
append,
assertInterface,
byteArrayToString,
canRecover,
chanCap,
chanLen,
chanrecv2,
checkDefer,
checkInterfaceType,
builtinClose,
convertInterface,
copy,
Defer,
deferredRecover,
emptyInterfaceCompare,
Go,
ifaceE2I2,
ifaceI2I2,
intArrayToString,
interfaceCompare,
intToString,
makeSlice,
mapdelete,
mapiter2,
mapiterinit,
mapiternext,
mapIndex,
mapLen,
New,
newChannel,
newMap,
newSelect,
panic,
printBool,
printComplex,
printDouble,
printEmptyInterface,
printInterface,
printInt64,
printNl,
printPointer,
printSlice,
printSpace,
printString,
printUint64,
receive,
recover,
registerGcRoots,
runtimeError,
selectdefault,
selectrecv2,
selectsend,
selectgo,
sendBig,
setDeferRetaddr,
strcmp,
stringiter2,
stringPlus,
stringSlice,
stringToByteArray,
stringToIntArray,
typeDescriptorsEqual,
undefer runtimeFnInfo
}
func newRuntimeInterface(module llvm.Module, tm *llvmTypeMap) (*runtimeInterface, error) {
var ri runtimeInterface
Bool := types.Typ[types.Bool]
Complex128 := types.Typ[types.Complex128]
Float64 := types.Typ[types.Float64]
Int32 := types.Typ[types.Int32]
Int64 := types.Typ[types.Int64]
Int := types.Typ[types.Int]
Rune := types.Typ[types.Rune]
String := types.Typ[types.String]
Uintptr := types.Typ[types.Uintptr]
UnsafePointer := types.Typ[types.UnsafePointer]
EmptyInterface := types.NewInterface(nil, nil)
ByteSlice := types.NewSlice(types.Typ[types.Byte])
IntSlice := types.NewSlice(types.Typ[types.Int])
AttrKind := llvm.AttributeKindID("nounwind")
NoUnwindAttr := module.Context().CreateEnumAttribute(AttrKind, 0)
AttrKind = llvm.AttributeKindID("noreturn")
NoReturnAttr := module.Context().CreateEnumAttribute(AttrKind, 0)
for _, rt := range [...]struct {
name string
rfi *runtimeFnInfo
args, res []types.Type
attrs []llvm.Attribute
}{
{
name: "__go_append",
rfi: &ri.append,
args: []types.Type{IntSlice, UnsafePointer, Uintptr, Uintptr},
res: []types.Type{IntSlice},
},
{
name: "__go_assert_interface",
rfi: &ri.assertInterface,
args: []types.Type{UnsafePointer, UnsafePointer},
res: []types.Type{UnsafePointer},
},
{
name: "__go_byte_array_to_string",
rfi: &ri.byteArrayToString,
args: []types.Type{UnsafePointer, Int},
res: []types.Type{String},
attrs: []llvm.Attribute{NoUnwindAttr},
},
{
name: "__go_can_recover",
rfi: &ri.canRecover,
args: []types.Type{UnsafePointer},
res: []types.Type{Bool},
},
{
name: "__go_chan_cap",
rfi: &ri.chanCap,
args: []types.Type{UnsafePointer},
res: []types.Type{Int},
},
{
name: "__go_chan_len",
rfi: &ri.chanLen,
args: []types.Type{UnsafePointer},
res: []types.Type{Int},
},
{
name: "runtime.chanrecv2",
rfi: &ri.chanrecv2,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
res: []types.Type{Bool},
},
{
name: "__go_check_defer",
rfi: &ri.checkDefer,
args: []types.Type{UnsafePointer},
},
{
name: "__go_check_interface_type",
rfi: &ri.checkInterfaceType,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
},
{
name: "__go_builtin_close",
rfi: &ri.builtinClose,
args: []types.Type{UnsafePointer},
},
{
name: "__go_convert_interface",
rfi: &ri.convertInterface,
args: []types.Type{UnsafePointer, UnsafePointer},
res: []types.Type{UnsafePointer},
},
{
name: "__go_copy",
rfi: &ri.copy,
args: []types.Type{UnsafePointer, UnsafePointer, Uintptr},
},
{
name: "__go_defer",
rfi: &ri.Defer,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
},
{
name: "__go_deferred_recover",
rfi: &ri.deferredRecover,
res: []types.Type{EmptyInterface},
},
{
name: "__go_empty_interface_compare",
rfi: &ri.emptyInterfaceCompare,
args: []types.Type{EmptyInterface, EmptyInterface},
res: []types.Type{Int},
},
{
name: "__go_go",
rfi: &ri.Go,
args: []types.Type{UnsafePointer, UnsafePointer},
},
{
name: "runtime.ifaceE2I2",
rfi: &ri.ifaceE2I2,
args: []types.Type{UnsafePointer, EmptyInterface},
res: []types.Type{EmptyInterface, Bool},
},
{
name: "runtime.ifaceI2I2",
rfi: &ri.ifaceI2I2,
args: []types.Type{UnsafePointer, EmptyInterface},
res: []types.Type{EmptyInterface, Bool},
},
{
name: "__go_int_array_to_string",
rfi: &ri.intArrayToString,
args: []types.Type{UnsafePointer, Int},
res: []types.Type{String},
},
{
name: "__go_int_to_string",
rfi: &ri.intToString,
args: []types.Type{Int},
res: []types.Type{String},
},
{
name: "__go_interface_compare",
rfi: &ri.interfaceCompare,
args: []types.Type{EmptyInterface, EmptyInterface},
res: []types.Type{Int},
},
{
name: "__go_make_slice2",
rfi: &ri.makeSlice,
args: []types.Type{UnsafePointer, Uintptr, Uintptr},
res: []types.Type{IntSlice},
},
{
name: "runtime.mapdelete",
rfi: &ri.mapdelete,
args: []types.Type{UnsafePointer, UnsafePointer},
},
{
name: "runtime.mapiter2",
rfi: &ri.mapiter2,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
},
{
name: "runtime.mapiterinit",
rfi: &ri.mapiterinit,
args: []types.Type{UnsafePointer, UnsafePointer},
},
{
name: "runtime.mapiternext",
rfi: &ri.mapiternext,
args: []types.Type{UnsafePointer},
},
{
name: "__go_map_index",
rfi: &ri.mapIndex,
args: []types.Type{UnsafePointer, UnsafePointer, Bool},
res: []types.Type{UnsafePointer},
},
{
name: "__go_map_len",
rfi: &ri.mapLen,
args: []types.Type{UnsafePointer},
res: []types.Type{Int},
},
{
name: "__go_new",
rfi: &ri.New,
args: []types.Type{UnsafePointer, Uintptr},
res: []types.Type{UnsafePointer},
attrs: []llvm.Attribute{NoUnwindAttr},
},
{
name: "__go_new_channel",
rfi: &ri.newChannel,
args: []types.Type{UnsafePointer, Uintptr},
res: []types.Type{UnsafePointer},
},
{
name: "__go_new_map",
rfi: &ri.newMap,
args: []types.Type{UnsafePointer, Uintptr},
res: []types.Type{UnsafePointer},
},
{
name: "runtime.newselect",
rfi: &ri.newSelect,
args: []types.Type{Int32},
res: []types.Type{UnsafePointer},
},
{
name: "__go_panic",
rfi: &ri.panic,
args: []types.Type{EmptyInterface},
attrs: []llvm.Attribute{NoReturnAttr},
},
{
name: "__go_print_bool",
rfi: &ri.printBool,
args: []types.Type{Bool},
},
{
name: "__go_print_complex",
rfi: &ri.printComplex,
args: []types.Type{Complex128},
},
{
name: "__go_print_double",
rfi: &ri.printDouble,
args: []types.Type{Float64},
},
{
name: "__go_print_empty_interface",
rfi: &ri.printEmptyInterface,
args: []types.Type{EmptyInterface},
},
{
name: "__go_print_interface",
rfi: &ri.printInterface,
args: []types.Type{EmptyInterface},
},
{
name: "__go_print_int64",
rfi: &ri.printInt64,
args: []types.Type{Int64},
},
{
name: "__go_print_nl",
rfi: &ri.printNl,
},
{
name: "__go_print_pointer",
rfi: &ri.printPointer,
args: []types.Type{UnsafePointer},
},
{
name: "__go_print_slice",
rfi: &ri.printSlice,
args: []types.Type{IntSlice},
},
{
name: "__go_print_space",
rfi: &ri.printSpace,
},
{
name: "__go_print_string",
rfi: &ri.printString,
args: []types.Type{String},
},
{
name: "__go_print_uint64",
rfi: &ri.printUint64,
args: []types.Type{Int64},
},
{
name: "__go_receive",
rfi: &ri.receive,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
},
{
name: "__go_recover",
rfi: &ri.recover,
res: []types.Type{EmptyInterface},
},
{
name: "__go_register_gc_roots",
rfi: &ri.registerGcRoots,
args: []types.Type{UnsafePointer},
},
{
name: "__go_runtime_error",
rfi: &ri.runtimeError,
args: []types.Type{Int32},
attrs: []llvm.Attribute{NoReturnAttr},
},
{
name: "runtime.selectdefault",
rfi: &ri.selectdefault,
args: []types.Type{UnsafePointer, Int32},
},
{
name: "runtime.selectgo",
rfi: &ri.selectgo,
args: []types.Type{UnsafePointer},
res: []types.Type{Int},
},
{
name: "runtime.selectrecv2",
rfi: &ri.selectrecv2,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, UnsafePointer, Int32},
},
{
name: "runtime.selectsend",
rfi: &ri.selectsend,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer, Int32},
},
{
name: "__go_send_big",
rfi: &ri.sendBig,
args: []types.Type{UnsafePointer, UnsafePointer, UnsafePointer},
},
{
name: "__go_set_defer_retaddr",
rfi: &ri.setDeferRetaddr,
args: []types.Type{UnsafePointer},
res: []types.Type{Bool},
},
{
name: "__go_strcmp",
rfi: &ri.strcmp,
args: []types.Type{String, String},
res: []types.Type{Int},
},
{
name: "__go_string_plus",
rfi: &ri.stringPlus,
args: []types.Type{String, String},
res: []types.Type{String},
},
{
name: "__go_string_slice",
rfi: &ri.stringSlice,
args: []types.Type{String, Int, Int},
res: []types.Type{String},
},
{
name: "__go_string_to_byte_array",
rfi: &ri.stringToByteArray,
args: []types.Type{String},
res: []types.Type{ByteSlice},
attrs: []llvm.Attribute{NoUnwindAttr},
},
{
name: "__go_string_to_int_array",
rfi: &ri.stringToIntArray,
args: []types.Type{String},
res: []types.Type{IntSlice},
},
{
name: "runtime.stringiter2",
rfi: &ri.stringiter2,
args: []types.Type{String, Int},
res: []types.Type{Int, Rune},
},
{
name: "__go_type_descriptors_equal",
rfi: &ri.typeDescriptorsEqual,
args: []types.Type{UnsafePointer, UnsafePointer},
res: []types.Type{Bool},
},
{
name: "__go_undefer",
rfi: &ri.undefer,
args: []types.Type{UnsafePointer},
},
} {
rt.rfi.init(tm, module, rt.name, rt.args, rt.res)
for _, attr := range rt.attrs {
rt.rfi.fn.AddFunctionAttr(attr)
}
}
memsetName := "llvm.memset.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
memsetType := llvm.FunctionType(
llvm.VoidType(),
[]llvm.Type{
llvm.PointerType(llvm.Int8Type(), 0),
llvm.Int8Type(),
tm.target.IntPtrType(),
llvm.Int1Type(),
},
false,
)
ri.memset = llvm.AddFunction(module, memsetName, memsetType)
memcpyName := "llvm.memcpy.p0i8.p0i8.i" + strconv.Itoa(tm.target.IntPtrType().IntTypeWidth())
memcpyType := llvm.FunctionType(
llvm.VoidType(),
[]llvm.Type{
llvm.PointerType(llvm.Int8Type(), 0),
llvm.PointerType(llvm.Int8Type(), 0),
llvm.Int64Type(),
llvm.Int1Type(),
},
false,
)
ri.memcpy = llvm.AddFunction(module, memcpyName, memcpyType)
returnaddressType := llvm.FunctionType(
llvm.PointerType(llvm.Int8Type(), 0),
[]llvm.Type{llvm.Int32Type()},
false,
)
ri.returnaddress = llvm.AddFunction(module, "llvm.returnaddress", returnaddressType)
gccgoPersonalityType := llvm.FunctionType(
llvm.Int32Type(),
[]llvm.Type{
llvm.Int32Type(),
llvm.Int64Type(),
llvm.PointerType(llvm.Int8Type(), 0),
llvm.PointerType(llvm.Int8Type(), 0),
},
false,
)
ri.gccgoPersonality = llvm.AddFunction(module, "__gccgo_personality_v0", gccgoPersonalityType)
ri.gccgoExceptionType = llvm.StructType(
[]llvm.Type{
llvm.PointerType(llvm.Int8Type(), 0),
llvm.Int32Type(),
},
false,
)
return &ri, nil
}
func (fr *frame) createZExtOrTrunc(v llvm.Value, t llvm.Type, name string) llvm.Value {
switch n := v.Type().IntTypeWidth() - t.IntTypeWidth(); {
case n < 0:
v = fr.builder.CreateZExt(v, fr.target.IntPtrType(), name)
case n > 0:
v = fr.builder.CreateTrunc(v, fr.target.IntPtrType(), name)
}
return v
}
func (fr *frame) createTypeMalloc(t types.Type) llvm.Value {
size := llvm.ConstInt(fr.target.IntPtrType(), uint64(fr.llvmtypes.Sizeof(t)), false)
malloc := fr.runtime.New.callOnly(fr, fr.types.ToRuntime(t), size)[0]
return fr.builder.CreateBitCast(malloc, llvm.PointerType(fr.types.ToLLVM(t), 0), "")
}
func (fr *frame) memsetZero(ptr llvm.Value, size llvm.Value) {
memset := fr.runtime.memset
ptr = fr.builder.CreateBitCast(ptr, llvm.PointerType(llvm.Int8Type(), 0), "")
fill := llvm.ConstNull(llvm.Int8Type())
size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
isvolatile := llvm.ConstNull(llvm.Int1Type())
fr.builder.CreateCall(memset, []llvm.Value{ptr, fill, size, isvolatile}, "")
}
func (fr *frame) memcpy(dest llvm.Value, src llvm.Value, size llvm.Value) {
memcpy := fr.runtime.memcpy
dest = fr.builder.CreateBitCast(dest, llvm.PointerType(llvm.Int8Type(), 0), "")
src = fr.builder.CreateBitCast(src, llvm.PointerType(llvm.Int8Type(), 0), "")
size = fr.createZExtOrTrunc(size, fr.target.IntPtrType(), "")
isvolatile := llvm.ConstNull(llvm.Int1Type())
fr.builder.CreateCall(memcpy, []llvm.Value{dest, src, size, isvolatile}, "")
}
func (fr *frame) returnAddress(level uint64) llvm.Value {
returnaddress := fr.runtime.returnaddress
levelValue := llvm.ConstInt(llvm.Int32Type(), level, false)
return fr.builder.CreateCall(returnaddress, []llvm.Value{levelValue}, "")
}

View File

@ -1,105 +0,0 @@
//===- slice.go - IR generation for slices --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for slices.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// makeSlice allocates a new slice with the optional length and capacity,
// initialising its contents to their zero values.
func (fr *frame) makeSlice(sliceType types.Type, length, capacity *govalue) *govalue {
length = fr.convert(length, types.Typ[types.Uintptr])
capacity = fr.convert(capacity, types.Typ[types.Uintptr])
runtimeType := fr.types.ToRuntime(sliceType)
llslice := fr.runtime.makeSlice.call(fr, runtimeType, length.value, capacity.value)
return newValue(llslice[0], sliceType)
}
func (fr *frame) slice(x llvm.Value, xtyp types.Type, low, high, max llvm.Value) llvm.Value {
if !low.IsNil() {
low = fr.createZExtOrTrunc(low, fr.types.inttype, "")
} else {
low = llvm.ConstNull(fr.types.inttype)
}
if !high.IsNil() {
high = fr.createZExtOrTrunc(high, fr.types.inttype, "")
}
if !max.IsNil() {
max = fr.createZExtOrTrunc(max, fr.types.inttype, "")
}
var arrayptr, arraylen, arraycap llvm.Value
var elemtyp types.Type
var errcode uint64
switch typ := xtyp.Underlying().(type) {
case *types.Pointer: // *array
errcode = gccgoRuntimeErrorARRAY_SLICE_OUT_OF_BOUNDS
arraytyp := typ.Elem().Underlying().(*types.Array)
elemtyp = arraytyp.Elem()
arrayptr = x
arrayptr = fr.builder.CreateBitCast(arrayptr, llvm.PointerType(llvm.Int8Type(), 0), "")
arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false)
arraycap = arraylen
case *types.Slice:
errcode = gccgoRuntimeErrorSLICE_SLICE_OUT_OF_BOUNDS
elemtyp = typ.Elem()
arrayptr = fr.builder.CreateExtractValue(x, 0, "")
arraylen = fr.builder.CreateExtractValue(x, 1, "")
arraycap = fr.builder.CreateExtractValue(x, 2, "")
case *types.Basic:
if high.IsNil() {
high = llvm.ConstAllOnes(fr.types.inttype) // -1
}
result := fr.runtime.stringSlice.call(fr, x, low, high)
return result[0]
default:
panic("unimplemented")
}
if high.IsNil() {
high = arraylen
}
if max.IsNil() {
max = arraycap
}
// Bounds checking: 0 <= low <= high <= max <= cap
zero := llvm.ConstNull(fr.types.inttype)
l0 := fr.builder.CreateICmp(llvm.IntSLT, low, zero, "")
hl := fr.builder.CreateICmp(llvm.IntSLT, high, low, "")
mh := fr.builder.CreateICmp(llvm.IntSLT, max, high, "")
cm := fr.builder.CreateICmp(llvm.IntSLT, arraycap, max, "")
cond := fr.builder.CreateOr(l0, hl, "")
cond = fr.builder.CreateOr(cond, mh, "")
cond = fr.builder.CreateOr(cond, cm, "")
fr.condBrRuntimeError(cond, errcode)
slicelen := fr.builder.CreateSub(high, low, "")
slicecap := fr.builder.CreateSub(max, low, "")
elemsize := llvm.ConstInt(fr.llvmtypes.inttype, uint64(fr.llvmtypes.Sizeof(elemtyp)), false)
offset := fr.builder.CreateMul(low, elemsize, "")
sliceptr := fr.builder.CreateInBoundsGEP(arrayptr, []llvm.Value{offset}, "")
llslicetyp := fr.llvmtypes.sliceBackendType().ToLLVM(fr.llvmtypes.ctx)
sliceValue := llvm.Undef(llslicetyp)
sliceValue = fr.builder.CreateInsertValue(sliceValue, sliceptr, 0, "")
sliceValue = fr.builder.CreateInsertValue(sliceValue, slicelen, 1, "")
sliceValue = fr.builder.CreateInsertValue(sliceValue, slicecap, 2, "")
return sliceValue
}

File diff suppressed because it is too large Load Diff

View File

@ -1,113 +0,0 @@
//===- strings.go - IR generation for string ops --------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for string operations.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"go/token"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
func (fr *frame) concatenateStrings(lhs, rhs *govalue) *govalue {
result := fr.runtime.stringPlus.call(fr, lhs.value, rhs.value)
return newValue(result[0], types.Typ[types.String])
}
func (fr *frame) compareStringEmpty(v llvm.Value) *govalue {
len := fr.builder.CreateExtractValue(v, 1, "")
result := fr.builder.CreateIsNull(len, "")
result = fr.builder.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
}
func (fr *frame) compareStrings(lhs, rhs *govalue, op token.Token) *govalue {
if op == token.EQL {
if lhs.value.IsNull() {
return fr.compareStringEmpty(rhs.value)
}
if rhs.value.IsNull() {
return fr.compareStringEmpty(lhs.value)
}
}
result := fr.runtime.strcmp.call(fr, lhs.value, rhs.value)[0]
zero := llvm.ConstNull(fr.types.inttype)
var pred llvm.IntPredicate
switch op {
case token.EQL:
pred = llvm.IntEQ
case token.LSS:
pred = llvm.IntSLT
case token.GTR:
pred = llvm.IntSGT
case token.LEQ:
pred = llvm.IntSLE
case token.GEQ:
pred = llvm.IntSGE
case token.NEQ:
panic("NEQ is handled in govalue.BinaryOp")
default:
panic("unreachable")
}
result = fr.builder.CreateICmp(pred, result, zero, "")
result = fr.builder.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
}
// stringIndex implements v = m[i]
func (fr *frame) stringIndex(s, i *govalue) *govalue {
ptr := fr.builder.CreateExtractValue(s.value, 0, "")
ptr = fr.builder.CreateGEP(ptr, []llvm.Value{i.value}, "")
return newValue(fr.builder.CreateLoad(ptr, ""), types.Typ[types.Byte])
}
func (fr *frame) stringIterInit(str *govalue) []*govalue {
indexptr := fr.allocaBuilder.CreateAlloca(fr.types.inttype, "")
fr.builder.CreateStore(llvm.ConstNull(fr.types.inttype), indexptr)
return []*govalue{str, newValue(indexptr, types.Typ[types.Int])}
}
// stringIterNext advances the iterator, and returns the tuple (ok, k, v).
func (fr *frame) stringIterNext(iter []*govalue) []*govalue {
str, indexptr := iter[0], iter[1]
k := fr.builder.CreateLoad(indexptr.value, "")
result := fr.runtime.stringiter2.call(fr, str.value, k)
fr.builder.CreateStore(result[0], indexptr.value)
ok := fr.builder.CreateIsNotNull(result[0], "")
ok = fr.builder.CreateZExt(ok, llvm.Int8Type(), "")
v := result[1]
return []*govalue{newValue(ok, types.Typ[types.Bool]), newValue(k, types.Typ[types.Int]), newValue(v, types.Typ[types.Rune])}
}
func (fr *frame) runeToString(v *govalue) *govalue {
v = fr.convert(v, types.Typ[types.Int])
result := fr.runtime.intToString.call(fr, v.value)
return newValue(result[0], types.Typ[types.String])
}
func (fr *frame) stringToRuneSlice(v *govalue) *govalue {
result := fr.runtime.stringToIntArray.call(fr, v.value)
runeslice := types.NewSlice(types.Typ[types.Rune])
return newValue(result[0], runeslice)
}
func (fr *frame) runeSliceToString(v *govalue) *govalue {
llv := v.value
ptr := fr.builder.CreateExtractValue(llv, 0, "")
len := fr.builder.CreateExtractValue(llv, 1, "")
result := fr.runtime.intArrayToString.call(fr, ptr, len)
return newValue(result[0], types.Typ[types.String])
}

View File

@ -1,144 +0,0 @@
//===- switches.go - misc utils -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements transformations and IR generation for switches.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"go/token"
"llvm.org/llgo/third_party/gotools/go/exact"
"llvm.org/llgo/third_party/gotools/go/ssa"
"llvm.org/llgo/third_party/gotools/go/ssa/ssautil"
"llvm.org/llvm/bindings/go/llvm"
)
// switchInstr is an instruction representing a switch on constant
// integer values.
type switchInstr struct {
ssa.Instruction
ssautil.Switch
}
func (sw *switchInstr) String() string {
return sw.Switch.String()
}
func (sw *switchInstr) Parent() *ssa.Function {
return sw.Default.Instrs[0].Parent()
}
func (sw *switchInstr) Block() *ssa.BasicBlock {
return sw.Start
}
func (sw *switchInstr) Operands(rands []*ssa.Value) []*ssa.Value {
return nil
}
func (sw *switchInstr) Pos() token.Pos {
return token.NoPos
}
// emitSwitch emits an LLVM switch instruction.
func (fr *frame) emitSwitch(instr *switchInstr) {
cases, _ := dedupConstCases(fr, instr.ConstCases)
ncases := len(cases)
elseblock := fr.block(instr.Default)
llswitch := fr.builder.CreateSwitch(fr.llvmvalue(instr.X), elseblock, ncases)
for _, c := range cases {
llswitch.AddCase(fr.llvmvalue(c.Value), fr.block(c.Body))
}
}
// transformSwitches replaces the final If statement in start blocks
// with a high-level switch instruction, and erases chained condition
// blocks.
func (fr *frame) transformSwitches(f *ssa.Function) {
for _, sw := range ssautil.Switches(f) {
if sw.ConstCases == nil {
// TODO(axw) investigate switch
// on hashes in type switches.
continue
}
if !isInteger(sw.X.Type()) && !isBoolean(sw.X.Type()) {
// LLVM switches can only operate on integers.
continue
}
instr := &switchInstr{Switch: sw}
sw.Start.Instrs[len(sw.Start.Instrs)-1] = instr
for _, c := range sw.ConstCases[1:] {
fr.blocks[c.Block.Index].EraseFromParent()
fr.blocks[c.Block.Index] = llvm.BasicBlock{}
}
// Fix predecessors in successor blocks for fixupPhis.
cases, duplicates := dedupConstCases(fr, instr.ConstCases)
for _, c := range cases {
for _, succ := range c.Block.Succs {
for i, pred := range succ.Preds {
if pred == c.Block {
succ.Preds[i] = sw.Start
break
}
}
}
}
// Remove redundant edges corresponding to duplicate cases
// that will not feature in the LLVM switch instruction.
for _, c := range duplicates {
for _, succ := range c.Block.Succs {
for i, pred := range succ.Preds {
if pred == c.Block {
head := succ.Preds[:i]
tail := succ.Preds[i+1:]
succ.Preds = append(head, tail...)
removePhiEdge(succ, i)
break
}
}
}
}
}
}
// dedupConstCases separates duplicate const cases.
//
// TODO(axw) fix this in go/ssa/ssautil.
func dedupConstCases(fr *frame, in []ssautil.ConstCase) (unique, duplicates []ssautil.ConstCase) {
unique = make([]ssautil.ConstCase, 0, len(in))
dedup:
for i, c1 := range in {
for _, c2 := range in[i+1:] {
if exact.Compare(c1.Value.Value, token.EQL, c2.Value.Value) {
duplicates = append(duplicates, c1)
continue dedup
}
}
unique = append(unique, c1)
}
return unique, duplicates
}
// removePhiEdge removes the i'th edge from each PHI
// instruction in the specified basic block.
func removePhiEdge(bb *ssa.BasicBlock, i int) {
for _, instr := range bb.Instrs {
instr, ok := instr.(*ssa.Phi)
if !ok {
return
}
head := instr.Edges[:i]
tail := instr.Edges[i+1:]
instr.Edges = append(head, tail...)
}
}

View File

@ -1,88 +0,0 @@
//===- targets.go - target data -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains functions for retrieving target-specific data.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"fmt"
"strings"
"llvm.org/llvm/bindings/go/llvm"
)
// llvmDataLayout returns the data layout string
// representation for the specified LLVM triple.
func llvmDataLayout(triple string) (string, error) {
// Triples are several fields separated by '-' characters.
// The first field is the architecture. The architecture's
// canonical form may include a '-' character, which would
// have been translated to '_' for inclusion in a triple.
arch := parseArch(triple[:strings.IndexRune(triple, '-')])
for target := llvm.FirstTarget(); target.C != nil; target = target.NextTarget() {
if arch == target.Name() {
machine := target.CreateTargetMachine(
triple, "", "",
llvm.CodeGenLevelDefault,
llvm.RelocDefault,
llvm.CodeModelDefault,
)
targetData := machine.CreateTargetData()
targetDataLayout := targetData.String()
targetData.Dispose()
machine.Dispose()
return targetDataLayout, nil
}
}
return "", fmt.Errorf("Invalid target triple: %s", triple)
}
// Based on parseArch from LLVM's lib/Support/Triple.cpp.
// This is used to match the target machine type.
func parseArch(arch string) string {
switch arch {
case "i386", "i486", "i586", "i686", "i786", "i886", "i986":
return "x86"
case "amd64", "x86_64":
return "x86-64"
case "powerpc":
return "ppc"
case "powerpc64", "ppu":
return "ppc64"
case "mblaze":
return "mblaze"
case "arm", "xscale":
return "arm"
case "thumb":
return "thumb"
case "spu", "cellspu":
return "cellspu"
case "msp430":
return "msp430"
case "mips", "mipseb", "mipsallegrex":
return "mips"
case "mipsel", "mipsallegrexel":
return "mipsel"
case "mips64", "mips64eb":
return "mips64"
case "mipsel64":
return "mipsel64"
case "r600", "hexagon", "sparc", "sparcv9", "tce",
"xcore", "nvptx", "nvptx64", "le32", "amdil":
return arch
}
if strings.HasPrefix(arch, "armv") {
return "arm"
} else if strings.HasPrefix(arch, "thumbv") {
return "thumb"
}
return "unknown"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
//===- types.go - convenience functions for types -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements convenience functions for dealing with types.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
)
func deref(t types.Type) types.Type {
return t.Underlying().(*types.Pointer).Elem()
}

View File

@ -1,39 +0,0 @@
//===- utils.go - misc utils ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements misellaneous utilities for IR generation.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
func (fr *frame) loadOrNull(cond, ptr llvm.Value, ty types.Type) *govalue {
startbb := fr.builder.GetInsertBlock()
loadbb := llvm.AddBasicBlock(fr.function, "")
contbb := llvm.AddBasicBlock(fr.function, "")
fr.builder.CreateCondBr(cond, loadbb, contbb)
fr.builder.SetInsertPointAtEnd(loadbb)
llty := fr.types.ToLLVM(ty)
typedptr := fr.builder.CreateBitCast(ptr, llvm.PointerType(llty, 0), "")
loadedval := fr.builder.CreateLoad(typedptr, "")
fr.builder.CreateBr(contbb)
fr.builder.SetInsertPointAtEnd(contbb)
llv := fr.builder.CreatePHI(llty, "")
llv.AddIncoming(
[]llvm.Value{llvm.ConstNull(llty), loadedval},
[]llvm.BasicBlock{startbb, loadbb},
)
return newValue(llv, ty)
}

View File

@ -1,637 +0,0 @@
//===- value.go - govalue and operations ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the govalue type, which combines an LLVM value with its Go
// type, and implements various basic operations on govalues.
//
//===----------------------------------------------------------------------===//
package irgen
import (
"fmt"
"go/token"
"llvm.org/llgo/third_party/gotools/go/exact"
"llvm.org/llgo/third_party/gotools/go/types"
"llvm.org/llvm/bindings/go/llvm"
)
// govalue contains an LLVM value and a Go type,
// representing the result of a Go expression.
type govalue struct {
value llvm.Value
typ types.Type
}
func (v *govalue) String() string {
return fmt.Sprintf("[llgo.govalue typ:%s value:%v]", v.typ, v.value)
}
// Create a new dynamic value from a (LLVM Value, Type) pair.
func newValue(v llvm.Value, t types.Type) *govalue {
return &govalue{v, t}
}
// TODO(axw) remove this, use .typ directly
func (v *govalue) Type() types.Type {
return v.typ
}
// newValueFromConst converts a constant value to an LLVM value.
func (fr *frame) newValueFromConst(v exact.Value, typ types.Type) *govalue {
switch {
case v == nil:
llvmtyp := fr.types.ToLLVM(typ)
return newValue(llvm.ConstNull(llvmtyp), typ)
case isString(typ):
if isUntyped(typ) {
typ = types.Typ[types.String]
}
llvmtyp := fr.types.ToLLVM(typ)
strval := exact.StringVal(v)
strlen := len(strval)
i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
var ptr llvm.Value
if strlen > 0 {
init := llvm.ConstString(strval, false)
ptr = llvm.AddGlobal(fr.module.Module, init.Type(), "")
ptr.SetInitializer(init)
ptr.SetLinkage(llvm.InternalLinkage)
ptr = llvm.ConstBitCast(ptr, i8ptr)
} else {
ptr = llvm.ConstNull(i8ptr)
}
len_ := llvm.ConstInt(fr.types.inttype, uint64(strlen), false)
llvmvalue := llvm.Undef(llvmtyp)
llvmvalue = llvm.ConstInsertValue(llvmvalue, ptr, []uint32{0})
llvmvalue = llvm.ConstInsertValue(llvmvalue, len_, []uint32{1})
return newValue(llvmvalue, typ)
case isInteger(typ):
if isUntyped(typ) {
typ = types.Typ[types.Int]
}
llvmtyp := fr.types.ToLLVM(typ)
var llvmvalue llvm.Value
if isUnsigned(typ) {
v, _ := exact.Uint64Val(v)
llvmvalue = llvm.ConstInt(llvmtyp, v, false)
} else {
v, _ := exact.Int64Val(v)
llvmvalue = llvm.ConstInt(llvmtyp, uint64(v), true)
}
return newValue(llvmvalue, typ)
case isBoolean(typ):
if isUntyped(typ) {
typ = types.Typ[types.Bool]
}
return newValue(boolLLVMValue(exact.BoolVal(v)), typ)
case isFloat(typ):
if isUntyped(typ) {
typ = types.Typ[types.Float64]
}
llvmtyp := fr.types.ToLLVM(typ)
floatval, _ := exact.Float64Val(v)
llvmvalue := llvm.ConstFloat(llvmtyp, floatval)
return newValue(llvmvalue, typ)
case typ == types.Typ[types.UnsafePointer]:
llvmtyp := fr.types.ToLLVM(typ)
v, _ := exact.Uint64Val(v)
llvmvalue := llvm.ConstInt(fr.types.inttype, v, false)
llvmvalue = llvm.ConstIntToPtr(llvmvalue, llvmtyp)
return newValue(llvmvalue, typ)
case isComplex(typ):
if isUntyped(typ) {
typ = types.Typ[types.Complex128]
}
llvmtyp := fr.types.ToLLVM(typ)
floattyp := llvmtyp.StructElementTypes()[0]
llvmvalue := llvm.ConstNull(llvmtyp)
realv := exact.Real(v)
imagv := exact.Imag(v)
realfloatval, _ := exact.Float64Val(realv)
imagfloatval, _ := exact.Float64Val(imagv)
llvmre := llvm.ConstFloat(floattyp, realfloatval)
llvmim := llvm.ConstFloat(floattyp, imagfloatval)
llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmre, []uint32{0})
llvmvalue = llvm.ConstInsertValue(llvmvalue, llvmim, []uint32{1})
return newValue(llvmvalue, typ)
}
// Special case for string -> [](byte|rune)
if u, ok := typ.Underlying().(*types.Slice); ok && isInteger(u.Elem()) {
if v.Kind() == exact.String {
strval := fr.newValueFromConst(v, types.Typ[types.String])
return fr.convert(strval, typ)
}
}
panic(fmt.Sprintf("unhandled: t=%s(%T), v=%v(%T)", typ, typ, v, v))
}
func (fr *frame) binaryOp(lhs *govalue, op token.Token, rhs *govalue) *govalue {
if op == token.NEQ {
result := fr.binaryOp(lhs, token.EQL, rhs)
return fr.unaryOp(result, token.NOT)
}
var result llvm.Value
b := fr.builder
switch typ := lhs.typ.Underlying().(type) {
case *types.Struct:
// TODO(axw) use runtime equality algorithm (will be suitably inlined).
// For now, we use compare all fields unconditionally and bitwise AND
// to avoid branching (i.e. so we don't create additional blocks).
value := newValue(boolLLVMValue(true), types.Typ[types.Bool])
for i := 0; i < typ.NumFields(); i++ {
t := typ.Field(i).Type()
lhs := newValue(b.CreateExtractValue(lhs.value, i, ""), t)
rhs := newValue(b.CreateExtractValue(rhs.value, i, ""), t)
value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs))
}
return value
case *types.Array:
// TODO(pcc): as above.
value := newValue(boolLLVMValue(true), types.Typ[types.Bool])
t := typ.Elem()
for i := int64(0); i < typ.Len(); i++ {
lhs := newValue(b.CreateExtractValue(lhs.value, int(i), ""), t)
rhs := newValue(b.CreateExtractValue(rhs.value, int(i), ""), t)
value = fr.binaryOp(value, token.AND, fr.binaryOp(lhs, token.EQL, rhs))
}
return value
case *types.Slice:
// []T == nil or nil == []T
lhsptr := b.CreateExtractValue(lhs.value, 0, "")
rhsptr := b.CreateExtractValue(rhs.value, 0, "")
isnil := b.CreateICmp(llvm.IntEQ, lhsptr, rhsptr, "")
isnil = b.CreateZExt(isnil, llvm.Int8Type(), "")
return newValue(isnil, types.Typ[types.Bool])
case *types.Signature:
// func == nil or nil == func
isnil := b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "")
isnil = b.CreateZExt(isnil, llvm.Int8Type(), "")
return newValue(isnil, types.Typ[types.Bool])
case *types.Interface:
return fr.compareInterfaces(lhs, rhs)
}
// Strings.
if isString(lhs.typ) {
if isString(rhs.typ) {
switch op {
case token.ADD:
return fr.concatenateStrings(lhs, rhs)
case token.EQL, token.LSS, token.GTR, token.LEQ, token.GEQ:
return fr.compareStrings(lhs, rhs, op)
default:
panic(fmt.Sprint("Unimplemented operator: ", op))
}
}
panic("unimplemented")
}
// Complex numbers.
if isComplex(lhs.typ) {
// XXX Should we represent complex numbers as vectors?
lhsval := lhs.value
rhsval := rhs.value
a_ := b.CreateExtractValue(lhsval, 0, "")
b_ := b.CreateExtractValue(lhsval, 1, "")
c_ := b.CreateExtractValue(rhsval, 0, "")
d_ := b.CreateExtractValue(rhsval, 1, "")
switch op {
case token.QUO:
// (a+bi)/(c+di) = (ac+bd)/(c**2+d**2) + (bc-ad)/(c**2+d**2)i
ac := b.CreateFMul(a_, c_, "")
bd := b.CreateFMul(b_, d_, "")
bc := b.CreateFMul(b_, c_, "")
ad := b.CreateFMul(a_, d_, "")
cpow2 := b.CreateFMul(c_, c_, "")
dpow2 := b.CreateFMul(d_, d_, "")
denom := b.CreateFAdd(cpow2, dpow2, "")
realnumer := b.CreateFAdd(ac, bd, "")
imagnumer := b.CreateFSub(bc, ad, "")
real_ := b.CreateFDiv(realnumer, denom, "")
imag_ := b.CreateFDiv(imagnumer, denom, "")
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
result = b.CreateInsertValue(lhsval, imag_, 1, "")
case token.MUL:
// (a+bi)(c+di) = (ac-bd)+(bc+ad)i
ac := b.CreateFMul(a_, c_, "")
bd := b.CreateFMul(b_, d_, "")
bc := b.CreateFMul(b_, c_, "")
ad := b.CreateFMul(a_, d_, "")
real_ := b.CreateFSub(ac, bd, "")
imag_ := b.CreateFAdd(bc, ad, "")
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
result = b.CreateInsertValue(lhsval, imag_, 1, "")
case token.ADD:
real_ := b.CreateFAdd(a_, c_, "")
imag_ := b.CreateFAdd(b_, d_, "")
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
result = b.CreateInsertValue(lhsval, imag_, 1, "")
case token.SUB:
real_ := b.CreateFSub(a_, c_, "")
imag_ := b.CreateFSub(b_, d_, "")
lhsval = b.CreateInsertValue(lhsval, real_, 0, "")
result = b.CreateInsertValue(lhsval, imag_, 1, "")
case token.EQL:
realeq := b.CreateFCmp(llvm.FloatOEQ, a_, c_, "")
imageq := b.CreateFCmp(llvm.FloatOEQ, b_, d_, "")
result = b.CreateAnd(realeq, imageq, "")
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
default:
panic(fmt.Errorf("unhandled operator: %v", op))
}
return newValue(result, lhs.typ)
}
// Floats and integers.
// TODO determine the NaN rules.
switch op {
case token.MUL:
if isFloat(lhs.typ) {
result = b.CreateFMul(lhs.value, rhs.value, "")
} else {
result = b.CreateMul(lhs.value, rhs.value, "")
}
return newValue(result, lhs.typ)
case token.QUO:
switch {
case isFloat(lhs.typ):
result = b.CreateFDiv(lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateSDiv(lhs.value, rhs.value, "")
default:
result = b.CreateUDiv(lhs.value, rhs.value, "")
}
return newValue(result, lhs.typ)
case token.REM:
switch {
case isFloat(lhs.typ):
result = b.CreateFRem(lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateSRem(lhs.value, rhs.value, "")
default:
result = b.CreateURem(lhs.value, rhs.value, "")
}
return newValue(result, lhs.typ)
case token.ADD:
if isFloat(lhs.typ) {
result = b.CreateFAdd(lhs.value, rhs.value, "")
} else {
result = b.CreateAdd(lhs.value, rhs.value, "")
}
return newValue(result, lhs.typ)
case token.SUB:
if isFloat(lhs.typ) {
result = b.CreateFSub(lhs.value, rhs.value, "")
} else {
result = b.CreateSub(lhs.value, rhs.value, "")
}
return newValue(result, lhs.typ)
case token.SHL, token.SHR:
return fr.shift(lhs, rhs, op)
case token.EQL:
if isFloat(lhs.typ) {
result = b.CreateFCmp(llvm.FloatOEQ, lhs.value, rhs.value, "")
} else {
result = b.CreateICmp(llvm.IntEQ, lhs.value, rhs.value, "")
}
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
case token.LSS:
switch {
case isFloat(lhs.typ):
result = b.CreateFCmp(llvm.FloatOLT, lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateICmp(llvm.IntSLT, lhs.value, rhs.value, "")
default:
result = b.CreateICmp(llvm.IntULT, lhs.value, rhs.value, "")
}
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
case token.LEQ:
switch {
case isFloat(lhs.typ):
result = b.CreateFCmp(llvm.FloatOLE, lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateICmp(llvm.IntSLE, lhs.value, rhs.value, "")
default:
result = b.CreateICmp(llvm.IntULE, lhs.value, rhs.value, "")
}
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
case token.GTR:
switch {
case isFloat(lhs.typ):
result = b.CreateFCmp(llvm.FloatOGT, lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateICmp(llvm.IntSGT, lhs.value, rhs.value, "")
default:
result = b.CreateICmp(llvm.IntUGT, lhs.value, rhs.value, "")
}
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
case token.GEQ:
switch {
case isFloat(lhs.typ):
result = b.CreateFCmp(llvm.FloatOGE, lhs.value, rhs.value, "")
case !isUnsigned(lhs.typ):
result = b.CreateICmp(llvm.IntSGE, lhs.value, rhs.value, "")
default:
result = b.CreateICmp(llvm.IntUGE, lhs.value, rhs.value, "")
}
result = b.CreateZExt(result, llvm.Int8Type(), "")
return newValue(result, types.Typ[types.Bool])
case token.AND: // a & b
result = b.CreateAnd(lhs.value, rhs.value, "")
return newValue(result, lhs.typ)
case token.AND_NOT: // a &^ b
rhsval := rhs.value
rhsval = b.CreateXor(rhsval, llvm.ConstAllOnes(rhsval.Type()), "")
result = b.CreateAnd(lhs.value, rhsval, "")
return newValue(result, lhs.typ)
case token.OR: // a | b
result = b.CreateOr(lhs.value, rhs.value, "")
return newValue(result, lhs.typ)
case token.XOR: // a ^ b
result = b.CreateXor(lhs.value, rhs.value, "")
return newValue(result, lhs.typ)
default:
panic(fmt.Sprint("Unimplemented operator: ", op))
}
panic("unreachable")
}
func (fr *frame) shift(lhs *govalue, rhs *govalue, op token.Token) *govalue {
rhs = fr.convert(rhs, lhs.Type())
lhsval := lhs.value
bits := rhs.value
unsigned := isUnsigned(lhs.Type())
// Shifting >= width of lhs yields undefined behaviour, so we must select.
max := llvm.ConstInt(bits.Type(), uint64(lhsval.Type().IntTypeWidth()-1), false)
var result llvm.Value
lessEqualWidth := fr.builder.CreateICmp(llvm.IntULE, bits, max, "")
if !unsigned && op == token.SHR {
bits := fr.builder.CreateSelect(lessEqualWidth, bits, max, "")
result = fr.builder.CreateAShr(lhsval, bits, "")
} else {
if op == token.SHL {
result = fr.builder.CreateShl(lhsval, bits, "")
} else {
result = fr.builder.CreateLShr(lhsval, bits, "")
}
zero := llvm.ConstNull(lhsval.Type())
result = fr.builder.CreateSelect(lessEqualWidth, result, zero, "")
}
return newValue(result, lhs.typ)
}
func (fr *frame) unaryOp(v *govalue, op token.Token) *govalue {
switch op {
case token.SUB:
var value llvm.Value
if isComplex(v.typ) {
realv := fr.builder.CreateExtractValue(v.value, 0, "")
imagv := fr.builder.CreateExtractValue(v.value, 1, "")
negzero := llvm.ConstFloatFromString(realv.Type(), "-0")
realv = fr.builder.CreateFSub(negzero, realv, "")
imagv = fr.builder.CreateFSub(negzero, imagv, "")
value = llvm.Undef(v.value.Type())
value = fr.builder.CreateInsertValue(value, realv, 0, "")
value = fr.builder.CreateInsertValue(value, imagv, 1, "")
} else if isFloat(v.typ) {
negzero := llvm.ConstFloatFromString(fr.types.ToLLVM(v.Type()), "-0")
value = fr.builder.CreateFSub(negzero, v.value, "")
} else {
value = fr.builder.CreateNeg(v.value, "")
}
return newValue(value, v.typ)
case token.ADD:
return v // No-op
case token.NOT:
value := fr.builder.CreateXor(v.value, boolLLVMValue(true), "")
return newValue(value, v.typ)
case token.XOR:
lhs := v.value
rhs := llvm.ConstAllOnes(lhs.Type())
value := fr.builder.CreateXor(lhs, rhs, "")
return newValue(value, v.typ)
default:
panic(fmt.Sprintf("Unhandled operator: %s", op))
}
}
func (fr *frame) convert(v *govalue, dsttyp types.Type) *govalue {
b := fr.builder
// If it's a stack allocated value, we'll want to compare the
// value type, not the pointer type.
srctyp := v.typ
// Get the underlying type, if any.
origdsttyp := dsttyp
dsttyp = dsttyp.Underlying()
srctyp = srctyp.Underlying()
// Identical (underlying) types? Just swap in the destination type.
if types.Identical(srctyp, dsttyp) {
return newValue(v.value, origdsttyp)
}
// Both pointer types with identical underlying types? Same as above.
if srctyp, ok := srctyp.(*types.Pointer); ok {
if dsttyp, ok := dsttyp.(*types.Pointer); ok {
srctyp := srctyp.Elem().Underlying()
dsttyp := dsttyp.Elem().Underlying()
if types.Identical(srctyp, dsttyp) {
return newValue(v.value, origdsttyp)
}
}
}
// string ->
if isString(srctyp) {
// (untyped) string -> string
// XXX should untyped strings be able to escape go/types?
if isString(dsttyp) {
return newValue(v.value, origdsttyp)
}
// string -> []byte
if isSlice(dsttyp, types.Byte) {
sliceValue := fr.runtime.stringToByteArray.callOnly(fr, v.value)[0]
return newValue(sliceValue, origdsttyp)
}
// string -> []rune
if isSlice(dsttyp, types.Rune) {
return fr.stringToRuneSlice(v)
}
}
// []byte -> string
if isSlice(srctyp, types.Byte) && isString(dsttyp) {
data := fr.builder.CreateExtractValue(v.value, 0, "")
len := fr.builder.CreateExtractValue(v.value, 1, "")
stringValue := fr.runtime.byteArrayToString.callOnly(fr, data, len)[0]
return newValue(stringValue, dsttyp)
}
// []rune -> string
if isSlice(srctyp, types.Rune) && isString(dsttyp) {
return fr.runeSliceToString(v)
}
// rune -> string
if isString(dsttyp) && isInteger(srctyp) {
return fr.runeToString(v)
}
// Unsafe pointer conversions.
llvm_type := fr.types.ToLLVM(dsttyp)
if dsttyp == types.Typ[types.UnsafePointer] { // X -> unsafe.Pointer
if _, isptr := srctyp.(*types.Pointer); isptr {
return newValue(v.value, origdsttyp)
} else if srctyp == types.Typ[types.Uintptr] {
value := b.CreateIntToPtr(v.value, llvm_type, "")
return newValue(value, origdsttyp)
}
} else if srctyp == types.Typ[types.UnsafePointer] { // unsafe.Pointer -> X
if _, isptr := dsttyp.(*types.Pointer); isptr {
return newValue(v.value, origdsttyp)
} else if dsttyp == types.Typ[types.Uintptr] {
value := b.CreatePtrToInt(v.value, llvm_type, "")
return newValue(value, origdsttyp)
}
}
lv := v.value
srcType := lv.Type()
switch srcType.TypeKind() {
case llvm.IntegerTypeKind:
switch llvm_type.TypeKind() {
case llvm.IntegerTypeKind:
srcBits := srcType.IntTypeWidth()
dstBits := llvm_type.IntTypeWidth()
delta := srcBits - dstBits
switch {
case delta < 0:
if !isUnsigned(srctyp) {
lv = b.CreateSExt(lv, llvm_type, "")
} else {
lv = b.CreateZExt(lv, llvm_type, "")
}
case delta > 0:
lv = b.CreateTrunc(lv, llvm_type, "")
}
return newValue(lv, origdsttyp)
case llvm.FloatTypeKind, llvm.DoubleTypeKind:
if !isUnsigned(v.Type()) {
lv = b.CreateSIToFP(lv, llvm_type, "")
} else {
lv = b.CreateUIToFP(lv, llvm_type, "")
}
return newValue(lv, origdsttyp)
}
case llvm.DoubleTypeKind:
switch llvm_type.TypeKind() {
case llvm.FloatTypeKind:
lv = b.CreateFPTrunc(lv, llvm_type, "")
return newValue(lv, origdsttyp)
case llvm.IntegerTypeKind:
if !isUnsigned(dsttyp) {
lv = b.CreateFPToSI(lv, llvm_type, "")
} else {
lv = b.CreateFPToUI(lv, llvm_type, "")
}
return newValue(lv, origdsttyp)
}
case llvm.FloatTypeKind:
switch llvm_type.TypeKind() {
case llvm.DoubleTypeKind:
lv = b.CreateFPExt(lv, llvm_type, "")
return newValue(lv, origdsttyp)
case llvm.IntegerTypeKind:
if !isUnsigned(dsttyp) {
lv = b.CreateFPToSI(lv, llvm_type, "")
} else {
lv = b.CreateFPToUI(lv, llvm_type, "")
}
return newValue(lv, origdsttyp)
}
}
// Complex -> complex. Complexes are only convertible to other
// complexes, contant conversions aside. So we can just check the
// source type here; given that the types are not identical
// (checked above), we can assume the destination type is the alternate
// complex type.
if isComplex(srctyp) {
var fpcast func(llvm.Builder, llvm.Value, llvm.Type, string) llvm.Value
var fptype llvm.Type
if srctyp == types.Typ[types.Complex64] {
fpcast = (llvm.Builder).CreateFPExt
fptype = llvm.DoubleType()
} else {
fpcast = (llvm.Builder).CreateFPTrunc
fptype = llvm.FloatType()
}
if fpcast != nil {
realv := b.CreateExtractValue(lv, 0, "")
imagv := b.CreateExtractValue(lv, 1, "")
realv = fpcast(b, realv, fptype, "")
imagv = fpcast(b, imagv, fptype, "")
lv = llvm.Undef(fr.types.ToLLVM(dsttyp))
lv = b.CreateInsertValue(lv, realv, 0, "")
lv = b.CreateInsertValue(lv, imagv, 1, "")
return newValue(lv, origdsttyp)
}
}
panic(fmt.Sprintf("unimplemented conversion: %s (%s) -> %s", v.typ, lv.Type(), origdsttyp))
}
// extractRealValue extracts the real component of a complex number.
func (fr *frame) extractRealValue(v *govalue) *govalue {
component := fr.builder.CreateExtractValue(v.value, 0, "")
if component.Type().TypeKind() == llvm.FloatTypeKind {
return newValue(component, types.Typ[types.Float32])
}
return newValue(component, types.Typ[types.Float64])
}
// extractRealValue extracts the imaginary component of a complex number.
func (fr *frame) extractImagValue(v *govalue) *govalue {
component := fr.builder.CreateExtractValue(v.value, 1, "")
if component.Type().TypeKind() == llvm.FloatTypeKind {
return newValue(component, types.Typ[types.Float32])
}
return newValue(component, types.Typ[types.Float64])
}
func boolLLVMValue(v bool) (lv llvm.Value) {
if v {
return llvm.ConstInt(llvm.Int8Type(), 1, false)
}
return llvm.ConstNull(llvm.Int8Type())
}

View File

@ -1,22 +0,0 @@
//===- version.go - version info ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file specifies the Go version supported by the IR generator.
//
//===----------------------------------------------------------------------===//
package irgen
const (
goVersion = "go1.4.2"
)
// GoVersion returns the version of Go that we are targeting.
func GoVersion() string {
return goVersion
}

View File

@ -1,49 +0,0 @@
diff -r a6e10414311a libgo/Makefile.am
--- a/libgo/Makefile.am Fri Jan 16 07:57:02 2015 -0800
+++ b/libgo/Makefile.am Fri Apr 03 15:07:47 2015 -0700
@@ -3738,7 +3738,6 @@
os/check \
path/check \
reflect/check \
- regexp/check \
runtime/check \
sort/check \
strconv/check \
@@ -3838,7 +3837,6 @@
os/user/check \
path/filepath/check \
regexp/syntax/check \
- runtime/pprof/check \
sync/atomic/check \
text/scanner/check \
text/tabwriter/check \
diff -r a6e10414311a libgo/Makefile.in
--- a/libgo/Makefile.in Fri Jan 16 07:57:02 2015 -0800
+++ b/libgo/Makefile.in Fri Apr 03 15:07:47 2015 -0700
@@ -2212,7 +2212,6 @@
os/check \
path/check \
reflect/check \
- regexp/check \
runtime/check \
sort/check \
strconv/check \
@@ -2312,7 +2311,6 @@
os/user/check \
path/filepath/check \
regexp/syntax/check \
- runtime/pprof/check \
sync/atomic/check \
text/scanner/check \
text/tabwriter/check \
diff -r a6e10414311a libgo/go/runtime/mfinal_test.go
--- a/libgo/go/runtime/mfinal_test.go Fri Jan 16 07:57:02 2015 -0800
+++ b/libgo/go/runtime/mfinal_test.go Fri Apr 03 15:07:47 2015 -0700
@@ -62,6 +62,7 @@
}()
<-done
runtime.GC()
+ runtime.GC()
select {
case <-ch:
case <-time.After(time.Second * 4):

File diff suppressed because it is too large Load Diff

View File

@ -1,19 +0,0 @@
#!/bin/sh -e
scriptpath=$(which "$0")
scriptpath=$(readlink -f "$scriptpath")
bindir=$(dirname "$scriptpath")
prefix=$(dirname "$bindir")
cmd="$1"
case "$cmd" in
build | get | install | run | test)
shift
PATH="$prefix/lib/llgo/go-path:$PATH" exec go "$cmd" -compiler gccgo "$@"
;;
*)
exec go "$@"
;;
esac

View File

@ -1,94 +0,0 @@
// Copyright 2014 The llgo Authors.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package ssaopt
import (
"go/token"
"llvm.org/llgo/third_party/gotools/go/ssa"
)
func escapes(val ssa.Value, bb *ssa.BasicBlock, pending []ssa.Value) bool {
for _, p := range pending {
if val == p {
return false
}
}
for _, ref := range *val.Referrers() {
switch ref := ref.(type) {
case *ssa.Phi:
// We must consider the variable to have escaped if it is
// possible for the program to see more than one "version"
// of the variable at once, as this requires the program
// to use heap allocation for the multiple versions.
//
// I (pcc) think that this is only possible (without stores)
// in the case where a phi node that (directly or indirectly)
// refers to the allocation dominates the allocation.
if ref.Block().Dominates(bb) {
return true
}
if escapes(ref, bb, append(pending, val)) {
return true
}
case *ssa.BinOp, *ssa.ChangeType, *ssa.Convert, *ssa.ChangeInterface, *ssa.MakeInterface, *ssa.Slice, *ssa.FieldAddr, *ssa.IndexAddr, *ssa.TypeAssert, *ssa.Extract:
if escapes(ref.(ssa.Value), bb, append(pending, val)) {
return true
}
case *ssa.Range, *ssa.DebugRef:
continue
case *ssa.UnOp:
if ref.Op == token.MUL || ref.Op == token.ARROW {
continue
}
if escapes(ref, bb, append(pending, val)) {
return true
}
case *ssa.Store:
if val == ref.Val {
return true
}
case *ssa.Call:
if builtin, ok := ref.Call.Value.(*ssa.Builtin); ok {
switch builtin.Name() {
case "cap", "len", "copy", "ssa:wrapnilchk":
continue
case "append":
if ref.Call.Args[0] == val && escapes(ref, bb, append(pending, val)) {
return true
}
default:
return true
}
} else {
return true
}
default:
return true
}
}
return false
}
func LowerAllocsToStack(f *ssa.Function) {
pending := make([]ssa.Value, 0, 10)
for _, b := range f.Blocks {
for _, instr := range b.Instrs {
if alloc, ok := instr.(*ssa.Alloc); ok && alloc.Heap && !escapes(alloc, alloc.Block(), pending) {
alloc.Heap = false
f.Locals = append(f.Locals, alloc)
}
}
}
}

View File

@ -1,16 +0,0 @@
configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
)
add_lit_testsuite(check-llgo "Running the llgo regression tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS
FileCheck
count
llgo
llgoi
libgo
not
)
set_target_properties(check-llgo PROPERTIES FOLDER "Tests")

View File

@ -1,7 +0,0 @@
// RUN: llgo -c -o /dev/null -g %s
package main
//line :1
func main() {
}

View File

@ -1,17 +0,0 @@
// RUN: not llgo -B 2>&1 | FileCheck --check-prefix=B %s
// RUN: not llgo -D 2>&1 | FileCheck --check-prefix=D %s
// RUN: not llgo -I 2>&1 | FileCheck --check-prefix=I %s
// RUN: not llgo -isystem 2>&1 | FileCheck --check-prefix=isystem %s
// RUN: not llgo -L 2>&1 | FileCheck --check-prefix=L %s
// RUN: not llgo -fload-plugin 2>&1 | FileCheck --check-prefix=fload-plugin %s
// RUN: not llgo -mllvm 2>&1 | FileCheck --check-prefix=mllvm %s
// RUN: not llgo -o 2>&1 | FileCheck --check-prefix=o %s
// B: missing argument after '-B'
// D: missing argument after '-D'
// I: missing argument after '-I'
// isystem: missing argument after '-isystem'
// L: missing argument after '-L'
// fload-plugin: missing argument after '-fload-plugin'
// mllvm: missing argument after '-mllvm'
// o: missing argument after '-o'

View File

@ -1,5 +0,0 @@
package main
func init() {
println("do some other stuff before main")
}

View File

@ -1,18 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: false
// CHECK-NEXT: true
// CHECK-NEXT: false
package main
func main() {
a := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
b := [...]int{10, 1, 2, 3, 4, 5, 6, 7, 8, 9}
c := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
println(a == b)
println(a == c)
println(b == c)
}

View File

@ -1,288 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
// CHECK-NEXT: 3
// CHECK-NEXT: 4
// CHECK-NEXT: 5
// CHECK-NEXT: 6
// CHECK-NEXT: 7
// CHECK-NEXT: 8
// CHECK-NEXT: 9
// CHECK-NEXT: 10
// CHECK-NEXT: 11
// CHECK-NEXT: 12
// CHECK-NEXT: 13
// CHECK-NEXT: 14
// CHECK-NEXT: 15
// CHECK-NEXT: 16
// CHECK-NEXT: 17
// CHECK-NEXT: 18
// CHECK-NEXT: 19
// CHECK-NEXT: 20
// CHECK-NEXT: 21
// CHECK-NEXT: 22
// CHECK-NEXT: 23
// CHECK-NEXT: 24
// CHECK-NEXT: 25
// CHECK-NEXT: 26
// CHECK-NEXT: 27
// CHECK-NEXT: 28
// CHECK-NEXT: 29
// CHECK-NEXT: 30
// CHECK-NEXT: 31
// CHECK-NEXT: 32
// CHECK-NEXT: 33
// CHECK-NEXT: 34
// CHECK-NEXT: 35
// CHECK-NEXT: 36
// CHECK-NEXT: 37
// CHECK-NEXT: 38
// CHECK-NEXT: 39
// CHECK-NEXT: 40
// CHECK-NEXT: 41
// CHECK-NEXT: 42
// CHECK-NEXT: 43
// CHECK-NEXT: 44
// CHECK-NEXT: 45
// CHECK-NEXT: 46
// CHECK-NEXT: 47
// CHECK-NEXT: 48
// CHECK-NEXT: 49
// CHECK-NEXT: 50
// CHECK-NEXT: 51
// CHECK-NEXT: 52
// CHECK-NEXT: 53
// CHECK-NEXT: 54
// CHECK-NEXT: 55
// CHECK-NEXT: 56
// CHECK-NEXT: 57
// CHECK-NEXT: 58
// CHECK-NEXT: 59
// CHECK-NEXT: 60
// CHECK-NEXT: 61
// CHECK-NEXT: 62
// CHECK-NEXT: 63
// CHECK-NEXT: 64
// CHECK-NEXT: 65
// CHECK-NEXT: 66
// CHECK-NEXT: 67
// CHECK-NEXT: 68
// CHECK-NEXT: 69
// CHECK-NEXT: 70
// CHECK-NEXT: 71
// CHECK-NEXT: 72
// CHECK-NEXT: 73
// CHECK-NEXT: 74
// CHECK-NEXT: 75
// CHECK-NEXT: 76
// CHECK-NEXT: 77
// CHECK-NEXT: 78
// CHECK-NEXT: 79
// CHECK-NEXT: 80
// CHECK-NEXT: 81
// CHECK-NEXT: 82
// CHECK-NEXT: 83
// CHECK-NEXT: 84
// CHECK-NEXT: 85
// CHECK-NEXT: 86
// CHECK-NEXT: 87
// CHECK-NEXT: 88
// CHECK-NEXT: 89
// CHECK-NEXT: 90
// CHECK-NEXT: 91
// CHECK-NEXT: 92
// CHECK-NEXT: 93
// CHECK-NEXT: 94
// CHECK-NEXT: 95
// CHECK-NEXT: 96
// CHECK-NEXT: 97
// CHECK-NEXT: 98
// CHECK-NEXT: 99
// CHECK-NEXT: 100
// CHECK-NEXT: 101
// CHECK-NEXT: 102
// CHECK-NEXT: 103
// CHECK-NEXT: 104
// CHECK-NEXT: 105
// CHECK-NEXT: 106
// CHECK-NEXT: 107
// CHECK-NEXT: 108
// CHECK-NEXT: 109
// CHECK-NEXT: 110
// CHECK-NEXT: 111
// CHECK-NEXT: 112
// CHECK-NEXT: 113
// CHECK-NEXT: 114
// CHECK-NEXT: 115
// CHECK-NEXT: 116
// CHECK-NEXT: 117
// CHECK-NEXT: 118
// CHECK-NEXT: 119
// CHECK-NEXT: 120
// CHECK-NEXT: 121
// CHECK-NEXT: 122
// CHECK-NEXT: 123
// CHECK-NEXT: 124
// CHECK-NEXT: 125
// CHECK-NEXT: 126
// CHECK-NEXT: 127
// CHECK-NEXT: 128
// CHECK-NEXT: 129
// CHECK-NEXT: 130
// CHECK-NEXT: 131
// CHECK-NEXT: 132
// CHECK-NEXT: 133
// CHECK-NEXT: 134
// CHECK-NEXT: 135
// CHECK-NEXT: 136
// CHECK-NEXT: 137
// CHECK-NEXT: 138
// CHECK-NEXT: 139
// CHECK-NEXT: 140
// CHECK-NEXT: 141
// CHECK-NEXT: 142
// CHECK-NEXT: 143
// CHECK-NEXT: 144
// CHECK-NEXT: 145
// CHECK-NEXT: 146
// CHECK-NEXT: 147
// CHECK-NEXT: 148
// CHECK-NEXT: 149
// CHECK-NEXT: 150
// CHECK-NEXT: 151
// CHECK-NEXT: 152
// CHECK-NEXT: 153
// CHECK-NEXT: 154
// CHECK-NEXT: 155
// CHECK-NEXT: 156
// CHECK-NEXT: 157
// CHECK-NEXT: 158
// CHECK-NEXT: 159
// CHECK-NEXT: 160
// CHECK-NEXT: 161
// CHECK-NEXT: 162
// CHECK-NEXT: 163
// CHECK-NEXT: 164
// CHECK-NEXT: 165
// CHECK-NEXT: 166
// CHECK-NEXT: 167
// CHECK-NEXT: 168
// CHECK-NEXT: 169
// CHECK-NEXT: 170
// CHECK-NEXT: 171
// CHECK-NEXT: 172
// CHECK-NEXT: 173
// CHECK-NEXT: 174
// CHECK-NEXT: 175
// CHECK-NEXT: 176
// CHECK-NEXT: 177
// CHECK-NEXT: 178
// CHECK-NEXT: 179
// CHECK-NEXT: 180
// CHECK-NEXT: 181
// CHECK-NEXT: 182
// CHECK-NEXT: 183
// CHECK-NEXT: 184
// CHECK-NEXT: 185
// CHECK-NEXT: 186
// CHECK-NEXT: 187
// CHECK-NEXT: 188
// CHECK-NEXT: 189
// CHECK-NEXT: 190
// CHECK-NEXT: 191
// CHECK-NEXT: 192
// CHECK-NEXT: 193
// CHECK-NEXT: 194
// CHECK-NEXT: 195
// CHECK-NEXT: 196
// CHECK-NEXT: 197
// CHECK-NEXT: 198
// CHECK-NEXT: 199
// CHECK-NEXT: 200
// CHECK-NEXT: 201
// CHECK-NEXT: 202
// CHECK-NEXT: 203
// CHECK-NEXT: 204
// CHECK-NEXT: 205
// CHECK-NEXT: 206
// CHECK-NEXT: 207
// CHECK-NEXT: 208
// CHECK-NEXT: 209
// CHECK-NEXT: 210
// CHECK-NEXT: 211
// CHECK-NEXT: 212
// CHECK-NEXT: 213
// CHECK-NEXT: 214
// CHECK-NEXT: 215
// CHECK-NEXT: 216
// CHECK-NEXT: 217
// CHECK-NEXT: 218
// CHECK-NEXT: 219
// CHECK-NEXT: 220
// CHECK-NEXT: 221
// CHECK-NEXT: 222
// CHECK-NEXT: 223
// CHECK-NEXT: 224
// CHECK-NEXT: 225
// CHECK-NEXT: 226
// CHECK-NEXT: 227
// CHECK-NEXT: 228
// CHECK-NEXT: 229
// CHECK-NEXT: 230
// CHECK-NEXT: 231
// CHECK-NEXT: 232
// CHECK-NEXT: 233
// CHECK-NEXT: 234
// CHECK-NEXT: 235
// CHECK-NEXT: 236
// CHECK-NEXT: 237
// CHECK-NEXT: 238
// CHECK-NEXT: 239
// CHECK-NEXT: 240
// CHECK-NEXT: 241
// CHECK-NEXT: 242
// CHECK-NEXT: 243
// CHECK-NEXT: 244
// CHECK-NEXT: 245
// CHECK-NEXT: 246
// CHECK-NEXT: 247
// CHECK-NEXT: 248
// CHECK-NEXT: 249
// CHECK-NEXT: 250
// CHECK-NEXT: 251
// CHECK-NEXT: 252
// CHECK-NEXT: 253
// CHECK-NEXT: 254
package main
func testBasics() {
var i [2]int
j := &i
i[0] = 123
i[1] = 456
println(i[0], i[1])
println(j[0], j[1])
i[0]++
i[1]--
println(i[0], i[1])
println(j[0], j[1])
}
func testByteIndex() {
var a [255]int
for i := 0; i < len(a); i++ {
a[i] = i
}
for i := byte(0); i < byte(len(a)); i++ {
println(a[i])
}
}
func main() {
//testBasics()
testByteIndex()
}

View File

@ -1,23 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0 0 0
// CHECK-NEXT: 1 1 1
// CHECK-NEXT: 2 2 2
// CHECK-NEXT: 3 0 0
// CHECK-NEXT: 4 4 4
// CHECK-NEXT: 0 10
// CHECK-NEXT: 1 20
// CHECK-NEXT: 2 30
package main
func main() {
a := [...]int{1: 1, 2: 2, 4: 4}
for i, val := range a {
println(i, val, a[i])
}
for i, val := range [...]int{10, 20, 30} {
println(i, val)
}
}

View File

@ -1,14 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 10
// CHECK-NEXT: 9
package main
func main() {
var a [10]int
b := a[1:]
println(len(a))
println(len(b))
}

View File

@ -1,22 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: +1.000000e+000
// CHECK-NEXT: +2.000000e+000
// CHECK-NEXT: +3.000000e+000
package main
var a1 = [...]float32{1.0, 2.0, 3.0}
func main() {
var a2 [3]float32
a2 = a1
println(a2[0])
println(a2[1])
println(a2[2])
// broken due to lack of promotion of
// stack to heap.
//println(a2[0], a2[1], a2[2])
}

View File

@ -1,21 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 246
// CHECK-NEXT: 123
// CHECK-NEXT: 124
// CHECK-NEXT: 123
package main
func main() {
x := 123
x *= 2
println(x)
x /= 2
println(x)
x += 1
println(x)
x -= 1
println(x)
}

View File

@ -1,13 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 123
package main
func main() {
var x int
px := &x
*px = 123
println(x)
}

View File

@ -1,40 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 123 456
// CHECK-NEXT: 456 123
// CHECK-NEXT: 456 123
// CHECK-NEXT: 123 456
// CHECK-NEXT: 123 456
package main
func xyz() (int, int) {
return 123, 456
}
func abc() (int, int) {
var a, b = xyz()
return a, b
}
type S struct {
a int
b int
}
func main() {
a, b := xyz()
println(a, b)
b, a = abc()
println(a, b)
// swap
println(a, b)
a, b = b, a
println(a, b)
var s S
s.a, s.b = a, b
println(s.a, s.b)
}

View File

@ -1,42 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 123
// CHECK-NEXT: 456
// CHECK-NEXT: 1 2
// CHECK-NEXT: 666 0
package main
func f1() (x int) {
x = 123
return
}
func f2() (x int) {
return 456
}
func f3() (x, y int) {
y, x = 2, 1
return
}
func f4() (x, _ int) {
x = 666
return
}
func main() {
x := f1()
println(x)
x = f2()
println(x)
var y int
x, y = f3()
println(x, y)
x, y = f4()
println(x, y)
}

View File

@ -1,43 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
// CHECK-NEXT: 3
// CHECK-NEXT: 4
// CHECK-NEXT: 5
// CHECK-NEXT: 6
// CHECK-NEXT: 7
// CHECK-NEXT: 8
// CHECK-NEXT: 9
// CHECK-NEXT: done
// CHECK-NEXT: !
package main
func f1() {
goto labeled
labeled:
goto done
return
done:
println("!")
}
func main() {
i := 0
start:
if i < 10 {
println(i)
i++
goto start
} else {
goto end
}
return
end:
println("done")
f1()
return
}

View File

@ -1,22 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
package main
func labeledBreak() {
var i int
L:
for ; i < 10; i++ {
switch {
default:
break L
}
}
println(i)
}
func main() {
labeledBreak()
}

View File

@ -1,41 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0 0
// CHECK-NEXT: 0 1
// CHECK-NEXT: 10
// CHECK-NEXT: 20
// CHECK-NEXT: 30
// CHECK-NEXT: 40
// CHECK-NEXT: 50
// CHECK-NEXT: 60
// CHECK-NEXT: 70
// CHECK-NEXT: 80
// CHECK-NEXT: 90
// CHECK-NEXT: 100
// CHECK-NEXT: -1
package main
func main() {
c := make(chan int)
println(len(c), cap(c))
c1 := make(chan int, 1)
println(len(c1), cap(c1))
f := func() {
n, ok := <-c
if ok {
c1 <- n * 10
} else {
c1 <- -1
}
}
for i := 0; i < 10; i++ {
go f()
c <- i + 1
println(<-c1)
}
go f()
close(c)
println(<-c1)
}

View File

@ -1,28 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
// CHECK-NEXT: 3
// CHECK-NEXT: 4
// CHECK-NEXT: 5
// CHECK-NEXT: 6
// CHECK-NEXT: 7
// CHECK-NEXT: 8
// CHECK-NEXT: 9
package main
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}()
for n := range ch {
println(n)
}
}

View File

@ -1,27 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: sent a value
// CHECK-NEXT: received 123
// CHECK-NEXT: default
package main
func f1() {
c := make(chan int, 1)
for i := 0; i < 3; i++ {
select {
case n, _ := <-c:
println("received", n)
c = nil
case c <- 123:
println("sent a value")
default:
println("default")
}
}
}
func main() {
f1()
}

View File

@ -1,20 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 1
// CHECK-NEXT: 2
// CHECK-NEXT: true
package main
func main() {
ch := make(chan int, uint8(1))
ch <- 1
println(<-ch)
ch <- 2
x, ok := <-ch
println(x)
println(ok)
}

View File

@ -1,17 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | count 0
package main
type A struct {
b1, b2 B
}
type B struct {
a1, a2 *A
}
func main() {
var a A
_ = a
}

View File

@ -1,15 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: abc
package main
func cat(a, b string) func(string) string {
return func(c string) string { return a + b + c }
}
func main() {
f := cat("a", "b")
println(f("c"))
}

View File

@ -1,15 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: false
package main
func main() {
a := false
f := func() {
make(chan *bool, 1) <- &a
}
f()
println(a)
}

View File

@ -1,24 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: (+1.000000e+000+2.000000e+000i)
// CHECK-NEXT: (-1.000000e+000-2.000000e+000i)
// CHECK-NEXT: true
// CHECK-NEXT: (+1.000000e+000+2.000000e+000i)
// CHECK-NEXT: (-1.000000e+000-2.000000e+000i)
// CHECK-NEXT: true
package main
func main() {
var f32 float32 = 1
var f64 float64 = 1
c64 := complex(f32, f32+1)
println(c64)
println(-c64)
println(c64 == c64)
c128 := complex(f64, f64+1)
println(c128)
println(-c128)
println(c128 == c128)
}

View File

@ -1,78 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 1 1
// CHECK-NEXT: 1 1 1 4
// CHECK-NEXT: 2147483647
// CHECK-NEXT: -2147483648
// CHECK-NEXT: 2147483647
// CHECK-NEXT: -127
// CHECK-NEXT: false
// CHECK-NEXT: 10000000000
// CHECK-NEXT: 1
// CHECK-NEXT: 3
package main
import "runtime"
const (
a = iota * 2
A = 1
B
C
D = Z + iota
)
const (
Z = iota
Big = 1<<31 - 1
Big2 = -2147483648
Big3 = 2147483647
)
const (
expbits32 uint = 8
bias32 = -1<<(expbits32-1) + 1
darwinAMD64 = runtime.GOOS == "darwin" && runtime.GOARCH == "amd64"
)
func f1() float32 {
return 0
}
func constArrayLen() {
a := [...]int{1, 2, 3}
const x = len(a)
println(x)
}
func main() {
println(a)
println(B)
println(A, A)
println(A, B, C, D)
println(Big)
println(Big2)
println(Big3)
println(bias32)
// Currently fails, due to difference in C printf and Go's println
// formatting of the exponent.
//println(10 * 1e9)
println(darwinAMD64)
// Test conversion.
println(int64(10) * 1e9)
// Ensure consts work just as well when declared inside a function.
const (
x_ = iota
y_
)
println(y_)
constArrayLen()
}

View File

@ -1,15 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | count 0
package main
func constIntToComplex() complex128 {
return 0
}
func main() {
var c64 complex64
var c128 complex128
c128 = complex128(c64)
c64 = complex64(c128)
}

View File

@ -1,103 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: 133
// CHECK-NEXT: 65413
// CHECK-NEXT: 4294967173
// CHECK-NEXT: 18446744073709551493
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: 123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: -123
// CHECK-NEXT: 133
// CHECK-NEXT: 65413
// CHECK-NEXT: 4294967173
// CHECK-NEXT: 18446744073709551493
// CHECK-NEXT: +1.230000e+002
// CHECK-NEXT: +1.230000e+002
// CHECK-NEXT: +1.230000e+002
// CHECK-NEXT: +1.230000e+002
// CHECK-NEXT: +1.234500e+004
// CHECK-NEXT: +1.234500e+004
// CHECK-NEXT: +1.234500e+004
// CHECK-NEXT: +1.234500e+004
// CHECK-NEXT: +1.234560e+005
// CHECK-NEXT: +1.234560e+005
// CHECK-NEXT: +1.234560e+005
// CHECK-NEXT: +1.234560e+005
// CHECK-NEXT: +1.234568e+010
// CHECK-NEXT: +1.234568e+010
// CHECK-NEXT: +1.234568e+010
// CHECK-NEXT: +1.234568e+010
package main
func main() {
// float to int
for _, f32 := range []float32{123.456, -123.456} {
println(int8(f32))
println(int16(f32))
println(int32(f32))
println(int64(f32))
println(uint8(f32))
println(uint16(f32))
println(uint32(f32))
println(uint64(f32))
}
for _, f64 := range []float64{123.456, -123.456} {
println(int8(f64))
println(int16(f64))
println(int32(f64))
println(int64(f64))
println(uint8(f64))
println(uint16(f64))
println(uint32(f64))
println(uint64(f64))
}
// int to float
var i8 int8 = 123
println(float32(i8))
println(float64(i8))
var ui8 uint8 = 123
println(float32(ui8))
println(float64(ui8))
var i16 int32 = 12345
println(float32(i16))
println(float64(i16))
var ui16 uint32 = 12345
println(float32(ui16))
println(float64(ui16))
var i32 int32 = 123456
println(float32(i32))
println(float64(i32))
var ui32 uint32 = 123456
println(float32(ui32))
println(float64(ui32))
var i64 int64 = 12345678910
println(float32(i64))
println(float64(i64))
var ui64 uint64 = 12345678910
println(float32(ui64))
println(float64(ui64))
}

View File

@ -1,44 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 2147483647
// CHECK-NEXT: 2147483647
// CHECK-NEXT: 2147483647
// CHECK-NEXT: 2147483648
// CHECK-NEXT: -2147483648
// CHECK-NEXT: 18446744071562067968
// CHECK-NEXT: 0
// CHECK-NEXT: 0
// CHECK-NEXT: 0
// CHECK-NEXT: -1
// CHECK-NEXT: 4294967295
// CHECK-NEXT: 4294967295
// CHECK-NEXT: 0
// CHECK-NEXT: 0
// CHECK-NEXT: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 1
// CHECK-NEXT: 1
package main
func signed(i32 int32) {
println(uint32(i32))
println(int64(i32))
println(uint64(i32))
}
func unsigned(u32 uint32) {
println(int32(u32))
println(int64(u32))
println(uint64(u32))
}
func main() {
signed(1<<31 - 1)
signed(-1 << 31)
signed(0)
unsigned(1<<32 - 1)
unsigned(0)
unsigned(1)
}

View File

@ -1,15 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | count 0
package main
type X struct{}
type Y X
func main() {
var x X
px := &x
py := (*Y)(&x)
py = (*Y)(px)
_ = py
}

View File

@ -1,125 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: f2.1
// CHECK-NEXT: f5
// CHECK-NEXT: recovered no error
// CHECK-NEXT: f5
// CHECK-NEXT: recovered: meep meep
// CHECK-NEXT: 888
// CHECK-NEXT: f5
// CHECK-NEXT: recovered no error
// CHECK-NEXT: f5
// CHECK-NEXT: recovered no error
// CHECK-NEXT: 888
// CHECK-NEXT: 456
// CHECK-NEXT: 999
// CHECK-NEXT: 999
// CHECK-NEXT: 123
// CHECK-NEXT: 999
// CHECK-NEXT: 999
// CHECK-NEXT: 246
// CHECK-NEXT: f2.2
// CHECK-NEXT: f2.3
// CHECK-NEXT: f1.1
// CHECK-NEXT: f1.2
// CHECK-NEXT: recovered: second
// CHECK-NEXT: ahoy
package main
type T struct {
value int
}
type T1 struct {
T
}
func (t T) abc() {
println(t.value)
}
func (t *T) def() {
println(t.value)
}
func (t *T) ghi(v int) {
println(v)
}
func printerr(err interface{}) {
if err != nil {
println("recovered:", err.(string))
} else {
println("recovered no error")
}
}
func f6() {
defer func() { printerr(recover()) }()
defer func() { panic("second") }()
panic("first")
}
func f5(panic_ bool) {
var t1 T1
t1.T.value = 888
defer t1.abc()
var f func(int)
f = func(recursion int) {
if recursion > 0 {
f(recursion - 1)
return
}
println("f5")
printerr(recover())
}
defer f(0) // will recover (after f(1))
defer f(1) // won't recover
if panic_ {
panic("meep meep")
}
}
func f4() {
var a T = T{999}
var b *T = &a
defer a.abc()
defer a.def()
defer a.ghi(123)
defer b.abc()
defer b.def()
defer b.ghi(456)
f5(true)
f5(false) // verify the recover in f5 works
}
func f3() (a int) {
defer func() { a *= 2 }()
f4()
return 123
}
func f2() {
defer func() { println("f2.3") }()
defer func(s string) { println(s) }("f2.2")
println("f2.1")
println(f3())
}
func f1() {
defer func() { println("f1.2") }()
defer func() { println("f1.1") }()
f2()
}
func builtins() {
defer println("ahoy")
}
func main() {
f1()
f6()
builtins()
}

View File

@ -1,11 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: (0x0,0x0)
package main
func main() {
err := recover()
println(err)
}

View File

@ -1,41 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 0
// CHECK-NEXT: 1
// CHECK-NEXT: 2
// CHECK-NEXT: 3
// CHECK-NEXT: 0
// CHECK-NEXT: 2
// CHECK-NEXT: 3
// CHECK-NEXT: 4
package main
func main() {
for i := 0; true; i++ {
println(i)
if i == 2 {
println(3)
break
}
println(1)
i++
continue
println("unreachable")
}
nums := [...]int{0, 1, 2, 3, 4, 5}
for n := range nums {
if n == 1 {
continue
}
println(n)
if n == 4 {
{
break
}
println("!")
}
}
}

View File

@ -1,28 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 246
// CHECK-NEXT: 123 true false
// vim: set ft=go :
package main
func test() func() int {
return blah
}
func blah() int {
return 123
}
func sret() (int, bool, bool) {
return 123, true, false
}
func main() {
f := test()
println(2 * f())
a, b, c := sret()
println(a, b, c)
}

View File

@ -1,26 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: true
// CHECK-NEXT: false
// CHECK-NEXT: true
// CHECK-NEXT: false
// CHECK-NEXT: false
// CHECK-NEXT: true
// CHECK-NEXT: false
// CHECK-NEXT: true
package main
func main() {
var f func()
println(f == nil)
println(f != nil)
println(nil == f)
println(nil != f)
f = func() {}
println(f == nil)
println(f != nil)
println(nil == f)
println(nil != f)
}

View File

@ -1,28 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 1
// CHECK-NEXT: 20
// CHECK-NEXT: extra: 10
package main
func swap(a, b int) (int, int) {
return b, a
}
func sub(a, b int) int {
return a - b
}
func printint(a int, extra ...int) {
println(a)
for _, b := range extra {
println("extra:", b)
}
}
func main() {
println(sub(swap(1, 2)))
printint(swap(10, 20))
}

View File

@ -1,53 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: f1
// CHECK-NEXT: f2
// CHECK-NEXT: f3
// CHECK-NEXT: f4
// CHECK-NEXT: 123
package main
func f1() {
if true {
println("f1")
return
}
for {
}
}
func f2() {
defer func() { println("f2") }()
if true {
return
}
for {
}
}
func f3() int {
if true {
println("f3")
return 123
}
for {
}
}
func f4() int {
defer func() { println("f4") }()
if true {
return 123
}
for {
}
}
func main() {
f1()
f2()
f3()
println(f4())
}

View File

@ -1,34 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: hello from T 1
// CHECK-NEXT: hello from T 2
package main
type T struct {
val int
}
func (t T) Hello(done chan bool) {
println("hello from T", t.val)
done <- true
}
type I interface {
Hello(chan bool)
}
func main() {
done := make(chan bool)
t := T{1}
go t.Hello(done)
<-done
var i I = T{2}
go i.Hello(done)
<-done
go println("hello builtin")
}

View File

@ -1,46 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: False()
// CHECK-NEXT: False()
// CHECK-NEXT: false
// CHECK-NEXT: False()
// CHECK-NEXT: True()
// CHECK-NEXT: true
// CHECK-NEXT: True()
// CHECK-NEXT: true
// CHECK-NEXT: True()
// CHECK-NEXT: true
// CHECK-NEXT: False()
// CHECK-NEXT: false
// CHECK-NEXT: False()
// CHECK-NEXT: false
// CHECK-NEXT: True()
// CHECK-NEXT: False()
// CHECK-NEXT: false
// CHECK-NEXT: True()
// CHECK-NEXT: True()
// CHECK-NEXT: true
package main
func False() bool {
println("False()")
return false
}
func True() bool {
println("True()")
return true
}
func main() {
println(False() || False())
println(False() || True())
println(True() || False())
println(True() || True())
println(False() && False())
println(False() && True())
println(True() && False())
println(True() && True())
}

View File

@ -1,17 +0,0 @@
// RUN: llgo -o %t %s %p/Inputs/init2.go
// RUN: %t 2>&1 | FileCheck %s
package main
// CHECK-DAG: do some other stuff before main
//func init()
// CHECK-DAG: do some stuff before main
func init() {
println("do some stuff before main")
}
// CHECK: main has been called
func main() {
println("main has been called")
}

View File

@ -1,61 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: x is nil
// CHECK-NEXT: i2v: 123456
// CHECK-NEXT: !
// CHECK-NEXT: (*X).F1: 123456
package main
type X struct{ x int }
func (x *X) F1() { println("(*X).F1:", x.x) }
func (x *X) F2() { println("(*X).F2") }
type I interface {
F1()
F2()
}
func main() {
var x interface{}
// x is nil. Let's make sure an assertion on it
// won't cause a panic.
if x, ok := x.(int32); ok {
println("i2v:", x)
}
if x == nil {
println("x is nil")
}
x = int32(123456)
// Let's try an interface-to-value assertion.
if x, ok := x.(int32); ok {
println("i2v:", x)
}
if x, ok := x.(int64); ok {
println("i2v:", x)
}
// This will fail the assertion.
if i, ok := x.(I); ok {
i.F1()
_ = i
} else {
println("!")
}
// Assign an *X, which should pass the assertion.
x_ := new(X)
x_.x = 123456
x = x_ //&X{x: 123456}
if i, ok := x.(I); ok {
i.F1()
_ = i
} else {
println("!")
}
}

View File

@ -1,43 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: expected: y != z
package main
type any interface{}
type Stringer interface {
String() string
}
type lessThanAWord struct {
a byte
}
func (l lessThanAWord) String() string {
return "!"
}
func makeAStringer() Stringer {
return lessThanAWord{}
}
func main() {
var x1, x2 int = 1, 2
var y any = x1
var z any = x2
if y != z {
println("expected: y != z")
} else {
println("unexpected: y == z")
}
/*
if y == x1 {
println("expected: y == x1")
} else {
println("unexpected: y == x1")
}
*/
//println(y.(int))
}

View File

@ -1,30 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: true
// CHECK-NEXT: true
package main
import "unsafe"
type I interface {
X()
}
type T int
func (t T) X() {
}
func main() {
var highbit uint32 = 1 << 31
var pos0 float32 = 0
var neg0 float32 = *(*float32)(unsafe.Pointer(&highbit))
var i1 interface{} = pos0
var i2 interface{} = neg0
println(i1 == i2)
var i3 interface{} = T(123)
var i4 I = T(123)
println(i3 == i4)
}

View File

@ -1,13 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: true
// CHECK-NEXT: false
package main
func main() {
var x interface{} = 123
println(x == 123)
println(x != 123)
}

View File

@ -1,22 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | count 0
package main
import "io"
type rdr struct{}
func (r rdr) Read(b []byte) (int, error) {
return 0, nil
}
func F(i interface{}) {
_ = i.(io.Reader)
}
func main() {
var r rdr
F(r)
F(&r)
}

View File

@ -1,32 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: A
// CHECK-NEXT: B
package main
type BI interface {
B()
}
type AI interface {
A()
BI
}
type S struct{}
func (s S) A() {
println("A")
}
func (s S) B() {
println("B")
}
func main() {
var ai AI = S{}
ai.A()
ai.B()
}

View File

@ -1,43 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: !!!! 123
// CHECK-NEXT: errno 123
package main
var errors = [...]string{}
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
return "-" + itoa(-val)
}
var buf [32]byte // big enough for int64
i := len(buf) - 1
for val >= 10 {
buf[i] = byte(val%10 + '0')
i--
val /= 10
}
buf[i] = byte(val + '0')
return string(buf[i:])
}
type Errno uintptr
func (e Errno) Error() string {
println("!!!!", uintptr(e))
if 0 <= int(e) && int(e) < len(errors) {
s := errors[e]
if s != "" {
return s
}
}
return "errno " + itoa(int(e))
}
func main() {
e := Errno(123)
i := (interface{})(e)
println(i.(error).Error())
}

View File

@ -1,33 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: 666
// CHECK-NEXT: The Beast
package main
type Numbered interface {
Number() int
}
type Named interface {
Name() string
}
type Beast struct{}
func (b *Beast) Number() int {
return 666
}
func (b *Beast) Name() string {
return "The Beast"
}
func main() {
var b Beast
var numbered Numbered = &b
var named Named = numbered.(Named)
println(numbered.Number())
println(named.Name())
}

View File

@ -1,16 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
package main
import "syscall"
type Signal interface {
Signal()
}
func main() {
var s Signal = syscall.SIGINT
// CHECK: ({{.*}},{{.*}})
println(s)
}

View File

@ -1,53 +0,0 @@
// RUN: llgo -o %t %s
// RUN: %t 2>&1 | FileCheck %s
// CHECK: X()
// CHECK-NEXT: Y()
// CHECK-NEXT: X()
// CHECK-NEXT: Y()
// CHECK-NEXT: X()
package main
type Stringer interface {
String() string
}
type X int
type Y int
type Z1 struct {
X
}
type Z2 struct {
Stringer
}
func (x X) String() string {
return "X()"
}
func (y *Y) String() string {
return "Y()"
}
func makeX() X {
return X(0)
}
func main() {
var z Stringer = X(0)
println(z.String())
z = new(Y)
println(z.String())
z = Z1{}
println(z.String())
z = Z2{new(Y)}
println(z.String())
println(makeX().String())
}

Some files were not shown because too many files have changed in this diff Show More