forked from OSchip/llvm-project
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:
parent
936d1427da
commit
372bfc65de
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"project_id" : "llgo",
|
||||
"conduit_uri" : "https://reviews.llvm.org/"
|
||||
}
|
|
@ -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)
|
308
llgo/LICENSE.TXT
308
llgo/LICENSE.TXT
|
@ -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.
|
|
@ -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.
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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...))
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
})
|
||||
}
|
|
@ -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."
|
|
@ -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
|
|
@ -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`
|
||||
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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 :
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)}
|
||||
}
|
|
@ -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])
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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}, "")
|
||||
}
|
|
@ -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
|
||||
}
|
1342
llgo/irgen/ssa.go
1342
llgo/irgen/ssa.go
File diff suppressed because it is too large
Load Diff
|
@ -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])
|
||||
}
|
|
@ -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...)
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
|
@ -1,7 +0,0 @@
|
|||
// RUN: llgo -c -o /dev/null -g %s
|
||||
|
||||
package main
|
||||
|
||||
//line :1
|
||||
func main() {
|
||||
}
|
|
@ -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'
|
|
@ -1,5 +0,0 @@
|
|||
package main
|
||||
|
||||
func init() {
|
||||
println("do some other stuff before main")
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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])
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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("!")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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")
|
||||
}
|
|
@ -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("!")
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
Loading…
Reference in New Issue