diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml new file mode 100644 index 0000000000000..e63431649f897 --- /dev/null +++ b/.buildkite/pipeline.yml @@ -0,0 +1,28 @@ +steps: + - label: "analyzegc" + commands: + - echo "--- Install apt-get pre-reqs" + - apt-get update + - apt-get install -y build-essential libatomic1 python python3 gfortran perl wget m4 cmake pkg-config curl + - echo "--- Install in-tree LLVM dependencies" + - make -j 6 -C deps install-llvm install-clang install-llvm-tools install-libuv install-utf8proc install-unwind + - echo "+++ run clangsa/analyzegc" + - make -j 6 -C test/clangsa + - make -j 6 -C src analyzegc + agents: + queue: "juliacpu" # this should be julia -- also in pipeline settings + # os: linux # tag missing for juliacpu queue + timeout_in_minutes: 60 + - label: "llvmpasses" + commands: + - echo "--- Install apt-get pre-reqs" + - apt-get update + - apt-get install -y build-essential libatomic1 python python3 gfortran perl wget m4 cmake pkg-config curl + - echo "+++ run llvmpasses" + - make -j 6 release + - make -j 6 -C src install-analysis-deps + - make -j 6 -C test/llvmpasses + agents: + queue: "juliacpu" # this should be julia -- also in pipeline settings + # os: linux # tag missing for juliacpu queue + timeout_in_minutes: 60 diff --git a/.clang-format b/.clang-format index 0322d0f6749a9..39b5767a50291 100644 --- a/.clang-format +++ b/.clang-format @@ -109,7 +109,6 @@ StatementMacros: - checked_intrinsic_ctype - cvt_iintrinsic - fpiseq_n - - fpislt_n - ter_fintrinsic - ter_intrinsic_ctype - un_fintrinsic diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 865abeebd82af..6cab5b68b11e9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,3 @@ -/.github/workflows/ @JuliaLang/github-actions +CODEOWNERS @JuliaLang/github-actions +/.github/ @JuliaLang/github-actions +/.buildkite/ @JuliaLang/github-actions diff --git a/CITATION.bib b/CITATION.bib index af8cffe7aa524..f1361a1eea0b8 100644 --- a/CITATION.bib +++ b/CITATION.bib @@ -8,68 +8,8 @@ @article{Julia-2017 pages={65--98}, year={2017}, publisher={SIAM}, - doi={10.1137/141000671} + doi={10.1137/141000671}, + url={https://epubs.siam.org/doi/10.1137/141000671} } -% The following citations are about specific aspects of Julia. - -@article{Julia-2019-a, - author = {Bezanson, Jeff and Chen, Jiahao and Chung, Benjamin and Karpinski, Stefan and Shah, Viral B. and Vitek, Jan and Zoubritzky, Lionel}, - title = {Julia: Dynamism and Performance Reconciled by Design}, - journal = {Proc. ACM Program. Lang.}, - issue_date = {November 2018}, - volume = {2}, - number = {OOPSLA}, - month = oct, - year = {2018}, - issn = {2475-1421}, - pages = {120:1--120:23}, - articleno = {120}, - numpages = {23}, - url = {https://doi.acm.org/10.1145/3276490}, - doi = {10.1145/3276490}, - acmid = {3276490}, - publisher = {ACM}, - address = {New York, NY, USA}, - keywords = {dynamic languages, just-in-time compilation, multiple dispatch}, -} - -@article{Julia-2019-b, - author = {Zappa Nardelli, Francesco and Belyakova, Julia and Pelenitsyn, Artem and Chung, Benjamin and Bezanson, Jeff and Vitek, Jan}, - title = {Julia Subtyping: A Rational Reconstruction}, - journal = {Proc. ACM Program. Lang.}, - issue_date = {November 2018}, - volume = {2}, - number = {OOPSLA}, - month = oct, - year = {2018}, - issn = {2475-1421}, - pages = {113:1--113:27}, - articleno = {113}, - numpages = {27}, - url = {https://doi.acm.org/10.1145/3276483}, - doi = {10.1145/3276483}, - acmid = {3276483}, - publisher = {ACM}, - address = {New York, NY, USA}, - keywords = {Multiple Dispatch, Subtyping}, -} - -@inproceedings{Julia-2014, - author = {Bezanson, Jeff and Chen, Jiahao and Karpinski, Stefan and Shah, Viral and Edelman, Alan}, - title = {Array Operators Using Multiple Dispatch: A Design Methodology for Array Implementations in Dynamic Languages}, - booktitle = {Proceedings of ACM SIGPLAN International Workshop on Libraries, Languages, and Compilers for Array Programming}, - series = {ARRAY'14}, - year = {2014}, - isbn = {978-1-4503-2937-8}, - location = {Edinburgh, United Kingdom}, - pages = {56:56--56:61}, - articleno = {56}, - numpages = {6}, - url = {https://doi.acm.org/10.1145/2627373.2627383}, - doi = {10.1145/2627373.2627383}, - acmid = {2627383}, - publisher = {ACM}, - address = {New York, NY, USA}, - keywords = {Julia, array indexing, dynamic dispatch, multiple dispatch, static analysis, type inference}, -} +% For more details on research related to Julia, see https://julialang.org/research diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fbca229de0d45..83d9bdd48f3a7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ If you are already familiar with Julia itself, this blog post by Katharine Hyatt ## Learning Julia -[The learning page](https://julialang.org/learning) has a great list of resources for new and experienced users alike. [This tutorial video](https://www.youtube.com/watch?v=vWkgEddb4-A) is one recommended starting point, as is the "[Invitation to Julia](https://www.youtube.com/watch?v=gQ1y5NUD_RI)" workshop video from JuliaCon 2015 ([slide materials here](https://github.com/dpsanders/invitation_to_julia)). The [Julia documentation](https://docs.julialang.org) covers the language and core library features, and is searchable. +[The learning page](https://julialang.org/learning) has a great list of resources for new and experienced users alike. ## Before filing an issue diff --git a/Make.inc b/Make.inc index 519720a861ed7..10f1b471fe7a6 100644 --- a/Make.inc +++ b/Make.inc @@ -45,7 +45,7 @@ USE_SYSTEM_BLAS:=0 USE_SYSTEM_LAPACK:=0 USE_SYSTEM_GMP:=0 USE_SYSTEM_MPFR:=0 -USE_SYSTEM_SUITESPARSE:=0 +USE_SYSTEM_LIBSUITESPARSE:=0 USE_SYSTEM_LIBUV:=0 USE_SYSTEM_UTF8PROC:=0 USE_SYSTEM_MBEDTLS:=0 @@ -472,13 +472,13 @@ USEGCC := 0 USECLANG := 1 endif -# Note: Supporting only macOS Mavericks and above +# Note: Supporting only macOS Yosemite and above ifeq ($(OS), Darwin) APPLE_ARCH := $(shell uname -m) USEGCC := 0 USECLANG := 1 ifneq ($(APPLE_ARCH),arm64) -MACOSX_VERSION_MIN := 10.9 +MACOSX_VERSION_MIN := 10.10 else MACOSX_VERSION_MIN := 11.0 endif @@ -587,6 +587,12 @@ endif #USEMSVC RANLIB := $(CROSS_COMPILE)ranlib OBJCOPY := $(CROSS_COMPILE)objcopy +ifneq ($(USEMSVC), 1) +CPP_STDOUT := $(CPP) -P +else +CPP_STDOUT := $(CPP) -E +endif + # file extensions ifeq ($(OS), WINNT) SHLIB_EXT := dll @@ -596,6 +602,21 @@ else SHLIB_EXT := so endif +ifeq ($(OS),WINNT) +define versioned_libname +$$(if $(2),$(1)-$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT)) +endef +else ifeq ($(OS),Darwin) +define versioned_libname +$$(if $(2),$(1).$(2).$(SHLIB_EXT),$(1).$(SHLIB_EXT)) +endef +else +define versioned_libname +$$(if $(2),$(1).$(SHLIB_EXT).$(2),$(1).$(SHLIB_EXT)) +endef +endif + + ifeq ($(SHLIB_EXT), so) define SONAME_FLAGS -Wl,-soname=$1 @@ -898,6 +919,7 @@ ifneq (,$(findstring aarch64,$(ARCH))) OPENBLAS_DYNAMIC_ARCH:=0 OPENBLAS_TARGET_ARCH:=ARMV8 USE_BLAS64:=1 +BINARY:=64 ifeq ($(OS),Darwin) # Apple Chips are all at least A12Z MCPU:=apple-a12 @@ -1008,22 +1030,18 @@ JCPPFLAGS+=-DSYSTEM_LLVM endif # SYSTEM_LLVM # Windows builds need a little help finding the LLVM libraries for llvm-config -LLVM_CONFIG_PATH_FIX := +# use delayed expansion (= not :=) because spawn isn't defined until later +# WINEPATH is only needed for a wine-based cross compile +LLVM_CONFIG_PATH_FIX = ifeq ($(OS),WINNT) -LLVM_CONFIG_PATH_FIX := PATH="$(build_bindir):$(PATH)" +LLVM_CONFIG_PATH_FIX = PATH="$(build_bindir):$(PATH)" WINEPATH="$(call cygpath_w,$(build_bindir));$(WINEPATH)" endif ifeq ($(BUILD_OS),$(OS)) -LLVM_CONFIG_HOST := $(LLVM_CONFIG) +LLVM_CONFIG_HOST = $(LLVM_CONFIG_PATH_FIX) $(LLVM_CONFIG) else LLVM_CONFIG_HOST := $(basename $(LLVM_CONFIG))-host$(BUILD_EXE) -ifeq (exists, $(shell [ -f '$(LLVM_CONFIG_HOST)' ] && echo exists )) -ifeq ($(shell $(LLVM_CONFIG_PATH_FIX) $(LLVM_CONFIG_HOST) --version),3.3) -# llvm-config-host <= 3.3 is broken, use llvm-config instead (in an emulator) -# use delayed expansion (= not :=) because spawn isn't defined until later -LLVM_CONFIG_HOST = $(LLVM_CONFIG_PATH_FIX) $(call spawn,$(LLVM_CONFIG)) -endif -else +ifneq (exists, $(shell [ -f '$(LLVM_CONFIG_HOST)' ] && echo exists )) # llvm-config-host does not exist (cmake build) LLVM_CONFIG_HOST = $(LLVM_CONFIG_PATH_FIX) $(call spawn,$(LLVM_CONFIG)) endif @@ -1147,8 +1165,10 @@ BB_TRIPLET_LIBGFORTRAN := $(subst $(SPACE),-,$(filter-out cxx%,$(subst -,$(SPACE BB_TRIPLET_CXXABI := $(subst $(SPACE),-,$(filter-out libgfortran%,$(subst -,$(SPACE),$(BB_TRIPLET_LIBGFORTRAN_CXXABI)))) BB_TRIPLET := $(subst $(SPACE),-,$(filter-out cxx%,$(filter-out libgfortran%,$(subst -,$(SPACE),$(BB_TRIPLET_LIBGFORTRAN_CXXABI))))) +LIBGFORTRAN_VERSION := $(subst libgfortran,,$(filter libgfortran%,$(subst -,$(SPACE),$(BB_TRIPLET_LIBGFORTRAN)))) + # This is the set of projects that BinaryBuilder dependencies are hooked up for. -BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM SUITESPARSE OPENLIBM GMP MBEDTLS LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP CSL +BB_PROJECTS := BLASTRAMPOLINE OPENBLAS LLVM LIBSUITESPARSE OPENLIBM GMP MBEDTLS LIBSSH2 NGHTTP2 MPFR CURL LIBGIT2 PCRE LIBUV LIBUNWIND DSFMT OBJCONV ZLIB P7ZIP CSL define SET_BB_DEFAULT # First, check to see if BB is disabled on a global setting ifeq ($$(USE_BINARYBUILDER),0) @@ -1167,7 +1187,7 @@ $(foreach proj,$(BB_PROJECTS),$(eval $(call SET_BB_DEFAULT,$(proj)))) # Warn if the user tries to build something that requires `gfortran` but they don't have it installed. ifeq ($(FC_VERSION),) -ifneq ($(USE_BINARYBUILDER_OPENBLAS)$(USE_BINARYBUILDER_SUITESPARSE),11) +ifneq ($(USE_BINARYBUILDER_OPENBLAS)$(USE_BINARYBUILDER_LIBSUITESPARSE),11) $(error "Attempting to build OpenBLAS or SuiteSparse without a functioning fortran compiler!") endif endif @@ -1354,8 +1374,8 @@ endif ifeq ($(USE_SYSTEM_BLAS),1) # Since the names don't line up (`BLAS` vs. `OPENBLAS`), manually gate: USE_BINARYBUILDER_OPENBLAS := 0 -# Disable BB SuiteSparse if we're using system BLAS -USE_BINARYBUILDER_SUITESPARSE := 0 +# Disable BB LIBSUITESPARSE if we're using system BLAS +USE_BINARYBUILDER_LIBSUITESPARSE := 0 endif ifeq ($(USE_SYSTEM_LIBM),1) @@ -1479,8 +1499,12 @@ ifneq ($(findstring $(OS),Linux FreeBSD),) LIBGCC_NAME := libgcc_s.$(SHLIB_EXT).1 endif - +# USE_SYSTEM_CSL causes it to get symlinked into build_private_shlibdir +ifeq ($(USE_SYSTEM_CSL),1) +LIBGCC_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_private_shlibdir)/$(LIBGCC_NAME)) +else LIBGCC_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/$(LIBGCC_NAME)) +endif LIBGCC_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBGCC_NAME)) # USE_SYSTEM_LIBM and USE_SYSTEM_OPENLIBM causes it to get symlinked into build_private_shlibdir @@ -1548,6 +1572,7 @@ PRINT_FLISP = echo '$(subst ','\'',$(1))'; $(1) PRINT_JULIA = echo '$(subst ','\'',$(1))'; $(1) endif + # Makefile debugging trick: # call print-VARIABLE to see the runtime value of any variable # (hardened against any special characters appearing in the output) diff --git a/Makefile b/Makefile index 823ff3b86339d..51bb09b094f1c 100644 --- a/Makefile +++ b/Makefile @@ -154,7 +154,8 @@ $(build_depsbindir)/stringreplace: $(JULIAHOME)/contrib/stringreplace.c | $(buil @$(call PRINT_CC, $(HOSTCC) -o $(build_depsbindir)/stringreplace $(JULIAHOME)/contrib/stringreplace.c) julia-base-cache: julia-sysimg-$(JULIA_BUILD_MODE) | $(DIRS) $(build_datarootdir)/julia - @JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) $(call spawn, $(JULIA_EXECUTABLE) --startup-file=no $(call cygpath_w,$(JULIAHOME)/etc/write_base_cache.jl) \ + @JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \ + $(call spawn, $(JULIA_EXECUTABLE) --startup-file=no $(call cygpath_w,$(JULIAHOME)/etc/write_base_cache.jl) \ $(call cygpath_w,$(build_datarootdir)/julia/base.cache)) # public libraries, that are installed in $(prefix)/lib @@ -169,8 +170,7 @@ ifeq ($(BUNDLE_DEBUG_LIBS),1) JL_PRIVATE_LIBS-0 += libjulia-internal-debug endif ifeq ($(USE_GPL_LIBS), 1) -JL_PRIVATE_LIBS-0 += libsuitesparse_wrapper -JL_PRIVATE_LIBS-$(USE_SYSTEM_SUITESPARSE) += libamd libbtf libcamd libccolamd libcholmod libcolamd libklu libldl librbio libspqr libsuitesparseconfig libumfpack +JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBSUITESPARSE) += libamd libbtf libcamd libccolamd libcholmod libcolamd libklu libldl librbio libspqr libsuitesparseconfig libumfpack endif JL_PRIVATE_LIBS-$(USE_SYSTEM_PCRE) += libpcre2-8 JL_PRIVATE_LIBS-$(USE_SYSTEM_DSFMT) += libdSFMT @@ -188,7 +188,7 @@ else JL_PRIVATE_LIBS-$(USE_SYSTEM_ZLIB) += libz endif ifeq ($(USE_LLVM_SHLIB),1) -JL_PRIVATE_LIBS-$(USE_SYSTEM_LLVM) += libLLVM libLLVM-11jl +JL_PRIVATE_LIBS-$(USE_SYSTEM_LLVM) += libLLVM libLLVM-12jl endif JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBUNWIND) += libunwind @@ -290,8 +290,11 @@ endif done \ done for suffix in $(JL_PRIVATE_LIBS-1) ; do \ - lib=$(build_private_libdir)/$${suffix}.$(SHLIB_EXT); \ - $(INSTALL_M) $$lib $(DESTDIR)$(private_libdir) ; \ + for lib in $(build_private_libdir)/$${suffix}.$(SHLIB_EXT)*; do \ + if [ "$${lib##*.}" != "dSYM" ]; then \ + $(INSTALL_M) $$lib $(DESTDIR)$(private_libdir) ; \ + fi \ + done \ done endif # Install `7z` into libexec/ @@ -448,7 +451,7 @@ endif echo "base/version_git.jl" > light-source-dist.tmp # Download all stdlibs and include the tarball filenames in light-source-dist.tmp - @$(MAKE) -C stdlib getall NO_GIT=1 + @$(MAKE) -C stdlib getall DEPS_GIT=0 USE_BINARYBUILDER=0 -ls stdlib/srccache/*.tar.gz >> light-source-dist.tmp -ls stdlib/*/StdlibArtifacts.toml >> light-source-dist.tmp @@ -472,7 +475,7 @@ source-dist: # Make tarball with Julia code plus all dependencies full-source-dist: light-source-dist.tmp # Get all the dependencies downloaded - @$(MAKE) -C deps getall NO_GIT=1 + @$(MAKE) -C deps getall DEPS_GIT=0 USE_BINARYBUILDER=0 # Create file full-source-dist.tmp to hold all the filenames that go into the tarball cp light-source-dist.tmp full-source-dist.tmp diff --git a/NEWS.md b/NEWS.md index e0885b713f7ae..fcd5168dd9514 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,10 +6,26 @@ New language features * `(; a, b) = x` can now be used to destructure properties `a` and `b` of `x`. This syntax is equivalent to `a = getproperty(x, :a)` and similarly for `b`. ([#39285]) +* Implicit multiplication by juxtaposition is now allowed for radical symbols (e.g., `x√y` and `x∛y`). ([#40173]) +* The short-circuiting operators `&&` and `||` can now be dotted to participate in broadcast fusion + as `.&&` and `.||`. ([#39594]) +* `⫪` (U+2AEA, `\Top`, `\downvDash`) and `⫫` (U+2AEB, `\Bot`, `\upvDash`, `\indep`) + may now be used as binary operators with comparison precedence. ([#39403]) +* Repeated semicolons may now be used inside array literals to separate dimensions of an array, + with the number of semicolons specifying the particular dimension. Just as the single semicolon + in `[A; B]` has always described concatenating along the first dimension (vertically), now two + semicolons `[A;; B]` do so in the second dimension (horizontally), three semicolons `;;;` in the + third, and so on. ([#33697]) Language changes ---------------- +* `macroexpand`, `@macroexpand`, and `@macroexpand1` no longer wrap errors in a `LoadError`. To reduce breakage, `@test_throws` has been modified so that many affected tests will still pass ([#38379]]. +* The middle dot `·` (`\cdotp` U+00b7) and the Greek interpunct `·` (U+0387) are now treated as equivalent to the dot operator `⋅` (`\cdot` U+22c5) (#25157). +* The minus sign `−` (`\minus` U+2212) is now treated as equivalent to the hyphen-minus sign `-` (U+002d). +* Destructuring will no longer mutate values on the left hand side while iterating through values on the right hand side. In the example + of an array `x`, `x[2], x[1] = x` will now swap the first and second entry of `x`, whereas it used to fill both entries with `x[1]` + because `x[2]` was mutated during the iteration of `x`. ([#40737]) Compiler/Runtime improvements ----------------------------- @@ -18,6 +34,8 @@ Compiler/Runtime improvements Command-line option changes --------------------------- +* The Julia `--project` option and the `JULIA_PROJECT` environment variable now support selecting shared environments like `.julia/environments/myenv` the same way the package management console does: use `julia --project=@myenv` resp. `export JULIA_PROJECT="@myenv"` ([#40025]). + Multi-threading changes ----------------------- @@ -32,20 +50,29 @@ New library functions * Two argument methods `findmax(f, domain)`, `argmax(f, domain)` and the corresponding `min` versions ([#27613]). * `isunordered(x)` returns true if `x` is value that is normally unordered, such as `NaN` or `missing`. +* New `keepat!(vector, inds)` function which is the inplace equivalent of `vector[inds]` + for a list `inds` of integers ([#36229]). * New macro `Base.@invokelatest f(args...; kwargs...)` provides a convenient way to call `Base.invokelatest(f, args...; kwargs...)` ([#37971]) +* Two arguments method `lock(f, lck)` now accepts a `Channel` as the second argument. ([#39312]) +* New functor `Returns(value)`, which returns `value` for any arguments ([#39794]) * New macro `Base.@invoke f(arg1::T1, arg2::T2; kwargs...)` provides an easier syntax to call `invoke(f, Tuple{T1,T2}, arg1, arg2; kwargs...)` ([#38438]) +* New macros `@something` and `@coalesce` which are short-circuiting versions of `something` and `coalesce`, respectively ([#40729]) +* New function `redirect_stdio` for redirecting `stdin`, `stdout` and `stderr` ([#37978]). New library features -------------------- * The optional keyword argument `context` of `sprint` can now be set to a tuple of `:key => value` pairs to specify multiple attributes. ([#39381]) +* `bytes2hex` and `hex2bytes` are no longer limited to arguments of type `Union{String,AbstractVector{UInt8}}` and now only require that they're iterable and have a length. ([#39710]) Standard library changes ------------------------ +* Long strings are now elided using the syntax `"head" ⋯ 12345 bytes ⋯ "tail"` when displayed in the REPL ([#40736]). * `count` and `findall` now accept an `AbstractChar` argument to search for a character in a string ([#38675]). * `range` now supports the `range(start, stop)` and `range(start, stop, length)` methods ([#39228]). * `range` now supports `start` as an optional keyword argument ([#38041]). +* Some operations on ranges will return a `StepRangeLen` instead of a `StepRange`, to allow the resulting step to be zero. Previously, `λ .* (1:9)` gave an error when `λ = 0`. ([#40320]) * `islowercase` and `isuppercase` are now compliant with the Unicode lower/uppercase categories ([#38574]). * `iseven` and `isodd` functions now support non-`Integer` numeric types ([#38976]). * `escape_string` can now receive a collection of characters in the keyword @@ -57,6 +84,24 @@ Standard library changes * `keys(::RegexMatch)` is now defined to return the capture's keys, by name if named, or by index if not ([#37299]). * `keys(::Generator)` is now defined to return the iterator's keys ([#34678]) * `RegexMatch` now iterate to give their captures. ([#34355]). +* `Test.@test` now accepts `broken` and `skip` boolean keyword arguments, which + mimic `Test.@test_broken` and `Test.@test_skip` behavior, but allows skipping + tests failing only under certain conditions. For example + ```julia + if T == Float64 + @test_broken isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) + else + @test isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) + end + ``` + can be replaced by + ```julia + @test isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) broken=(T == Float64) + ``` + ([#39322]) +* `@lock` is now exported from Base ([#39588]). +* The experimental function `Base.catch_stack()` has been renamed to `current_exceptions()`, exported from Base and given a more specific return type ([#29901]) +* Some degree trigonometric functions, `sind`, `cosd`, `tand`, `asind`, `acosd`, `asecd`, `acscd`, `acotd`, `atand` now accept an square matrix ([#39758]). #### Package Manager @@ -67,6 +112,14 @@ Standard library changes * On aarch64, OpenBLAS now uses an ILP64 BLAS like all other 64-bit platforms. ([#39436]) * OpenBLAS is updated to 0.3.13. ([#39216]) * SuiteSparse is updated to 5.8.1. ([#39455]) +* The shape of an `UpperHessenberg` matrix is preserved under certain arithmetic operations, e.g. when multiplying or dividing by an `UpperTriangular` matrix. ([#40039]) +* `cis(A)` now supports matrix arguments ([#40194]). +* `dot` now supports `UniformScaling` with `AbstractMatrix` ([#40250]). +* `qr[!]` and `lu[!]` now support `LinearAlgebra.PivotingStrategy` (singleton type) values + as their optional `pivot` argument: defaults are `qr(A, NoPivot())` (vs. + `qr(A, ColumnNorm())` for pivoting) and `lu(A, RowMaximum())` (vs. `lu(A, NoPivot())` + without pivoting); the former `Val{true/false}`-based calls are deprecated. ([#40623]) +* `det(M::AbstractMatrix{BigInt})` now calls `det_bareiss(M)`, which uses the [Bareiss](https://en.wikipedia.org/wiki/Bareiss_algorithm) algorithm to calculate precise values.([#40868]). #### Markdown @@ -82,6 +135,9 @@ Standard library changes #### SparseArrays +* new `sizehint!(::SparseMatrixCSC, ::Integer)` method ([#30676]). +* `cholesky()` now fully preserves the user-specified permutation. ([#40560]) +* `issparse` now applies consistently to all wrapper arrays, including nested, by checking `issparse` on the wrapped parent array ([#37644]). #### Dates @@ -103,10 +159,13 @@ Standard library changes * `mmap` is now exported ([#39816]). +#### DelimitedFiles + +* `readdlm` now defaults to `use_mmap=false` on all OSes for consistent reliability in abnormal filesystem situations ([#40415]). Deprecated or removed --------------------- -- Multiple successive semicolons in an array expresion were previously ignored (e.g. `[1 ;; 2] == [1 ; 2]`). Multiple semicolons are being reserved for future syntax and may have different behavior in a future release. +- Multiple successive semicolons in an array expresion were previously ignored (e.g., `[1 ;; 2] == [1 ; 2]`). This is now being used to separate dimensions for array literals. (see **New language features**) External dependencies diff --git a/README.md b/README.md index ca913ec539b48..cb1fc2bdd8180 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,6 @@ helpful to start contributing to the Julia codebase. - [**StackOverflow**](https://stackoverflow.com/questions/tagged/julia-lang) - [**Twitter**](https://twitter.com/JuliaLanguage) -- [**Meetup**](https://julia.meetup.com/) - [**Learning resources**](https://julialang.org/learning/) ## Binary Installation @@ -73,14 +72,14 @@ First, make sure you have all the [required dependencies](https://github.com/JuliaLang/julia/blob/master/doc/build/build.md#required-build-tools-and-external-libraries) installed. Then, acquire the source code by cloning the git repository: - git clone git://github.com/JuliaLang/julia.git + git clone https://github.com/JuliaLang/julia.git By default you will be building the latest unstable version of Julia. However, most users should use the most recent stable version of Julia. You can get this version by changing to the Julia directory and running: - git checkout v1.5.3 + git checkout v1.6.1 Now run `make` to build the `julia` executable. @@ -145,10 +144,7 @@ Support for editing Julia is available for many [Sublime Text](https://github.com/JuliaEditorSupport/Julia-sublime), and many others. -Supported IDEs include: [Juno](http://junolab.org/) (Atom plugin), -[julia-vscode](https://github.com/JuliaEditorSupport/julia-vscode) (VS -Code plugin), and -[julia-intellij](https://github.com/JuliaEditorSupport/julia-intellij) -(IntelliJ IDEA plugin). The popular [Jupyter](https://jupyter.org/) -notebook interface is available through -[IJulia](https://github.com/JuliaLang/IJulia.jl). +Supported IDEs include: [julia-vscode](https://github.com/JuliaEditorSupport/julia-vscode) (VS +Code plugin), [Juno](http://junolab.org/) (Atom plugin). [Jupyter](https://jupyter.org/) +notebooks are available through the [IJulia](https://github.com/JuliaLang/IJulia.jl) package, and +[Pluto](https://github.com/fonsp/Pluto.jl) notebooks through the Pluto.jl package. diff --git a/base/Base.jl b/base/Base.jl index 3b53173827610..1ffb747d982ae 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -213,12 +213,11 @@ include("methodshow.jl") include("cartesian.jl") using .Cartesian include("multidimensional.jl") -include("permuteddimsarray.jl") -using .PermutedDimsArrays include("broadcast.jl") using .Broadcast -using .Broadcast: broadcasted, broadcasted_kwsyntax, materialize, materialize! +using .Broadcast: broadcasted, broadcasted_kwsyntax, materialize, materialize!, + broadcast_preserving_zero_d, andand, oror # missing values include("missing.jl") @@ -231,7 +230,9 @@ include("sysinfo.jl") include("libc.jl") using .Libc: getpid, gethostname, time -include("env.jl") +# Logging +include("logging.jl") +using .CoreLogging # Concurrency include("linked_list.jl") @@ -243,9 +244,7 @@ include("task.jl") include("threads_overloads.jl") include("weakkeydict.jl") -# Logging -include("logging.jl") -using .CoreLogging +include("env.jl") # BinaryPlatforms, used by Artifacts include("binaryplatforms.jl") @@ -293,6 +292,9 @@ end include("reducedim.jl") # macros in this file relies on string.jl include("accumulate.jl") +include("permuteddimsarray.jl") +using .PermutedDimsArrays + # basic data structures include("ordering.jl") using .Order @@ -337,6 +339,9 @@ include("meta.jl") include("stacktraces.jl") using .StackTraces +# experimental API's +include("experimental.jl") + # utilities include("deepcopy.jl") include("download.jl") @@ -360,9 +365,6 @@ include("util.jl") include("asyncmap.jl") -# experimental API's -include("experimental.jl") - # deprecated functions include("deprecated.jl") @@ -424,6 +426,9 @@ for match = _methods(+, (Int, Int), -1, get_world_counter()) Core.svec(1, 2) == Core.svec(3, 4) any(t->t[1].line > 1, [(LineNumberNode(2,:none), :(1+1))]) + # Code loading uses this + sortperm(mtime.(readdir(".")), rev=true) + break # only actually need to do this once end diff --git a/base/Makefile b/base/Makefile index e024e546f94d3..56e1cbebf21bf 100644 --- a/base/Makefile +++ b/base/Makefile @@ -6,12 +6,6 @@ include $(JULIAHOME)/Make.inc TAGGED_RELEASE_BANNER := "" -ifneq ($(USEMSVC), 1) -CPP_STDOUT := $(CPP) -P -else -CPP_STDOUT := $(CPP) -E -endif - all: $(addprefix $(BUILDDIR)/,pcre_h.jl errno_h.jl build_h.jl.phony features_h.jl file_constants.jl uv_constants.jl version_git.jl.phony) PCRE_CONST := 0x[0-9a-fA-F]+|[0-9]+|\([\-0-9]+\) @@ -169,53 +163,69 @@ endif # echo "$$P" define symlink_system_library -symlink_$1: $$(build_private_libdir)/$1.$$(SHLIB_EXT) -$$(build_private_libdir)/$1.$$(SHLIB_EXT): - REALPATH=`$$(call spawn,$$(build_depsbindir)/libwhich) -p $$(notdir $$@)` && \ - $$(call resolve_path,REALPATH) && \ - [ -e "$$$$REALPATH" ] && \ - ([ ! -e "$$@" ] || rm "$$@") && \ - echo ln -sf "$$$$REALPATH" "$$@" && \ - ln -sf "$$$$REALPATH" "$$@" -ifneq ($2,) -ifneq ($$(USE_SYSTEM_$2),0) -SYMLINK_SYSTEM_LIBRARIES += symlink_$1 -endif +libname_$2 := $$(notdir $(call versioned_libname,$2,$3)) +libpath_$2 := $$(shell $$(call spawn,$$(build_depsbindir)/libwhich) -p $$(libname_$2) 2>/dev/null) +symlink_$2: $$(build_private_libdir)/$$(libname_$2) +$$(build_private_libdir)/$$(libname_$2): + @if [ -e "$$(libpath_$2)" ]; then \ + REALPATH=$$(libpath_$2); \ + $$(call resolve_path,REALPATH) && \ + [ -e "$$$$REALPATH" ] && \ + ([ ! -e "$$@" ] || rm "$$@") && \ + echo ln -sf "$$$$REALPATH" "$$@" && \ + ln -sf "$$$$REALPATH" "$$@"; \ + else \ + if [ "$4" != "ALLOW_FAILURE" ]; then \ + echo "System library symlink failure: Unable to locate $$(libname_$2) on your system!" >&2; \ + false; \ + fi; \ + fi +ifneq ($$(USE_SYSTEM_$1),0) +SYMLINK_SYSTEM_LIBRARIES += symlink_$2 endif endef # the following excludes: libuv.a, libutf8proc.a -$(eval $(call symlink_system_library,$(LIBMNAME))) ifneq ($(USE_SYSTEM_LIBM),0) -SYMLINK_SYSTEM_LIBRARIES += symlink_$(LIBMNAME) +$(eval $(call symlink_system_library,LIBM,$(LIBMNAME))) else ifneq ($(USE_SYSTEM_OPENLIBM),0) -SYMLINK_SYSTEM_LIBRARIES += symlink_$(LIBMNAME) +$(eval $(call symlink_system_library,OPENLIBM,$(LIBMNAME))) endif -$(eval $(call symlink_system_library,libpcre2-8,PCRE)) -$(eval $(call symlink_system_library,libdSFMT,DSFMT)) -$(eval $(call symlink_system_library,$(LIBBLASNAME),BLAS)) +$(eval $(call symlink_system_library,CSL,libgcc_s,1)) +ifneq (,$(LIBGFORTRAN_VERSION)) +$(eval $(call symlink_system_library,CSL,libgfortran,$(LIBGFORTRAN_VERSION))) +endif +$(eval $(call symlink_system_library,CSL,libquadmath,0)) +$(eval $(call symlink_system_library,CSL,libstdc++,6)) +# We allow libssp, libatomic and libgomp to fail as they are not available on all systems +$(eval $(call symlink_system_library,CSL,libssp,0,ALLOW_FAILURE)) +$(eval $(call symlink_system_library,CSL,libatomic,1,ALLOW_FAILURE)) +$(eval $(call symlink_system_library,CSL,libgomp,1,ALLOW_FAILURE)) +$(eval $(call symlink_system_library,PCRE,libpcre2-8)) +$(eval $(call symlink_system_library,DSFMT,libdSFMT)) +$(eval $(call symlink_system_library,BLAS,$(LIBBLASNAME))) ifneq ($(LIBLAPACKNAME),$(LIBBLASNAME)) -$(eval $(call symlink_system_library,$(LIBLAPACKNAME),LAPACK)) +$(eval $(call symlink_system_library,LAPACK,$(LIBLAPACKNAME))) endif -$(eval $(call symlink_system_library,libgmp,GMP)) -$(eval $(call symlink_system_library,libmpfr,MPFR)) -$(eval $(call symlink_system_library,libmbedtls,MBEDTLS)) -$(eval $(call symlink_system_library,libmbedcrypto,MBEDTLS)) -$(eval $(call symlink_system_library,libmbedx509,MBEDTLS)) -$(eval $(call symlink_system_library,libssh2,LIBSSH2)) -$(eval $(call symlink_system_library,libnghttp2,NGHTTP2)) -$(eval $(call symlink_system_library,libcurl,CURL)) -$(eval $(call symlink_system_library,libgit2,LIBGIT2)) -$(eval $(call symlink_system_library,libamd,SUITESPARSE)) -$(eval $(call symlink_system_library,libcamd,SUITESPARSE)) -$(eval $(call symlink_system_library,libccolamd,SUITESPARSE)) -$(eval $(call symlink_system_library,libcholmod,SUITESPARSE)) -$(eval $(call symlink_system_library,libcolamd,SUITESPARSE)) -$(eval $(call symlink_system_library,libumfpack,SUITESPARSE)) -$(eval $(call symlink_system_library,libspqr,SUITESPARSE)) -$(eval $(call symlink_system_library,libsuitesparseconfig,SUITESPARSE)) +$(eval $(call symlink_system_library,GMP,libgmp)) +$(eval $(call symlink_system_library,MPFR,libmpfr)) +$(eval $(call symlink_system_library,MBEDTLS,libmbedtls)) +$(eval $(call symlink_system_library,MBEDTLS,libmbedcrypto)) +$(eval $(call symlink_system_library,MBEDTLS,libmbedx509)) +$(eval $(call symlink_system_library,LIBSSH2,libssh2)) +$(eval $(call symlink_system_library,NGHTTP2,libnghttp2)) +$(eval $(call symlink_system_library,CURL,libcurl)) +$(eval $(call symlink_system_library,LIBGIT2,libgit2)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libamd)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libcamd)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libccolamd)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libcholmod)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libcolamd)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libumfpack)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libspqr)) +$(eval $(call symlink_system_library,LIBSUITESPARSE,libsuitesparseconfig)) # EXCLUDED LIBRARIES (installed/used, but not vendored for use with dlopen): # libunwind endif # WINNT diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 4bc3c4f70ebb4..88947e582fda5 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -8,6 +8,8 @@ Supertype for `N`-dimensional arrays (or array-like types) with elements of type `T`. [`Array`](@ref) and other types are subtypes of this. See the manual section on the [`AbstractArray` interface](@ref man-interface-array). + +See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), [`ndims`](@ref). """ AbstractArray @@ -24,6 +26,8 @@ dimension to just get the length of that dimension. Note that `size` may not be defined for arrays with non-standard indices, in which case [`axes`](@ref) may be useful. See the manual chapter on [arrays with custom indices](@ref man-custom-indices). +See also: [`length`](@ref), [`ndims`](@ref), [`eachindex`](@ref), [`sizeof`](@ref). + # Examples ```jldoctest julia> A = fill(1, (2,3,4)); @@ -75,6 +79,8 @@ end Return the tuple of valid indices for array `A`. +See also: [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref). + # Examples ```jldoctest @@ -96,7 +102,8 @@ end Return `true` if the indices of `A` start with something other than 1 along any axis. If multiple arguments are passed, equivalent to `has_offset_axes(A) | has_offset_axes(B) | ...`. """ -has_offset_axes(A) = _tuple_any(x->Int(first(x))::Int != 1, axes(A)) +has_offset_axes(A) = _tuple_any(x->Int(first(x))::Int != 1, axes(A)) +has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges) has_offset_axes(A...) = _tuple_any(has_offset_axes, A) has_offset_axes(::Colon) = false @@ -112,6 +119,19 @@ axes1(iter) = oneto(length(iter)) unsafe_indices(A) = axes(A) unsafe_indices(r::AbstractRange) = (oneto(unsafe_length(r)),) # Ranges use checked_sub for size +""" + keys(a::AbstractArray) + +Return an efficient array describing all valid indices for `a` arranged in the shape of `a` itself. + +They keys of 1-dimensional arrays (vectors) are integers, whereas all other N-dimensional +arrays use [`CartesianIndex`](@ref) to describe their locations. Often the special array +types [`LinearIndices`](@ref) and [`CartesianIndices`](@ref) are used to efficiently +represent these arrays of integers and `CartesianIndex`es, respectively. + +Note that the `keys` of an array might not be the most efficient index type; for maximum +performance use [`eachindex`](@ref) instead. +""" keys(a::AbstractArray) = CartesianIndices(axes(a)) keys(a::AbstractVector) = LinearIndices(a) @@ -173,6 +193,8 @@ For dictionary types, this will be a `Pair{KeyType,ValType}`. The definition instead of types. However the form that accepts a type argument should be defined for new types. +See also: [`keytype`](@ref), [`typeof`](@ref). + # Examples ```jldoctest julia> eltype(fill(1f0, (2,2))) @@ -201,6 +223,8 @@ elsize(A::AbstractArray) = elsize(typeof(A)) Return the number of dimensions of `A`. +See also: [`size`](@ref), [`axes`](@ref). + # Examples ```jldoctest julia> A = fill(1, (3,4,5)); @@ -210,7 +234,7 @@ julia> ndims(A) ``` """ ndims(::AbstractArray{T,N}) where {T,N} = N -ndims(::Type{<:AbstractArray{T,N}}) where {T,N} = N +ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N """ length(collection) -> Integer @@ -219,6 +243,8 @@ Return the number of elements in the collection. Use [`lastindex`](@ref) to get the last valid index of an indexable collection. +See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref). + # Examples ```jldoctest julia> length(1:5) @@ -335,6 +361,8 @@ Return the last index of `collection`. If `d` is given, return the last index of The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and `A[lastindex(A, 1), lastindex(A, 2)]`, respectively. +See also: [`axes`](@ref), [`firstindex`](@ref), [`eachindex`](@ref), [`prevind`](@ref). + # Examples ```jldoctest julia> lastindex([1,2,4]) @@ -353,6 +381,11 @@ lastindex(a, d) = (@_inline_meta; last(axes(a, d))) Return the first index of `collection`. If `d` is given, return the first index of `collection` along dimension `d`. +The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and +`A[1, firstindex(A, 2)]`, respectively. + +See also: [`first`](@ref), [`axes`](@ref), [`lastindex`](@ref), [`nextind`](@ref). + # Examples ```jldoctest julia> firstindex([1,2,4]) @@ -373,6 +406,8 @@ first(a::AbstractArray) = a[first(eachindex(a))] Get the first element of an iterable collection. Return the start point of an [`AbstractRange`](@ref) even if it is empty. +See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref). + # Examples ```jldoctest julia> first(2:2:10) @@ -391,9 +426,11 @@ end """ first(itr, n::Integer) -Get the first `n` elements of the iterable collection `itr`, or fewer elements if `v` is not +Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not long enough. +See also: [`startswith`](@ref), [`Iterators.take`](@ref). + !!! compat "Julia 1.6" This method requires at least Julia 1.6. @@ -425,6 +462,8 @@ Get the last element of an ordered collection, if it can be computed in O(1) tim accomplished by calling [`lastindex`](@ref) to get the last index. Return the end point of an [`AbstractRange`](@ref) even if it is empty. +See also [`first`](@ref), [`endswith`](@ref). + # Examples ```jldoctest julia> last(1:2:10) @@ -439,7 +478,7 @@ last(a) = a[end] """ last(itr, n::Integer) -Get the last `n` elements of the iterable collection `itr`, or fewer elements if `v` is not +Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not long enough. !!! compat "Julia 1.6" @@ -471,6 +510,8 @@ end Return a tuple of the memory strides in each dimension. +See also: [`stride`](@ref). + # Examples ```jldoctest julia> A = fill(1, (3,4,5)); @@ -486,6 +527,8 @@ function strides end Return the distance in memory (in number of elements) between adjacent elements in dimension `k`. +See also: [`strides`](@ref). + # Examples ```jldoctest julia> A = fill(1, (3,4,5)); @@ -659,6 +702,8 @@ Return `true` if the given `index` is within the bounds of arrays can extend this method in order to provide a specialized bounds checking implementation. +See also [`checkbounds`](@ref). + # Examples ```jldoctest julia> checkindex(Bool, 1:20, 8) @@ -734,6 +779,7 @@ julia> similar(falses(10), Float64, 2, 4) 2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314 ``` +See also: [`undef`](@ref), [`isassigned`](@ref). """ similar(a::AbstractArray{T}) where {T} = similar(a, T) similar(a::AbstractArray, ::Type{T}) where {T} = similar(a, T, to_shape(axes(a))) @@ -746,6 +792,7 @@ similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T} = similar(a, # define this method to convert supported axes to Ints, with the expectation that an offset array # package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}} similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims)) +similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims)) # similar creates an Array by default similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N} = Array{T,N}(undef, dims) @@ -789,6 +836,8 @@ similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims) Create an empty vector similar to `v`, optionally changing the `eltype`. +See also: [`empty!`](@ref), [`isempty`](@ref), [`isassigned`](@ref). + # Examples ```jldoctest @@ -813,6 +862,7 @@ elements in `dst`. If `dst` and `src` are of the same type, `dst == src` should hold after the call. If `dst` and `src` are multidimensional arrays, they must have equal [`axes`](@ref). + See also [`copyto!`](@ref). !!! compat "Julia 1.1" @@ -920,11 +970,12 @@ end """ copyto!(dest::AbstractArray, src) -> dest - Copy all elements from collection `src` to array `dest`, whose length must be greater than or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten, the other elements are left untouched. +See also [`copy!`](@ref Base.copy!), [`copy`](@ref). + # Examples ```jldoctest julia> x = [1., 0., 3., 0., 5.]; @@ -1170,7 +1221,7 @@ function getindex(A::AbstractArray, I...) _getindex(IndexStyle(A), A, to_indices(A, I)...) end # To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...) -getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...] +@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...] function unsafe_getindex(A::AbstractArray, I...) @_inline_meta @@ -1490,7 +1541,7 @@ AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}} _typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n) _typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T = - _typed_vcat!(_typed_vcat_similar(V, T, mapreduce(length, +, V)), V) + _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V) function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T pos = 1 @@ -1604,7 +1655,7 @@ _cat_size_shape(dims, shape) = shape _cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = () _cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape -_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(b -> 1, Val(length(dims))) +_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims))) @inline _cshp(ndim::Int, dims, shape, ::Tuple{}) = (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...) @inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) = @@ -1778,6 +1829,24 @@ dimensions for every new input array and putting zero blocks elsewhere. For exam `cat(matrices...; dims=(1,2))` builds a block diagonal matrix, i.e. a block matrix with `matrices[1]`, `matrices[2]`, ... as diagonal blocks and matching zero blocks away from the diagonal. + +See also [`hcat`](@ref), [`vcat`](@ref), [`hvcat`](@ref), [`repeat`](@ref). + +# Examples +```jldoctest +julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2) +2×6×1 Array{Float64, 3}: +[:, :, 1] = + 1.0 2.0 3.14159 10.0 10.0 10.0 + 3.0 4.0 3.14159 10.0 10.0 10.0 + +julia> cat(true, trues(2,2), trues(4)', dims=(1,2)) +4×7 Matrix{Bool}: + 1 0 0 0 0 0 0 + 0 1 1 0 0 0 0 + 0 1 1 0 0 0 0 + 0 0 0 1 1 1 1 +``` """ @inline cat(A...; dims) = _cat(dims, A...) _cat(catdims, A::AbstractArray{T}...) where {T} = cat_t(T, A...; dims=catdims) @@ -1810,7 +1879,7 @@ function hvcat(nbc::Integer, as...) mod(n,nbc) != 0 && throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc")) nbr = div(n,nbc) - hvcat(ntuple(i->nbc, nbr), as...) + hvcat(ntuple(Returns(nbc), nbr), as...) end """ @@ -1835,7 +1904,7 @@ julia> hvcat((3,3), a,b,c,d,e,f) 1 2 3 4 5 6 -julia> [a b;c d; e f] +julia> [a b; c d; e f] 3×2 Matrix{Int64}: 1 2 3 4 @@ -1962,6 +2031,357 @@ function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T T[rs...;] end +# nd concatenation + +""" + hvncat(dims::Tuple{Vararg{Int}}, row_first, values...) + hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...) + +Horizontal, vertical, and n-dimensional concatenation of many `values` in one call. + +This function is called +for block matrix syntax. The first argument either specifies the shape of the concatenation, +similar to `hvcat`, as a tuple of tuples, or the dimensions that specify the key number of +elements along each axis, and is used to determine the output dimensions. The `dims` form +is more performant, and is used by default when the concatenation operation has the same +number of elements along each axis (e.g., [a b; c d;;; e f ; g h]). The `shape` form is used +when the number of elements along each axis is unbalanced (e.g., [a b ; c]). Unbalanced +syntax needs additional validation overhead. + +# Examples +```jldoctest +julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6 +(1, 2, 3, 4, 5, 6) + +julia> [a b c;;; d e f] +1×3×2 Array{Int64, 3}: +[:, :, 1] = + 1 2 3 + +[:, :, 2] = + 4 5 6 + +julia> hvncat((2,1,3), false, a,b,c,d,e,f) +2×1×3 Array{Int64, 3}: +[:, :, 1] = + 1 + 2 + +[:, :, 2] = + 3 + 4 + +[:, :, 3] = + 5 + 6 + +julia> [a b;;; c d;;; e f] +1×2×3 Array{Int64, 3}: +[:, :, 1] = + 1 2 + +[:, :, 2] = + 3 4 + +[:, :, 3] = + 5 6 + +julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f) +1×3×2 Array{Int64, 3}: +[:, :, 1] = + 1 2 3 + +[:, :, 2] = + 4 5 6 +``` +""" +hvncat(::Tuple{}, ::Bool) = [] +hvncat(::Tuple{}, ::Bool, xs...) = [] +hvncat(::Tuple{Vararg{Any, 1}}, ::Bool, xs...) = vcat(xs...) # methods assume 2+ dimensions +hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...) +hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...) + +_hvncat(::Union{Tuple, Int}, ::Bool) = [] +_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...) +_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...) +_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...) +_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...) +_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...) + +typed_hvncat(::Type{T}, ::Tuple{}, ::Bool) where T = Vector{T}() +typed_hvncat(::Type{T}, ::Tuple{}, ::Bool, xs...) where T = Vector{T}() +typed_hvncat(T::Type, ::Tuple{Vararg{Any, 1}}, ::Bool, xs...) = typed_vcat(T, xs...) # methods assume 2+ dimensions +typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...) +typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...) + +_typed_hvncat(::Type{T}, ::Tuple{}, ::Bool) where T = Vector{T}() +_typed_hvncat(::Type{T}, ::Tuple{}, ::Bool, xs...) where T = Vector{T}() +_typed_hvncat(::Type{T}, ::Tuple{}, ::Bool, xs::Number...) where T = Vector{T}() +function _typed_hvncat(::Type{T}, dims::Tuple{Vararg{Int, N}}, row_first::Bool, xs::Number...) where {T, N} + A = Array{T, N}(undef, dims...) + lengtha = length(A) # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations + lengthx = length(xs) # Cuts from 3 allocations to 1. + if lengtha != lengthx + throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)")) + end + hvncat_fill!(A, row_first, xs) + return A +end + +function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple) + # putting these in separate functions leads to unnecessary allocations + if row_first + nr, nc = size(A, 1), size(A, 2) + nrc = nr * nc + @inbounds na = prod(size(A)[3:end]) + k = 1 + @inbounds for d ∈ 1:na + dd = nrc * (d - 1) + for i ∈ 1:nr + Ai = dd + i + for j ∈ 1:nc + A[Ai] = xs[k] + k += 1 + Ai += nr + end + end + end + else + @inbounds for k ∈ eachindex(xs) + A[k] = xs[k] + end + end +end + +_typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters +_typed_hvncat(::Type{T}, ::Val) where T = Vector{T}() +_typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N = _typed_hvncat(T, (ntuple(x -> 1, N - 1)..., length(xs)), false, xs...) +function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N} + # optimization for arrays that can be concatenated by copying them linearly into the destination + # conditions: the elements must all have 1- or 0-length dimensions above N + @inbounds for a ∈ as + ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) || + return _typed_hvncat(T, (ntuple(x -> 1, N - 1)..., length(as)), false, as...) + end + + nd = max(N, ndims(as[1])) + + Ndim = 0 + @inbounds for i ∈ 1:lastindex(as) + Ndim += cat_size(as[i], N) + for d ∈ 1:N - 1 + cat_size(as[1], d) == cat_size(as[i], d) || throw(ArgumentError("mismatched size along axis $d in element $i")) + end + end + + @inbounds A = Array{T, nd}(undef, ntuple(d -> cat_size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...) + k = 1 + @inbounds for a ∈ as + for i ∈ eachindex(a) + A[k] = a[i] + k += 1 + end + end + return A +end + +cat_ndims(a) = 0 +cat_ndims(a::AbstractArray) = ndims(a) + +function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N} + # optimization for scalars and 1-length arrays that can be concatenated by copying them linearly + # into the destination + nd = N + Ndim = 0 + @inbounds for a ∈ as + if a isa AbstractArray + cat_size(a, N) == length(a) || + throw(ArgumentError("all dimensions of elements other than $N must be of length 1")) + nd = max(nd, cat_ndims(a)) + end + Ndim += cat_size(a, N) + end + + @inbounds A = Array{T, nd}(undef, ntuple(x -> 1, N - 1)..., Ndim, ntuple(x -> 1, nd - N)...) + + k = 1 + @inbounds for a ∈ as + if a isa AbstractArray + lena = length(a) + copyto!(A, k, a, 1, lena) + k += lena + else + A[k] = a + k += 1 + end + end + return A +end + +function _typed_hvncat(::Type{T}, dims::Tuple{Vararg{Int, N}}, row_first::Bool, as...) where {T, N} + d1 = row_first ? 2 : 1 + d2 = row_first ? 1 : 2 + + # discover dimensions + @inbounds nd = max(N, cat_ndims(as[1])) + outdims = zeros(Int, nd) + + # discover number of rows or columns + @inbounds for i ∈ 1:dims[d1] + outdims[d1] += cat_size(as[i], d1) + end + + currentdims = zeros(Int, nd) + blockcount = 0 + @inbounds for i ∈ eachindex(as) + currentdims[d1] += cat_size(as[i], d1) + if currentdims[d1] == outdims[d1] + currentdims[d1] = 0 + for d ∈ (d2, 3:nd...) + currentdims[d] += cat_size(as[i], d) + if outdims[d] == 0 # unfixed dimension + blockcount += 1 + if blockcount == (d > length(dims) ? 1 : dims[d]) # last expected member of dimension + outdims[d] = currentdims[d] + currentdims[d] = 0 + blockcount = 0 + else + break + end + else # fixed dimension + if currentdims[d] == outdims[d] # end of dimension + currentdims[d] = 0 + elseif currentdims[d] < outdims[d] # dimension in progress + break + else # exceeded dimension + ArgumentError("argument $i has too many elements along axis $d") |> throw + end + end + end + elseif currentdims[d1] > outdims[d1] # exceeded dimension + ArgumentError("argument $i has too many elements along axis $d1") |> throw + end + end + + # calling sum() leads to 3 extra allocations + len = 0 + for a ∈ as + len += cat_length(a) + end + outlen = prod(outdims) + outlen == 0 && ArgumentError("too few elements in arguments, unable to infer dimensions") |> throw + len == outlen || ArgumentError("too many elements in arguments; expected $(outlen), got $(len)") |> throw + + # copy into final array + A = Array{T, nd}(undef, outdims...) + # @assert all(==(0), currentdims) + outdims .= 0 + hvncat_fill!(A, currentdims, outdims, d1, d2, as) + return A +end + +function _typed_hvncat(::Type{T}, shape::Tuple{Vararg{Tuple, N}}, row_first::Bool, as...) where {T, N} + d1 = row_first ? 2 : 1 + d2 = row_first ? 1 : 2 + shape = collect(shape) # saves allocations later + @inbounds shapelength = shape[end][1] + lengthas = length(as) + shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)")) + + # discover dimensions + @inbounds nd = max(N, cat_ndims(as[1])) + outdims = zeros(Int, nd) + currentdims = zeros(Int, nd) + blockcounts = zeros(Int, nd) + shapepos = ones(Int, nd) + + @inbounds for i ∈ eachindex(as) + wasstartblock = false + for d ∈ 1:N + ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d + dsize = cat_size(as[i], ad) + blockcounts[d] += 1 + + if d == 1 || i == 1 || wasstartblock + currentdims[d] += dsize + elseif dsize != cat_size(as[i - 1], ad) + ArgumentError("argument $i has a mismatched number of elements along axis $ad; expected $(cat_size(as[i - 1], ad)), got $dsize") |> throw + end + + wasstartblock = blockcounts[d] == 1 # remember for next dimension + + isendblock = blockcounts[d] == shape[d][shapepos[d]] + if isendblock + if outdims[d] == 0 + outdims[d] = currentdims[d] + elseif outdims[d] != currentdims[d] + ArgumentError("argument $i has a mismatched number of elements along axis $ad; expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize") |> throw + end + currentdims[d] = 0 + blockcounts[d] = 0 + shapepos[d] += 1 + end + end + end + + if row_first + @inbounds outdims[1], outdims[2] = outdims[2], outdims[1] + end + + # @assert all(==(0), currentdims) + # @assert all(==(0), blockcounts) + + # copy into final array + A = Array{T, nd}(undef, outdims...) + hvncat_fill!(A, currentdims, blockcounts, d1, d2, as) + return A +end + +@inline function hvncat_fill!(A::Array{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple{Vararg}) where {T, N} + outdims = size(A) + offsets = scratch1 + inneroffsets = scratch2 + @inbounds for a ∈ as + if isa(a, AbstractArray) + for ai ∈ a + Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N) + A[Ai] = ai + + for j ∈ 1:N + inneroffsets[j] += 1 + inneroffsets[j] < cat_size(a, j) && break + inneroffsets[j] = 0 + end + end + else + Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N) + A[Ai] = a + end + + for j ∈ (d1, d2, 3:N...) + offsets[j] += cat_size(a, j) + offsets[j] < outdims[j] && break + offsets[j] = 0 + end + end +end + +@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int}, + outdims::Tuple{Vararg{Int}}, nd::Int) + Ai = inneroffsets[1] + offsets[1] + 1 + for j ∈ 2:nd + increment = inneroffsets[j] + offsets[j] + for k ∈ 1:j-1 + increment *= outdims[k] + end + Ai += increment + end + Ai +end + +cat_length(a::AbstractArray) = length(a) +cat_length(::Any) = 1 + ## Reductions and accumulates ## function isequal(A::AbstractArray, B::AbstractArray) @@ -2128,18 +2548,28 @@ end foreach(f, c...) -> Nothing Call function `f` on each element of iterable `c`. -For multiple iterable arguments, `f` is called elementwise. -`foreach` should be used instead of `map` when the results of `f` are not +For multiple iterable arguments, `f` is called elementwise, and iteration stops when +any iterator is finished. + +`foreach` should be used instead of [`map`](@ref) when the results of `f` are not needed, for example in `foreach(println, array)`. # Examples ```jldoctest -julia> a = 1:3:7; +julia> tri = 1:3:7; res = Int[]; -julia> foreach(x -> println(x^2), a) -1 -16 -49 +julia> foreach(x -> push!(res, x^2), tri) + +julia> res +3-element Vector{$(Int)}: + 1 + 16 + 49 + +julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z') +1 with a +4 with b +7 with c ``` """ foreach(f) = (f(); nothing) @@ -2160,6 +2590,8 @@ colons go in this expression. The results are concatenated along the remaining d For example, if `dims` is `[1,2]` and `A` is 4-dimensional, `f` is called on `A[:,:,i,j]` for all `i` and `j`. +See also [`eachcol`](@ref), [`eachslice`](@ref). + # Examples ```jldoctest julia> a = reshape(Vector(1:16),(2,2,2,2)) @@ -2238,9 +2670,9 @@ function mapslices(f, A::AbstractArray; dims) end nextra = max(0, length(dims)-ndims(r1)) if eltype(Rsize) == Int - Rsize[dims] = [size(r1)..., ntuple(d->1, nextra)...] + Rsize[dims] = [size(r1)..., ntuple(Returns(1), nextra)...] else - Rsize[dims] = [axes(r1)..., ntuple(d->OneTo(1), nextra)...] + Rsize[dims] = [axes(r1)..., ntuple(Returns(OneTo(1)), nextra)...] end R = similar(r1, tuple(Rsize...,)) @@ -2306,9 +2738,9 @@ mapany(f, itr) = Any[f(x) for x in itr] map(f, c...) -> collection Transform collection `c` by applying `f` to each element. For multiple collection arguments, -apply `f` elementwise. +apply `f` elementwise, and stop when when any of them is exhausted. -See also: [`mapslices`](@ref) +See also [`map!`](@ref), [`foreach`](@ref), [`mapreduce`](@ref), [`mapslices`](@ref), [`zip`](@ref), [`Iterators.map`](@ref). # Examples ```jldoctest @@ -2318,7 +2750,7 @@ julia> map(x -> x * 2, [1, 2, 3]) 4 6 -julia> map(+, [1, 2, 3], [10, 20, 30]) +julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000]) 3-element Vector{Int64}: 11 22 @@ -2363,7 +2795,9 @@ end map!(function, destination, collection...) Like [`map`](@ref), but stores the result in `destination` rather than a new -collection. `destination` must be at least as large as the first collection. +collection. `destination` must be at least as large as the smallest collection. + +See also: [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref). # Examples ```jldoctest @@ -2376,6 +2810,14 @@ julia> a 2.0 4.0 6.0 + +julia> map!(+, zeros(Int, 5), 100:999, 1:3) +5-element Vector{$(Int)}: + 101 + 103 + 105 + 0 + 0 ``` """ function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F} @@ -2476,3 +2918,46 @@ function rest(a::AbstractArray{T}, state...) where {T} sizehint!(v, length(a)) return foldl(push!, Iterators.rest(a, state...), init=v) end + + +## keepat! ## + +""" + keepat!(a::AbstractVector, inds) + +Remove the items at all the indices which are not given by `inds`, +and return the modified `a`. +Items which are kept are shifted to fill the resulting gaps. + +`inds` must be an iterator of sorted and unique integer indices. +See also [`deleteat!`](@ref). + +!!! compat "Julia 1.7" + This function is available as of Julia 1.7. + +# Examples +```jldoctest +julia> keepat!([6, 5, 4, 3, 2, 1], 1:2:5) +3-element Vector{Int64}: + 6 + 4 + 2 +``` +""" +function keepat!(a::AbstractVector, inds) + local prev + i = firstindex(a) + for k in inds + if @isdefined(prev) + prev < k || throw(ArgumentError("indices must be unique and sorted")) + end + ak = a[k] # must happen even when i==k for bounds checking + if i != k + @inbounds a[i] = ak # k > i, so a[i] is inbounds + end + prev = k + i = nextind(a, i) + end + deleteat!(a, i:lastindex(a)) + return a +end diff --git a/base/abstractarraymath.jl b/base/abstractarraymath.jl index 953c190ab12ef..4dd24214a63fc 100644 --- a/base/abstractarraymath.jl +++ b/base/abstractarraymath.jl @@ -36,7 +36,7 @@ julia> vec(1:3) 1:3 ``` -See also [`reshape`](@ref). +See also [`reshape`](@ref), [`dropdims`](@ref). """ vec(a::AbstractArray) = reshape(a,length(a)) vec(a::AbstractVector) = a @@ -48,9 +48,15 @@ _sub(t::Tuple, s::Tuple) = _sub(tail(t), tail(s)) """ dropdims(A; dims) -Remove the dimensions specified by `dims` from array `A`. -Elements of `dims` must be unique and within the range `1:ndims(A)`. -`size(A,i)` must equal 1 for all `i` in `dims`. +Return an array with the same data as `A`, but with the dimensions specified by +`dims` removed. `size(A,d)` must equal 1 for every `d` in `dims`, +and repeated dimensions or numbers outside `1:ndims(A)` are forbidden. + +The result shares the same underlying data as `A`, such that the +result is mutable if and only if `A` is mutable, and setting elements of one +alters the values of the other. + +See also: [`reshape`](@ref), [`vec`](@ref). # Examples ```jldoctest @@ -60,11 +66,17 @@ julia> a = reshape(Vector(1:4),(2,2,1,1)) 1 3 2 4 -julia> dropdims(a; dims=3) +julia> b = dropdims(a; dims=3) 2×2×1 Array{Int64, 3}: [:, :, 1] = 1 3 2 4 + +julia> b[1,1,1] = 5; a +2×2×1×1 Array{Int64, 4}: +[:, :, 1, 1] = + 5 3 + 2 4 ``` """ dropdims(A; dims) = _dropdims(A, dims) @@ -76,13 +88,8 @@ function _dropdims(A::AbstractArray, dims::Dims) dims[j] == dims[i] && throw(ArgumentError("dropped dims must be unique")) end end - d = () - for i = 1:ndims(A) - if !in(i, dims) - d = tuple(d..., axes(A, i)) - end - end - reshape(A, d::typeof(_sub(axes(A), dims))) + ax = _foldoneto((ds, d) -> d in dims ? ds : (ds..., axes(A,d)), (), Val(ndims(A))) + reshape(A, ax::typeof(_sub(axes(A), dims))) end _dropdims(A::AbstractArray, dim::Integer) = _dropdims(A, (Int(dim),)) @@ -106,6 +113,8 @@ Return a view of all the data of `A` where the index for dimension `d` equals `i Equivalent to `view(A,:,:,...,i,:,:,...)` where `i` is in position `d`. +See also: [`eachslice`](@ref). + # Examples ```jldoctest julia> A = [1 2 3 4; 5 6 7 8] @@ -117,13 +126,18 @@ julia> selectdim(A, 2, 3) 2-element view(::Matrix{Int64}, :, 3) with eltype Int64: 3 7 + +julia> selectdim(A, 2, 3:4) +2×2 view(::Matrix{Int64}, :, 3:4) with eltype Int64: + 3 4 + 7 8 ``` """ @inline selectdim(A::AbstractArray, d::Integer, i) = _selectdim(A, d, i, _setindex(i, d, map(Slice, axes(A))...)) @noinline function _selectdim(A, d, i, idxs) d >= 1 || throw(ArgumentError("dimension must be ≥ 1, got $d")) nd = ndims(A) - d > nd && (i == 1 || throw(BoundsError(A, (ntuple(k->Colon(),d-1)..., i)))) + d > nd && (i == 1 || throw(BoundsError(A, (ntuple(Returns(Colon()),d-1)..., i)))) return view(A, idxs...) end @@ -138,6 +152,8 @@ Circularly shift, i.e. rotate, the data in an array. The second argument is a tu vector giving the amount to shift in each dimension, or an integer to shift only in the first dimension. +See also: [`circshift!`](@ref), [`circcopy!`](@ref), [`bitrotate`](@ref), [`<<`](@ref). + # Examples ```jldoctest julia> b = reshape(Vector(1:16), (4,4)) @@ -185,8 +201,6 @@ julia> circshift(a, -1) 1 1 ``` - -See also [`circshift!`](@ref). """ function circshift(a::AbstractArray, shiftamt) circshift!(similar(a), a, map(Integer, (shiftamt...,))) @@ -199,6 +213,8 @@ end Construct an array by repeating array `A` a given number of times in each dimension, specified by `counts`. +See also: [`fill`](@ref), [`Iterators.repeated`](@ref), [`Iterators.cycle`](@ref). + # Examples ```jldoctest julia> repeat([1, 2, 3], 2) @@ -225,7 +241,7 @@ function repeat(A::AbstractArray, counts...) end """ - repeat(A::AbstractArray; inner=ntuple(x->1, ndims(A)), outer=ntuple(x->1, ndims(A))) + repeat(A::AbstractArray; inner=ntuple(Returns(1), ndims(A)), outer=ntuple(Returns(1), ndims(A))) Construct an array by repeating the entries of `A`. The i-th element of `inner` specifies the number of times that the individual entries of the i-th dimension of `A` should be @@ -392,7 +408,7 @@ end#module Create a generator that iterates over the first dimension of vector or matrix `A`, returning the rows as `AbstractVector` views. -See also [`eachcol`](@ref) and [`eachslice`](@ref). +See also [`eachcol`](@ref), [`eachslice`](@ref), [`mapslices`](@ref). !!! compat "Julia 1.1" This function requires at least Julia 1.1. @@ -460,7 +476,7 @@ the data from the other dimensions in `A`. Only a single dimension in `dims` is currently supported. Equivalent to `(view(A,:,:,...,i,:,: ...)) for i in axes(A, dims))`, where `i` is in position `dims`. -See also [`eachrow`](@ref), [`eachcol`](@ref), and [`selectdim`](@ref). +See also [`eachrow`](@ref), [`eachcol`](@ref), [`mapslices`](@ref), and [`selectdim`](@ref). !!! compat "Julia 1.1" This function requires at least Julia 1.1. @@ -491,7 +507,7 @@ julia> collect(eachslice(M, dims=2)) length(dims) == 1 || throw(ArgumentError("only single dimensions are supported")) dim = first(dims) dim <= ndims(A) || throw(DimensionMismatch("A doesn't have $dim dimensions")) - inds_before = ntuple(d->(:), dim-1) - inds_after = ntuple(d->(:), ndims(A)-dim) + inds_before = ntuple(Returns(:), dim-1) + inds_after = ntuple(Returns(:), ndims(A)-dim) return (view(A, inds_before..., i, inds_after...) for i in axes(A, dim)) end diff --git a/base/abstractdict.jl b/base/abstractdict.jl index cfd964759bcce..e4565c98fbcbe 100644 --- a/base/abstractdict.jl +++ b/base/abstractdict.jl @@ -249,7 +249,7 @@ merge!(combine::Callable, args...) = mergewith!(combine, args...) """ keytype(type) -Get the key type of an dictionary type. Behaves similarly to [`eltype`](@ref). +Get the key type of a dictionary type. Behaves similarly to [`eltype`](@ref). # Examples ```jldoctest @@ -263,7 +263,7 @@ keytype(a::AbstractDict) = keytype(typeof(a)) """ valtype(type) -Get the value type of an dictionary type. Behaves similarly to [`eltype`](@ref). +Get the value type of a dictionary type. Behaves similarly to [`eltype`](@ref). # Examples ```jldoctest diff --git a/base/abstractset.jl b/base/abstractset.jl index 179b9f7be5d4b..442bbcb4bff48 100644 --- a/base/abstractset.jl +++ b/base/abstractset.jl @@ -13,6 +13,8 @@ copy!(dst::AbstractSet, src::AbstractSet) = union!(empty!(dst), src) Construct the union of sets. Maintain order with arrays. +See also: [`intersect`](@ref), [`isdisjoint`](@ref), [`vcat`](@ref), [`Iterators.flatten`](@ref). + # Examples ```jldoctest julia> union([1, 2], [3, 4]) @@ -81,7 +83,11 @@ end max_values(::Type) = typemax(Int) max_values(T::Union{map(X -> Type{X}, BitIntegerSmall_types)...}) = 1 << (8*sizeof(T)) # saturated addition to prevent overflow with typemax(Int) -max_values(T::Union) = max(max_values(T.a), max_values(T.b), max_values(T.a) + max_values(T.b)) +function max_values(T::Union) + a = max_values(T.a)::Int + b = max_values(T.b)::Int + return max(a, b, a + b) +end max_values(::Type{Bool}) = 2 max_values(::Type{Nothing}) = 1 @@ -101,6 +107,8 @@ end Construct the intersection of sets. Maintain order with arrays. +See also: [`setdiff`](@ref), [`isdisjoint`](@ref), [`issubset`](@ref Base.issubset), [`issetequal`](@ref). + # Examples ```jldoctest julia> intersect([1, 2, 3], [3, 4, 5]) @@ -145,6 +153,8 @@ intersect!(s::AbstractSet, itr) = Construct the set of elements in `s` but not in any of the iterables in `itrs`. Maintain order with arrays. +See also [`setdiff!`](@ref), [`union`](@ref) and [`intersect`](@ref). + # Examples ```jldoctest julia> setdiff([1,2,3], [3,4,5]) @@ -194,6 +204,8 @@ Construct the symmetric difference of elements in the passed in sets. When `s` is not an `AbstractSet`, the order is maintained. Note that in this case the multiplicity of elements matters. +See also [`symdiff!`](@ref), [`setdiff`](@ref), [`union`](@ref) and [`intersect`](@ref). + # Examples ```jldoctest julia> symdiff([1,2,3], [3,4,5], [4,5,6]) @@ -246,6 +258,8 @@ function ⊇ end Determine whether every element of `a` is also in `b`, using [`in`](@ref). +See also [`⊊`](@ref), [`⊈`](@ref), [`∩`](@ref intersect), [`∪`](@ref union), [`contains`](@ref). + # Examples ```jldoctest julia> issubset([1, 2], [1, 2, 3]) @@ -306,6 +320,8 @@ function ⊋ end Determines if `a` is a subset of, but not equal to, `b`. +See also [`issubset`](@ref) (`⊆`), [`⊈`](@ref). + # Examples ```jldoctest julia> (1, 2) ⊊ (1, 2, 3) @@ -329,6 +345,8 @@ function ⊉ end Negation of `⊆` and `⊇`, i.e. checks that `a` is not a subset of `b`. +See also [`issubset`](@ref) (`⊆`), [`⊊`](@ref). + # Examples ```jldoctest julia> (1, 2) ⊈ (2, 3) @@ -351,6 +369,8 @@ false Determine whether `a` and `b` have the same elements. Equivalent to `a ⊆ b && b ⊆ a` but more efficient when possible. +See also: [`isdisjoint`](@ref), [`union`](@ref). + # Examples ```jldoctest julia> issetequal([1, 2], [1, 2, 3]) @@ -384,6 +404,8 @@ end Return whether the collections `v1` and `v2` are disjoint, i.e. whether their intersection is empty. +See also: [`issetequal`](@ref), [`intersect`](@ref). + !!! compat "Julia 1.5" This function requires at least Julia 1.5. """ diff --git a/base/accumulate.jl b/base/accumulate.jl index f90f85b315d7c..6f0b6e7d05ba3 100644 --- a/base/accumulate.jl +++ b/base/accumulate.jl @@ -204,6 +204,8 @@ Cumulative product of an iterator. See also [`cumprod!`](@ref) to use a preallocated output array, both for performance and to control the precision of the output (e.g. to avoid overflow). +See also [`cumprod!`](@ref), [`accumulate`](@ref), [`cumsum`](@ref). + !!! compat "Julia 1.5" `cumprod` on a non-array iterator requires at least Julia 1.5. @@ -291,10 +293,10 @@ function accumulate(op, A; dims::Union{Nothing,Integer}=nothing, kw...) # This branch takes care of the cases not handled by `_accumulate!`. return collect(Iterators.accumulate(op, A; kw...)) end - nt = kw.data - if nt isa NamedTuple{()} + nt = values(kw) + if isempty(kw) out = similar(A, promote_op(op, eltype(A), eltype(A))) - elseif nt isa NamedTuple{(:init,)} + elseif keys(nt) === (:init,) out = similar(A, promote_op(op, typeof(nt.init), eltype(A))) else throw(ArgumentError("acccumulate does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) @@ -354,10 +356,10 @@ julia> B ``` """ function accumulate!(op, B, A; dims::Union{Integer, Nothing} = nothing, kw...) - nt = kw.data - if nt isa NamedTuple{()} + nt = values(kw) + if isempty(kw) _accumulate!(op, B, A, dims, nothing) - elseif nt isa NamedTuple{(:init,)} + elseif keys(kw) === (:init,) _accumulate!(op, B, A, dims, Some(nt.init)) else throw(ArgumentError("acccumulate! does not support the keyword arguments $(setdiff(keys(nt), (:init,)))")) diff --git a/base/array.jl b/base/array.jl index e680d035897be..33c1b7f268562 100644 --- a/base/array.jl +++ b/base/array.jl @@ -9,7 +9,7 @@ The objects called do not have matching dimensionality. Optional argument `msg` descriptive error string. """ struct DimensionMismatch <: Exception - msg::AbstractString + msg::String end DimensionMismatch() = DimensionMismatch("") @@ -54,6 +54,8 @@ Array One-dimensional dense array with elements of type `T`, often used to represent a mathematical vector. Alias for [`Array{T,1}`](@ref). + +See also [`empty`](@ref), [`similar`](@ref) and [`zero`](@ref) for creating vectors. """ const Vector{T} = Array{T,1} @@ -62,12 +64,28 @@ const Vector{T} = Array{T,1} Two-dimensional dense array with elements of type `T`, often used to represent a mathematical matrix. Alias for [`Array{T,2}`](@ref). + +See also [`fill`](@ref), [`zeros`](@ref), [`undef`](@ref) and [`similar`](@ref) +for creating matrices. """ const Matrix{T} = Array{T,2} + """ VecOrMat{T} -Union type of [`Vector{T}`](@ref) and [`Matrix{T}`](@ref). +Union type of [`Vector{T}`](@ref) and [`Matrix{T}`](@ref) which allows functions to accept either a Matrix or a Vector. + +# Examples +```jldoctest +julia> Vector{Float64} <: VecOrMat{Float64} +true + +julia> Matrix{Float64} <: VecOrMat{Float64} +true + +julia> Array{Float64, 3} <: VecOrMat{Float64} +false +``` """ const VecOrMat{T} = Union{Vector{T}, Matrix{T}} @@ -343,6 +361,8 @@ end Create a shallow copy of `x`: the outer structure is copied, but not all internal values. For example, copying an array produces a new array with identically-same elements as the original. + +See also [`copy!`](@ref Base.copy!), [`copyto!`](@ref). """ copy @@ -420,6 +440,8 @@ array of floats, with each element initialized to `1.0`. `dims` may be specified as either a tuple or a sequence of arguments. For example, the common idiom `fill(x)` creates a zero-dimensional array containing the single value `x`. +See also: [`fill!`](@ref), [`zeros`](@ref), [`ones`](@ref), [`similar`](@ref). + # Examples ```jldoctest julia> fill(1.0, (2,3)) @@ -456,7 +478,7 @@ fill(v, dims::Tuple{}) = (a=Array{typeof(v),0}(undef, dims); fill!(a, v); a) zeros([T=Float64,] dims...) Create an `Array`, with element type `T`, of all zeros with size specified by `dims`. -See also [`fill`](@ref), [`ones`](@ref). +See also [`fill`](@ref), [`ones`](@ref), [`zero`](@ref). # Examples ```jldoctest @@ -477,7 +499,7 @@ function zeros end ones([T=Float64,] dims...) Create an `Array`, with element type `T`, of all ones with size specified by `dims`. -See also: [`fill`](@ref), [`zeros`](@ref). +See also [`fill`](@ref), [`zeros`](@ref). # Examples ```jldoctest @@ -587,6 +609,8 @@ Return an `Array` of all items in a collection or iterator. For dictionaries, re [`HasShape`](@ref IteratorSize) trait, the result will have the same shape and number of dimensions as the argument. +Used by comprehensions to turn a generator into an `Array`. + # Examples ```jldoctest julia> collect(1:2:13) @@ -598,6 +622,13 @@ julia> collect(1:2:13) 9 11 13 + +julia> [x^2 for x in 1:8 if isodd(x)] +4-element Vector{Int64}: + 1 + 9 + 25 + 49 ``` """ collect(itr) = _collect(1:1 #= Array =#, itr, IteratorEltype(itr), IteratorSize(itr)) @@ -803,16 +834,20 @@ function getindex end @eval getindex(A::Array, i1::Int, i2::Int, I::Int...) = (@_inline_meta; arrayref($(Expr(:boundscheck)), A, i1, i2, I...)) # Faster contiguous indexing using copyto! for UnitRange and Colon -function getindex(A::Array, I::UnitRange{Int}) +function getindex(A::Array, I::AbstractUnitRange{<:Integer}) @_inline_meta @boundscheck checkbounds(A, I) lI = length(I) - X = similar(A, lI) + X = similar(A, axes(I)) if lI > 0 - unsafe_copyto!(X, 1, A, first(I), lI) + copyto!(X, firstindex(X), A, first(I), lI) end return X end + +# getindex for carrying out logical indexing for AbstractUnitRange{Bool} as Bool <: Integer +getindex(a::Array, r::AbstractUnitRange{Bool}) = getindex(a, to_index(r)) + function getindex(A::Array, c::Colon) lI = length(A) X = similar(A, lI) @@ -921,6 +956,8 @@ collection to it. The result of the preceding example is equivalent to `append!( 5, 6])`. For `AbstractSet` objects, [`union!`](@ref) can be used instead. See [`sizehint!`](@ref) for notes about the performance model. + +See also [`pushfirst!`](@ref). """ function push! end @@ -928,7 +965,7 @@ function push!(a::Array{T,1}, item) where T # convert first so we don't grow the array if the assignment won't work itemT = convert(T, item) _growend!(a, 1) - a[end] = itemT + @inbounds a[end] = itemT return a end @@ -970,6 +1007,9 @@ themselves in another collection. The result of the preceding example is equival `push!([1, 2, 3], 4, 5, 6)`. See [`sizehint!`](@ref) for notes about the performance model. + +See also [`vcat`](@ref) for vectors, [`union!`](@ref) for sets, +and [`prepend!`](@ref) and [`pushfirst!`](@ref) for the opposite order. """ function append!(a::Vector, items::AbstractVector) itemindices = eachindex(items) @@ -1144,6 +1184,8 @@ Remove an item in `collection` and return it. If `collection` is an ordered container, the last item is returned; for unordered containers, an arbitrary element is returned. +See also: [`popfirst!`](@ref), [`popat!`](@ref), [`delete!`](@ref), [`deleteat!`](@ref), [`splice!`](@ref), and [`push!`](@ref). + # Examples ```jldoctest julia> A=[1, 2, 3] @@ -1192,7 +1234,8 @@ Remove the item at the given `i` and return it. Subsequent items are shifted to fill the resulting gap. When `i` is not a valid index for `a`, return `default`, or throw an error if `default` is not specified. -See also [`deleteat!`](@ref) and [`splice!`](@ref). + +See also: [`pop!`](@ref), [`popfirst!`](@ref), [`deleteat!`](@ref), [`splice!`](@ref). !!! compat "Julia 1.5" This function is available as of Julia 1.5. @@ -1265,6 +1308,8 @@ Remove the first `item` from `collection`. This function is called `shift` in many other programming languages. +See also: [`pop!`](@ref), [`popat!`](@ref), [`delete!`](@ref). + # Examples ```jldoctest julia> A = [1, 2, 3, 4, 5, 6] @@ -1303,6 +1348,8 @@ end Insert an `item` into `a` at the given `index`. `index` is the index of `item` in the resulting `a`. +See also: [`push!`](@ref), [`replace`](@ref), [`popat!`](@ref), [`splice!`](@ref). + # Examples ```jldoctest julia> insert!([6, 5, 4, 2, 1], 4, 3) @@ -1330,6 +1377,8 @@ end Remove the item at the given `i` and return the modified `a`. Subsequent items are shifted to fill the resulting gap. +See also: [`delete!`](@ref), [`popat!`](@ref), [`splice!`](@ref). + # Examples ```jldoctest julia> deleteat!([6, 5, 4, 3, 2, 1], 2) @@ -1441,6 +1490,8 @@ Subsequent items are shifted left to fill the resulting gap. If specified, replacement values from an ordered collection will be spliced in place of the removed item. +See also: [`replace`](@ref), [`delete!`](@ref), [`deleteat!`](@ref), [`pop!`](@ref), [`popat!`](@ref). + # Examples ```jldoctest julia> A = [6, 5, 4, 3, 2, 1]; splice!(A, 5) @@ -1590,7 +1641,7 @@ end reverse(v [, start=1 [, stop=length(v) ]] ) Return a copy of `v` reversed from start to stop. See also [`Iterators.reverse`](@ref) -for reverse-order iteration without making a copy. +for reverse-order iteration without making a copy, and in-place [`reverse!`](@ref). # Examples ```jldoctest @@ -1734,7 +1785,7 @@ function vcat(arrays::Vector{T}...) where T return arr end -_cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x))) +_cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(Returns(1), n-1)..., length(x))) ## find ## @@ -1793,6 +1844,8 @@ To search for other kinds of values, pass a predicate as the first argument. Indices or keys are of the same type as those returned by [`keys(A)`](@ref) and [`pairs(A)`](@ref). +See also: [`findall`](@ref), [`findnext`](@ref), [`findlast`](@ref), [`searchsortedfirst`](@ref). + # Examples ```jldoctest julia> A = [false, false, true, false] @@ -1934,6 +1987,8 @@ or `nothing` if not found. Indices are of the same type as those returned by [`keys(A)`](@ref) and [`pairs(A)`](@ref). +See also: [`findnext`](@ref), [`findfirst`](@ref), [`findall`](@ref). + # Examples ```jldoctest julia> A = [false, false, true, true] @@ -1979,6 +2034,8 @@ Return `nothing` if there is no `true` value in `A`. Indices or keys are of the same type as those returned by [`keys(A)`](@ref) and [`pairs(A)`](@ref). +See also: [`findfirst`](@ref), [`findprev`](@ref), [`findall`](@ref). + # Examples ```jldoctest julia> A = [true, false, true, false] @@ -2171,6 +2228,8 @@ To search for other kinds of values, pass a predicate as the first argument. Indices or keys are of the same type as those returned by [`keys(A)`](@ref) and [`pairs(A)`](@ref). +See also: [`findfirst`](@ref), [`searchsorted`](@ref). + # Examples ```jldoctest julia> A = [true, false, false, true] @@ -2228,6 +2287,8 @@ Return an array containing the first index in `b` for each value in `a` that is a member of `b`. The output array contains `nothing` wherever `a` is not a member of `b`. +See also: [`sortperm`](@ref), [`findfirst`](@ref). + # Examples ```jldoctest julia> a = ['a', 'b', 'c', 'b', 'd', 'a']; @@ -2361,6 +2422,8 @@ The function `f` is passed one argument. !!! compat "Julia 1.4" Support for `a` as a tuple requires at least Julia 1.4. +See also: [`filter!`](@ref), [`Iterators.filter`](@ref). + # Examples ```jldoctest julia> a = 1:10 diff --git a/base/arrayshow.jl b/base/arrayshow.jl index f942f87787484..1e9f3e59729e6 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -271,17 +271,21 @@ end # typeinfo agnostic # n-dimensional arrays -show_nd(io::IO, a::AbstractArray, print_matrix::Function, label_slices::Bool) = - _show_nd(io, inferencebarrier(a), print_matrix, label_slices, map(unitrange, axes(a))) +show_nd(io::IO, a::AbstractArray, print_matrix::Function, show_full::Bool) = + _show_nd(io, inferencebarrier(a), print_matrix, show_full, map(unitrange, axes(a))) -function _show_nd(io::IO, @nospecialize(a::AbstractArray), print_matrix::Function, label_slices::Bool, axs::Tuple{Vararg{AbstractUnitRange}}) +function _show_nd(io::IO, @nospecialize(a::AbstractArray), print_matrix::Function, show_full::Bool, axs::Tuple{Vararg{AbstractUnitRange}}) limit::Bool = get(io, :limit, false) if isempty(a) return end tailinds = tail(tail(axs)) nd = ndims(a)-2 - for I in CartesianIndices(tailinds) + show_full || print(io, "[") + Is = CartesianIndices(tailinds) + lastidxs = first(Is).I + reached_last_d = false + for I in Is idxs = I.I if limit for i = 1:nd @@ -296,7 +300,9 @@ function _show_nd(io::IO, @nospecialize(a::AbstractArray), print_matrix::Functio @goto skip end end - print(io, "...\n\n") + print(io, ";"^(i+2)) + print(io, " \u2026 ") + show_full && print(io, "\n\n") @goto skip end if ind[firstindex(ind)+2] < ii <= ind[end-3] @@ -305,13 +311,29 @@ function _show_nd(io::IO, @nospecialize(a::AbstractArray), print_matrix::Functio end end end - if label_slices + if show_full _show_nd_label(io, a, idxs) end slice = view(a, axs[1], axs[2], idxs...) - print_matrix(io, slice) - print(io, idxs == map(last,tailinds) ? "" : "\n\n") + if show_full + print_matrix(io, slice) + print(io, idxs == map(last,tailinds) ? "" : "\n\n") + else + idxdiff = lastidxs .- idxs .< 0 + if any(idxdiff) + lastchangeindex = 2 + findlast(idxdiff) + print(io, ";"^lastchangeindex) + lastchangeindex == ndims(a) && (reached_last_d = true) + print(io, " ") + end + print_matrix(io, slice) + end @label skip + lastidxs = idxs + end + if !show_full + reached_last_d || print(io, ";"^(nd+2)) + print(io, "]") end end @@ -386,9 +408,9 @@ end preceded by `prefix`, supposed to encode the type of the elements. """ _show_nonempty(io::IO, X::AbstractMatrix, prefix::String) = - _show_nonempty(io, inferencebarrier(X), prefix, axes(X)) + _show_nonempty(io, inferencebarrier(X), prefix, false, axes(X)) -function _show_nonempty(io::IO, @nospecialize(X::AbstractMatrix), prefix::String, axs::Tuple{AbstractUnitRange,AbstractUnitRange}) +function _show_nonempty(io::IO, @nospecialize(X::AbstractMatrix), prefix::String, drop_brackets::Bool, axs::Tuple{AbstractUnitRange,AbstractUnitRange}) @assert !isempty(X) limit = get(io, :limit, false)::Bool indr, indc = axs @@ -407,7 +429,7 @@ function _show_nonempty(io::IO, @nospecialize(X::AbstractMatrix), prefix::String cdots = true end end - print(io, prefix, "[") + drop_brackets || print(io, prefix, "[") for rr in (rr1, rr2) for i in rr for cr in (cr1, cr2) @@ -429,12 +451,16 @@ function _show_nonempty(io::IO, @nospecialize(X::AbstractMatrix), prefix::String end last(rr) != last(indr) && rdots && print(io, "\u2026 ; ") end - print(io, "]") + if !drop_brackets + nc > 1 || print(io, ";;") + print(io, "]") + end + return nothing end _show_nonempty(io::IO, X::AbstractArray, prefix::String) = - show_nd(io, X, (io, slice) -> _show_nonempty(io, slice, prefix), false) + show_nd(io, X, (io, slice) -> _show_nonempty(io, inferencebarrier(slice), prefix, true, axes(slice)), false) # a specific call path is used to show vectors (show_vector) _show_nonempty(::IO, ::AbstractVector, ::String) = diff --git a/base/baseext.jl b/base/baseext.jl index 75ef96caa94be..8ebd599312453 100644 --- a/base/baseext.jl +++ b/base/baseext.jl @@ -2,6 +2,17 @@ # extensions to Core types to add features in Base +""" + VecElement{T} + +A wrapper type that holds a single value of type `T`. When used in the context of an +`NTuple{N, VecElement{T}} where {T, N}` object, it provides a hint to the runtime +system to align that struct to be more amenable to vectorization optimization +opportunities. In `ccall`, such an NTuple in the type signature will also use the +vector register ABI, rather than the usual struct ABI. +""" +VecElement + # hook up VecElement constructor to Base.convert VecElement{T}(arg) where {T} = VecElement{T}(convert(T, arg)) convert(::Type{T}, arg::T) where {T<:VecElement} = arg diff --git a/base/binaryplatforms.jl b/base/binaryplatforms.jl index 8c9c6768090e0..aff1de4a80993 100644 --- a/base/binaryplatforms.jl +++ b/base/binaryplatforms.jl @@ -141,7 +141,7 @@ function Base.setindex!(p::AbstractPlatform, v::String, k::String) return p end -# Hash definitino to ensure that it's stable +# Hash definition to ensure that it's stable function Base.hash(p::Platform, h::UInt) h += 0x506c6174666f726d % UInt h = hash(p.tags, h) diff --git a/base/bitarray.jl b/base/bitarray.jl index 6175a492cac75..1db84cad37a1c 100644 --- a/base/bitarray.jl +++ b/base/bitarray.jl @@ -1707,6 +1707,8 @@ map!(::typeof(identity), dest::BitArray, A::BitArray) = copyto!(dest, A) for (T, f) in ((:(Union{typeof(&), typeof(*), typeof(min)}), :(&)), (:(Union{typeof(|), typeof(max)}), :(|)), (:(Union{typeof(xor), typeof(!=)}), :xor), + (:(typeof(nand)), :nand), + (:(typeof(nor)), :nor), (:(Union{typeof(>=), typeof(^)}), :((p, q) -> p | ~q)), (:(typeof(<=)), :((p, q) -> ~p | q)), (:(typeof(==)), :((p, q) -> ~xor(p, q))), diff --git a/base/bool.jl b/base/bool.jl index 92a27543d2fbc..d42cfb0603279 100644 --- a/base/bool.jl +++ b/base/bool.jl @@ -14,6 +14,8 @@ typemax(::Type{Bool}) = true Boolean not. Implements [three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), returning [`missing`](@ref) if `x` is `missing`. +See also [`~`](@ref) for bitwise not. + # Examples ```jldoctest julia> !true @@ -70,6 +72,74 @@ julia> [true; true; false] .⊻ [true; false; false] """ xor(x::Bool, y::Bool) = (x != y) +""" + nand(x, y) + ⊼(x, y) + +Bitwise nand (not and) of `x` and `y`. Implements +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), +returning [`missing`](@ref) if one of the arguments is `missing`. + +The infix operation `a ⊼ b` is a synonym for `nand(a,b)`, and +`⊼` can be typed by tab-completing `\\nand` or `\\barwedge` in the Julia REPL. + +# Examples +```jldoctest +julia> nand(true, false) +true + +julia> nand(true, true) +false + +julia> nand(true, missing) +missing + +julia> false ⊼ false +true + +julia> [true; true; false] .⊼ [true; false; false] +3-element BitVector: + 0 + 1 + 1 +``` +""" +nand(x...) = ~(&)(x...) + +""" + nor(x, y) + ⊽(x, y) + +Bitwise nor (not or) of `x` and `y`. Implements +[three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), +returning [`missing`](@ref) if one of the arguments is `missing`. + +The infix operation `a ⊽ b` is a synonym for `nor(a,b)`, and +`⊽` can be typed by tab-completing `\\nor` or `\\veebar` in the Julia REPL. + +# Examples +```jldoctest +julia> nor(true, false) +false + +julia> nor(true, true) +false + +julia> nor(true, missing) +false + +julia> false ⊽ false +true + +julia> [true; true; false] .⊽ [true; false; false] +3-element BitVector: + 0 + 0 + 1 +``` +""" +nor(x...) = ~(|)(x...) + >>(x::Bool, c::UInt) = Int(x) >> c <<(x::Bool, c::UInt) = Int(x) << c >>>(x::Bool, c::UInt) = Int(x) >>> c diff --git a/base/broadcast.jl b/base/broadcast.jl index de3263a64011b..d7546643220ba 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -11,7 +11,7 @@ using .Base.Cartesian using .Base: Indices, OneTo, tail, to_shape, isoperator, promote_typejoin, @pure, _msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache, unalias import .Base: copy, copyto!, axes -export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcastable, dotview, @__dot__, broadcast_preserving_zero_d, BroadcastFunction +export broadcast, broadcast!, BroadcastStyle, broadcast_axes, broadcastable, dotview, @__dot__, BroadcastFunction ## Computing the result's axes: deprecated name const broadcast_axes = axes @@ -179,6 +179,21 @@ function Broadcasted{Style}(f::F, args::Args, axes=nothing) where {Style, F, Arg Broadcasted{Style, typeof(axes), Core.Typeof(f), Args}(f, args, axes) end +struct AndAnd end +andand = AndAnd() +broadcasted(::AndAnd, a, b) = broadcasted((a, b) -> a && b, a, b) +function broadcasted(::AndAnd, a, bc::Broadcasted) + bcf = flatten(bc) + broadcasted((a, args...) -> a && bcf.f(args...), a, bcf.args...) +end +struct OrOr end +const oror = OrOr() +broadcasted(::OrOr, a, b) = broadcasted((a, b) -> a || b, a, b) +function broadcasted(::OrOr, a, bc::Broadcasted) + bcf = flatten(bc) + broadcasted((a, args...) -> a || bcf.f(args...), a, bcf.args...) +end + Base.convert(::Type{Broadcasted{NewStyle}}, bc::Broadcasted{Style,Axes,F,Args}) where {NewStyle,Style,Axes,F,Args} = Broadcasted{NewStyle,Axes,F,Args}(bc.f, bc.args, bc.axes) @@ -684,7 +699,7 @@ Base.RefValue{String}("hello") """ broadcastable(x::Union{Symbol,AbstractString,Function,UndefInitializer,Nothing,RoundingMode,Missing,Val,Ptr,AbstractPattern,Pair}) = Ref(x) broadcastable(::Type{T}) where {T} = Ref{Type{T}}(T) -broadcastable(x::Union{AbstractArray,Number,Ref,Tuple,Broadcasted}) = x +broadcastable(x::Union{AbstractArray,Number,Char,Ref,Tuple,Broadcasted}) = x # Default to collecting iterables — which will error for non-iterables broadcastable(x) = collect(x) broadcastable(::Union{AbstractDict, NamedTuple}) = throw(ArgumentError("broadcasting over dictionaries and `NamedTuple`s is reserved")) @@ -1138,15 +1153,20 @@ broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r::LinRange, x::Number) = LinRa broadcasted(::DefaultArrayStyle{1}, ::typeof(-), x::Number, r::LinRange) = LinRange(x - r.start, x - r.stop, length(r)) broadcasted(::DefaultArrayStyle{1}, ::typeof(-), r1::AbstractRange, r2::AbstractRange) = r1 - r2 -broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::AbstractRange) = range(x*first(r), step=x*step(r), length=length(r)) +# at present Base.range_start_step_length(1,0,5) is an error, so for 0 .* (-2:2) we explicitly construct StepRangeLen: +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::AbstractRange) = StepRangeLen(x*first(r), x*step(r), length(r)) broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::StepRangeLen{T}) where {T} = StepRangeLen{typeof(x*T(r.ref))}(x*r.ref, x*r.step, length(r), r.offset) broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::Number, r::LinRange) = LinRange(x * r.start, x * r.stop, r.len) -# separate in case of noncommutative multiplication -broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::AbstractRange, x::Number) = range(first(r)*x, step=step(r)*x, length=length(r)) +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), x::AbstractFloat, r::OrdinalRange) = + Base.range_start_step_length(x*first(r), x*step(r), length(r)) # 0.2 .* (-2:2) needs TwicePrecision +# separate in case of noncommutative multiplication: +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::AbstractRange, x::Number) = StepRangeLen(first(r)*x, step(r)*x, length(r)) broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::StepRangeLen{T}, x::Number) where {T} = StepRangeLen{typeof(T(r.ref)*x)}(r.ref*x, r.step*x, length(r), r.offset) broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::LinRange, x::Number) = LinRange(r.start * x, r.stop * x, r.len) +broadcasted(::DefaultArrayStyle{1}, ::typeof(*), r::OrdinalRange, x::AbstractFloat) = + Base.range_start_step_length(first(r)*x, step(r)*x, length(r)) broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::AbstractRange, x::Number) = range(first(r)/x, step=step(r)/x, length=length(r)) broadcasted(::DefaultArrayStyle{1}, ::typeof(/), r::StepRangeLen{T}, x::Number) where {T} = @@ -1257,15 +1277,9 @@ function __dot__(x::Expr) tmp = x.head === :(<:) ? :.<: : :.>: Expr(:call, tmp, dotargs...) else - if x.head === :&& || x.head === :|| - error(""" - Using `&&` and `||` is disallowed in `@.` expressions. - Use `&` or `|` for elementwise logical operations. - """) - end - head = string(x.head) - if last(head) == '=' && first(head) != '.' - Expr(Symbol('.',head), dotargs...) + head = String(x.head)::String + if last(head) == '=' && first(head) != '.' || head == "&&" || head == "||" + Expr(Symbol('.', head), dotargs...) else Expr(x.head, dotargs...) end @@ -1300,7 +1314,13 @@ macro __dot__(x) esc(__dot__(x)) end -@inline broadcasted_kwsyntax(f, args...; kwargs...) = broadcasted((args...)->f(args...; kwargs...), args...) +@inline function broadcasted_kwsyntax(f, args...; kwargs...) + if isempty(kwargs) # some BroadcastStyles dispatch on `f`, so try to preserve its type + return broadcasted(f, args...) + else + return broadcasted((args...) -> f(args...; kwargs...), args...) + end +end @inline function broadcasted(f, args...) args′ = map(broadcastable, args) broadcasted(combine_styles(args′...), f, args′...) diff --git a/base/channels.jl b/base/channels.jl index fc6e1381b64b5..1557504bbe21e 100644 --- a/base/channels.jl +++ b/base/channels.jl @@ -295,7 +295,7 @@ function close_chnl_on_taskdone(t::Task, c::Channel) end struct InvalidStateException <: Exception - msg::AbstractString + msg::String state::Symbol end @@ -422,6 +422,7 @@ n_avail(c::Channel) = isbuffered(c) ? length(c.data) : length(c.cond_put.waitq) isempty(c::Channel) = isbuffered(c) ? isempty(c.data) : isempty(c.cond_put.waitq) lock(c::Channel) = lock(c.cond_take) +lock(f, c::Channel) = lock(f, c.cond_take) unlock(c::Channel) = unlock(c.cond_take) trylock(c::Channel) = trylock(c.cond_take) diff --git a/base/char.jl b/base/char.jl index a4071d37e41b2..0584471cb6a33 100644 --- a/base/char.jl +++ b/base/char.jl @@ -108,8 +108,9 @@ end ismalformed(c::AbstractChar) -> Bool Return `true` if `c` represents malformed (non-Unicode) data according to the -encoding used by `c`. Defaults to `false` for non-`Char` types. See also -[`show_invalid`](@ref). +encoding used by `c`. Defaults to `false` for non-`Char` types. + +See also [`show_invalid`](@ref). """ ismalformed(c::AbstractChar) = false @@ -117,8 +118,9 @@ ismalformed(c::AbstractChar) = false isoverlong(c::AbstractChar) -> Bool Return `true` if `c` represents an overlong UTF-8 sequence. Defaults -to `false` for non-`Char` types. See also [`decode_overlong`](@ref) -and [`show_invalid`](@ref). +to `false` for non-`Char` types. + +See also [`decode_overlong`](@ref) and [`show_invalid`](@ref). """ isoverlong(c::AbstractChar) = false diff --git a/base/client.jl b/base/client.jl index d9df2f04922dd..7e5f1ab5c5d58 100644 --- a/base/client.jl +++ b/base/client.jl @@ -98,13 +98,13 @@ function display_error(io::IO, er, bt) showerror(IOContext(io, :limit => true), er, bt, backtrace = bt!==nothing) println(io) end -function display_error(io::IO, stack::Vector) +function display_error(io::IO, stack::ExceptionStack) printstyled(io, "ERROR: "; bold=true, color=Base.error_color()) bt = Any[ (x[1], scrub_repl_backtrace(x[2])) for x in stack ] show_exception_stack(IOContext(io, :limit => true), bt) println(io) end -display_error(stack::Vector) = display_error(stderr, stack) +display_error(stack::ExceptionStack) = display_error(stderr, stack) display_error(er, bt=nothing) = display_error(stderr, er, bt) function eval_user_input(errio, @nospecialize(ast), show_value::Bool) @@ -143,7 +143,7 @@ function eval_user_input(errio, @nospecialize(ast), show_value::Bool) @error "SYSTEM: display_error(errio, lasterr) caused an error" end errcount += 1 - lasterr = catch_stack() + lasterr = current_exceptions() if errcount > 2 @error "It is likely that something important is broken, and Julia will not be able to continue normally" errcount break @@ -257,7 +257,7 @@ function exec_options(opts) try load_julia_startup() catch - invokelatest(display_error, catch_stack()) + invokelatest(display_error, current_exceptions()) !(repl || is_interactive) && exit(1) end end @@ -291,7 +291,7 @@ function exec_options(opts) try include(Main, PROGRAM_FILE) catch - invokelatest(display_error, catch_stack()) + invokelatest(display_error, current_exceptions()) if !is_interactive::Bool exit(1) end @@ -494,7 +494,7 @@ function _start() try exec_options(JLOptions()) catch - invokelatest(display_error, catch_stack()) + invokelatest(display_error, current_exceptions()) exit(1) end if is_interactive && get(stdout, :color, false) diff --git a/base/cmd.jl b/base/cmd.jl index 809bc0f3c0a57..0d66cb932a04a 100644 --- a/base/cmd.jl +++ b/base/cmd.jl @@ -63,7 +63,7 @@ while changing the settings of the optional keyword arguments: array or tuple of `"var"=>val` pairs. In order to modify (rather than replace) the existing environment, initialize `env` with `copy(ENV)` and then set `env["var"]=val` as desired. To add to an environment block within a `Cmd` object without replacing all - elements, use `addenv()` which will return a `Cmd` object with the updated environment. + elements, use [`addenv()`](@ref) which will return a `Cmd` object with the updated environment. * `dir::AbstractString`: Specify a working directory for the command (instead of the current directory). @@ -236,9 +236,11 @@ Set environment variables to use when running the given `command`. `env` is eith dictionary mapping strings to strings, an array of strings of the form `"var=val"`, or zero or more `"var"=>val` pair arguments. In order to modify (rather than replace) the existing environment, create `env` through `copy(ENV)` and then setting `env["var"]=val` -as desired, or use `addenv`. +as desired, or use [`addenv`](@ref). The `dir` keyword argument can be used to specify a working directory for the command. + +See also [`Cmd`](@ref), [`addenv`](@ref), [`ENV`](@ref), [`pwd`](@ref). """ setenv(cmd::Cmd, env; dir="") = Cmd(cmd; env=byteenv(env), dir=dir) setenv(cmd::Cmd, env::Pair{<:AbstractString}...; dir="") = @@ -248,10 +250,12 @@ setenv(cmd::Cmd; dir="") = Cmd(cmd; dir=dir) """ addenv(command::Cmd, env...; inherit::Bool = true) -Merge new environment mappings into the given `Cmd` object, returning a new `Cmd` object. +Merge new environment mappings into the given [`Cmd`](@ref) object, returning a new `Cmd` object. Duplicate keys are replaced. If `command` does not contain any environment values set already, it inherits the current environment at time of `addenv()` call if `inherit` is `true`. +See also [`Cmd`](@ref), [`setenv`](@ref), [`ENV`](@ref). + !!! compat "Julia 1.6" This function requires Julia 1.6 or later. """ diff --git a/base/combinatorics.jl b/base/combinatorics.jl index d966065852b3a..daa534e068af6 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -91,7 +91,7 @@ function isperm(P::Tuple) end end -isperm(P::Any16) = _isperm(P) +isperm(P::Any32) = _isperm(P) # swap columns i and j of a, in-place function swapcols!(a::AbstractMatrix, i, j) @@ -228,8 +228,15 @@ invpermute!(a, p::AbstractVector) = invpermute!!(a, copymutable(p)) Return the inverse permutation of `v`. If `B = A[v]`, then `A == B[invperm(v)]`. +See also [`sortperm`](@ref), [`invpermute!`](@ref), [`isperm`](@ref), [`permutedims`](@ref). + # Examples ```jldoctest +julia> p = (2, 3, 1); + +julia> invperm(p) +(3, 1, 2) + julia> v = [2; 4; 3; 1]; julia> invperm(v) @@ -286,7 +293,7 @@ function invperm(P::Tuple) end end -invperm(P::Any16) = Tuple(invperm(collect(P))) +invperm(P::Any32) = Tuple(invperm(collect(P))) #XXX This function should be moved to Combinatorics.jl but is currently used by Base.DSP. """ diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 6eefc453111c9..553344bbde0f0 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -137,12 +137,12 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), if splitunions splitsigs = switchtupleunion(sig) for sig_n in splitsigs - rt, edgecycle, edge = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, sv) + rt, edgecycle, edgelimited, edge = abstract_call_method(interp, method, sig_n, svec(), multiple_matches, sv) if edge !== nothing push!(edges, edge) end this_argtypes = applicable_argtypes === nothing ? argtypes : applicable_argtypes[i] - const_rt, const_result = abstract_call_method_with_const_args(interp, rt, f, this_argtypes, match, sv, edgecycle, false) + const_rt, const_result = abstract_call_method_with_const_args(interp, rt, f, this_argtypes, match, sv, edgecycle, edgelimited, false) if const_rt !== rt && const_rt ⊑ rt rt = const_rt end @@ -156,14 +156,14 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), end end else - this_rt, edgecycle, edge = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv) + this_rt, edgecycle, edgelimited, edge = abstract_call_method(interp, method, sig, match.sparams, multiple_matches, sv) if edge !== nothing push!(edges, edge) end # try constant propagation with argtypes for this match # this is in preparation for inlining, or improving the return result this_argtypes = applicable_argtypes === nothing ? argtypes : applicable_argtypes[i] - const_this_rt, const_result = abstract_call_method_with_const_args(interp, this_rt, f, this_argtypes, match, sv, edgecycle, false) + const_this_rt, const_result = abstract_call_method_with_const_args(interp, this_rt, f, this_argtypes, match, sv, edgecycle, edgelimited, false) if const_this_rt !== this_rt && const_this_rt ⊑ this_rt this_rt = const_this_rt end @@ -184,7 +184,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), end condval = maybe_extract_const_bool(this_conditional) for i = 1:length(argtypes) - fargs[i] isa Slot || continue + fargs[i] isa SlotNumber || continue if this_conditional isa InterConditional && this_conditional.slot == i vtype = this_conditional.vtype elsetype = this_conditional.elsetype @@ -222,7 +222,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), # find the first argument which supports refinment, # and intersect all equvalent arguments with it arg = fargs[i] - arg isa Slot || continue # can't refine + arg isa SlotNumber || continue # can't refine old = argtypes[i] old isa Type || continue # unlikely to refine id = slot_id(arg) @@ -284,9 +284,6 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f), return CallMeta(rettype, info) end -widenwrappedconditional(@nospecialize(typ)) = widenconditional(typ) -widenwrappedconditional(typ::LimitedAccuracy) = LimitedAccuracy(widenconditional(typ.typ), typ.causes) - function add_call_backedges!(interp::AbstractInterpreter, @nospecialize(rettype), edges::Vector{MethodInstance}, @@ -315,7 +312,7 @@ const RECURSION_MSG = "Bounded recursion detected. Call was widened to force con function abstract_call_method(interp::AbstractInterpreter, method::Method, @nospecialize(sig), sparams::SimpleVector, hardlimit::Bool, sv::InferenceState) if method.name === :depwarn && isdefined(Main, :Base) && method.module === Main.Base add_remark!(interp, sv, "Refusing to infer into `depwarn`") - return Any, false, nothing + return Any, false, false, nothing end topmost = nothing # Limit argument type tuple growth of functions: @@ -323,6 +320,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp # and from the same method. # Returns the topmost occurrence of that repeated edge. edgecycle = false + edgelimited = false # The `method_for_inference_heuristics` will expand the given method's generator if # necessary in order to retrieve this field from the generated `CodeInfo`, if it exists. # The other `CodeInfo`s we inspect will already have this field inflated, so we just @@ -383,7 +381,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp # we have a self-cycle in the call-graph, but not in the inference graph (typically): # break this edge now (before we record it) by returning early # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases) - return Any, true, nothing + return Any, true, true, nothing end topmost = nothing edgecycle = true @@ -432,7 +430,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp # since it's very unlikely that we'll try to inline this, # or want make an invoke edge to its calling convention return type. # (non-typically, this means that we lose the ability to detect a guaranteed StackOverflow in some cases) - return Any, true, nothing + return Any, true, true, nothing end add_remark!(interp, sv, RECURSION_MSG) topmost = topmost::InferenceState @@ -440,6 +438,7 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp poison_callstack(sv, parentframe === nothing ? topmost : parentframe) sig = newsig sparams = svec() + edgelimited = true end end @@ -471,14 +470,14 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp rt, edge = typeinf_edge(interp, method, sig, sparams, sv) if edge === nothing - edgecycle = true + edgecycle = edgelimited = true end - return rt, edgecycle, edge + return rt, edgecycle, edgelimited, edge end function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nospecialize(rettype), @nospecialize(f), argtypes::Vector{Any}, match::MethodMatch, - sv::InferenceState, edgecycle::Bool, + sv::InferenceState, edgecycle::Bool, edgelimited::Bool, va_override::Bool) mi = maybe_get_const_prop_profitable(interp, rettype, f, argtypes, match, sv, edgecycle) mi === nothing && return Any, nothing @@ -489,7 +488,11 @@ function abstract_call_method_with_const_args(interp::AbstractInterpreter, @nosp # if there might be a cycle, check to make sure we don't end up # calling ourselves here. if edgecycle && _any(InfStackUnwind(sv)) do infstate - return match.method === infstate.linfo.def && any(infstate.result.overridden_by_const) + # if the type complexity limiting didn't decide to limit the call signature (`edgelimited = false`) + # we can relax the cycle detection by comparing `MethodInstance`s and allow inference to + # propagate different constant elements if the recursion is finite over the lattice + return (edgelimited ? match.method === infstate.linfo.def : mi === infstate.linfo) && + any(infstate.result.overridden_by_const) end add_remark!(interp, sv, "[constprop] Edge cycle encountered") return Any, nothing @@ -983,10 +986,10 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U # try to simulate this as a real conditional (`cnd ? x : y`), so that the penalty for using `ifelse` instead isn't too high a = ssa_def_slot(fargs[3], sv) b = ssa_def_slot(fargs[4], sv) - if isa(a, Slot) && slot_id(cnd.var) == slot_id(a) + if isa(a, SlotNumber) && slot_id(cnd.var) == slot_id(a) tx = (cnd.vtype ⊑ tx ? cnd.vtype : tmeet(tx, widenconst(cnd.vtype))) end - if isa(b, Slot) && slot_id(cnd.var) == slot_id(b) + if isa(b, SlotNumber) && slot_id(cnd.var) == slot_id(b) ty = (cnd.elsetype ⊑ ty ? cnd.elsetype : tmeet(ty, widenconst(cnd.elsetype))) end return tmerge(tx, ty) @@ -1007,7 +1010,7 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U # perform very limited back-propagation of type information for `is` and `isa` if f === isa a = ssa_def_slot(fargs[2], sv) - if isa(a, Slot) + if isa(a, SlotNumber) aty = widenconst(argtypes[2]) if rt === Const(false) return Conditional(a, Union{}, aty) @@ -1030,7 +1033,7 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U aty = argtypes[2] bty = argtypes[3] # if doing a comparison to a singleton, consider returning a `Conditional` instead - if isa(aty, Const) && isa(b, Slot) + if isa(aty, Const) && isa(b, SlotNumber) if rt === Const(false) aty = Union{} elseif rt === Const(true) @@ -1040,7 +1043,7 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U end return Conditional(b, aty, bty) end - if isa(bty, Const) && isa(a, Slot) + if isa(bty, Const) && isa(a, SlotNumber) if rt === Const(false) bty = Union{} elseif rt === Const(true) @@ -1051,10 +1054,10 @@ function abstract_call_builtin(interp::AbstractInterpreter, f::Builtin, fargs::U return Conditional(a, bty, aty) end # narrow the lattice slightly (noting the dependency on one of the slots), to promote more effective smerge - if isa(b, Slot) + if isa(b, SlotNumber) return Conditional(b, rt === Const(false) ? Union{} : bty, rt === Const(true) ? Union{} : bty) end - if isa(a, Slot) + if isa(a, SlotNumber) return Conditional(a, rt === Const(false) ? Union{} : aty, rt === Const(true) ? Union{} : aty) end elseif f === Core.Compiler.not_int @@ -1128,7 +1131,7 @@ function abstract_invoke(interp::AbstractInterpreter, argtypes::Vector{Any}, sv: end method, valid_worlds = result update_valid_age!(sv, valid_worlds) - (ti, env) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector + (ti, env::SimpleVector) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), nargtype, method.sig)::SimpleVector rt, edge = typeinf_edge(interp, method, ti, env, sv) edge !== nothing && add_backedge!(edge::MethodInstance, sv) return CallMeta(rt, InvokeCallInfo(MethodMatch(ti, env, method, argtype <: method.sig))) @@ -1231,7 +1234,7 @@ end function abstract_call_opaque_closure(interp::AbstractInterpreter, closure::PartialOpaque, argtypes::Vector{Any}, sv::InferenceState) pushfirst!(argtypes, closure.env) sig = argtypes_to_type(argtypes) - rt, edgecycle, edge = abstract_call_method(interp, closure.source::Method, sig, Core.svec(), false, sv) + rt, edgecycle, edgelimited, edge = abstract_call_method(interp, closure.source::Method, sig, Core.svec(), false, sv) edge !== nothing && add_backedge!(edge, sv) tt = closure.typ sigT = unwrap_unionall(tt).parameters[1] @@ -1239,7 +1242,7 @@ function abstract_call_opaque_closure(interp::AbstractInterpreter, closure::Part info = OpaqueClosureCallInfo(match) if !edgecycle const_rettype, result = abstract_call_method_with_const_args(interp, rt, closure, argtypes, - match, sv, edgecycle, closure.isva) + match, sv, edgecycle, edgelimited, closure.isva) if const_rettype ⊑ rt rt = const_rettype end @@ -1358,7 +1361,7 @@ function abstract_eval_special_value(interp::AbstractInterpreter, @nospecialize( return Const((e::QuoteNode).value) elseif isa(e, SSAValue) return abstract_eval_ssavalue(e::SSAValue, sv.src) - elseif isa(e, Slot) || isa(e, Argument) + elseif isa(e, SlotNumber) || isa(e, Argument) return (vtypes[slot_id(e)]::VarState).typ elseif isa(e, GlobalRef) return abstract_eval_global(e.mod, e.name) @@ -1410,7 +1413,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), end elseif e.head === :new t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1] - if isconcretetype(t) && !t.mutable + if isconcretetype(t) && !t.name.mutable args = Vector{Any}(undef, length(e.args)-1) ats = Vector{Any}(undef, length(e.args)-1) anyconst = false @@ -1447,12 +1450,12 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), end elseif e.head === :splatnew t = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv))[1] - if length(e.args) == 2 && isconcretetype(t) && !t.mutable + if length(e.args) == 2 && isconcretetype(t) && !t.name.mutable at = abstract_eval_value(interp, e.args[2], vtypes, sv) n = fieldcount(t) - if isa(at, Const) && (val = at.val; isa(val, Tuple)) && n == length(val) && - let t = t, val = val; _all(i->val[i] isa fieldtype(t, i), 1:n); end - t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, val)) + if isa(at, Const) && isa(at.val, Tuple) && n == length(at.val) && + let t = t; _all(i->getfield(at.val, i) isa fieldtype(t, i), 1:n); end + t = Const(ccall(:jl_new_structt, Any, (Any, Any), t, at.val)) elseif isa(at, PartialStruct) && at ⊑ Tuple && n == length(at.fields) && let t = t, at = at; _all(i->at.fields[i] ⊑ fieldtype(t, i), 1:n); end t = PartialStruct(t, at.fields) @@ -1502,7 +1505,7 @@ function abstract_eval_statement(interp::AbstractInterpreter, @nospecialize(e), elseif e.head === :isdefined sym = e.args[1] t = Bool - if isa(sym, Slot) + if isa(sym, SlotNumber) vtyp = vtypes[slot_id(sym)] if vtyp.typ === Bottom t = Const(false) # never assigned previously @@ -1634,7 +1637,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) @assert !frame.inferred frame.dont_work_on_me = true # mark that this function is currently on the stack W = frame.ip - s = frame.stmt_types + states = frame.stmt_types n = frame.nstmts nargs = frame.nargs def = frame.linfo.def @@ -1659,7 +1662,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) edges === nothing || empty!(edges) frame.stmt_info[pc] = nothing stmt = frame.src.code[pc] - changes = s[pc]::VarTable + changes = states[pc]::VarTable t = nothing hd = isa(stmt, Expr) ? stmt.head : nothing @@ -1670,13 +1673,17 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) elseif isa(stmt, GotoNode) pc´ = (stmt::GotoNode).label elseif isa(stmt, GotoIfNot) - condt = abstract_eval_value(interp, stmt.cond, changes, frame) + condx = stmt.cond + condt = abstract_eval_value(interp, condx, changes, frame) if condt === Bottom empty!(frame.pclimitations) - end - if condt === Bottom break end + if !(isa(condt, Const) || isa(condt, Conditional)) && isa(condx, SlotNumber) + # if this non-`Conditional` object is a slot, we form and propagate + # the conditional constraint on it + condt = Conditional(condx, Const(true), Const(false)) + end condval = maybe_extract_const_bool(condt) l = stmt.dest::Int if !isempty(frame.pclimitations) @@ -1698,14 +1705,14 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) changes_else = conditional_changes(changes_else, condt.elsetype, condt.var) changes = conditional_changes(changes, condt.vtype, condt.var) end - newstate_else = stupdate!(s[l], changes_else) + newstate_else = stupdate!(states[l], changes_else) if newstate_else !== nothing # add else branch to active IP list if l < frame.pc´´ frame.pc´´ = l end push!(W, l) - s[l] = newstate_else + states[l] = newstate_else end end elseif isa(stmt, ReturnNode) @@ -1753,16 +1760,16 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) l = stmt.args[1]::Int frame.cur_hand = Pair{Any,Any}(l, frame.cur_hand) # propagate type info to exception handler - old = s[l] + old = states[l] newstate_catch = stupdate!(old, changes) if newstate_catch !== nothing if l < frame.pc´´ frame.pc´´ = l end push!(W, l) - s[l] = newstate_catch + states[l] = newstate_catch end - typeassert(s[l], VarTable) + typeassert(states[l], VarTable) frame.handler_at[l] = frame.cur_hand elseif hd === :leave for i = 1:((stmt.args[1])::Int) @@ -1776,12 +1783,12 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) end frame.src.ssavaluetypes[pc] = t lhs = stmt.args[1] - if isa(lhs, Slot) + if isa(lhs, SlotNumber) changes = StateUpdate(lhs, VarState(t, false), changes, false) end elseif hd === :method fname = stmt.args[1] - if isa(fname, Slot) + if isa(fname, SlotNumber) changes = StateUpdate(fname, VarState(Any, false), changes, false) end elseif hd === :inbounds || hd === :meta || hd === :loopinfo || hd === :code_coverage_effect @@ -1802,7 +1809,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) # the handling for Expr(:enter) propagates all changes from before the try/catch # so this only needs to propagate any changes l = frame.cur_hand.first::Int - if stupdate1!(s[l]::VarTable, changes::StateUpdate) !== false + if stupdate1!(states[l]::VarTable, changes::StateUpdate) !== false if l < frame.pc´´ frame.pc´´ = l end @@ -1820,19 +1827,19 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) pc´ > n && break # can't proceed with the fast-path fall-through frame.handler_at[pc´] = frame.cur_hand - newstate = stupdate!(s[pc´], changes) + newstate = stupdate!(states[pc´], changes) if isa(stmt, GotoNode) && frame.pc´´ < pc´ # if we are processing a goto node anyways, # (such as a terminator for a loop, if-else, or try block), # consider whether we should jump to an older backedge first, # to try to traverse the statements in approximate dominator order if newstate !== nothing - s[pc´] = newstate + states[pc´] = newstate end push!(W, pc´) pc = frame.pc´´ elseif newstate !== nothing - s[pc´] = newstate + states[pc´] = newstate pc = pc´ elseif pc´ in W pc = pc´ @@ -1845,8 +1852,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState) nothing end -function conditional_changes(changes::VarTable, @nospecialize(typ), var::Slot) - if typ ⊑ (changes[slot_id(var)]::VarState).typ +function conditional_changes(changes::VarTable, @nospecialize(typ), var::SlotNumber) + oldtyp = (changes[slot_id(var)]::VarState).typ + # approximate test for `typ ∩ oldtyp` being better than `oldtyp` + # since we probably formed these types with `typesubstract`, the comparison is likely simple + if ignorelimited(typ) ⊑ ignorelimited(oldtyp) + # typ is better unlimited, but we may still need to compute the tmeet with the limit "causes" since we ignored those in the comparison + oldtyp isa LimitedAccuracy && (typ = tmerge(typ, LimitedAccuracy(Bottom, oldtyp.causes))) return StateUpdate(var, VarState(typ, false), changes, true) end return changes diff --git a/base/compiler/methodtable.jl b/base/compiler/methodtable.jl index 1a0b4076f3ed9..cff9e21fccb41 100644 --- a/base/compiler/methodtable.jl +++ b/base/compiler/methodtable.jl @@ -47,7 +47,7 @@ CachedMethodTable(table::T) where T = Find all methods in the given method table `view` that are applicable to the given signature `sig`. If no applicable methods are found, an empty result is -returned. If the number of applicable methods exeeded the specified limit, +returned. If the number of applicable methods exceeded the specified limit, `missing` is returned. """ function findall(@nospecialize(sig::Type{<:Tuple}), table::InternalMethodTable; limit::Int=typemax(Int)) diff --git a/base/compiler/ssair/domtree.jl b/base/compiler/ssair/domtree.jl index 1ab2876b769da..c2f056a0c027b 100644 --- a/base/compiler/ssair/domtree.jl +++ b/base/compiler/ssair/domtree.jl @@ -244,7 +244,7 @@ function update_level!(nodes::Vector{DomTreeNode}, node::BBNumber, level::Int) end """ -The main Semi-NCA algrithm. Matches Figure 2.8 in [LG05]. Note that the +The main Semi-NCA algorithm. Matches Figure 2.8 in [LG05]. Note that the pseudocode in [LG05] is not entirely accurate. The best way to understand what's happening is to read [LT79], then the description of SLT in [LG05] (warning: inconsistent notation), then the description of Semi-NCA. diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index f95ff55b75e84..0420d137da69e 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -103,7 +103,7 @@ function CFGInliningState(ir::IRCode) end # Tells the inliner that we're now inlining into block `block`, meaning -# all previous blocks have been proceesed and can be added to the new cfg +# all previous blocks have been processed and can be added to the new cfg function inline_into_block!(state::CFGInliningState, block::Int) if state.first_bb != block new_range = state.first_bb+1:block @@ -710,7 +710,7 @@ function compileable_specialization(et::Union{EdgeTracker, Nothing}, match::Meth end function compileable_specialization(et::Union{EdgeTracker, Nothing}, result::InferenceResult) - mi = specialize_method(result.linfo.def, result.linfo.specTypes, + mi = specialize_method(result.linfo.def::Method, result.linfo.specTypes, result.linfo.sparam_vals, false, true) mi !== nothing && et !== nothing && push!(et, mi::MethodInstance) return mi @@ -746,8 +746,10 @@ function resolve_todo(todo::InliningTodo, state::InliningState) end end - if isconst && state.et !== nothing - push!(state.et, todo.mi) + et = state.et + + if isconst && et !== nothing + push!(et, todo.mi) return ConstantCase(src) end @@ -756,14 +758,13 @@ function resolve_todo(todo::InliningTodo, state::InliningState) end if src === nothing - return compileable_specialization(state.et, spec.match) + return compileable_specialization(et, spec.match) end if isa(src, IRCode) src = copy(src) end - et = state.et et !== nothing && push!(et, todo.mi) return InliningTodo(todo.mi, src) end diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index f27c71c2bcd6c..114b8c6033615 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -328,8 +328,8 @@ function lift_leaves(compact::IncrementalCompact, @nospecialize(stmt), if isa(typ, UnionAll) typ = unwrap_unionall(typ) end - (isa(typ, DataType) && (!typ.abstract)) || return nothing - @assert !typ.mutable + (isa(typ, DataType) && (!typ.name.abstract)) || return nothing + @assert !typ.name.mutable if length(def.args) < 1 + field if field > fieldcount(typ) return nothing @@ -625,7 +625,7 @@ function getfield_elim_pass!(ir::IRCode) if isa(typ, UnionAll) typ = unwrap_unionall(typ) end - if typ isa DataType && !typ.mutable + if typ isa DataType && !typ.name.mutable process_immutable_preserve(new_preserves, compact, def) old_preserves[pidx] = nothing continue @@ -662,7 +662,7 @@ function getfield_elim_pass!(ir::IRCode) def, typeconstraint = stmt.args[2], struct_typ - if struct_typ.mutable + if struct_typ.name.mutable isa(def, SSAValue) || continue let intermediaries = IdSet() callback = function(@nospecialize(pi), ssa::AnySSAValue) @@ -775,7 +775,7 @@ function getfield_elim_pass!(ir::IRCode) end # Could still end up here if we tried to setfield! and immutable, which would # error at runtime, but is not illegal to have in the IR. - typ.mutable || continue + typ.name.mutable || continue # Partition defuses by field fielddefuse = SSADefUse[SSADefUse() for _ = 1:fieldcount(typ)] ok = true diff --git a/base/compiler/ssair/show.jl b/base/compiler/ssair/show.jl index c1f4e0f25f506..1f1c838c62ae7 100644 --- a/base/compiler/ssair/show.jl +++ b/base/compiler/ssair/show.jl @@ -192,7 +192,7 @@ example (taken from `@code_typed sin(1.0)`): ``` The three annotations are indicated with `*`. The first one is the line number of the -active function (printed once whenver the outer most line number changes). The second +active function (printed once whenever the outer most line number changes). The second is the inlining indicator. The number of lines indicate the level of nesting, with a half-size line (╷) indicating the start of a scope and a full size line (│) indicating a continuing scope. The last annotation is the most complicated one. It is a heuristic @@ -201,7 +201,7 @@ scope that hasn't been printed before. Let's work a number of examples to see th and tradeoffs involved. ``` -f() = leaf_function() # Delibarately not defined to end up in the IR verbatim +f() = leaf_function() # Deliberately not defined to end up in the IR verbatim g() = f() h() = g() top_function() = h() @@ -455,7 +455,7 @@ function DILineInfoPrinter(linetable::Vector, showtypes::Bool=false) if frame.line != typemax(frame.line) && frame.line != 0 print(io, ":", frame.line) end - print(io, " within `", method_name(frame), "'") + print(io, " within `", method_name(frame), "`") if collapse method = method_name(frame) while nctx < nframes @@ -487,31 +487,81 @@ function DILineInfoPrinter(linetable::Vector, showtypes::Bool=false) return emit_lineinfo_update end +# line_info_preprinter(io::IO, indent::String, idx::Int) may print relevant info +# at the beginning of the line, and should at least print `indent`. It returns a +# string that will be printed after the final basic-block annotation. +# line_info_postprinter(io::IO, typ, used::Bool) prints the type-annotation at the end +# of the statement +# should_print_stmt(idx::Int) -> Bool: whether the statement at index `idx` should be +# printed as part of the IR or not +# bb_color: color used for printing the basic block brackets on the left +struct IRShowConfig + line_info_preprinter + line_info_postprinter + should_print_stmt + bb_color::Symbol + function IRShowConfig(line_info_preprinter, line_info_postprinter=default_expr_type_printer; + should_print_stmt=Returns(true), bb_color::Symbol=:light_black) + return new(line_info_preprinter, line_info_postprinter, should_print_stmt, bb_color) + end +end -function show_ir(io::IO, code::IRCode, expr_type_printer=default_expr_type_printer; verbose_linetable=false) - cols = (displaysize(io)::Tuple{Int,Int})[2] - used = BitSet() +struct _UNDEF + global const UNDEF = _UNDEF.instance +end + +function _stmt(code::IRCode, idx::Int) stmts = code.stmts - isempty(stmts) && return # unlikely, but avoid errors from reducing over empty sets - cfg = code.cfg - max_bb_idx_size = length(string(length(cfg.blocks))) - new_nodes = code.new_nodes.stmts - new_nodes_info = code.new_nodes.info - bb_idx = 1 - for stmt in stmts - scan_ssa_use!(push!, used, stmt[:inst]) - end - if any(i -> !isassigned(new_nodes.inst, i), 1:length(new_nodes)) - printstyled(io, "ERROR: New node array has unset entry\n", color=:red) - new_nodes_perm = filter(i -> isassigned(new_nodes.inst, i), 1:length(new_nodes)) - else - new_nodes_perm = collect(1:length(new_nodes)) - end - for nn in new_nodes_perm - scan_ssa_use!(push!, used, new_nodes[nn][:inst]) + return isassigned(stmts.inst, idx) ? stmts[idx][:inst] : UNDEF +end +function _stmt(code::CodeInfo, idx::Int) + code = code.code + return isassigned(code, idx) ? code[idx] : UNDEF +end + +function _type(code::IRCode, idx::Int) + stmts = code.stmts + return isassigned(stmts.type, idx) ? stmts[idx][:type] : UNDEF +end +function _type(code::CodeInfo, idx::Int) + types = code.ssavaluetypes + types isa Vector{Any} || return nothing + return isassigned(types, idx) ? types[idx] : UNDEF +end + +function statement_indices_to_labels(stmt, cfg::CFG) + # convert statement index to labels, as expected by print_stmt + if stmt isa Expr + if stmt.head === :enter && length(stmt.args) == 1 && stmt.args[1] isa Int + stmt = Expr(:enter, block_for_inst(cfg, stmt.args[1]::Int)) + end + elseif isa(stmt, GotoIfNot) + stmt = GotoIfNot(stmt.cond, block_for_inst(cfg, stmt.dest)) + elseif stmt isa GotoNode + stmt = GotoNode(block_for_inst(cfg, stmt.label)) + elseif stmt isa PhiNode + e = stmt.edges + stmt = PhiNode(Int32[block_for_inst(cfg, Int(e[i])) for i in 1:length(e)], stmt.values) end - sort!(new_nodes_perm, by = x -> (x = new_nodes_info[x]; (x.pos, x.attach_after))) - perm_idx = 1 + return stmt +end + +# Show a single statement, code.stmts[idx]/code.code[idx], in the context of the whole IRCode/CodeInfo. +# Returns the updated value of bb_idx. +# pop_new_node!(idx::Int) -> (node_idx, new_node_inst, new_node_type) may return a new +# node at the current index `idx`, which is printed before the statement at index +# `idx`. This function is repeatedly called until it returns `nothing` +function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo}, idx::Int, config::IRShowConfig, + used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing)) + return show_ir_stmt(io, code, idx, config.line_info_preprinter, config.line_info_postprinter, + used, cfg, bb_idx; pop_new_node!, config.bb_color) +end + +function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo}, idx::Int, line_info_preprinter, line_info_postprinter, + used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing), bb_color=:light_black) + stmt = _stmt(code, idx) + type = _type(code, idx) + max_bb_idx_size = length(string(length(cfg.blocks))) if isempty(used) maxlength_idx = 0 @@ -519,251 +569,214 @@ function show_ir(io::IO, code::IRCode, expr_type_printer=default_expr_type_print maxused = maximum(used) maxlength_idx = length(string(maxused)) end - if !verbose_linetable - (loc_annotations, loc_methods, loc_lineno) = compute_ir_line_annotations(code) - max_loc_width = maximum(length(str) for str in loc_annotations) - max_lineno_width = maximum(length(str) for str in loc_lineno) - max_method_width = maximum(length(str) for str in loc_methods) + + if stmt === UNDEF + # This is invalid, but do something useful rather + # than erroring, to make debugging easier + printstyled(io, "#UNDEF\n", color=:red) + return bb_idx end - max_depth = maximum(compute_inlining_depth(code.linetable, stmts[i][:line]) for i in 1:length(stmts.line)) - last_stack = [] - for idx in 1:length(stmts) - if !isassigned(stmts.inst, idx) - # This is invalid, but do something useful rather - # than erroring, to make debugging easier - printstyled(io, "#UNDEF\n", color=:red) - continue - end - stmt = stmts[idx] + + i = 1 + while true + next = pop_new_node!(idx) # Compute BB guard rail if bb_idx > length(cfg.blocks) - # Even if invariants are violated, try our best to still print - bbrange = (length(cfg.blocks) == 0 ? 1 : last(cfg.blocks[end].stmts) + 1):typemax(Int) - bb_idx_str = "!" - bb_type = "─" + # If invariants are violated, print a special leader + linestart = " "^(max_bb_idx_size + 2) # not inside a basic block bracket + inlining_indent = line_info_preprinter(io, linestart, i == 1 ? idx : 0) + printstyled(io, "!!! ", "─"^max_bb_idx_size, color=bb_color) else bbrange = cfg.blocks[bb_idx].stmts bbrange = bbrange.start:bbrange.stop - bb_idx_str = string(bb_idx) - bb_type = length(cfg.blocks[bb_idx].preds) <= 1 ? "─" : "┄" - end - bb_pad = max_bb_idx_size - length(bb_idx_str) - bb_start_str = string(bb_idx_str, " ", bb_type, "─"^bb_pad, " ") - bb_guard_rail_cont = string("│ ", " "^max_bb_idx_size) - if idx == first(bbrange) - bb_guard_rail = bb_start_str - else - bb_guard_rail = bb_guard_rail_cont - end - # Print linetable information - if verbose_linetable - stack = compute_loc_stack(code.linetable, stmt[:line]) - # We need to print any stack frames that did not exist in the last stack - ndepth = max(1, length(stack)) - rail = string(" "^(max_depth+1-ndepth), "│"^ndepth) - start_column = cols - max_depth - 10 - for (i, x) in enumerate(stack) - if i > length(last_stack) || last_stack[i] != x - entry = code.linetable[x] - printstyled(io, "\e[$(start_column)G$(rail)\e[1G", color = :light_black) - print(io, bb_guard_rail) - ssa_guard = " "^(maxlength_idx + 4 + (i - 1)) - entry_label = "$(ssa_guard)$(method_name(entry)) at $(entry.file):$(entry[:line]) " - hline = string("─"^(start_column-length(entry_label)-length(bb_guard_rail)+max_depth-i), "┐") - printstyled(io, string(entry_label, hline), "\n"; color=:light_black) - bb_guard_rail = bb_guard_rail_cont - end - end - printstyled(io, "\e[$(start_column)G$(rail)\e[1G", color = :light_black) - last_stack = stack - else - if idx <= length(loc_annotations) - # N.B.: The line array length not matching is invalid, - # but let's be robust here - annotation = loc_annotations[idx] - loc_method = loc_methods[idx] - lineno = loc_lineno[idx] + # Print line info update + linestart = idx == first(bbrange) ? " " : sprint(io -> printstyled(io, "│ ", color=bb_color), context=io) + linestart *= " "^max_bb_idx_size + # idx == 0 means only indentation is printed, so we don't print linfos + # multiple times if the are new nodes + inlining_indent = line_info_preprinter(io, linestart, i == 1 ? idx : 0) + + if i == 1 && idx == first(bbrange) + bb_idx_str = string(bb_idx) + bb_pad = max_bb_idx_size - length(bb_idx_str) + bb_type = length(cfg.blocks[bb_idx].preds) <= 1 ? "─" : "┄" + printstyled(io, bb_idx_str, " ", bb_type, "─"^bb_pad, color=bb_color) + elseif next === nothing && idx == last(bbrange) # print separator + printstyled(io, "└", "─"^(1 + max_bb_idx_size), color=bb_color) else - annotation = "!" - loc_method = "" - lineno = "" - end - # Print location information right aligned. If the line below is too long, it'll overwrite this, - # but that's what we want. - if get(io, :color, false) - method_start_column = cols - max_method_width - max_loc_width - 2 - filler = " "^(max_loc_width-length(annotation)) - printstyled(io, "\e[$(method_start_column)G$(annotation)$(filler)$(loc_method)\e[1G", color = :light_black) + printstyled(io, "│ ", " "^max_bb_idx_size, color=bb_color) end - printstyled(io, lineno, " "^(max_lineno_width - length(lineno) + 1); color = :light_black) - end - idx != last(bbrange) && print(io, bb_guard_rail) - print_sep = false - if idx == last(bbrange) - print_sep = true end - floop = true - # print new nodes first in the right position - while perm_idx <= length(new_nodes_perm) - node_idx = new_nodes_perm[perm_idx] - if new_nodes_info[node_idx].pos != idx - break - end - perm_idx += 1 - if !floop && !verbose_linetable - print(io, " "^(max_lineno_width + 1)) - end - if print_sep - if idx == first(bbrange) && floop - print(io, bb_start_str) - else - print(io, "│ ", " "^max_bb_idx_size) - end - end - print_sep = true - floop = false - new_node = new_nodes[node_idx] - node_idx += length(stmts) - show_type = should_print_ssa_type(new_node[:inst]) - with_output_color(:green, io) do io′ - print_stmt(io′, node_idx, new_node[:inst], used, maxlength_idx, false, show_type) - end - if !isassigned(stmts.type, idx) # try to be robust against errors - printstyled(io, "::#UNDEF", color=:red) - elseif show_type - expr_type_printer(io, new_node[:type], node_idx in used) - end - println(io) - end - if !floop && !verbose_linetable - print(io, " "^(max_lineno_width + 1)) - end - if print_sep - if idx == first(bbrange) && floop - print(io, bb_start_str) - elseif idx == last(bbrange) - print(io, "└", "─"^(1 + max_bb_idx_size), " ") - else - print(io, "│ ", " "^max_bb_idx_size) + print(io, inlining_indent, " ") + + if next === nothing + if bb_idx <= length(cfg.blocks) && idx == last(bbrange) + bb_idx += 1 end + break end - if idx == last(bbrange) - bb_idx += 1 + + # print new nodes first in the right position + node_idx, new_node_inst, new_node_type = next + + @assert new_node_inst !== UNDEF # we filtered these out earlier + show_type = should_print_ssa_type(new_node_inst) + with_output_color(:green, io) do io′ + print_stmt(io′, node_idx, new_node_inst, used, maxlength_idx, false, show_type) end - show_type = should_print_ssa_type(stmt[:inst]) - print_stmt(io, idx, stmt[:inst], used, maxlength_idx, true, show_type) - if !isassigned(stmts.type, idx) # try to be robust against errors + + if new_node_type === UNDEF # try to be robust against errors printstyled(io, "::#UNDEF", color=:red) elseif show_type - expr_type_printer(io, stmt[:type], idx in used) + line_info_postprinter(io, new_node_type, node_idx in used) end println(io) + i += 1 end -end - -# Show a single statement, code.code[idx], in the context of the whole CodeInfo. -# Returns the updated value of bb_idx. -# line_info_preprinter(io::IO, indent::String, idx::Int) may print relevant info -# at the beginning of the line, and should at least print `indent`. It returns a -# string that will be printed after the final basic-block annotation. -# line_info_postprinter(io::IO, typ, used::Bool) prints the type-annotation at the end -# of the statement -function show_ir_stmt(io::IO, code::CodeInfo, idx::Int, line_info_preprinter, line_info_postprinter, used::BitSet, cfg::CFG, bb_idx::Int) - stmts = code.code - types = code.ssavaluetypes - max_bb_idx_size = length(string(length(cfg.blocks))) - - if isempty(used) - maxlength_idx = 0 - else - maxused = maximum(used) - maxlength_idx = length(string(maxused)) - end - - if !isassigned(stmts, idx) - # This is invalid, but do something useful rather - # than erroring, to make debugging easier - printstyled(io, "#UNDEF\n", color=:red) - return bb_idx - end - stmt = stmts[idx] - # Compute BB guard rail - if bb_idx > length(cfg.blocks) - # If invariants are violated, print a special leader - linestart = " "^(max_bb_idx_size + 2) # not inside a basic block bracket - inlining_indent = line_info_preprinter(io, linestart, idx) - printstyled(io, "!!! ", "─"^max_bb_idx_size, color=:light_black) - else - bbrange = cfg.blocks[bb_idx].stmts - bbrange = bbrange.start:bbrange.stop - # Print line info update - linestart = idx == first(bbrange) ? " " : sprint(io -> printstyled(io, "│ ", color=:light_black), context=io) - linestart *= " "^max_bb_idx_size - inlining_indent = line_info_preprinter(io, linestart, idx) - if idx == first(bbrange) - bb_idx_str = string(bb_idx) - bb_pad = max_bb_idx_size - length(bb_idx_str) - bb_type = length(cfg.blocks[bb_idx].preds) <= 1 ? "─" : "┄" - printstyled(io, bb_idx_str, " ", bb_type, "─"^bb_pad, color=:light_black) - elseif idx == last(bbrange) # print separator - printstyled(io, "└", "─"^(1 + max_bb_idx_size), color=:light_black) - else - printstyled(io, "│ ", " "^max_bb_idx_size, color=:light_black) - end - if idx == last(bbrange) - bb_idx += 1 - end + if code isa CodeInfo + stmt = statement_indices_to_labels(stmt, cfg) end - print(io, inlining_indent, " ") - # convert statement index to labels, as expected by print_stmt - if stmt isa Expr - if stmt.head === :enter && length(stmt.args) == 1 && stmt.args[1] isa Int - stmt = Expr(:enter, block_for_inst(cfg, stmt.args[1]::Int)) - end - elseif isa(stmt, GotoIfNot) - stmt = GotoIfNot(stmt.cond, block_for_inst(cfg, stmt.dest)) - elseif stmt isa GotoNode - stmt = GotoNode(block_for_inst(cfg, stmt.label)) - elseif stmt isa PhiNode - e = stmt.edges - stmt = PhiNode(Int32[block_for_inst(cfg, Int(e[i])) for i in 1:length(e)], stmt.values) - end - show_type = types isa Vector{Any} && should_print_ssa_type(stmt) + show_type = type !== nothing && should_print_ssa_type(stmt) print_stmt(io, idx, stmt, used, maxlength_idx, true, show_type) - if types isa Vector{Any} # ignore types for pre-inference code - if !isassigned(types, idx) + if type !== nothing # ignore types for pre-inference code + if type === UNDEF # This is an error, but can happen if passes don't update their type information printstyled(io, "::#UNDEF", color=:red) elseif show_type - typ = types[idx] - line_info_postprinter(io, typ, idx in used) + line_info_postprinter(io, type, idx in used) end end println(io) return bb_idx end +function ircode_new_nodes_iter(code::IRCode) + stmts = code.stmts + new_nodes = code.new_nodes.stmts + new_nodes_info = code.new_nodes.info + new_nodes_perm = filter(i -> isassigned(new_nodes.inst, i), 1:length(new_nodes)) + sort!(new_nodes_perm, by = x -> (x = new_nodes_info[x]; (x.pos, x.attach_after))) + perm_idx = Ref(1) + + function (idx::Int) + perm_idx[] <= length(new_nodes_perm) || return nothing + node_idx = new_nodes_perm[perm_idx[]] + if new_nodes_info[node_idx].pos != idx + return nothing + end + perm_idx[] += 1 + new_node = new_nodes[node_idx] + new_node_inst = isassigned(new_nodes.inst, node_idx) ? new_node[:inst] : UNDEF + new_node_type = isassigned(new_nodes.type, node_idx) ? new_node[:type] : UNDEF + node_idx += length(stmts) + return node_idx, new_node_inst, new_node_type + end +end + +# print only line numbers on the left, some of the method names and nesting depth on the right +function inline_linfo_printer(code::IRCode) + loc_annotations, loc_methods, loc_lineno = compute_ir_line_annotations(code) + max_loc_width = maximum(length, loc_annotations) + max_lineno_width = maximum(length, loc_lineno) + max_method_width = maximum(length, loc_methods) + + function (io::IO, indent::String, idx::Int) + cols = (displaysize(io)::Tuple{Int,Int})[2] + + if idx == 0 + annotation = "" + loc_method = "" + lineno = "" + elseif idx <= length(loc_annotations) + # N.B.: The line array length not matching is invalid, + # but let's be robust here + annotation = loc_annotations[idx] + loc_method = loc_methods[idx] + lineno = loc_lineno[idx] + else + annotation = "!" + loc_method = "" + lineno = "" + end + # Print location information right aligned. If the line below is too long, it'll overwrite this, + # but that's what we want. + if get(io, :color, false) + method_start_column = cols - max_method_width - max_loc_width - 2 + filler = " "^(max_loc_width-length(annotation)) + printstyled(io, "\e[$(method_start_column)G$(annotation)$(filler)$(loc_method)\e[1G", color = :light_black) + end + printstyled(io, lineno, " "^(max_lineno_width - length(lineno) + 1); color = :light_black) + return "" + end +end + +_strip_color(s::String) = replace(s, r"\e\[\d+m" => "") + +function statementidx_lineinfo_printer(f, code::IRCode) + printer = f(code.linetable) + function (io::IO, indent::String, idx::Int) + printer(io, indent, idx > 0 ? code.stmts[idx][:line] : typemin(Int32)) + end +end function statementidx_lineinfo_printer(f, code::CodeInfo) printer = f(code.linetable) - return (io::IO, indent::String, idx::Int) -> printer(io, indent, idx > 0 ? code.codelocs[idx] : typemin(Int32)) + function (io::IO, indent::String, idx::Int) + printer(io, indent, idx > 0 ? code.codelocs[idx] : typemin(Int32)) + end end -statementidx_lineinfo_printer(code::CodeInfo) = statementidx_lineinfo_printer(DILineInfoPrinter, code) +statementidx_lineinfo_printer(code) = statementidx_lineinfo_printer(DILineInfoPrinter, code) -function show_ir(io::IO, code::CodeInfo, line_info_preprinter=statementidx_lineinfo_printer(code), line_info_postprinter=default_expr_type_printer) +function stmts_used(code::IRCode, warn_unset_entry=true) + stmts = code.stmts + used = BitSet() + for stmt in stmts + scan_ssa_use!(push!, used, stmt[:inst]) + end + new_nodes = code.new_nodes.stmts + for nn in 1:length(new_nodes) + if isassigned(new_nodes.inst, nn) + scan_ssa_use!(push!, used, new_nodes[nn][:inst]) + elseif warn_unset_entry + printstyled(io, "ERROR: New node array has unset entry\n", color=:red) + warn_unset_entry = false + end + end + return used +end + +function stmts_used(code::CodeInfo) stmts = code.code used = BitSet() - cfg = compute_basic_blocks(stmts) for stmt in stmts scan_ssa_use!(push!, used, stmt) end + return used +end + +function default_config(code::IRCode; verbose_linetable=false) + return IRShowConfig(verbose_linetable ? statementidx_lineinfo_printer(code) + : inline_linfo_printer(code); + bb_color=:normal) +end +default_config(code::CodeInfo) = IRShowConfig(statementidx_lineinfo_printer(code)) + +function show_ir(io::IO, code::Union{IRCode, CodeInfo}, config::IRShowConfig=default_config(code); + pop_new_node! = code isa IRCode ? ircode_new_nodes_iter(code) : Returns(nothing)) + stmts = code isa IRCode ? code.stmts : code.code + used = stmts_used(code) + cfg = code isa IRCode ? code.cfg : compute_basic_blocks(stmts) bb_idx = 1 for idx in 1:length(stmts) - bb_idx = show_ir_stmt(io, code, idx, line_info_preprinter, line_info_postprinter, used, cfg, bb_idx) + if config.should_print_stmt(code, idx, used) + bb_idx = show_ir_stmt(io, code, idx, config, used, cfg, bb_idx; pop_new_node!) + elseif bb_idx <= length(cfg.blocks) && idx == cfg.blocks[bb_idx].stmts.stop + bb_idx += 1 + end end max_bb_idx_size = length(string(length(cfg.blocks))) - line_info_preprinter(io, " "^(max_bb_idx_size + 2), 0) + config.line_info_preprinter(io, " "^(max_bb_idx_size + 2), 0) nothing end diff --git a/base/compiler/ssair/verify.jl b/base/compiler/ssair/verify.jl index 6c2953c12c505..653923ace6e8e 100644 --- a/base/compiler/ssair/verify.jl +++ b/base/compiler/ssair/verify.jl @@ -111,7 +111,7 @@ function verify_ir(ir::IRCode, print::Bool=true) end elseif isexpr(terminator, :enter) @label enter_check - if length(block.succs) != 2 || (block.succs != [terminator.args[1], idx+1] && block.succs != [idx+1, terminator.args[1]]) + if length(block.succs) != 2 || (block.succs != Int[terminator.args[1], idx+1] && block.succs != Int[idx+1, terminator.args[1]]) @verify_error "Block $idx successors ($(block.succs)), does not match :enter terminator" error("") end diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 921fbdfe32d03..5ae32d31ec189 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -28,15 +28,17 @@ const DATATYPE_NAME_FIELDINDEX = fieldindex(DataType, :name) const DATATYPE_PARAMETERS_FIELDINDEX = fieldindex(DataType, :parameters) const DATATYPE_TYPES_FIELDINDEX = fieldindex(DataType, :types) const DATATYPE_SUPER_FIELDINDEX = fieldindex(DataType, :super) -const DATATYPE_MUTABLE_FIELDINDEX = fieldindex(DataType, :mutable) const DATATYPE_INSTANCE_FIELDINDEX = fieldindex(DataType, :instance) -const DATATYPE_ABSTRACT_FIELDINDEX = fieldindex(DataType, :abstract) const DATATYPE_NAMES_FIELDINDEX = fieldindex(DataType, :names) +const DATATYPE_HASH_FIELDINDEX = fieldindex(DataType, :hash) const TYPENAME_NAME_FIELDINDEX = fieldindex(Core.TypeName, :name) const TYPENAME_MODULE_FIELDINDEX = fieldindex(Core.TypeName, :module) const TYPENAME_NAMES_FIELDINDEX = fieldindex(Core.TypeName, :names) const TYPENAME_WRAPPER_FIELDINDEX = fieldindex(Core.TypeName, :wrapper) +const TYPENAME_MUTABLE_FIELDINDEX = fieldindex(Core.TypeName, :mutable) +const TYPENAME_ABSTRACT_FIELDINDEX = fieldindex(Core.TypeName, :abstract) +const TYPENAME_HASH_FIELDINDEX = fieldindex(Core.TypeName, :hash) ########## # tfuncs # @@ -88,7 +90,7 @@ function instanceof_tfunc(@nospecialize(t)) # a real instance must be within the declared bounds of the type, # so we can intersect with the original wrapper. tr = typeintersect(tr, t′′.name.wrapper) - isconcrete = !t′′.abstract + isconcrete = !t′′.name.abstract if tr === Union{} # runtime unreachable (our inference Type{T} where S is # uninhabited with any runtime T that exists) @@ -193,7 +195,6 @@ add_tfunc(ne_float, 2, 2, cmp_tfunc, 2) add_tfunc(lt_float, 2, 2, cmp_tfunc, 2) add_tfunc(le_float, 2, 2, cmp_tfunc, 2) add_tfunc(fpiseq, 2, 2, cmp_tfunc, 1) -add_tfunc(fpislt, 2, 2, cmp_tfunc, 1) add_tfunc(eq_float_fast, 2, 2, cmp_tfunc, 1) add_tfunc(ne_float_fast, 2, 2, cmp_tfunc, 1) add_tfunc(lt_float_fast, 2, 2, cmp_tfunc, 1) @@ -272,7 +273,7 @@ function isdefined_tfunc(@nospecialize(arg1), @nospecialize(sym)) return Bool end a1 = unwrap_unionall(a1) - if isa(a1, DataType) && !a1.abstract + if isa(a1, DataType) && !a1.name.abstract if a1 === Module Symbol <: widenconst(sym) || return Bottom if isa(sym, Const) && isa(sym.val, Symbol) && isa(arg1, Const) && isdefined(arg1.val, sym.val) @@ -405,7 +406,7 @@ function nfields_tfunc(@nospecialize(x)) isa(x, Conditional) && return Const(0) x = unwrap_unionall(widenconst(x)) isconstType(x) && return Const(nfields(x.parameters[1])) - if isa(x, DataType) && !x.abstract + if isa(x, DataType) && !x.name.abstract if !(x.name === Tuple.name && isvatuple(x)) && !(x.name === _NAMEDTUPLE_NAME && !isconcretetype(x)) return Const(isdefined(x, :types) ? length(x.types) : length(x.name.names)) @@ -530,7 +531,7 @@ function typeof_tfunc(@nospecialize(t)) return typeof_tfunc(t.ub) elseif isa(t, UnionAll) u = unwrap_unionall(t) - if isa(u, DataType) && !u.abstract + if isa(u, DataType) && !u.name.abstract if u.name === Tuple.name uu = typeof_concrete_vararg(u) if uu !== nothing @@ -613,10 +614,9 @@ is_dt_const_field(fld::Int) = ( fld == DATATYPE_PARAMETERS_FIELDINDEX || fld == DATATYPE_TYPES_FIELDINDEX || fld == DATATYPE_SUPER_FIELDINDEX || - fld == DATATYPE_MUTABLE_FIELDINDEX || fld == DATATYPE_INSTANCE_FIELDINDEX || fld == DATATYPE_NAMES_FIELDINDEX || - fld == DATATYPE_ABSTRACT_FIELDINDEX + fld == DATATYPE_HASH_FIELDINDEX ) function const_datatype_getfield_tfunc(@nospecialize(sv), fld::Int) if fld == DATATYPE_INSTANCE_FIELDINDEX @@ -650,7 +650,7 @@ function fieldcount_noerror(@nospecialize t) end abstr = true else - abstr = t.abstract || (t.name === Tuple.name && isvatuple(t)) + abstr = t.name.abstract || (t.name === Tuple.name && isvatuple(t)) end if abstr return nothing @@ -718,7 +718,7 @@ function getfield_nothrow(@nospecialize(s00), @nospecialize(name), @nospecialize getfield_nothrow(rewrap(s.b, s00), name, inbounds) elseif isa(s, DataType) # Can't say anything about abstract types - s.abstract && return false + s.name.abstract && return false # If all fields are always initialized, and bounds check is disabled, we can assume # we don't throw if bounds_check_disabled && !isvatuple(s) && s.name !== NamedTuple.body.body.name && fieldcount(s) == s.ninitialized @@ -776,6 +776,9 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) if (fld == TYPENAME_NAME_FIELDINDEX || fld == TYPENAME_MODULE_FIELDINDEX || fld == TYPENAME_WRAPPER_FIELDINDEX || + fld == TYPENAME_MUTABLE_FIELDINDEX || + fld == TYPENAME_ABSTRACT_FIELDINDEX || + fld == TYPENAME_HASH_FIELDINDEX || (fld == TYPENAME_NAMES_FIELDINDEX && isdefined(sv, fld))) return Const(getfield(sv, fld)) end @@ -800,7 +803,7 @@ function getfield_tfunc(@nospecialize(s00), @nospecialize(name)) end s = widenconst(s) end - if isType(s) || !isa(s, DataType) || s.abstract + if isType(s) || !isa(s, DataType) || s.name.abstract return Any end s = s::DataType @@ -926,7 +929,7 @@ function _fieldtype_nothrow(@nospecialize(s), exact::Bool, name::Const) return exact ? (a || b) : (a && b) end u isa DataType || return false - u.abstract && return false + u.name.abstract && return false if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u) # TODO: better approximate inference return false @@ -957,8 +960,8 @@ function fieldtype_tfunc(@nospecialize(s0), @nospecialize(name)) end if s0 === Any || s0 === Type || DataType ⊑ s0 || UnionAll ⊑ s0 # For a generic DataType, one of the fields could still be a TypeVar - # which is not a Type - return Union{Type, TypeVar} + # which is not a Type. Tuple{...} can also contain Symbols etc. + return Any end # fieldtype only accepts Types if isa(s0, Const) && !(isa(s0.val, DataType) || isa(s0.val, UnionAll) || isa(s0.val, Union)) @@ -986,14 +989,14 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) return tmerge(_fieldtype_tfunc(rewrap(u.a, s), exact, name), _fieldtype_tfunc(rewrap(u.b, s), exact, name)) end - u isa DataType || return Union{Type, TypeVar} - if u.abstract + u isa DataType || return Any + if u.name.abstract # Abstract types have no fields exact && return Bottom # Type{...} without free typevars has no subtypes, so it is actually # exact, even if `exact` is false. isType(u) && !has_free_typevars(u.parameters[1]) && return Bottom - return Union{Type, TypeVar} + return Any end if u.name === _NAMEDTUPLE_NAME && !isconcretetype(u) # TODO: better approximate inference @@ -1020,8 +1023,15 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) else ft1 = Type{ft1} end + elseif ft1 isa Type || ft1 isa TypeVar + if ft1 === Any && u.name === Tuple.name + # Tuple{:x} is possible in this case + ft1 = Any + else + ft1 = Type{ft} where ft<:ft1 + end else - ft1 = Type{ft} where ft<:ft1 + ft1 = Const(ft1) end t = tmerge(t, ft1) t === Any && break @@ -1044,6 +1054,9 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) else ft = ftypes[fld] end + if !isa(ft, Type) && !isa(ft, TypeVar) + return Const(ft) + end exactft = exact || (!has_free_typevars(ft) && u.name !== Tuple.name) ft = rewrap_unionall(ft, s) @@ -1053,6 +1066,10 @@ function _fieldtype_tfunc(@nospecialize(s), exact::Bool, @nospecialize(name)) end return Type{ft} end + if u.name === Tuple.name && ft === Any + # Tuple{:x} is possible + return Any + end return Type{<:ft} end add_tfunc(fieldtype, 2, 3, fieldtype_tfunc, 0) diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index a20ef946723a7..765aaa730ff18 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -428,8 +428,7 @@ function finish(me::InferenceState, interp::AbstractInterpreter) # prepare to run optimization passes on fulltree s_edges = me.stmt_edges[1] if s_edges === nothing - s_edges = [] - me.stmt_edges[1] = s_edges + s_edges = me.stmt_edges[1] = [] end for edges in me.stmt_edges edges === nothing && continue @@ -540,7 +539,7 @@ function annotate_slot_load!(e::Expr, vtypes::VarTable, sv::InferenceState, unde subex = e.args[i] if isa(subex, Expr) annotate_slot_load!(subex, vtypes, sv, undefs) - elseif isa(subex, Slot) + elseif isa(subex, SlotNumber) e.args[i] = visit_slot_load!(subex, vtypes, sv, undefs) end end @@ -549,13 +548,13 @@ end function annotate_slot_load(@nospecialize(e), vtypes::VarTable, sv::InferenceState, undefs::Array{Bool,1}) if isa(e, Expr) annotate_slot_load!(e, vtypes, sv, undefs) - elseif isa(e, Slot) + elseif isa(e, SlotNumber) return visit_slot_load!(e, vtypes, sv, undefs) end return e end -function visit_slot_load!(sl::Slot, vtypes::VarTable, sv::InferenceState, undefs::Array{Bool,1}) +function visit_slot_load!(sl::SlotNumber, vtypes::VarTable, sv::InferenceState, undefs::Array{Bool,1}) id = slot_id(sl) s = vtypes[id] vt = widenconditional(ignorelimited(s.typ)) @@ -584,7 +583,7 @@ function record_slot_assign!(sv::InferenceState) if isa(st_i, VarTable) && isa(expr, Expr) && expr.head === :(=) lhs = expr.args[1] rhs = expr.args[2] - if isa(lhs, Slot) + if isa(lhs, SlotNumber) vt = widenconst(sv.src.ssavaluetypes[i]) if vt !== Bottom id = slot_id(lhs) @@ -660,7 +659,7 @@ function type_annotate!(sv::InferenceState, run_optimizer::Bool) body[i] = ReturnNode(annotate_slot_load(expr.val, st_i, sv, undefs)) elseif isa(expr, GotoIfNot) body[i] = GotoIfNot(annotate_slot_load(expr.cond, st_i, sv, undefs), expr.dest) - elseif isa(expr, Slot) + elseif isa(expr, SlotNumber) body[i] = visit_slot_load!(expr, st_i, sv, undefs) end else diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index e2668e15c9e2c..6391d4029b58e 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -19,7 +19,7 @@ import Core: Const, PartialStruct # The type of this value might be Bool. -# However, to enable a limited amount of back-propagagation, +# However, to enable a limited amount of back-propagation, # we also keep some information about how this Bool value was created. # In particular, if you branch on this value, then may assume that in # the true branch, the type of `var` will be limited by `vtype` and in @@ -33,7 +33,7 @@ import Core: Const, PartialStruct # end # ``` struct Conditional - var::Slot + var::SlotNumber vtype elsetype function Conditional( @@ -84,14 +84,14 @@ end const VarTable = Array{Any,1} struct StateUpdate - var::Union{Slot,SSAValue} + var::SlotNumber vtype::VarState state::VarTable conditional::Bool end # Represent that the type estimate has been approximated, due to "causes" -# (only used in abstractinterpret, doesn't appear in optimize) +# (only used in abstract interpretion, doesn't appear in optimization) # N.B. in the lattice, this is epsilon smaller than `typ` (except Union{}) struct LimitedAccuracy typ @@ -313,28 +313,26 @@ function widenconditional(typ::AnyConditional) end widenconditional(t::LimitedAccuracy) = error("unhandled LimitedAccuracy") +widenwrappedconditional(@nospecialize(typ)) = widenconditional(typ) +widenwrappedconditional(typ::LimitedAccuracy) = LimitedAccuracy(widenconditional(typ.typ), typ.causes) + ignorelimited(@nospecialize typ) = typ ignorelimited(typ::LimitedAccuracy) = typ.typ function stupdate!(state::Nothing, changes::StateUpdate) newst = copy(changes.state) - if isa(changes.var, Slot) - changeid = slot_id(changes.var::Slot) - newst[changeid] = changes.vtype - # remove any Conditional for this Slot from the vtable - # (unless this change is came from the conditional) - if !changes.conditional - for i = 1:length(newst) - newtype = newst[i] - if isa(newtype, VarState) - newtypetyp = ignorelimited(newtype.typ) - if isa(newtypetyp, Conditional) && slot_id(newtypetyp.var) == changeid - newtypetyp = widenconditional(newtypetyp) - if newtype.typ isa LimitedAccuracy - newtypetyp = LimitedAccuracy(newtypetyp, newtype.typ.causes) - end - newst[i] = VarState(newtypetyp, newtype.undef) - end + changeid = slot_id(changes.var) + newst[changeid] = changes.vtype + # remove any Conditional for this slot from the vtable + # (unless this change is came from the conditional) + if !changes.conditional + for i = 1:length(newst) + newtype = newst[i] + if isa(newtype, VarState) + newtypetyp = ignorelimited(newtype.typ) + if isa(newtypetyp, Conditional) && slot_id(newtypetyp.var) == changeid + newtypetyp = widenwrappedconditional(newtype.typ) + newst[i] = VarState(newtypetyp, newtype.undef) end end end @@ -343,11 +341,8 @@ function stupdate!(state::Nothing, changes::StateUpdate) end function stupdate!(state::VarTable, changes::StateUpdate) - if !isa(changes.var, Slot) - return stupdate!(state, changes.state) - end newstate = nothing - changeid = slot_id(changes.var::Slot) + changeid = slot_id(changes.var) for i = 1:length(state) if i == changeid newtype = changes.vtype @@ -355,15 +350,12 @@ function stupdate!(state::VarTable, changes::StateUpdate) newtype = changes.state[i] end oldtype = state[i] - # remove any Conditional for this Slot from the vtable + # remove any Conditional for this slot from the vtable # (unless this change is came from the conditional) if !changes.conditional && isa(newtype, VarState) newtypetyp = ignorelimited(newtype.typ) if isa(newtypetyp, Conditional) && slot_id(newtypetyp.var) == changeid - newtypetyp = widenconditional(newtypetyp) - if newtype.typ isa LimitedAccuracy - newtypetyp = LimitedAccuracy(newtypetyp, newtype.typ.causes) - end + newtypetyp = widenwrappedconditional(newtype.typ) newtype = VarState(newtypetyp, newtype.undef) end end @@ -393,11 +385,8 @@ stupdate!(state::Nothing, changes::VarTable) = copy(changes) stupdate!(state::Nothing, changes::Nothing) = nothing function stupdate1!(state::VarTable, change::StateUpdate) - if !isa(change.var, Slot) - return false - end - changeid = slot_id(change.var::Slot) - # remove any Conditional for this Slot from the catch block vtable + changeid = slot_id(change.var) + # remove any Conditional for this slot from the catch block vtable # (unless this change is came from the conditional) if !change.conditional for i = 1:length(state) diff --git a/base/compiler/typelimits.jl b/base/compiler/typelimits.jl index cb584a6788f59..372989e114022 100644 --- a/base/compiler/typelimits.jl +++ b/base/compiler/typelimits.jl @@ -128,7 +128,15 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec end return Vararg{VaT} elseif isa(t, DataType) - if isa(c, DataType) + if isa(c, Core.TypeofVararg) + # Tuple{Vararg{T}} --> Tuple{T} is OK + return _limit_type_size(t, c.T, sources, depth, 0) + elseif isType(t) # allow taking typeof as Type{...}, but ensure it doesn't start nesting + tt = unwrap_unionall(t.parameters[1]) + (!isa(tt, DataType) || isType(tt)) && (depth += 1) + is_derived_type_from_any(tt, sources, depth) && return t + return Type + elseif isa(c, DataType) tP = t.parameters cP = c.parameters if t.name === c.name && !isempty(cP) @@ -158,15 +166,6 @@ function _limit_type_size(@nospecialize(t), @nospecialize(c), sources::SimpleVec return Tuple{Q...} end end - elseif isa(c, Core.TypeofVararg) - # Tuple{Vararg{T}} --> Tuple{T} is OK - return _limit_type_size(t, c.T, sources, depth, 0) - end - if isType(t) # allow taking typeof as Type{...}, but ensure it doesn't start nesting - tt = unwrap_unionall(t.parameters[1]) - if isa(tt, DataType) && !isType(tt) - is_derived_type_from_any(tt, sources, depth) && return t - end end if allowed_tuplelen < 1 && t.name === Tuple.name return Any @@ -226,9 +225,19 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe return t !== 1 && !(0 <= t < c) # alternatively, could use !(abs(t) <= abs(c) || abs(t) < n) for some n end # base case for data types - if isa(t, DataType) + if isa(t, Core.TypeofVararg) + if isa(c, Core.TypeofVararg) + return type_more_complex(unwrapva(t), unwrapva(c), sources, depth + 1, tupledepth, 0) + end + elseif isa(t, DataType) tP = t.parameters - if isa(c, DataType) && t.name === c.name + if isa(c, Core.TypeofVararg) + return type_more_complex(t, unwrapva(c), sources, depth, tupledepth, 0) + elseif isType(t) # allow taking typeof any source type anywhere as Type{...}, as long as it isn't nesting Type{Type{...}} + tt = unwrap_unionall(t.parameters[1]) + (!isa(tt, DataType) || isType(tt)) && (depth += 1) + return !is_derived_type_from_any(tt, sources, depth) + elseif isa(c, DataType) && t.name === c.name cP = c.parameters length(cP) < length(tP) && return true length(cP) > length(tP) && !isvarargtype(tP[end]) && depth == 1 && return false @@ -236,7 +245,7 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe # allow creating variation within a nested tuple, but only so deep if t.name === Tuple.name && tupledepth > 0 tupledepth -= 1 - elseif !isvarargtype(t) + else tupledepth = 0 end isgenerator = (t.name.name === :Generator && t.name.module === _topmod(t.name.module)) @@ -247,7 +256,7 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe let tPi = unwrap_unionall(tPi), cPi = unwrap_unionall(cPi) if isa(tPi, DataType) && isa(cPi, DataType) && - !tPi.abstract && !cPi.abstract && + !tPi.name.abstract && !cPi.name.abstract && sym_isless(cPi.name.name, tPi.name.name) # allow collect on (anonymous) Generators to nest, provided that their functions are appropriately ordered # TODO: is there a better way? @@ -258,15 +267,6 @@ function type_more_complex(@nospecialize(t), @nospecialize(c), sources::SimpleVe type_more_complex(tPi, cPi, sources, depth + 1, tupledepth, 0) && return true end return false - elseif isvarargtype(c) - return type_more_complex(t, unwrapva(c), sources, depth, tupledepth, 0) - end - if isType(t) # allow taking typeof any source type anywhere as Type{...}, as long as it isn't nesting Type{Type{...}} - tt = unwrap_unionall(t.parameters[1]) - if isa(tt, DataType) && !isType(tt) - is_derived_type_from_any(tt, sources, depth) || return true - return false - end end end return true diff --git a/base/compiler/validation.jl b/base/compiler/validation.jl index 751b594130ad2..f6b89f8f5cd04 100644 --- a/base/compiler/validation.jl +++ b/base/compiler/validation.jl @@ -51,7 +51,7 @@ const SIGNATURE_NARGS_MISMATCH = "method signature does not match number of meth const SLOTNAMES_NARGS_MISMATCH = "CodeInfo for method contains fewer slotnames than the number of method arguments" struct InvalidCodeError <: Exception - kind::AbstractString + kind::String meta::Any end InvalidCodeError(kind::AbstractString) = InvalidCodeError(kind, nothing) diff --git a/base/complex.jl b/base/complex.jl index 7cf266f2bc4de..4fe736a7c0465 100644 --- a/base/complex.jl +++ b/base/complex.jl @@ -7,6 +7,8 @@ Complex number type with real and imaginary part of type `T`. `ComplexF16`, `ComplexF32` and `ComplexF64` are aliases for `Complex{Float16}`, `Complex{Float32}` and `Complex{Float64}` respectively. + +See also: [`Real`](@ref), [`complex`](@ref), [`real`](@ref). """ struct Complex{T<:Real} <: Number re::T @@ -20,10 +22,15 @@ Complex(x::Real) = Complex(x, zero(x)) The imaginary unit. +See also: [`imag`](@ref), [`angle`](@ref), [`complex`](@ref). + # Examples ```jldoctest julia> im * im -1 + 0im + +julia> (2.0 + 3im)^2 +-5.0 + 12.0im ``` """ const im = Complex(false, true) @@ -54,6 +61,8 @@ float(::Type{Complex{T}}) where {T} = Complex{float(T)} Return the real part of the complex number `z`. +See also: [`imag`](@ref), [`reim`](@ref), [`complex`](@ref), [`isreal`](@ref), [`Real`](@ref). + # Examples ```jldoctest julia> real(1 + 3im) @@ -67,6 +76,8 @@ real(z::Complex) = z.re Return the imaginary part of the complex number `z`. +See also: [`conj`](@ref), [`reim`](@ref), [`adjoint`](@ref), [`angle`](@ref). + # Examples ```jldoctest julia> imag(1 + 3im) @@ -254,6 +265,8 @@ end Compute the complex conjugate of a complex number `z`. +See also: [`angle`](@ref), [`adjoint`](@ref). + # Examples ```jldoctest julia> conj(1 + 3im) @@ -533,6 +546,8 @@ end Return ``\\exp(iz)``. +See also [`cispi`](@ref), [`angle`](@ref). + # Examples ```jldoctest julia> cis(π) ≈ -1 @@ -574,6 +589,8 @@ end Compute the phase angle in radians of a complex number `z`. +See also: [`atan`](@ref), [`cis`](@ref). + # Examples ```jldoctest julia> rad2deg(angle(1 + im)) diff --git a/base/condition.jl b/base/condition.jl index 4b9f57e47ab29..cf0bca8d9dc46 100644 --- a/base/condition.jl +++ b/base/condition.jl @@ -76,7 +76,6 @@ trylock(c::GenericCondition) = trylock(c.lock) islocked(c::GenericCondition) = islocked(c.lock) lock(f, c::GenericCondition) = lock(f, c.lock) -unlock(f, c::GenericCondition) = unlock(f, c.lock) # have waiter wait for c function _wait2(c::GenericCondition, waiter::Task) diff --git a/base/deepcopy.jl b/base/deepcopy.jl index 36c9c399def54..abe8a07fc9a3e 100644 --- a/base/deepcopy.jl +++ b/base/deepcopy.jl @@ -53,7 +53,7 @@ end function deepcopy_internal(@nospecialize(x), stackdict::IdDict) T = typeof(x)::DataType nf = nfields(x) - if T.mutable + if T.name.mutable if haskey(stackdict, x) return stackdict[x] end @@ -87,7 +87,7 @@ end function deepcopy_internal(x::Array, stackdict::IdDict) if haskey(stackdict, x) - return stackdict[x] + return stackdict[x]::typeof(x) end _deepcopy_array_t(x, eltype(x), stackdict) end diff --git a/base/deprecated.jl b/base/deprecated.jl index 45adac55a355c..d60cc3393662c 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -117,12 +117,14 @@ function firstcaller(bt::Vector, funcsyms) end found = lkup.func in funcsyms # look for constructor type name - if !found && lkup.linfo isa Core.MethodInstance + if !found li = lkup.linfo - ft = ccall(:jl_first_argument_datatype, Any, (Any,), li.def.sig) - if isa(ft, DataType) && ft.name === Type.body.name - ft = unwrap_unionall(ft.parameters[1]) - found = (isa(ft, DataType) && ft.name.name in funcsyms) + if li isa Core.MethodInstance + ft = ccall(:jl_first_argument_datatype, Any, (Any,), (li.def::Method).sig) + if isa(ft, DataType) && ft.name === Type.body.name + ft = unwrap_unionall(ft.parameters[1]) + found = (isa(ft, DataType) && ft.name.name in funcsyms) + end end end end @@ -235,7 +237,20 @@ function parameter_upper_bound(t::UnionAll, idx) end # these were internal functions, but some packages seem to be relying on them -@deprecate cat_shape(dims, shape::Tuple{}, shapes::Tuple...) cat_shape(dims, shapes) +@deprecate cat_shape(dims, shape::Tuple{}, shapes::Tuple...) cat_shape(dims, shapes) false cat_shape(dims, shape::Tuple{}) = () # make sure `cat_shape(dims, ())` do not recursively calls itself # END 1.6 deprecations + +# BEGIN 1.7 deprecations + +# the plan is to eventually overload getproperty to access entries of the dict +@noinline function getproperty(x::Pairs, s::Symbol) + depwarn("use values(kwargs) and keys(kwargs) instead of kwargs.data and kwargs.itr", :getproperty, force=true) + return getfield(x, s) +end + +# This function was marked as experimental and not exported. +@deprecate catch_stack(task=current_task(); include_bt=true) current_exceptions(task; backtrace=include_bt) false + +# END 1.7 deprecations diff --git a/base/dict.jl b/base/dict.jl index cc5c9efb6ada8..0ad77959f8225 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -792,12 +792,20 @@ function get(dict::ImmutableDict, key, default) return default end +function get(default::Callable, dict::ImmutableDict, key) + while isdefined(dict, :parent) + isequal(dict.key, key) && return dict.value + dict = dict.parent + end + return default() +end + # this actually defines reverse iteration (e.g. it should not be used for merge/copy/filter type operations) function iterate(d::ImmutableDict{K,V}, t=d) where {K, V} !isdefined(t, :parent) && return nothing (Pair{K,V}(t.key, t.value), t.parent) end -length(t::ImmutableDict) = count(x->true, t) +length(t::ImmutableDict) = count(Returns(true), t) isempty(t::ImmutableDict) = !isdefined(t, :parent) empty(::ImmutableDict, ::Type{K}, ::Type{V}) where {K, V} = ImmutableDict{K,V}() diff --git a/base/div.jl b/base/div.jl index 2df79fbdc6124..226d155a7bc01 100644 --- a/base/div.jl +++ b/base/div.jl @@ -5,14 +5,14 @@ """ div(x, y, r::RoundingMode=RoundToZero) -The quotient from Euclidean division. Computes x/y, rounded to an integer according -to the rounding mode `r`. In other words, the quantity +The quotient from Euclidean (integer) division. Computes x/y, rounded to +an integer according to the rounding mode `r`. In other words, the quantity round(x/y,r) without any intermediate rounding. -See also: [`fld`](@ref), [`cld`](@ref) which are special cases of this function +See also [`fld`](@ref) and [`cld`](@ref), which are special cases of this function. # Examples: ```jldoctest @@ -88,12 +88,16 @@ rem(x::Integer, y::Integer, r::RoundingMode{:Nearest}) = divrem(x, y, r)[2] Largest integer less than or equal to `x/y`. Equivalent to `div(x, y, RoundDown)`. -See also: [`div`](@ref) +See also [`div`](@ref), [`cld`](@ref), [`fld1`](@ref). # Examples ```jldoctest julia> fld(7.3,5.5) 1.0 + +julia> fld.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + -2 -2 -1 -1 -1 0 0 0 1 1 1 ``` Because `fld(x, y)` implements strictly correct floored rounding based on the true value of floating-point numbers, unintuitive situations can arise. For example: @@ -118,12 +122,16 @@ fld(a, b) = div(a, b, RoundDown) Smallest integer larger than or equal to `x/y`. Equivalent to `div(x, y, RoundUp)`. -See also: [`div`](@ref) +See also [`div`](@ref), [`fld`](@ref). # Examples ```jldoctest julia> cld(5.5,2.2) 3.0 + +julia> cld.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + -1 -1 -1 0 0 0 1 1 1 2 2 ``` """ cld(a, b) = div(a, b, RoundUp) @@ -136,6 +144,8 @@ The quotient and remainder from Euclidean division. Equivalent to `(div(x,y,r), rem(x,y,r))`. Equivalently, with the default value of `r`, this call is equivalent to `(x÷y, x%y)`. +See also: [`fldmod`](@ref), [`cld`](@ref). + # Examples ```jldoctest julia> divrem(3,7) @@ -211,6 +221,8 @@ end The floored quotient and modulus after division. A convenience wrapper for `divrem(x, y, RoundDown)`. Equivalent to `(fld(x,y), mod(x,y))`. + +See also: [`fld`](@ref), [`cld`](@ref), [`fldmod1`](@ref). """ fldmod(x,y) = divrem(x, y, RoundDown) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 5233b08e0ead3..d45fbd3ee07d2 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -276,6 +276,19 @@ julia> z """ kw"global" +""" + ' ' + +A pair of single-quote characters delimit a [`Char`](@ref) (that is, character) literal. + +# Examples +```jldoctest +julia> 'j' +'j': ASCII/Unicode U+006A (category Ll: Letter, lowercase) +``` +""" +kw"''" + """ = @@ -452,6 +465,18 @@ For other purposes, `:( ... )` and `quote .. end` blocks are treated identically """ kw"quote" +""" + @ + +The at sign followed by a macro name marks a macro call. Macros provide the +ability to include generated code in the final body of a program. A macro maps +a tuple of arguments, expressed as space-separated expressions or a +function-call-like argument list, to a returned *expression*. The resulting +expression is compiled directly into the surrounding code. See +[Metaprogramming](@ref man-macros) for more details and examples. +""" +kw"@" + """ {} @@ -602,6 +627,32 @@ the last expression in the function body. """ kw"function" +""" + x -> y + +Create an anonymous function mapping argument(s) `x` to the function body `y`. + +```jldoctest +julia> f = x -> x^2 + 2x - 1 +#1 (generic function with 1 method) + +julia> f(2) +7 +``` + +Anonymous functions can also be defined for multiple argumets. +```jldoctest +julia> g = (x,y) -> x^2 + y^2 +#2 (generic function with 1 method) + +julia> g(2,3) +13 +``` + +See the manual section on [anonymous functions](@ref man-anonymous-functions) for more details. +""" +kw"->" + """ return @@ -692,7 +743,7 @@ See the manual section on [control flow](@ref man-conditional-evaluation) for mo ``` julia> x = 1; y = 2; -julia> println(x > y ? "x is larger" : "y is larger") +julia> x > y ? println("x is larger") : println("y is larger") y is larger ``` """ @@ -950,6 +1001,19 @@ kw";" x && y Short-circuiting boolean AND. + +See also [`&`](@ref), the ternary operator `? :`, and the manual section on [control flow](@ref man-conditional-evaluation). + +# Examples +```jldoctest +julia> x = 3; + +julia> x > 1 && x < 10 && x isa Int +true + +julia> x < 0 && error("expected positive x") +false +``` """ kw"&&" @@ -957,6 +1021,17 @@ kw"&&" x || y Short-circuiting boolean OR. + +See also: [`|`](@ref), [`xor`](@ref), [`&&`](@ref). + +# Examples +```jldoctest +julia> pi < 3 || ℯ < 3 +true + +julia> false || true || println("neither is true!") +true +``` """ kw"||" @@ -1180,6 +1255,8 @@ devnull Nothing A type with no fields that is the type of [`nothing`](@ref). + +See also: [`isnothing`](@ref), [`Some`](@ref), [`Missing`](@ref). """ Nothing @@ -1188,6 +1265,8 @@ Nothing The singleton instance of type [`Nothing`](@ref), used by convention when there is no value to return (as in a C `void` function) or when a variable or field holds no value. + +See also: [`isnothing`](@ref), [`something`](@ref), [`missing`](@ref). """ nothing @@ -1730,6 +1809,8 @@ NaN julia> false * NaN 0.0 ``` + +See also: [`digits`](@ref), [`iszero`](@ref), [`NaN`](@ref). """ Bool @@ -1816,10 +1897,18 @@ Symbol(x...) Construct a tuple of the given objects. +See also [`Tuple`](@ref), [`NamedTuple`](@ref). + # Examples ```jldoctest -julia> tuple(1, 'a', pi) -(1, 'a', π) +julia> tuple(1, 'b', pi) +(1, 'b', π) + +julia> ans === (1, 'b', π) +true + +julia> Tuple(Real[1, 2, pi]) # takes a collection +(1, 2, π) ``` """ tuple @@ -1882,6 +1971,8 @@ setfield! Get the concrete type of `x`. +See also [`eltype`](@ref). + # Examples ```jldoctest julia> a = 1//2; @@ -1938,7 +2029,7 @@ isdefined """ Vector{T}(undef, n) -Construct an uninitialized [`Vector{T}`](@ref) of length `n`. See [`undef`](@ref). +Construct an uninitialized [`Vector{T}`](@ref) of length `n`. # Examples ```julia-repl @@ -1988,14 +2079,19 @@ Vector{T}(::Missing, n) """ Matrix{T}(undef, m, n) -Construct an uninitialized [`Matrix{T}`](@ref) of size `m`×`n`. See [`undef`](@ref). +Construct an uninitialized [`Matrix{T}`](@ref) of size `m`×`n`. # Examples ```julia-repl julia> Matrix{Float64}(undef, 2, 3) 2×3 Array{Float64, 2}: - 6.93517e-310 6.93517e-310 6.93517e-310 - 6.93517e-310 6.93517e-310 1.29396e-320 + 2.36365e-314 2.28473e-314 5.0e-324 + 2.26704e-314 2.26711e-314 NaN + +julia> similar(ans, Int32, 2, 2) +2×2 Matrix{Int32}: + 490537216 1277177453 + 1 1936748399 ``` """ Matrix{T}(::UndefInitializer, m, n) @@ -2043,19 +2139,28 @@ containing elements of type `T`. `N` can either be supplied explicitly, as in `Array{T,N}(undef, dims)`, or be determined by the length or number of `dims`. `dims` may be a tuple or a series of integer arguments corresponding to the lengths in each dimension. If the rank `N` is supplied explicitly, then it must -match the length or number of `dims`. See [`undef`](@ref). +match the length or number of `dims`. Here [`undef`](@ref) is +the [`UndefInitializer`](@ref). # Examples ```julia-repl julia> A = Array{Float64, 2}(undef, 2, 3) # N given explicitly -2×3 Array{Float64, 2}: +2×3 Matrix{Float64}: 6.90198e-310 6.90198e-310 6.90198e-310 6.90198e-310 6.90198e-310 0.0 -julia> B = Array{Float64}(undef, 2) # N determined by the input -2-element Array{Float64, 1}: - 1.87103e-320 - 0.0 +julia> B = Array{Float64}(undef, 4) # N determined by the input +4-element Vector{Float64}: + 2.360075077e-314 + NaN + 2.2671131793e-314 + 2.299821756e-314 + +julia> similar(B, 2, 4, 1) # use typeof(B), and the given size +2×4×1 Array{Float64, 3}: +[:, :, 1] = + 2.26703e-314 2.26708e-314 0.0 2.80997e-314 + 0.0 2.26703e-314 2.26708e-314 0.0 ``` """ Array{T,N}(::UndefInitializer, dims) @@ -2132,10 +2237,12 @@ Alias for `UndefInitializer()`, which constructs an instance of the singleton ty [`UndefInitializer`](@ref), used in array initialization to indicate the array-constructor-caller would like an uninitialized array. +See also: [`missing`](@ref), [`similar`](@ref). + # Examples ```julia-repl julia> Array{Float64, 1}(undef, 3) -3-element Array{Float64, 1}: +3-element Vector{Float64}: 2.2752528595e-314 2.202942107e-314 2.275252907e-314 @@ -2171,6 +2278,8 @@ julia> +(1, 20, 4) Unary minus operator. +See also: [`abs`](@ref), [`flipsign`](@ref). + # Examples ```jldoctest julia> -1 @@ -2276,6 +2385,9 @@ AssertionError An error occurred while [`include`](@ref Base.include)ing, [`require`](@ref Base.require)ing, or [`using`](@ref) a file. The error specifics should be available in the `.error` field. + +!!! compat "Julia 1.7" + LoadErrors are no longer emitted by `@macroexpand`, `@macroexpand1`, and `macroexpand` as of Julia 1.7. """ LoadError @@ -2379,6 +2491,8 @@ number of trailing elements. `Vararg{T,N}` corresponds to exactly `N` elements o `Vararg{T}` corresponds to zero or more elements of type `T`. `Vararg` tuple types are used to represent the arguments accepted by varargs methods (see the section on [Varargs Functions](@ref) in the manual.) +See also [`NTuple`](@ref). + # Examples ```jldoctest julia> mytupletype = Tuple{AbstractString, Vararg{Int}} @@ -2411,6 +2525,8 @@ is considered an abstract type, and tuple types are only concrete if their param field names; fields are only accessed by index. See the manual section on [Tuple Types](@ref). + +See also [`Vararg`](@ref), [`NTuple`](@ref), [`tuple`](@ref), [`NamedTuple`](@ref). """ Tuple @@ -2582,4 +2698,46 @@ A quoted piece of code, that does not support interpolation. See the [manual sec """ QuoteNode + +""" + " +`"` Is used to delimit string literals. + +# Examples + +```jldoctest +julia> "Hello World!" +"Hello World!" + +julia> "Hello World!\\n" +"Hello World!\\n" +``` + +See also [`\"""`](@ref \"\"\"). +""" +kw"\"" + +""" + \""" +`\"""` is used to delimit string literals. Strings created by triple quotation marks can contain `"` characters without escaping and are dedented to the level of the least-indented line. This is useful for defining strings within code that is indented. + +# Examples + +```jldoctest +julia> \"""Hello World!\""" +"Hello World!" + +julia> \"""Contains "quote" characters\""" +"Contains \\"quote\\" characters" + +julia> \""" + Hello, + world.\""" +"Hello,\\nworld." +``` + +See also [`"`](@ref \") +""" +kw"\"\"\"" + end diff --git a/base/docs/utils.jl b/base/docs/utils.jl index 841af2d2c2b9b..cac029295d81e 100644 --- a/base/docs/utils.jl +++ b/base/docs/utils.jl @@ -43,6 +43,12 @@ show(io::IO, ::MIME"text/html", h::HTML{<:Function}) = h.content(io) @html_str -> Docs.HTML Create an `HTML` object from a literal string. + +# Examples +```jldoctest +julia> html"Julia" +HTML{String}("Julia") +``` """ macro html_str(s) :(HTML($s)) @@ -89,6 +95,12 @@ hash(t::T, h::UInt) where {T<:Union{HTML,Text}} = hash(T, hash(t.content, h)) @text_str -> Docs.Text Create a `Text` object from a literal string. + +# Examples +```jldoctest +julia> text"Julia" +Julia +``` """ macro text_str(s) :(Text($s)) diff --git a/base/env.jl b/base/env.jl index 8f5256f25915e..7d47a4de090a3 100644 --- a/base/env.jl +++ b/base/env.jl @@ -32,7 +32,7 @@ if Sys.iswindows() function _unsetenv(svar::AbstractString) var = cwstring(svar) ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL) - windowserror(:setenv, ret == 0) + windowserror(:setenv, ret == 0 && Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND) end else # !windows _getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) @@ -77,7 +77,7 @@ variable may result in an uppercase `ENV` key.) const ENV = EnvDict() getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k) -get(::EnvDict, k::AbstractString, def) = access_env(k->def, k) +get(::EnvDict, k::AbstractString, def) = access_env(Returns(def), k) get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k) in(k::AbstractString, ::KeySet{String, EnvDict}) = _hasenv(k) pop!(::EnvDict, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v) @@ -87,7 +87,7 @@ setindex!(::EnvDict, v, k::AbstractString) = _setenv(k,string(v)) push!(::EnvDict, kv::Pair{<:AbstractString}) = setindex!(ENV, kv.second, kv.first) if Sys.iswindows() - GESW() = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos)) + GESW() = (pos = ccall(:GetEnvironmentStringsW, stdcall, Ptr{UInt16}, ()); (pos, pos)) function winuppercase(s::AbstractString) isempty(s) && return s LOCALE_INVARIANT = 0x0000007f @@ -99,32 +99,43 @@ if Sys.iswindows() return transcode(String, ws) end function iterate(hash::EnvDict, block::Tuple{Ptr{UInt16},Ptr{UInt16}} = GESW()) - if unsafe_load(block[1]) == 0 - ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2]) - return nothing + while true + if unsafe_load(block[1]) == 0 + ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2]) + return nothing + end + pos = block[1] + blk = block[2] + len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos) + buf = Vector{UInt16}(undef, len) + GC.@preserve buf unsafe_copyto!(pointer(buf), pos, len) + env = transcode(String, buf) + pos += (len + 1) * 2 + if !isempty(env) + m = findnext('=', env, nextind(env, firstindex(env))) + else + m = nothing + end + if m === nothing + @warn "malformed environment entry: $env" + continue + end + return (Pair{String,String}(winuppercase(env[1:prevind(env, m)]), env[nextind(env, m):end]), (pos, blk)) end - pos = block[1] - blk = block[2] - len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos) - buf = Vector{UInt16}(undef, len) - GC.@preserve buf unsafe_copyto!(pointer(buf), pos, len) - env = transcode(String, buf) - m = match(r"^(=?[^=]+)=(.*)$"s, env) - if m === nothing - error("malformed environment entry: $env") - end - return (Pair{String,String}(winuppercase(m.captures[1]), m.captures[2]), (pos+(len+1)*2, blk)) end else # !windows function iterate(::EnvDict, i=0) - env = ccall(:jl_environ, Any, (Int32,), i) - env === nothing && return nothing - env = env::String - m = match(r"^(.*?)=(.*)$"s, env) - if m === nothing - error("malformed environment entry: $env") + while true + env = ccall(:jl_environ, Any, (Int32,), i) + env === nothing && return nothing + env = env::String + m = findfirst('=', env) + if m === nothing + @warn "malformed environment entry: $env" + nothing + end + return (Pair{String,String}(env[1:prevind(env, m)], env[nextind(env, m):end]), i+1) end - return (Pair{String,String}(m.captures[1], m.captures[2]), i+1) end end # os-test diff --git a/base/error.jl b/base/error.jl index 72c13396e3fc4..9116d00618900 100644 --- a/base/error.jl +++ b/base/error.jl @@ -54,7 +54,7 @@ exception will continue propagation as if it had not been caught. the program state at the time of the error so you're encouraged to instead throw a new exception using `throw(e)`. In Julia 1.1 and above, using `throw(e)` will preserve the root cause exception on the stack, as - described in [`catch_stack`](@ref). + described in [`current_exceptions`](@ref). """ rethrow() = ccall(:jl_rethrow, Bottom, ()) rethrow(@nospecialize(e)) = ccall(:jl_rethrow_other, Bottom, (Any,), e) @@ -123,32 +123,38 @@ function catch_backtrace() return _reformat_bt(bt::Vector{Ptr{Cvoid}}, bt2::Vector{Any}) end +struct ExceptionStack <: AbstractArray{Any,1} + stack +end + """ - catch_stack(task=current_task(); [inclue_bt=true]) + current_exceptions(task=current_task(); [inclue_bt=true]) Get the stack of exceptions currently being handled. For nested catch blocks there may be more than one current exception in which case the most recently -thrown exception is last in the stack. The stack is returned as a Vector of -`(exception,backtrace)` pairs, or a Vector of exceptions if `include_bt` is -false. +thrown exception is last in the stack. The stack is returned as an +`ExceptionStack` which is an AbstractVector of named tuples +`(exception,backtrace)`. If `backtrace` is false, the backtrace in each pair +will be set to `nothing`. Explicitly passing `task` will return the current exception stack on an arbitrary task. This is useful for inspecting tasks which have failed due to uncaught exceptions. -!!! compat "Julia 1.1" - This function is experimental in Julia 1.1 and will likely be renamed in a - future release (see https://github.com/JuliaLang/julia/pull/29901). +!!! compat "Julia 1.7" + This function went by the experiemental name `catch_stack()` in Julia + 1.1–1.6, and had a plain Vector-of-tuples as a return type. """ -function catch_stack(task=current_task(); include_bt=true) - raw = ccall(:jl_get_excstack, Any, (Any,Cint,Cint), task, include_bt, typemax(Cint))::Vector{Any} +function current_exceptions(task=current_task(); backtrace=true) + raw = ccall(:jl_get_excstack, Any, (Any,Cint,Cint), task, backtrace, typemax(Cint))::Vector{Any} formatted = Any[] - stride = include_bt ? 3 : 1 + stride = backtrace ? 3 : 1 for i = reverse(1:stride:length(raw)) - e = raw[i] - push!(formatted, include_bt ? (e,Base._reformat_bt(raw[i+1],raw[i+2])) : e) + exc = raw[i] + bt = backtrace ? Base._reformat_bt(raw[i+1],raw[i+2]) : nothing + push!(formatted, (exception=exc,backtrace=bt)) end - formatted + ExceptionStack(formatted) end ## keyword arg lowering generates calls to this ## diff --git a/base/errorshow.jl b/base/errorshow.jl index 2baf5d2471315..1d2745f63b297 100644 --- a/base/errorshow.jl +++ b/base/errorshow.jl @@ -9,7 +9,7 @@ This method is used to display the exception after a call to [`throw`](@ref). # Examples ```jldoctest julia> struct MyException <: Exception - msg::AbstractString + msg::String end julia> function Base.showerror(io::IO, err::MyException) @@ -92,7 +92,7 @@ function showerror(io::IO, ex, bt; backtrace=true) end function showerror(io::IO, ex::LoadError, bt; backtrace=true) - print(io, "LoadError: ") + !isa(ex.error, LoadError) && print(io, "LoadError: ") showerror(io, ex.error, bt, backtrace=backtrace) print(io, "\nin expression starting at $(ex.file):$(ex.line)") end @@ -159,14 +159,8 @@ showerror(io::IO, ex::UndefKeywordError) = print(io, "UndefKeywordError: keyword argument $(ex.var) not assigned") function showerror(io::IO, ex::UndefVarError) - if ex.var in [:UTF16String, :UTF32String, :WString, :utf16, :utf32, :wstring, :RepString] - return showerror(io, ErrorException(""" - `$(ex.var)` has been moved to the package LegacyStrings.jl: - Run Pkg.add("LegacyStrings") to install LegacyStrings on Julia v0.5-; - Then do `using LegacyStrings` to get `$(ex.var)`. - """)) - end print(io, "UndefVarError: $(ex.var) not defined") + Experimental.show_error_hints(io, ex) end function showerror(io::IO, ex::InexactError) @@ -248,7 +242,7 @@ function showerror(io::IO, ex::MethodError) if f === Base.convert && length(arg_types_param) == 2 && !is_arg_types f_is_function = true show_convert_error(io, ex, arg_types_param) - elseif isempty(methods(f)) && isa(f, DataType) && f.abstract + elseif isempty(methods(f)) && isa(f, DataType) && f.name.abstract print(io, "no constructors have been defined for ", f) elseif isempty(methods(f)) && !isa(f, Function) && !isa(f, Type) print(io, "objects of type ", ft, " are not callable") @@ -552,13 +546,6 @@ end # replace `sf` as needed. const update_stackframes_callback = Ref{Function}(identity) -function replaceuserpath(str) - str = replace(str, homedir() => "~") - # seems to be necessary for some paths with small letter drive c:// etc - str = replace(str, lowercasefirst(homedir()) => "~") - return str -end - const STACKTRACE_MODULECOLORS = [:magenta, :cyan, :green, :yellow] const STACKTRACE_FIXEDCOLORS = IdDict(Base => :light_black, Core => :light_black) @@ -698,7 +685,7 @@ end function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, modulecolor) file, line = string(frame.file), frame.line stacktrace_expand_basepaths() && (file = something(find_source_file(file), file)) - stacktrace_contract_userdir() && (file = replaceuserpath(file)) + stacktrace_contract_userdir() && (file = contractuser(file)) # Used by the REPL to make it possible to open # the location of a stackframe/method in the editor. @@ -738,13 +725,7 @@ function print_stackframe(io, i, frame::StackFrame, n::Int, digit_align_width, m # filename, separator, line # use escape codes for formatting, printstyled can't do underlined and color # codes are bright black (90) and underlined (4) - function print_underlined(io::IO, s...) - colored = get(io, :color, false)::Bool - start_s = colored ? "\033[90;4m" : "" - end_s = colored ? "\033[0m" : "" - print(io, start_s, s..., end_s) - end - print_underlined(io, pathparts[end], ":", line) + printstyled(io, pathparts[end], ":", line; color = :light_black, underline = true) # inlined printstyled(io, inlined ? " [inlined]" : "", color = :light_black) @@ -868,7 +849,7 @@ function process_backtrace(t::Vector, limit::Int=typemax(Int); skipC = true) return _simplify_include_frames(ret) end -function show_exception_stack(io::IO, stack::Vector) +function show_exception_stack(io::IO, stack) # Display exception stack with the top of the stack first. This ordering # means that the user doesn't have to scroll up in the REPL to discover the # root cause. @@ -892,3 +873,29 @@ function show(io::IO, ip::InterpreterIP) print(io, " in $(ip.code) at statement $(Int(ip.stmt))") end end + +# handler for displaying a hint in case the user tries to call +# the instance of a number (probably missing the operator) +# eg: (1 + 2)(3 + 4) +function noncallable_number_hint_handler(io, ex, arg_types, kwargs) + @nospecialize + if ex.f isa Number + print(io, "\nMaybe you forgot to use an operator such as ") + printstyled(io, "*, ^, %, / etc. ", color=:cyan) + print(io, "?") + end +end + +Experimental.register_error_hint(noncallable_number_hint_handler, MethodError) + +# ExceptionStack implementation +size(s::ExceptionStack) = size(s.stack) +getindex(s::ExceptionStack, i::Int) = s.stack[i] + +function show(io::IO, ::MIME"text/plain", stack::ExceptionStack) + nexc = length(stack) + printstyled(io, nexc, "-element ExceptionStack", nexc == 0 ? "" : ":\n") + show_exception_stack(io, stack) +end +show(io::IO, stack::ExceptionStack) = show(io, MIME("text/plain"), stack) + diff --git a/base/essentials.jl b/base/essentials.jl index 1a0e971d3a73f..d9a9ab4b0d721 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -26,7 +26,7 @@ abstract type AbstractDict{K,V} end """ Iterators.Pairs(values, keys) <: AbstractDict{eltype(keys), eltype(values)} -Transforms an indexable container into an Dictionary-view of the same data. +Transforms an indexable container into a Dictionary-view of the same data. Modifying the key-space of the underlying data may invalidate this object. """ struct Pairs{K, V, I, A} <: AbstractDict{K, V} @@ -131,7 +131,8 @@ end Tests whether variable `s` is defined in the current scope. -See also [`isdefined`](@ref). +See also [`isdefined`](@ref) for field properties and [`isassigned`](@ref) for +array indexes or [`haskey`](@ref) for other mappings. # Examples ```jldoctest @@ -217,6 +218,8 @@ julia> y = convert(Vector{Int}, x); julia> y === x true ``` + +See also: [`round`](@ref), [`trunc`](@ref), [`oftype`](@ref), [`reinterpret`](@ref). """ function convert end @@ -249,6 +252,8 @@ argtail(x, rest...) = rest Return a `Tuple` consisting of all but the first component of `x`. +See also: [`front`](@ref Base.front), [`rest`](@ref Base.rest), [`first`](@ref), [`Iterators.peel`](@ref). + # Examples ```jldoctest julia> Base.tail((1,2,3)) @@ -809,6 +814,8 @@ values(itr) = itr A type with no fields whose singleton instance [`missing`](@ref) is used to represent missing values. + +See also: [`skipmissing`](@ref), [`nonmissingtype`](@ref), [`Nothing`](@ref). """ struct Missing end @@ -816,6 +823,8 @@ struct Missing end missing The singleton instance of type [`Missing`](@ref) representing a missing value. + +See also: [`NaN`](@ref), [`skipmissing`](@ref), [`nonmissingtype`](@ref). """ const missing = Missing() @@ -823,6 +832,8 @@ const missing = Missing() ismissing(x) Indicate whether `x` is [`missing`](@ref). + +See also: [`skipmissing`](@ref), [`isnothing`](@ref), [`isnan`](@ref). """ ismissing(x) = x === missing diff --git a/base/experimental.jl b/base/experimental.jl index b928b6ba0e1d9..7e30792dda4e8 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -114,7 +114,8 @@ parent module. Supported values are 0, 1, 2, and 3. The effective optimization level is the minimum of that specified on the -command line and in per-module settings. +command line and in per-module settings. If a `--min-optlevel` value is +set on the command line, that is enforced as a lower bound. """ macro optlevel(n::Int) return Expr(:meta, :optlevel, n) diff --git a/base/exports.jl b/base/exports.jl index adfb1772600d3..f27ac7f96c883 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -70,6 +70,7 @@ export Rational, Regex, RegexMatch, + Returns, RoundFromZero, RoundDown, RoundingMode, @@ -168,6 +169,10 @@ export ≢, xor, ⊻, + nand, + nor, + ⊼, + ⊽, %, ÷, &, @@ -386,6 +391,7 @@ export first, hcat, hvcat, + hvncat, indexin, argmax, argmin, @@ -498,6 +504,7 @@ export count, delete!, deleteat!, + keepat!, eltype, empty!, empty, @@ -670,6 +677,7 @@ export istaskstarted, istaskfailed, lock, + @lock, notify, ReentrantLock, schedule, @@ -682,6 +690,7 @@ export timedwait, asyncmap, asyncmap!, + errormonitor, # channels take!, @@ -692,9 +701,11 @@ export # missing values coalesce, + @coalesce, ismissing, missing, skipmissing, + @something, something, isnothing, nonmissingtype, @@ -707,6 +718,7 @@ export # errors backtrace, catch_backtrace, + current_exceptions, error, rethrow, retry, @@ -821,6 +833,7 @@ export readline, readlines, readuntil, + redirect_stdio, redirect_stderr, redirect_stdin, redirect_stdout, @@ -912,7 +925,7 @@ export uperm, walkdir, -# external processes ## TODO: whittle down these exports. +# external processes detach, getpid, ignorestatus, diff --git a/base/expr.jl b/base/expr.jl index 38a1c4e7089cb..4d6401b002a76 100644 --- a/base/expr.jl +++ b/base/expr.jl @@ -230,12 +230,6 @@ end `@pure` gives the compiler a hint for the definition of a pure function, helping for type inference. -A pure function can only depend on immutable information. -This also means a `@pure` function cannot use any global mutable state, including -generic functions. Calls to generic functions depend on method tables which are -mutable global state. -Use with caution, incorrect `@pure` annotation of a function may introduce -hard to identify bugs. Double check for calls to generic functions. This macro is intended for internal compiler use and may be subject to changes. """ macro pure(ex) diff --git a/base/fastmath.jl b/base/fastmath.jl index a7d8b86fcb26a..c01a8a5b225f7 100644 --- a/base/fastmath.jl +++ b/base/fastmath.jl @@ -273,6 +273,9 @@ end # Math functions +exp2_fast(x::Union{Float32,Float64}) = Base.Math.exp2_fast(x) +exp_fast(x::Union{Float32,Float64}) = Base.Math.exp_fast(x) +exp10_fast(x::Union{Float32,Float64}) = Base.Math.exp10_fast(x) # builtins @@ -282,28 +285,6 @@ pow_fast(x::FloatTypes, ::Val{p}) where {p} = pow_fast(x, p) # inlines already v @inline pow_fast(x, v::Val) = Base.literal_pow(^, x, v) sqrt_fast(x::FloatTypes) = sqrt_llvm_fast(x) - -# libm - -const libm = Base.libm_name - -for f in (:acosh, :asinh, :atanh, :cbrt, - :cosh, :exp2, :expm1, :log10, :log1p, :log2, - :log, :sinh, :tanh) - f_fast = fast_op[f] - @eval begin - $f_fast(x::Float32) = - ccall(($(string(f,"f")),libm), Float32, (Float32,), x) - $f_fast(x::Float64) = - ccall(($(string(f)),libm), Float64, (Float64,), x) - end -end - -pow_fast(x::Float32, y::Float32) = - ccall(("powf",libm), Float32, (Float32,Float32), x, y) -pow_fast(x::Float64, y::Float64) = - ccall(("pow",libm), Float64, (Float64,Float64), x, y) - sincos_fast(v::FloatTypes) = sincos(v) @inline function sincos_fast(v::Float16) diff --git a/base/file.jl b/base/file.jl index e1e323700344f..3a038863107bc 100644 --- a/base/file.jl +++ b/base/file.jl @@ -34,6 +34,8 @@ export Get the current working directory. +See also: [`cd`](@ref), [`tempdir`](@ref). + # Examples ```julia-repl julia> pwd() @@ -67,6 +69,8 @@ end Set the current working directory. +See also: [`pwd`](@ref), [`mkdir`](@ref), [`mkpath`](@ref), [`mktempdir`](@ref). + # Examples ```julia-repl julia> cd("/home/JuliaUser/Projects/julia") @@ -673,6 +677,8 @@ the temporary directory is automatically deleted when the process exits. The `cleanup` keyword argument was added in Julia 1.3. Relatedly, starting from 1.3, Julia will remove the temporary paths created by `mktempdir` when the Julia process exits, unless `cleanup` is explicitly set to `false`. + +See also: [`mktemp`](@ref), [`mkdir`](@ref). """ function mktempdir(parent::AbstractString=tempdir(); prefix::AbstractString=temp_prefix, cleanup::Bool=true) @@ -707,6 +713,8 @@ end Apply the function `f` to the result of [`mktemp(parent)`](@ref) and remove the temporary file upon completion. + +See also: [`mktempdir`](@ref). """ function mktemp(fn::Function, parent::AbstractString=tempdir()) (tmp_path, tmp_io) = mktemp(parent, cleanup=false) @@ -730,6 +738,8 @@ end Apply the function `f` to the result of [`mktempdir(parent; prefix)`](@ref) and remove the temporary directory all of its contents upon completion. +See also: [`mktemp`](@ref), [`mkdir`](@ref). + !!! compat "Julia 1.2" The `prefix` keyword argument was added in Julia 1.2. """ diff --git a/base/float.jl b/base/float.jl index cb4000b51fac2..06603940f8f19 100644 --- a/base/float.jl +++ b/base/float.jl @@ -36,6 +36,20 @@ const Inf = Inf64 Inf, Inf64 Positive infinity of type [`Float64`](@ref). + +See also: [`isfinite`](@ref), [`typemax`](@ref), [`NaN`](@ref), [`Inf32`](@ref). + +# Examples +```jldoctest +julia> π/0 +Inf + +julia> +1.0 / -0.0 +-Inf + +julia> ℯ^-Inf +0.0 +``` """ Inf, Inf64 @@ -44,6 +58,20 @@ const NaN = NaN64 NaN, NaN64 A not-a-number value of type [`Float64`](@ref). + +See also: [`isnan`](@ref), [`missing`](@ref), [`NaN32`](@ref), [`Inf`](@ref). + +# Examples +```jldoctest +julia> 0/0 +NaN + +julia> Inf - Inf +NaN + +julia> NaN == NaN, isequal(NaN, NaN), NaN === NaN +(false, true, true) +``` """ NaN, NaN64 @@ -226,6 +254,17 @@ Bool(x::Float16) = x==0 ? false : x==1 ? true : throw(InexactError(:Bool, Bool, float(x) Convert a number or array to a floating point data type. + +See also: [`complex`](@ref), [`oftype`](@ref), [`convert`](@ref). + +# Examples +```jldoctest +julia> float(1:1000) +1.0:1.0:1000.0 + +julia> float(typemax(Int32)) +2.147483647e9 +``` """ float(x) = AbstractFloat(x) @@ -400,9 +439,19 @@ end isequal(x::Float16, y::Float16) = fpiseq(x, y) isequal(x::Float32, y::Float32) = fpiseq(x, y) isequal(x::Float64, y::Float64) = fpiseq(x, y) -isless( x::Float16, y::Float16) = fpislt(x, y) -isless( x::Float32, y::Float32) = fpislt(x, y) -isless( x::Float64, y::Float64) = fpislt(x, y) + +# interpret as sign-magnitude integer +@inline function _fpint(x) + IntT = inttype(typeof(x)) + ix = reinterpret(IntT, x) + return ifelse(ix < zero(IntT), ix ⊻ typemax(IntT), ix) +end + +@inline function isless(a::T, b::T) where T<:IEEEFloat + (isnan(a) || isnan(b)) && return !isnan(a) + + return _fpint(a) < _fpint(b) +end # Exact Float (Tf) vs Integer (Ti) comparisons # Assumes: @@ -418,7 +467,7 @@ isless( x::Float64, y::Float64) = fpislt(x, y) # b. unsafe_convert undefined behaviour if fy == Tf(typemax(Ti)) # (but consequently x == fy > y) for Ti in (Int64,UInt64,Int128,UInt128) - for Tf in (Float16,Float32,Float64) + for Tf in (Float32,Float64) @eval begin function ==(x::$Tf, y::$Ti) fy = ($Tf)(y) @@ -469,6 +518,8 @@ abs(x::Float64) = abs_float(x) Test whether a number value is a NaN, an indeterminate value which is neither an infinity nor a finite number ("not a number"). + +See also: [`iszero`](@ref), [`isone`](@ref), [`isinf`](@ref), [`ismissing`](@ref). """ isnan(x::AbstractFloat) = (x != x)::Bool isnan(x::Number) = false @@ -481,6 +532,8 @@ isfinite(x::Integer) = true isinf(f) -> Bool Test whether a number is infinite. + +See also: [`Inf`](@ref), [`iszero`](@ref), [`isfinite`](@ref), [`isnan`](@ref). """ isinf(x::Real) = !isnan(x) & !isfinite(x) @@ -641,7 +694,7 @@ uabs(x::BitSigned) = unsigned(abs(x)) nextfloat(x::AbstractFloat, n::Integer) The result of `n` iterative applications of `nextfloat` to `x` if `n >= 0`, or `-n` -applications of `prevfloat` if `n < 0`. +applications of [`prevfloat`](@ref) if `n < 0`. """ function nextfloat(f::IEEEFloat, d::Integer) F = typeof(f) @@ -686,6 +739,8 @@ end Return the smallest floating point number `y` of the same type as `x` such `x < y`. If no such `y` exists (e.g. if `x` is `Inf` or `NaN`), then return `x`. + +See also: [`prevfloat`](@ref), [`eps`](@ref), [`issubnormal`](@ref). """ nextfloat(x::AbstractFloat) = nextfloat(x,1) @@ -693,7 +748,7 @@ nextfloat(x::AbstractFloat) = nextfloat(x,1) prevfloat(x::AbstractFloat, n::Integer) The result of `n` iterative applications of `prevfloat` to `x` if `n >= 0`, or `-n` -applications of `nextfloat` if `n < 0`. +applications of [`nextfloat`](@ref) if `n < 0`. """ prevfloat(x::AbstractFloat, d::Integer) = nextfloat(x, -d) @@ -815,6 +870,8 @@ floatmin(x::T) where {T<:AbstractFloat} = floatmin(T) Return the largest finite number representable by the floating-point type `T`. +See also: [`typemax`](@ref), [`floatmin`](@ref), [`eps`](@ref). + # Examples ```jldoctest julia> floatmax(Float16) @@ -825,6 +882,9 @@ julia> floatmax(Float32) julia> floatmax() 1.7976931348623157e308 + +julia> typemax(Float64) +Inf ``` """ floatmax(x::T) where {T<:AbstractFloat} = floatmax(T) @@ -879,6 +939,8 @@ is the nearest floating point number to ``y``, then |y-x| \\leq \\operatorname{eps}(x)/2. ``` +See also: [`nextfloat`](@ref), [`issubnormal`](@ref), [`floatmax`](@ref). + # Examples ```jldoctest julia> eps(1.0) @@ -910,6 +972,17 @@ bswap(x::IEEEFloat) = bswap_int(x) uinttype(::Type{Float64}) = UInt64 uinttype(::Type{Float32}) = UInt32 uinttype(::Type{Float16}) = UInt16 +inttype(::Type{Float64}) = Int64 +inttype(::Type{Float32}) = Int32 +inttype(::Type{Float16}) = Int16 +# float size of integer +floattype(::Type{UInt64}) = Float64 +floattype(::Type{UInt32}) = Float32 +floattype(::Type{UInt16}) = Float16 +floattype(::Type{Int64}) = Float64 +floattype(::Type{Int32}) = Float32 +floattype(::Type{Int16}) = Float16 + ## Array operations on floating point numbers ## diff --git a/base/floatfuncs.jl b/base/floatfuncs.jl index 2bca2989bab0b..60134ee91919d 100644 --- a/base/floatfuncs.jl +++ b/base/floatfuncs.jl @@ -225,9 +225,11 @@ end """ isapprox(x, y; atol::Real=0, rtol::Real=atol>0 ? 0 : √eps, nans::Bool=false[, norm::Function]) -Inexact equality comparison: `true` if `norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))`. The -default `atol` is zero and the default `rtol` depends on the types of `x` and `y`. The keyword -argument `nans` determines whether or not NaN values are considered equal (defaults to false). +Inexact equality comparison. Two numbers compare equal if their relative distance *or* their +absolute distance is within tolerance bounds: `isapprox` returns `true` if +`norm(x-y) <= max(atol, rtol*max(norm(x), norm(y)))`. The default `atol` is zero and the +default `rtol` depends on the types of `x` and `y`. The keyword argument `nans` determines +whether or not NaN values are considered equal (defaults to false). For real or complex floating-point values, if an `atol > 0` is not specified, `rtol` defaults to the square root of [`eps`](@ref) of the type of `x` or `y`, whichever is bigger (least precise). @@ -259,13 +261,16 @@ but an absurdly large tolerance if `x` is the # Examples ```jldoctest -julia> 0.1 ≈ (0.1 - 1e-10) +julia> isapprox(0.1, 0.15; atol=0.05) true -julia> isapprox(10, 11; atol = 2) +julia> isapprox(0.1, 0.15; rtol=0.34) true -julia> isapprox([10.0^9, 1.0], [10.0^9, 2.0]) +julia> isapprox(0.1, 0.15; rtol=0.33) +false + +julia> 0.1 + 1e-10 ≈ 0.1 true julia> 1e-10 ≈ 0 @@ -273,6 +278,9 @@ false julia> isapprox(1e-10, 0, atol=1e-8) true + +julia> isapprox([10.0^9, 1.0], [10.0^9, 2.0]) # using `norm` +true ``` """ function isapprox(x::Number, y::Number; @@ -287,6 +295,9 @@ end Create a function that compares its argument to `x` using `≈`, i.e. a function equivalent to `y -> y ≈ x`. The keyword arguments supported here are the same as those in the 2-argument `isapprox`. + +!!! compat "Julia 1.5" + This method requires Julia 1.5 or later. """ isapprox(y; kwargs...) = x -> isapprox(x, y; kwargs...) diff --git a/base/gmp.jl b/base/gmp.jl index d0446e7d3d169..0fa475a2c6801 100644 --- a/base/gmp.jl +++ b/base/gmp.jl @@ -4,13 +4,13 @@ module GMP export BigInt -import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, +import .Base: *, +, -, /, <, <<, >>, >>>, <=, ==, >, >=, ^, (~), (&), (|), xor, nand, nor, binomial, cmp, convert, div, divrem, factorial, cld, fld, gcd, gcdx, lcm, mod, ndigits, promote_rule, rem, show, isqrt, string, powermod, sum, trailing_zeros, trailing_ones, count_ones, tryparse_internal, bin, oct, dec, hex, isequal, invmod, _prevpow2, _nextpow2, ndigits0zpb, widen, signed, unsafe_trunc, trunc, iszero, isone, big, flipsign, signbit, - sign, hastypemax, isodd, digits! + sign, hastypemax, isodd, iseven, digits!, hash, hash_integer if Clong == Int32 const ClongMax = Union{Int8, Int16, Int32} @@ -343,6 +343,7 @@ end rem(x::Integer, ::Type{BigInt}) = BigInt(x) isodd(x::BigInt) = MPZ.tstbit(x, 0) +iseven(x::BigInt) = !isodd(x) function (::Type{T})(x::BigInt) where T<:Base.BitUnsigned if sizeof(T) < sizeof(Limb) @@ -768,8 +769,11 @@ end if Limb === UInt # this condition is true most (all?) of the time, and in this case we can define - # an optimized version of the above hash_integer(::Integer, ::UInt) method for BigInt - # used e.g. for Rational{BigInt} + # an optimized version for BigInt of hash_integer (used e.g. for Rational{BigInt}), + # and of hash + + using .Base: hash_uint + function hash_integer(n::BigInt, h::UInt) GC.@preserve n begin s = n.size @@ -799,7 +803,7 @@ if Limb === UInt limb <= typemin(Int) % UInt && return hash(-(limb % Int), h) end pow = trailing_zeros(x) - nd = ndigits0z(x, 2) + nd = Base.ndigits0z(x, 2) idx = _divLimb(pow) + 1 shift = _modLimb(pow) % UInt upshift = BITS_PER_LIMB - shift @@ -931,7 +935,7 @@ function Base.://(x::Rational{BigInt}, y::Rational{BigInt}) if iszero(x.num) throw(DivideError()) end - return (isneg(x.num) ? -one(BigFloat) : one(BigFloat)) // y.num + return (isneg(x.num) ? -one(BigInt) : one(BigInt)) // y.num end zq = _MPQ() ccall((:__gmpq_div, :libgmp), Cvoid, diff --git a/base/hashing.jl b/base/hashing.jl index 26b18f11c2fe2..c6319a9e070ea 100644 --- a/base/hashing.jl +++ b/base/hashing.jl @@ -3,17 +3,19 @@ ## hashing a single value ## """ - hash(x[, h::UInt]) + hash(x[, h::UInt]) -> UInt Compute an integer hash code such that `isequal(x,y)` implies `hash(x)==hash(y)`. The optional second argument `h` is a hash code to be mixed with the result. New types should implement the 2-argument form, typically by calling the 2-argument `hash` method recursively in order to mix hashes of the contents with each other (and with `h`). -Typically, any type that implements `hash` should also implement its own `==` (hence -`isequal`) to guarantee the property mentioned above. Types supporting subtraction +Typically, any type that implements `hash` should also implement its own [`==`](@ref) (hence +[`isequal`](@ref)) to guarantee the property mentioned above. Types supporting subtraction (operator `-`) should also implement [`widen`](@ref), which is required to hash values inside heterogeneous arrays. + +See also: [`objectid`](@ref), [`Dict`](@ref), [`Set`](@ref). """ hash(x::Any) = hash(x, zero(UInt)) hash(w::WeakRef, h::UInt) = hash(w.value, h) diff --git a/base/iddict.jl b/base/iddict.jl index a03edbb60723b..7247a85c9afc8 100644 --- a/base/iddict.jl +++ b/base/iddict.jl @@ -3,7 +3,7 @@ """ IdDict([itr]) -`IdDict{K,V}()` constructs a hash table using object-id as hash and +`IdDict{K,V}()` constructs a hash table using [`objectid`](@ref) as hash and `===` as equality with keys of type `K` and values of type `V`. See [`Dict`](@ref) for further help. In the example below, The `Dict` diff --git a/base/indices.jl b/base/indices.jl index 462e62c6d8883..079dc067c8572 100644 --- a/base/indices.jl +++ b/base/indices.jl @@ -106,26 +106,38 @@ IndexStyle(::IndexStyle, ::IndexStyle) = IndexCartesian() promote_shape(::Tuple{}, ::Tuple{}) = () -function promote_shape(a::Tuple{Int,}, b::Tuple{Int,}) - if a[1] != b[1] - throw(DimensionMismatch("dimensions must match: a has dims $a, b has dims $b")) +# Consistent error message for promote_shape mismatch, hiding implementation details like +# OneTo. When b ≡ nothing, it is omitted; i can be supplied for an index. +function throw_promote_shape_mismatch(a::Tuple{T,Vararg{T}}, + b::Union{Nothing,Tuple{T,Vararg{T}}}, + i = nothing) where {T} + _has_axes = T <: AbstractUnitRange + _normalize(d) = map(x -> _has_axes ? (firstindex(x):lastindex(x)) : x, d) + _things = _has_axes ? "axes" : "size" + msg = "dimensions must match: a has $(_things) $(_normalize(a))" + if b ≢ nothing + msg *= ", b has $(_things) $(_normalize(b))" + end + if i ≢ nothing + msg *= ", mismatch at $(i)" end + throw(DimensionMismatch(msg)) +end + +function promote_shape(a::Tuple{Int,}, b::Tuple{Int,}) + a[1] != b[1] && throw_promote_shape_mismatch(a, b) return a end function promote_shape(a::Tuple{Int,Int}, b::Tuple{Int,}) - if a[1] != b[1] || a[2] != 1 - throw(DimensionMismatch("dimensions must match: a has dims $a, b has dims $b")) - end + (a[1] != b[1] || a[2] != 1) && throw_promote_shape_mismatch(a, b) return a end promote_shape(a::Tuple{Int,}, b::Tuple{Int,Int}) = promote_shape(b, a) function promote_shape(a::Tuple{Int, Int}, b::Tuple{Int, Int}) - if a[1] != b[1] || a[2] != b[2] - throw(DimensionMismatch("dimensions must match: a has dims $a, b has dims $b")) - end + (a[1] != b[1] || a[2] != b[2]) && throw_promote_shape_mismatch(a, b) return a end @@ -153,14 +165,10 @@ function promote_shape(a::Dims, b::Dims) return promote_shape(b, a) end for i=1:length(b) - if a[i] != b[i] - throw(DimensionMismatch("dimensions must match: a has dims $a, b has dims $b, mismatch at $i")) - end + a[i] != b[i] && throw_promote_shape_mismatch(a, b, i) end for i=length(b)+1:length(a) - if a[i] != 1 - throw(DimensionMismatch("dimensions must match: a has dims $a, must have singleton at dim $i")) - end + a[i] != 1 && throw_promote_shape_mismatch(a, nothing, i) end return a end @@ -174,14 +182,10 @@ function promote_shape(a::Indices, b::Indices) return promote_shape(b, a) end for i=1:length(b) - if a[i] != b[i] - throw(DimensionMismatch("dimensions must match: a has dims $a, b has dims $b, mismatch at $i")) - end + a[i] != b[i] && throw_promote_shape_mismatch(a, b, i) end for i=length(b)+1:length(a) - if a[i] != 1:1 - throw(DimensionMismatch("dimensions must match: a has dims $a, must have singleton at dim $i")) - end + a[i] != 1:1 && throw_promote_shape_mismatch(a, nothing, i) end return a end diff --git a/base/initdefs.jl b/base/initdefs.jl index 6e4a4a593b446..eee4b9ef4f325 100644 --- a/base/initdefs.jl +++ b/base/initdefs.jl @@ -81,8 +81,7 @@ Here is an overview of some of the subdirectories that may exist in a depot: * `packages`: Contains packages, some of which were explicitly installed and some which are implicit dependencies. Maintained by `Pkg.jl`. * `registries`: Contains package registries. By default only `General`. Maintained by `Pkg.jl`. -See also: -[`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), and +See also [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), and [Code Loading](@ref code-loading). """ const DEPOT_PATH = String[] @@ -161,7 +160,7 @@ have special meanings: The fully expanded value of `LOAD_PATH` that is searched for projects and packages can be seen by calling the `Base.load_path()` function. -See also: +See also [`JULIA_LOAD_PATH`](@ref JULIA_LOAD_PATH), [`JULIA_PROJECT`](@ref JULIA_PROJECT), [`JULIA_DEPOT_PATH`](@ref JULIA_DEPOT_PATH), and @@ -235,7 +234,7 @@ function init_active_project() ACTIVE_PROJECT[] = project === nothing ? nothing : project == "" ? nothing : - project == "@." ? current_project() : abspath(expanduser(project)) + startswith(project, "@") ? load_path_expand(project) : abspath(expanduser(project)) end ## load path expansion: turn LOAD_PATH entries into concrete paths ## @@ -307,6 +306,12 @@ function active_project(search_load_path::Bool=true) end end +""" + load_path() + +Return the fully expanded value of [`LOAD_PATH`](@ref) that is searched for projects and +packages. +""" function load_path() paths = String[] for env in LOAD_PATH diff --git a/base/int.jl b/base/int.jl index 02a9ace0fe3f1..c6b50c3a646bc 100644 --- a/base/int.jl +++ b/base/int.jl @@ -154,6 +154,8 @@ when `abs` is applied to the minimum representable value of a signed integer. That is, when `x == typemin(typeof(x))`, `abs(x) == x < 0`, not `-x` as might be expected. +See also: [`abs2`](@ref), [`unsigned`](@ref), [`sign`](@ref). + # Examples ```jldoctest julia> abs(-3) @@ -178,12 +180,17 @@ abs(x::Signed) = flipsign(x,x) Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as unsigned without checking for negative values. + +See also: [`signed`](@ref), [`sign`](@ref), [`signbit`](@ref). + # Examples ```jldoctest julia> unsigned(-2) 0xfffffffffffffffe + julia> unsigned(2) 0x0000000000000002 + julia> signed(unsigned(-2)) -2 ``` @@ -196,6 +203,8 @@ unsigned(x::BitSigned) = reinterpret(typeof(convert(Unsigned, zero(x))), x) Convert a number to a signed integer. If the argument is unsigned, it is reinterpreted as signed without checking for overflow. + +See also: [`unsigned`](@ref), [`sign`](@ref), [`signbit`](@ref). """ signed(x) = x % typeof(convert(Signed, zero(x))) signed(x::BitUnsigned) = reinterpret(typeof(convert(Signed, zero(x))), x) @@ -233,6 +242,8 @@ exceptions, see note below). type, and so rounding error may occur. In particular, if the exact result is very close to `y`, then it may be rounded to `y`. +See also: [`rem`](@ref), [`div`](@ref), [`fld`](@ref), [`mod1`](@ref), [`invmod`](@ref). + ```jldoctest julia> mod(8, 3) 2 @@ -248,6 +259,10 @@ julia> mod(eps(), 3) julia> mod(-eps(), 3) 3.0 + +julia> mod.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + 1 2 0 1 2 0 1 2 0 1 2 ``` """ function mod(x::T, y::T) where T<:Integer @@ -272,6 +287,8 @@ rem(x::T, y::T) where {T<:BitUnsigned64} = checked_urem_int(x, y) Bitwise not. +See also: [`!`](@ref), [`&`](@ref), [`|`](@ref). + # Examples ```jldoctest julia> ~4 @@ -293,6 +310,8 @@ Bitwise and. Implements [three-valued logic](https://en.wikipedia.org/wiki/Three returning [`missing`](@ref) if one operand is `missing` and the other is `true`. Add parentheses for function application form: `(&)(x, y)`. +See also: [`|`](@ref), [`xor`](@ref), [`&&`](@ref). + # Examples ```jldoctest julia> 4 & 10 @@ -316,6 +335,8 @@ false Bitwise or. Implements [three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic), returning [`missing`](@ref) if one operand is `missing` and the other is `false`. +See also: [`&`](@ref), [`xor`](@ref), [`||`](@ref). + # Examples ```jldoctest julia> 4 | 10 @@ -369,6 +390,9 @@ Number of ones in the binary representation of `x`. ```jldoctest julia> count_ones(7) 3 + +julia> count_ones(Int32(-1)) +32 ``` """ count_ones(x::BitInteger) = (ctpop_int(x) % Int)::Int @@ -408,6 +432,9 @@ Number of zeros in the binary representation of `x`. ```jldoctest julia> count_zeros(Int32(2 ^ 16 - 1)) 16 + +julia> count_zeros(-1) +0 ``` """ count_zeros(x::Integer) = count_ones(~x) @@ -498,6 +525,8 @@ A negative value of `k` will rotate to the right instead. !!! compat "Julia 1.5" This function requires Julia 1.5 or later. +See also: [`<<`](@ref), [`circshift`](@ref), [`BitArray`](@ref). + ```jldoctest julia> bitrotate(UInt8(114), 2) 0xc9 @@ -559,7 +588,9 @@ is less than or equal to `x`. `trunc(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits`, `sigdigits` and `base` work as for [`round`](@ref). +Keywords `digits`, `sigdigits` and `base` work as for [`round`](@ref). + +See also: [`%`](@ref rem), [`floor`](@ref), [`unsigned`](@ref). """ function trunc end @@ -574,7 +605,7 @@ equal to `x`. `floor(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits`, `sigdigits` and `base` work as for [`round`](@ref). +Keywords `digits`, `sigdigits` and `base` work as for [`round`](@ref). """ function floor end @@ -589,7 +620,7 @@ equal to `x`. `ceil(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not representable. -`digits`, `sigdigits` and `base` work as for [`round`](@ref). +Keywords `digits`, `sigdigits` and `base` work as for [`round`](@ref). """ function ceil end @@ -702,6 +733,8 @@ function typemin end The highest value representable by the given (real) numeric `DataType`. +See also: [`floatmax`](@ref), [`typemin`](@ref), [`eps`](@ref). + # Examples ```jldoctest julia> typemax(Int8) @@ -709,6 +742,12 @@ julia> typemax(Int8) julia> typemax(UInt32) 0xffffffff + +julia> typemax(Float64) +Inf + +julia> floatmax(Float32) # largest finite floating point number +3.4028235f38 ``` """ function typemax end diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 35140a81367e6..e312000ac39f1 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -117,8 +117,9 @@ function lcm(a::T, b::T) where T<:Integer end end -gcd(a::Union{Integer,Rational}) = a -lcm(a::Union{Integer,Rational}) = a +gcd(a::Integer) = checked_abs(a) +gcd(a::Rational) = checked_abs(a.num) // a.den +lcm(a::Union{Integer,Rational}) = gcd(a) gcd(a::Unsigned, b::Signed) = gcd(promote(a, abs(b))...) gcd(a::Signed, b::Unsigned) = gcd(promote(abs(a), b)...) gcd(a::Real, b::Real) = gcd(promote(a,b)...) @@ -303,8 +304,7 @@ end const HWReal = Union{Int8,Int16,Int32,Int64,UInt8,UInt16,UInt32,UInt64,Float32,Float64} const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} -# Core.Compiler has complicated logic to inline x^2 and x^3 for -# numeric types. In terms of Val we can do it much more simply. +# Inline x^2 and x^3 for Val # (The first argument prevents unexpected behavior if a function ^ # is defined that is not equal to Base.^) @inline literal_pow(::typeof(^), x::HWNumber, ::Val{0}) = one(x) @@ -318,11 +318,11 @@ const HWNumber = Union{HWReal, Complex{<:HWReal}, Rational{<:HWReal}} # for other types, define x^-n as inv(x)^n so that negative literal powers can # be computed in a type-stable way even for e.g. integers. -@inline @generated function literal_pow(f::typeof(^), x, ::Val{p}) where {p} +@inline function literal_pow(f::typeof(^), x, ::Val{p}) where {p} if p < 0 - :(literal_pow(^, inv(x), $(Val{-p}()))) + literal_pow(^, inv(x), Val(-p)) else - :(f(x,$p)) + f(x, p) end end @@ -388,6 +388,8 @@ _prevpow2(x::Integer) = reinterpret(typeof(x),x < 0 ? -_prevpow2(unsigned(-x)) : Test whether `n` is an integer power of two. +See also [`count_ones`](@ref), [`prevpow`](@ref), [`nextpow`](@ref). + # Examples ```jldoctest julia> ispow2(4) @@ -419,6 +421,8 @@ ispow2(x::Integer) = x > 0 && count_ones(x) == 1 The smallest `a^n` not less than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must be greater than 0. +See also [`prevpow`](@ref). + # Examples ```jldoctest julia> nextpow(2, 7) @@ -433,8 +437,6 @@ julia> nextpow(5, 20) julia> nextpow(4, 16) 16 ``` - -See also [`prevpow`](@ref). """ function nextpow(a::Real, x::Real) x <= 0 && throw(DomainError(x, "`x` must be positive.")) @@ -456,6 +458,8 @@ end The largest `a^n` not greater than `x`, where `n` is a non-negative integer. `a` must be greater than 1, and `x` must not be less than 1. +See also [`nextpow`](@ref), [`isqrt`](@ref). + # Examples ```jldoctest julia> prevpow(2, 7) @@ -470,7 +474,6 @@ julia> prevpow(5, 20) julia> prevpow(4, 16) 16 ``` -See also [`nextpow`](@ref). """ function prevpow(a::Real, x::Real) x < 1 && throw(DomainError(x, "`x` must be ≥ 1.")) @@ -612,6 +615,8 @@ Compute the number of digits in integer `n` written in base `base` (`base` must not be in `[-1, 0, 1]`), optionally padded with zeros to a specified size (the result will never be less than `pad`). +See also [`digits`](@ref), [`count_ones`](@ref). + # Examples ```jldoctest julia> ndigits(12345) @@ -625,6 +630,9 @@ julia> string(1022, base=16) julia> ndigits(123, pad=5) 5 + +julia> ndigits(-123) +3 ``` """ ndigits(x::Integer; base::Integer=10, pad::Integer=1) = max(pad, ndigits0z(x, base)) @@ -749,12 +757,15 @@ split_sign(n::Unsigned) = n, false Convert an integer `n` to a string in the given `base`, optionally specifying a number of digits to pad to. +See also [`digits`](@ref), [`bitstring`](@ref), [`count_zeros`](@ref). + +# Examples ```jldoctest julia> string(5, base = 13, pad = 4) "0005" -julia> string(13, base = 5, pad = 4) -"0023" +julia> string(-13, base = 5, pad = 4) +"-0023" ``` """ function string(n::Integer; base::Integer = 10, pad::Integer = 1) @@ -783,10 +794,12 @@ string(b::Bool) = b ? "true" : "false" A string giving the literal bit representation of a number. +See also [`count_ones`](@ref), [`count_zeros`](@ref), [`digits`](@ref). + # Examples ```jldoctest -julia> bitstring(4) -"0000000000000000000000000000000000000000000000000000000000000100" +julia> bitstring(Int32(4)) +"00000000000000000000000000000100" julia> bitstring(2.2) "0100000000000001100110011001100110011001100110011001100110011010" @@ -807,9 +820,12 @@ Return an array with element type `T` (default `Int`) of the digits of `n` in th base, optionally padded with zeros to a specified size. More significant digits are at higher indices, such that `n == sum(digits[k]*base^(k-1) for k=1:length(digits))`. +See also [`ndigits`](@ref), [`digits!`](@ref), +and for base 2 also [`bitstring`](@ref), [`count_ones`](@ref). + # Examples ```jldoctest -julia> digits(10, base = 10) +julia> digits(10) 2-element Vector{Int64}: 0 1 @@ -821,14 +837,18 @@ julia> digits(10, base = 2) 0 1 -julia> digits(10, base = 2, pad = 6) -6-element Vector{Int64}: - 0 - 1 - 0 - 1 - 0 - 0 +julia> digits(-256, base = 10, pad = 5) +5-element Vector{Int64}: + -6 + -5 + -2 + 0 + 0 + +julia> n = rand(-999:999); + +julia> n == evalpoly(13, digits(n, base = 13)) +true ``` """ digits(n::Integer; base::Integer = 10, pad::Integer = 1) = @@ -934,6 +954,8 @@ Factorial of `n`. If `n` is an [`Integer`](@ref), the factorial is computed as a integer (promoted to at least 64 bits). Note that this may overflow if `n` is not small, but you can use `factorial(big(n))` to compute the result exactly in arbitrary precision. +See also [`binomial`](@ref). + # Examples ```jldoctest julia> factorial(6) @@ -948,9 +970,6 @@ julia> factorial(big(21)) 51090942171709440000 ``` -# See also -* [`binomial`](@ref) - # External links * [Factorial](https://en.wikipedia.org/wiki/Factorial) on Wikipedia. """ @@ -980,6 +999,8 @@ If ``n`` is negative, then it is defined in terms of the identity \\binom{n}{k} = (-1)^k \\binom{k-n-1}{k} ``` +See also [`factorial`](@ref). + # Examples ```jldoctest julia> binomial(5, 3) @@ -992,9 +1013,6 @@ julia> binomial(-5, 3) -35 ``` -# See also -* [`factorial`](@ref) - # External links * [Binomial coefficient](https://en.wikipedia.org/wiki/Binomial_coefficient) on Wikipedia. """ diff --git a/base/io.jl b/base/io.jl index dc588a8efd0e9..aa9ef22c9d306 100644 --- a/base/io.jl +++ b/base/io.jl @@ -15,7 +15,7 @@ struct EOFError <: Exception end A system call failed with an error code (in the `errno` global variable). """ struct SystemError <: Exception - prefix::AbstractString + prefix::String errnum::Int32 extrainfo SystemError(p::AbstractString, e::Integer, extrainfo) = new(p, e, extrainfo) @@ -1034,7 +1034,7 @@ end Return an iterable object yielding [`read(io, T)`](@ref). -See also: [`skipchars`](@ref), [`eachline`](@ref), [`readuntil`](@ref) +See also [`skipchars`](@ref), [`eachline`](@ref), [`readuntil`](@ref). !!! compat "Julia 1.6" `readeach` requires Julia 1.6 or later. diff --git a/base/iobuffer.jl b/base/iobuffer.jl index 8df6af0087137..e204eca906cbf 100644 --- a/base/iobuffer.jl +++ b/base/iobuffer.jl @@ -353,8 +353,7 @@ isopen(io::GenericIOBuffer) = io.readable || io.writable || io.seekable || bytes """ take!(b::IOBuffer) -Obtain the contents of an `IOBuffer` as an array, without copying. Afterwards, the -`IOBuffer` is reset to its initial state. +Obtain the contents of an `IOBuffer` as an array. Afterwards, the `IOBuffer` is reset to its initial state. # Examples ```jldoctest diff --git a/base/iostream.jl b/base/iostream.jl index 35255752bd1b5..98f15fd8a7db7 100644 --- a/base/iostream.jl +++ b/base/iostream.jl @@ -13,7 +13,7 @@ Mostly used to represent files returned by [`open`](@ref). mutable struct IOStream <: IO handle::Ptr{Cvoid} ios::Array{UInt8,1} - name::AbstractString + name::String mark::Int64 lock::ReentrantLock _dolock::Bool diff --git a/base/irrationals.jl b/base/irrationals.jl index 545d9091ee840..b1ecaf8557090 100644 --- a/base/irrationals.jl +++ b/base/irrationals.jl @@ -22,7 +22,9 @@ abstract type AbstractIrrational <: Real end Irrational{sym} <: AbstractIrrational Number type representing an exact irrational value denoted by the -symbol `sym`. +symbol `sym`, such as [`π`](@ref pi), [`ℯ`](@ref) and [`γ`](@ref Base.MathConstants.eulergamma). + +See also [`@irrational`], [`AbstractIrrational`](@ref). """ struct Irrational{sym} <: AbstractIrrational end diff --git a/base/iterators.jl b/base/iterators.jl index eebffed16dcfb..8bbd39d689cce 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -221,7 +221,7 @@ CartesianIndex(1, 2) d CartesianIndex(2, 2) e ``` -See also: [`IndexStyle`](@ref), [`axes`](@ref). +See also [`IndexStyle`](@ref), [`axes`](@ref). """ pairs(::IndexLinear, A::AbstractArray) = Pairs(A, LinearIndices(A)) pairs(::IndexCartesian, A::AbstractArray) = Pairs(A, CartesianIndices(axes(A))) @@ -235,30 +235,30 @@ pairs(A::AbstractArray) = pairs(IndexCartesian(), A) pairs(A::AbstractVector) = pairs(IndexLinear(), A) # pairs(v::Pairs) = v # listed for reference, but already defined from being an AbstractDict -length(v::Pairs) = length(v.itr) -axes(v::Pairs) = axes(v.itr) -size(v::Pairs) = size(v.itr) +length(v::Pairs) = length(getfield(v, :itr)) +axes(v::Pairs) = axes(getfield(v, :itr)) +size(v::Pairs) = size(getfield(v, :itr)) @propagate_inbounds function iterate(v::Pairs{K, V}, state...) where {K, V} - x = iterate(v.itr, state...) + x = iterate(getfield(v, :itr), state...) x === nothing && return x indx, n = x - item = v.data[indx] + item = getfield(v, :data)[indx] return (Pair{K, V}(indx, item), n) end -@inline isdone(v::Pairs, state...) = isdone(v.itr, state...) +@inline isdone(v::Pairs, state...) = isdone(getfield(v, :itr), state...) IteratorSize(::Type{<:Pairs{<:Any, <:Any, I}}) where {I} = IteratorSize(I) IteratorSize(::Type{<:Pairs{<:Any, <:Any, <:Base.AbstractUnitRange, <:Tuple}}) = HasLength() -reverse(v::Pairs) = Pairs(v.data, reverse(v.itr)) +reverse(v::Pairs) = Pairs(getfield(v, :data), reverse(getfield(v, :itr))) -haskey(v::Pairs, key) = (key in v.itr) -keys(v::Pairs) = v.itr -values(v::Pairs) = v.data # TODO: this should be a view of data subset by itr -getindex(v::Pairs, key) = v.data[key] -setindex!(v::Pairs, value, key) = (v.data[key] = value; v) -get(v::Pairs, key, default) = get(v.data, key, default) -get(f::Base.Callable, v::Pairs, key) = get(f, v.data, key) +haskey(v::Pairs, key) = (key in getfield(v, :itr)) +keys(v::Pairs) = getfield(v, :itr) +values(v::Pairs) = getfield(v, :data) # TODO: this should be a view of data subset by itr +getindex(v::Pairs, key) = getfield(v, :data)[key] +setindex!(v::Pairs, value, key) = (getfield(v, :data)[key] = value; v) +get(v::Pairs, key, default) = get(getfield(v, :data), key, default) +get(f::Base.Callable, v::Pairs, key) = get(f, getfield(v, :data), key) # zip @@ -276,6 +276,8 @@ the `zip` iterator is a tuple of values of its subiterators. `zip` orders the calls to its subiterators in such a way that stateful iterators will not advance when another iterator finishes in the current iteration. +See also: [`enumerate`](@ref), [`splat`](@ref Base.splat). + # Examples ```jldoctest julia> a = 1:5 @@ -429,6 +431,12 @@ julia> foreach(println, f) 1 3 5 + +julia> [x for x in [1, 2, 3, 4, 5] if isodd(x)] # collects a generator over Iterators.filter +3-element Vector{Int64}: + 1 + 3 + 5 ``` """ filter(flt, itr) = Filter(flt, itr) @@ -526,6 +534,8 @@ end An iterator that yields the same elements as `iter`, but starting at the given `state`. +See also: [`Iterators.drop`](@ref), [`Iterators.peel`](@ref), [`Base.rest`](@ref). + # Examples ```jldoctest julia> collect(Iterators.rest([1,2,3,4], 2)) @@ -544,6 +554,8 @@ rest(itr) = itr Returns the first element and an iterator over the remaining elements. +See also: [`Iterators.drop`](@ref), [`Iterators.take`](@ref). + # Examples ```jldoctest julia> (a, rest) = Iterators.peel("abc"); @@ -622,6 +634,8 @@ end An iterator that generates at most the first `n` elements of `iter`. +See also: [`drop`](@ref Iterators.drop), [`peel`](@ref Iterators.peel), [`first`](@ref), [`take!`](@ref). + # Examples ```jldoctest julia> a = 1:2:11 @@ -833,6 +847,8 @@ end An iterator that cycles through `iter` forever. If `iter` is empty, so is `cycle(iter)`. +See also: [`Iterators.repeated`](@ref), [`repeat`](@ref). + # Examples ```jldoctest julia> for (i, v) in enumerate(Iterators.cycle("hello")) @@ -872,6 +888,8 @@ repeated(x) = Repeated(x) An iterator that generates the value `x` forever. If `n` is specified, generates `x` that many times (equivalent to `take(repeated(x), n)`). +See also: [`Iterators.cycle`](@ref), [`repeat`](@ref). + # Examples ```jldoctest julia> a = Iterators.repeated([1 2], 4); @@ -907,12 +925,17 @@ Return an iterator over the product of several iterators. Each generated element a tuple whose `i`th element comes from the `i`th argument iterator. The first iterator changes the fastest. +See also: [`zip`](@ref), [`Iterators.flatten`](@ref). + # Examples ```jldoctest julia> collect(Iterators.product(1:2, 3:5)) 2×3 Matrix{Tuple{Int64, Int64}}: (1, 3) (1, 4) (1, 5) (2, 3) (2, 4) (2, 5) + +julia> ans == [(x,y) for x in 1:2, y in 3:5] # collects a generator involving Iterators.product +true ``` """ product(iters...) = ProductIterator(iters) @@ -1042,6 +1065,15 @@ julia> collect(Iterators.flatten((1:2, 8:9))) 2 8 9 + +julia> [(x,y) for x in 0:1 for y in 'a':'c'] # collects generators involving Iterators.flatten +6-element Vector{Tuple{Int64, Char}}: + (0, 'a') + (0, 'b') + (0, 'c') + (1, 'a') + (1, 'b') + (1, 'c') ``` """ flatten(itr) = Flatten(itr) @@ -1139,15 +1171,15 @@ function length(itr::PartitionIterator) return cld(l, itr.n) end -function iterate(itr::PartitionIterator{<:AbstractRange}, state=1) - state > length(itr.c) && return nothing - r = min(state + itr.n - 1, length(itr.c)) +function iterate(itr::PartitionIterator{<:AbstractRange}, state = firstindex(itr.c)) + state > lastindex(itr.c) && return nothing + r = min(state + itr.n - 1, lastindex(itr.c)) return @inbounds itr.c[state:r], r + 1 end -function iterate(itr::PartitionIterator{<:AbstractArray}, state=1) - state > length(itr.c) && return nothing - r = min(state + itr.n - 1, length(itr.c)) +function iterate(itr::PartitionIterator{<:AbstractArray}, state = firstindex(itr.c)) + state > lastindex(itr.c) && return nothing + r = min(state + itr.n - 1, lastindex(itr.c)) return @inbounds view(itr.c, state:r), r + 1 end @@ -1211,6 +1243,12 @@ julia> collect(a) 2-element Vector{Char}: 'e': ASCII/Unicode U+0065 (category Ll: Letter, lowercase) 'f': ASCII/Unicode U+0066 (category Ll: Letter, lowercase) + +julia> Iterators.reset!(a); popfirst!(a) +'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase) + +julia> Iterators.reset!(a, "hello"); popfirst!(a) +'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase) ``` ```jldoctest @@ -1239,7 +1277,7 @@ mutable struct Stateful{T, VS} end end -function reset!(s::Stateful{T,VS}, itr::T) where {T,VS} +function reset!(s::Stateful{T,VS}, itr::T=s.itr) where {T,VS} s.itr = itr setfield!(s, :nextvalstate, iterate(itr)) s.taken = 0 @@ -1300,7 +1338,7 @@ length(s::Stateful) = length(s.itr) - s.taken Returns the one and only element of collection `x`, and throws an `ArgumentError` if the collection has zero or multiple elements. -See also: [`first`](@ref), [`last`](@ref). +See also [`first`](@ref), [`last`](@ref). !!! compat "Julia 1.4" This method requires at least Julia 1.4. @@ -1310,7 +1348,7 @@ See also: [`first`](@ref), [`last`](@ref). @boundscheck if i === nothing throw(ArgumentError("Collection is empty, must contain exactly 1 element")) end - (ret, state) = i + (ret, state) = i::NTuple{2,Any} @boundscheck if iterate(x, state) !== nothing throw(ArgumentError("Collection has multiple elements, must contain exactly 1 element")) end diff --git a/base/libc.jl b/base/libc.jl index 547561ac964ba..cb0f05f1dec7b 100644 --- a/base/libc.jl +++ b/base/libc.jl @@ -131,7 +131,7 @@ Suspends execution for `s` seconds. This function does not yield to Julia's scheduler and therefore blocks the Julia thread that it is running on for the duration of the sleep time. -See also: [`sleep`](@ref) +See also [`sleep`](@ref). """ systemsleep diff --git a/base/libuv.jl b/base/libuv.jl index 82298516f4a1b..c63045f4b1b68 100644 --- a/base/libuv.jl +++ b/base/libuv.jl @@ -74,7 +74,7 @@ end ## Libuv error handling ## struct IOError <: Exception - msg::AbstractString + msg::String code::Int32 IOError(msg::AbstractString, code::Integer) = new(msg, code) end diff --git a/base/loading.jl b/base/loading.jl index 1f317b1b161d9..10a59de688b7c 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -203,7 +203,6 @@ function get_updated_dict(p::TOML.Parser, f::CachedTOMLDict) f.mtime = s.mtime f.size = s.size f.hash = new_hash - @debug "Cache of TOML file $(repr(f.path)) invalid, reparsing..." TOML.reinit!(p, String(content); filepath=f.path) return f.d = TOML.parse(p) end @@ -222,7 +221,6 @@ parsed_toml(project_file::AbstractString) = parsed_toml(project_file, TOML_CACHE function parsed_toml(project_file::AbstractString, toml_cache::TOMLCache, toml_lock::ReentrantLock) lock(toml_lock) do if !haskey(toml_cache.d, project_file) - @debug "Creating new cache for $(repr(project_file))" d = CachedTOMLDict(toml_cache.p, project_file) toml_cache.d[project_file] = d return d.d @@ -312,21 +310,35 @@ function pathof(m::Module) pkgid === nothing && return nothing origin = get(Base.pkgorigins, pkgid, nothing) origin === nothing && return nothing - origin.path === nothing && return nothing - return fixup_stdlib_path(origin.path) + path = origin.path + path === nothing && return nothing + return fixup_stdlib_path(path) end """ - pkgdir(m::Module) + pkgdir(m::Module[, paths::String...]) + +Return the root directory of the package that imported module `m`, +or `nothing` if `m` was not imported from a package. Optionally further +path component strings can be provided to construct a path within the +package root. + +```julia +julia> pkgdir(Foo) +"/path/to/Foo.jl" + +julia> pkgdir(Foo, "src", "file.jl") +"/path/to/Foo.jl/src/file.jl" +``` - Return the root directory of the package that imported module `m`, - or `nothing` if `m` was not imported from a package. - """ -function pkgdir(m::Module) +!!! compat "Julia 1.7" + The optional argument `paths` requires at least Julia 1.7. +""" +function pkgdir(m::Module, paths::String...) rootmodule = Base.moduleroot(m) path = pathof(rootmodule) path === nothing && return nothing - return dirname(dirname(path)) + return joinpath(dirname(dirname(path)), paths...) end ## generic project & manifest API ## @@ -563,7 +575,8 @@ function explicit_manifest_entry_path(manifest_file::String, pkg::PkgId, entry:: hash === nothing && return nothing hash = SHA1(hash) # Keep the 4 since it used to be the default - for slug in (version_slug(pkg.uuid, hash, 4), version_slug(pkg.uuid, hash)) + uuid = pkg.uuid::UUID # checked within `explicit_manifest_uuid_path` + for slug in (version_slug(uuid, hash, 4), version_slug(uuid, hash)) for depot in DEPOT_PATH path = abspath(depot, "packages", pkg.name, slug) ispath(path) && return path @@ -1303,16 +1316,20 @@ end const MAX_NUM_PRECOMPILE_FILES = Ref(10) -function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout) +function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, internal_stdout::IO = stdout, + ignore_loaded_modules::Bool = true) + @nospecialize internal_stderr internal_stdout # decide where to put the resulting cache file cachepath = compilecache_dir(pkg) # build up the list of modules that we want the precompile process to preserve concrete_deps = copy(_concrete_dependencies) - for (key, mod) in loaded_modules - if !(mod === Main || mod === Core || mod === Base) - push!(concrete_deps, key => module_build_id(mod)) + if ignore_loaded_modules + for (key, mod) in loaded_modules + if !(mod === Main || mod === Core || mod === Base) + push!(concrete_deps, key => module_build_id(mod)) + end end end # run the expression and cache the result @@ -1745,7 +1762,7 @@ function stale_cachefile(modpath::String, cachefile::String) # now check if this file is fresh relative to its source files if !skip_timecheck if !samefile(includes[1].filename, modpath) - @debug "Rejecting cache file $cachefile because it is for file $(includes[1].filename)) not file $modpath" + @debug "Rejecting cache file $cachefile because it is for file $(includes[1].filename) not file $modpath" return true # cache file was compiled from a different path end for (modkey, req_modkey) in requires diff --git a/base/lock.jl b/base/lock.jl index b013a593cde84..07253211984fc 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -201,6 +201,22 @@ function trylock(f, l::AbstractLock) return false end +""" + @lock l expr + +Macro version of `lock(f, l::AbstractLock)` but with `expr` instead of `f` function. +Expands to: +```julia +lock(l) +try + expr +finally + unlock(l) +end +``` +This is similar to using [`lock`](@ref) with a `do` block, but avoids creating a closure +and thus can improve the performance. +""" macro lock(l, expr) quote temp = $(esc(l)) @@ -213,6 +229,13 @@ macro lock(l, expr) end end +""" + @lock_nofail l expr + +Equivalent to `@lock l expr` for cases in which we can guarantee that the function +will not throw any error. In this case, avoiding try-catch can improve the performance. +See [`@lock`](@ref). +""" macro lock_nofail(l, expr) quote temp = $(esc(l)) diff --git a/base/logging.jl b/base/logging.jl index 066523771f5fb..2404c1107e58c 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -611,21 +611,25 @@ attached to the task. """ current_logger() = current_logstate().logger +const closed_stream = IOBuffer(UInt8[]) +close(closed_stream) #------------------------------------------------------------------------------- # SimpleLogger """ - SimpleLogger(stream=stderr, min_level=Info) + SimpleLogger([stream,] min_level=Info) Simplistic logger for logging all messages with level greater than or equal to -`min_level` to `stream`. +`min_level` to `stream`. If stream is closed then messages with log level +greater or equal to `Warn` will be logged to `stderr` and below to `stdout`. """ struct SimpleLogger <: AbstractLogger stream::IO min_level::LogLevel message_limits::Dict{Any,Int} end -SimpleLogger(stream::IO=stderr, level=Info) = SimpleLogger(stream, level, Dict{Any,Int}()) +SimpleLogger(stream::IO, level=Info) = SimpleLogger(stream, level, Dict{Any,Int}()) +SimpleLogger(level=Info) = SimpleLogger(closed_stream, level) shouldlog(logger::SimpleLogger, level, _module, group, id) = get(logger.message_limits, id, 1) > 0 @@ -644,7 +648,11 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module, remaining > 0 || return end buf = IOBuffer() - iob = IOContext(buf, logger.stream) + stream = logger.stream + if !isopen(stream) + stream = level < Warn ? stdout : stderr + end + iob = IOContext(buf, stream) levelstr = level == Warn ? "Warning" : string(level) msglines = split(chomp(string(message)::String), '\n') println(iob, "┌ ", levelstr, ": ", msglines[1]) @@ -656,10 +664,10 @@ function handle_message(logger::SimpleLogger, level::LogLevel, message, _module, println(iob, "│ ", key, " = ", val) end println(iob, "└ @ ", _module, " ", filepath, ":", line) - write(logger.stream, take!(buf)) + write(stream, take!(buf)) nothing end -_global_logstate = LogState(SimpleLogger(Core.stderr, CoreLogging.Info)) +_global_logstate = LogState(SimpleLogger()) end # CoreLogging diff --git a/base/math.jl b/base/math.jl index 42f10760ed4fb..003d4e0c8f831 100644 --- a/base/math.jl +++ b/base/math.jl @@ -47,15 +47,17 @@ end Return `x` if `lo <= x <= hi`. If `x > hi`, return `hi`. If `x < lo`, return `lo`. Arguments are promoted to a common type. +See also [`clamp!`](@ref), [`min`](@ref), [`max`](@ref). + # Examples ```jldoctest -julia> clamp.([pi, 1.0, big(10.)], 2., 9.) +julia> clamp.([pi, 1.0, big(10)], 2.0, 9.0) 3-element Vector{BigFloat}: 3.141592653589793238462643383279502884197169399375105820974944592307816406286198 2.0 9.0 -julia> clamp.([11,8,5],10,6) # an example where lo > hi +julia> clamp.([11, 8, 5], 10, 6) # an example where lo > hi 3-element Vector{Int64}: 6 6 @@ -73,12 +75,18 @@ clamp(x::X, lo::L, hi::H) where {X,L,H} = Clamp `x` between `typemin(T)` and `typemax(T)` and convert the result to type `T`. +See also [`trunc`](@ref). + # Examples ```jldoctest julia> clamp(200, Int8) 127 + julia> clamp(-200, Int8) -128 + +julia> trunc(Int, 4pi^2) +39 ``` """ clamp(x, ::Type{T}) where {T<:Integer} = clamp(x, typemin(T), typemax(T)) % T @@ -89,6 +97,19 @@ clamp(x, ::Type{T}) where {T<:Integer} = clamp(x, typemin(T), typemax(T)) % T Restrict values in `array` to the specified range, in-place. See also [`clamp`](@ref). + +# Examples +```jldoctest +julia> row = collect(-4:4)'; + +julia> clamp!(row, 0, Inf) +1×9 adjoint(::Vector{Int64}) with eltype Int64: + 0 0 0 0 0 1 2 3 4 + +julia> clamp.((-4:4)', 0, Inf) +1×9 Matrix{Float64}: + 0.0 0.0 0.0 0.0 0.0 1.0 2.0 3.0 4.0 +``` """ function clamp!(x::AbstractArray, lo, hi) @inbounds for i in eachindex(x) @@ -205,6 +226,8 @@ end @horner(x, p...) Evaluate `p[1] + x * (p[2] + x * (....))`, i.e. a polynomial via Horner's rule. + +See also [`@evalpoly`](@ref), [`evalpoly`](@ref). """ macro horner(x, p...) xesc, pesc = esc(x), esc.(p) @@ -224,6 +247,8 @@ that is, the coefficients are given in ascending order by power of `z`. This ma to efficient inline code that uses either Horner's method or, for complex `z`, a more efficient Goertzel-like algorithm. +See also [`evalpoly`](@ref). + # Examples ```jldoctest julia> @evalpoly(3, 1, 0, 1) @@ -241,6 +266,20 @@ macro evalpoly(z, p...) :(evalpoly($zesc, ($(pesc...),))) end +# polynomial evaluation using compensated summation. +# much more accurate, especially when lo can be combined with other rounding errors +@inline function exthorner(x, p::Tuple) + hi, lo = p[end], zero(x) + for i in length(p)-1:-1:1 + pi = p[i] + prod = hi*x + err = fma(hi, x, -prod) + hi = pi+prod + lo = fma(lo, x, prod - (hi - pi) + err) + end + return hi, lo +end + """ rad2deg(x) @@ -259,6 +298,8 @@ rad2deg(z::AbstractFloat) = z * (180 / oftype(z, pi)) Convert `x` from degrees to radians. +See also: [`rad2deg`](@ref), [`sind`](@ref). + # Examples ```jldoctest julia> deg2rad(90) @@ -365,23 +406,6 @@ Compute the inverse hyperbolic sine of `x`. """ asinh(x::Number) -""" - expm1(x) - -Accurately compute ``e^x-1``. It avoids the loss of precision involved in the direct -evaluation of exp(x)-1 for small values of x. -# Examples -```jldoctest -julia> expm1(1e-16) -1.0e-16 - -julia> exp(1e-16) - 1 -0.0 -``` -""" -expm1(x) -expm1(x::Float64) = ccall((:expm1,libm), Float64, (Float64,), x) -expm1(x::Float32) = ccall((:expm1f,libm), Float32, (Float32,), x) # utility for converting NaN return to DomainError # the branch in nan_dom_err prevents its callers from inlining, so be sure to force it @@ -393,6 +417,8 @@ expm1(x::Float32) = ccall((:expm1f,libm), Float32, (Float32,), x) sin(x) Compute sine of `x`, where `x` is in radians. + +See also [`sind`], [`sinpi`], [`sincos`], [`cis`]. """ sin(x::Number) @@ -400,6 +426,8 @@ sin(x::Number) cos(x) Compute cosine of `x`, where `x` is in radians. + +See also [`cosd`], [`cospi`], [`sincos`], [`cis`]. """ cos(x::Number) @@ -444,6 +472,8 @@ atanh(x::Number) Compute the natural logarithm of `x`. Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. Use complex negative arguments to obtain complex results. +See also [`log1p`], [`log2`], [`log10`]. + # Examples ```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*" julia> log(2) @@ -465,6 +495,8 @@ log(x::Number) Compute the logarithm of `x` to base 2. Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. +See also: [`exp2`](@ref), [`ldexp`](@ref), [`ispow2`](@ref). + # Examples ```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*" julia> log2(4) @@ -542,6 +574,8 @@ end Return ``\\sqrt{x}``. Throws [`DomainError`](@ref) for negative [`Real`](@ref) arguments. Use complex negative arguments instead. The prefix operator `√` is equivalent to `sqrt`. +See also: [`hypot`](@ref). + # Examples ```jldoctest; filter = r"Stacktrace:(\\n \\[[0-9]+\\].*)*" julia> sqrt(big(81)) @@ -556,6 +590,13 @@ Stacktrace: julia> sqrt(big(complex(-81))) 0.0 + 9.0im + +julia> .√(1:4) +4-element Vector{Float64}: + 1.0 + 1.4142135623730951 + 1.7320508075688772 + 2.0 ``` """ sqrt(x) @@ -1154,7 +1195,7 @@ include("special/log.jl") # Float16 definitions -for func in (:sin,:cos,:tan,:asin,:acos,:atan,:sinh,:cosh,:tanh,:asinh,:acosh, +for func in (:sin,:cos,:tan,:asin,:acos,:atan,:cosh,:tanh,:asinh,:acosh, :atanh,:log,:log2,:log10,:sqrt,:lgamma,:log1p) @eval begin $func(a::Float16) = Float16($func(Float32(a))) @@ -1162,13 +1203,12 @@ for func in (:sin,:cos,:tan,:asin,:acos,:atan,:sinh,:cosh,:tanh,:asinh,:acosh, end end -for func in (:exp,:exp2,:exp10) +for func in (:exp,:exp2,:exp10,:sinh) @eval $func(a::ComplexF16) = ComplexF16($func(ComplexF32(a))) end atan(a::Float16,b::Float16) = Float16(atan(Float32(a),Float32(b))) -cbrt(a::Float16) = Float16(cbrt(Float32(a))) sincos(a::Float16) = Float16.(sincos(Float32(a))) for f in (:sin, :cos, :tan, :asin, :atan, :acos, diff --git a/base/mathconstants.jl b/base/mathconstants.jl index a3d1be99becbb..156dc9e1ce39a 100644 --- a/base/mathconstants.jl +++ b/base/mathconstants.jl @@ -23,10 +23,17 @@ Base.@irrational catalan 0.91596559417721901505 catalan The constant pi. +Unicode `π` can be typed by writing `\\pi` then pressing tab in the Julia REPL, and in many editors. + +See also: [`sinpi`](@ref), [`sincospi`](@ref), [`deg2rad`](@ref). + # Examples ```jldoctest julia> pi π = 3.1415926535897... + +julia> 1/2pi +0.15915494309189535 ``` """ π, const pi = π @@ -37,10 +44,20 @@ julia> pi The constant ℯ. +Unicode `ℯ` can be typed by writing `\\euler` and pressing tab in the Julia REPL, and in many editors. + +See also: [`exp`](@ref), [`cis`](@ref), [`cispi`](@ref). + # Examples ```jldoctest julia> ℯ ℯ = 2.7182818284590... + +julia> log(ℯ) +1 + +julia> ℯ^(im)π ≈ -1 +true ``` """ ℯ, const e = ℯ @@ -55,6 +72,11 @@ Euler's constant. ```jldoctest julia> Base.MathConstants.eulergamma γ = 0.5772156649015... + +julia> dx = 10^-6; + +julia> sum(-exp(-x) * log(x) for x in dx:dx:100) * dx +0.5772078382499134 ``` """ γ, const eulergamma = γ @@ -69,6 +91,9 @@ The golden ratio. ```jldoctest julia> Base.MathConstants.golden φ = 1.6180339887498... + +julia> (2ans - 1)^2 ≈ 5 +true ``` """ φ, const golden = φ @@ -82,6 +107,9 @@ Catalan's constant. ```jldoctest julia> Base.MathConstants.catalan catalan = 0.9159655941772... + +julia> sum(log(x)/(1+x^2) for x in 1:0.01:10^6) * 0.01 +0.9159466120554123 ``` """ catalan diff --git a/base/meta.jl b/base/meta.jl index 98bbcc8cdd358..d4847dc476247 100644 --- a/base/meta.jl +++ b/base/meta.jl @@ -188,7 +188,7 @@ The expression passed to the [`parse`](@ref) function could not be interpreted a expression. """ struct ParseError <: Exception - msg::AbstractString + msg::String end function _parse_string(text::AbstractString, filename::AbstractString, @@ -203,21 +203,32 @@ end """ parse(str, start; greedy=true, raise=true, depwarn=true) -Parse the expression string and return an expression (which could later be passed to eval -for execution). `start` is the index of the first character to start parsing. If `greedy` is -`true` (default), `parse` will try to consume as much input as it can; otherwise, it will -stop as soon as it has parsed a valid expression. Incomplete but otherwise syntactically -valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true` -(default), syntax errors other than incomplete expressions will raise an error. If `raise` -is `false`, `parse` will return an expression that will raise an error upon evaluation. If -`depwarn` is `false`, deprecation warnings will be suppressed. +Parse the expression string and return an expression (which could later be +passed to eval for execution). `start` is the code unit index into `str` of the +first character to start parsing at (as with all string indexing, these are not +character indices). If `greedy` is `true` (default), `parse` will try to consume +as much input as it can; otherwise, it will stop as soon as it has parsed a +valid expression. Incomplete but otherwise syntactically valid expressions will +return `Expr(:incomplete, "(error message)")`. If `raise` is `true` (default), +syntax errors other than incomplete expressions will raise an error. If `raise` +is `false`, `parse` will return an expression that will raise an error upon +evaluation. If `depwarn` is `false`, deprecation warnings will be suppressed. ```jldoctest -julia> Meta.parse("x = 3, y = 5", 7) -(:(y = 5), 13) +julia> Meta.parse("(α, β) = 3, 5", 1) # start of string +(:((α, β) = (3, 5)), 16) -julia> Meta.parse("x = 3, y = 5", 5) -(:((3, y) = 5), 13) +julia> Meta.parse("(α, β) = 3, 5", 1, greedy=false) +(:((α, β)), 9) + +julia> Meta.parse("(α, β) = 3, 5", 16) # end of string +(nothing, 16) + +julia> Meta.parse("(α, β) = 3, 5", 11) # index of 3 +(:((3, 5)), 16) + +julia> Meta.parse("(α, β) = 3, 5", 11, greedy=false) +(3, 13) ``` """ function parse(str::AbstractString, pos::Integer; greedy::Bool=true, raise::Bool=true, diff --git a/base/methodshow.jl b/base/methodshow.jl index 961328c7c9684..937ff02a1786d 100644 --- a/base/methodshow.jl +++ b/base/methodshow.jl @@ -295,6 +295,7 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru end show(io::IO, ms::MethodList) = show_method_table(io, ms) +show(io::IO, ::MIME"text/plain", ms::MethodList) = show_method_table(io, ms) show(io::IO, mt::Core.MethodTable) = show_method_table(io, MethodList(mt)) function inbase(m::Module) diff --git a/base/missing.jl b/base/missing.jl index 343e8014bbb0e..3176c56772602 100644 --- a/base/missing.jl +++ b/base/missing.jl @@ -12,7 +12,7 @@ where it is not supported. The error message, in the `msg` field may provide more specific details. """ struct MissingException <: Exception - msg::AbstractString + msg::String end showerror(io::IO, ex::MissingException) = @@ -179,8 +179,8 @@ xor(b::Bool, a::Missing) = missing xor(::Missing, ::Integer) = missing xor(::Integer, ::Missing) = missing -*(d::Missing, x::AbstractString) = missing -*(d::AbstractString, x::Missing) = missing +*(d::Missing, x::Union{AbstractString,AbstractChar}) = missing +*(d::Union{AbstractString,AbstractChar}, x::Missing) = missing function float(A::AbstractArray{Union{T, Missing}}) where {T} U = typeof(float(zero(T))) @@ -201,6 +201,8 @@ Use [`collect`](@ref) to obtain an `Array` containing the non-`missing` values i be a `Vector` since it is not possible to remove missings while preserving dimensions of the input. +See also [`coalesce`](@ref), [`ismissing`](@ref), [`something`](@ref). + # Examples ```jldoctest julia> x = skipmissing([1, missing, 2]) @@ -281,24 +283,24 @@ mapreduce(f, op, itr::SkipMissing{<:AbstractArray}) = function _mapreduce(f, op, ::IndexLinear, itr::SkipMissing{<:AbstractArray}) A = itr.x - local ai + ai = missing inds = LinearIndices(A) i = first(inds) ilast = last(inds) - while i <= ilast + for outer i in i:ilast @inbounds ai = A[i] - ai === missing || break - i += 1 + ai !== missing && break end - i > ilast && return mapreduce_empty(f, op, eltype(itr)) + ai === missing && return mapreduce_empty(f, op, eltype(itr)) a1::eltype(itr) = ai + i == typemax(typeof(i)) && return mapreduce_first(f, op, a1) i += 1 - while i <= ilast + ai = missing + for outer i in i:ilast @inbounds ai = A[i] - ai === missing || break - i += 1 + ai !== missing && break end - i > ilast && return mapreduce_first(f, op, a1) + ai === missing && return mapreduce_first(f, op, a1) # We know A contains at least two non-missing entries: the result cannot be nothing something(mapreduce_impl(f, op, itr, first(inds), last(inds))) end @@ -312,32 +314,35 @@ mapreduce_impl(f, op, A::SkipMissing, ifirst::Integer, ilast::Integer) = @noinline function mapreduce_impl(f, op, itr::SkipMissing{<:AbstractArray}, ifirst::Integer, ilast::Integer, blksize::Int) A = itr.x - if ifirst == ilast + if ifirst > ilast + return nothing + elseif ifirst == ilast @inbounds a1 = A[ifirst] if a1 === missing return nothing else return Some(mapreduce_first(f, op, a1)) end - elseif ifirst + blksize > ilast + elseif ilast - ifirst < blksize # sequential portion - local ai + ai = missing i = ifirst - while i <= ilast + for outer i in i:ilast @inbounds ai = A[i] - ai === missing || break - i += 1 + ai !== missing && break end - i > ilast && return nothing + ai === missing && return nothing a1 = ai::eltype(itr) + i == typemax(typeof(i)) && return Some(mapreduce_first(f, op, a1)) i += 1 - while i <= ilast + ai = missing + for outer i in i:ilast @inbounds ai = A[i] - ai === missing || break - i += 1 + ai !== missing && break end - i > ilast && return Some(mapreduce_first(f, op, a1)) + ai === missing && return Some(mapreduce_first(f, op, a1)) a2 = ai::eltype(itr) + i == typemax(typeof(i)) && return Some(op(f(a1), f(a2))) i += 1 v = op(f(a1), f(a2)) @simd for i = i:ilast @@ -349,7 +354,7 @@ mapreduce_impl(f, op, A::SkipMissing, ifirst::Integer, ilast::Integer) = return Some(v) else # pairwise portion - imid = (ifirst + ilast) >> 1 + imid = ifirst + (ilast - ifirst) >> 1 v1 = mapreduce_impl(f, op, itr, ifirst, imid, blksize) v2 = mapreduce_impl(f, op, itr, imid+1, ilast, blksize) if v1 === nothing && v2 === nothing @@ -396,12 +401,12 @@ function filter(f, itr::SkipMissing{<:AbstractArray}) end """ - coalesce(x, y...) + coalesce(x...) Return the first value in the arguments which is not equal to [`missing`](@ref), if any. Otherwise return `missing`. -See also [`something`](@ref). +See also [`skipmissing`](@ref), [`something`](@ref), [`@coalesce`](@ref). # Examples @@ -423,3 +428,39 @@ function coalesce end coalesce() = missing coalesce(x::Missing, y...) = coalesce(y...) coalesce(x::Any, y...) = x + + +""" + @coalesce(x...) + +Short-circuiting version of [`coalesce`](@ref). + +# Examples +```jldoctest +julia> f(x) = (println("f(\$x)"); missing); + +julia> a = 1; + +julia> a = @coalesce a f(2) f(3) error("`a` is still missing") +1 + +julia> b = missing; + +julia> b = @coalesce b f(2) f(3) error("`b` is still missing") +f(2) +f(3) +ERROR: `b` is still missing +[...] +``` + +!!! compat "Julia 1.7" + This macro is available as of Julia 1.7. +""" +macro coalesce(args...) + expr = :(missing) + for arg in reverse(args) + expr = :((val = $arg) !== missing ? val : $expr) + end + return esc(:(let val; $expr; end)) +end + diff --git a/base/mpfr.jl b/base/mpfr.jl index c85531856f5c9..8f24cd8c0ab38 100644 --- a/base/mpfr.jl +++ b/base/mpfr.jl @@ -151,6 +151,11 @@ global precision; `convert` will always return `x`. convenience since decimal literals are converted to `Float64` when parsed, so `BigFloat(2.1)` may not yield what you expect. +See also: +- [`@big_str`](@ref) +- [`rounding`](@ref) and [`setrounding`](@ref) +- [`precision`](@ref) and [`setprecision`](@ref) + !!! compat "Julia 1.1" `precision` as a keyword argument requires at least Julia 1.1. In Julia 1.0 `precision` is the second positional argument (`BigFloat(x, precision)`). @@ -169,11 +174,6 @@ julia> BigFloat("2.1", RoundUp) julia> BigFloat("2.1", RoundUp, precision=128) 2.100000000000000000000000000000000000007 ``` - -# See also -- [`@big_str`](@ref) -- [`rounding`](@ref) and [`setrounding`](@ref) -- [`precision`](@ref) and [`setprecision`](@ref) """ BigFloat(x, r::RoundingMode) @@ -339,7 +339,7 @@ Float32(x::BigFloat, r::MPFRRoundingMode=ROUNDING_MODE[]) = Float32(x::BigFloat, r::RoundingMode) = Float32(x, convert(MPFRRoundingMode, r)) # TODO: avoid double rounding -Float16(x::BigFloat) = Float16(Float32(x)) +Float16(x::BigFloat) = Float16(Float64(x)) promote_rule(::Type{BigFloat}, ::Type{<:Real}) = BigFloat promote_rule(::Type{BigInt}, ::Type{<:AbstractFloat}) = BigFloat @@ -982,7 +982,7 @@ function _prettify_bigfloat(s::String)::String neg = startswith(int, '-') neg == true && (int = lstrip(int, '-')) @assert length(int) == 1 - string(neg ? '-' : "", '0', '.', '0'^(-expo-1), int, frac) + string(neg ? '-' : "", '0', '.', '0'^(-expo-1), int, frac == "0" ? "" : frac) end else string(mantissa, 'e', exponent) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 9acb97a486fbb..474e19e7e5f5b 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -104,9 +104,9 @@ module IteratorsMD # zeros and ones zero(::CartesianIndex{N}) where {N} = zero(CartesianIndex{N}) - zero(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(x -> 0, Val(N))) + zero(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(Returns(0), Val(N))) oneunit(::CartesianIndex{N}) where {N} = oneunit(CartesianIndex{N}) - oneunit(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(x -> 1, Val(N))) + oneunit(::Type{CartesianIndex{N}}) where {N} = CartesianIndex(ntuple(Returns(1), Val(N))) # arithmetic, min/max @inline (-)(index::CartesianIndex{N}) where {N} = @@ -125,9 +125,11 @@ module IteratorsMD # comparison @inline isless(I1::CartesianIndex{N}, I2::CartesianIndex{N}) where {N} = _isless(0, I1.I, I2.I) - @inline function _isless(ret, I1::NTuple{N,Int}, I2::NTuple{N,Int}) where N - newret = ifelse(ret==0, icmp(I1[N], I2[N]), ret) - _isless(newret, Base.front(I1), Base.front(I2)) + @inline function _isless(ret, I1::Tuple{Int,Vararg{Int,N}}, I2::Tuple{Int,Vararg{Int,N}}) where {N} + newret = ifelse(ret==0, icmp(last(I1), last(I2)), ret) + t1, t2 = Base.front(I1), Base.front(I2) + # avoid dynamic dispatch by telling the compiler relational invariants + return isa(t1, Tuple{}) ? _isless(newret, (), ()) : _isless(newret, t1, t2::Tuple{Int,Vararg{Int}}) end _isless(ret, ::Tuple{}, ::Tuple{}) = ifelse(ret==1, true, false) icmp(a, b) = ifelse(isless(a,b), 1, ifelse(a==b, 0, -1)) @@ -168,6 +170,7 @@ module IteratorsMD error("iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`") # Iteration + const OrdinalRangeInt = OrdinalRange{Int, Int} """ CartesianIndices(sz::Dims) -> R CartesianIndices((istart:[istep:]istop, jstart:[jstep:]jstop, ...)) -> R @@ -262,13 +265,13 @@ module IteratorsMD For cartesian to linear index conversion, see [`LinearIndices`](@ref). """ - struct CartesianIndices{N,R<:NTuple{N,OrdinalRange{Int, Int}}} <: AbstractArray{CartesianIndex{N},N} + struct CartesianIndices{N,R<:NTuple{N,OrdinalRangeInt}} <: AbstractArray{CartesianIndex{N},N} indices::R end CartesianIndices(::Tuple{}) = CartesianIndices{0,typeof(())}(()) function CartesianIndices(inds::NTuple{N,OrdinalRange{<:Integer, <:Integer}}) where {N} - indices = map(r->convert(OrdinalRange{Int, Int}, r), inds) + indices = map(r->convert(OrdinalRangeInt, r), inds) CartesianIndices{N, typeof(indices)}(indices) end @@ -278,7 +281,7 @@ module IteratorsMD CartesianIndices(A::AbstractArray) = CartesianIndices(axes(A)) - _convert2ind(sz::Bool) = Base.OneTo(Int(sz)) + _convert2ind(sz::Bool) = Base.OneTo(Int8(sz)) _convert2ind(sz::Integer) = Base.OneTo(sz) _convert2ind(sz::AbstractUnitRange) = first(sz):last(sz) _convert2ind(sz::OrdinalRange) = first(sz):step(sz):last(sz) @@ -394,19 +397,21 @@ module IteratorsMD # `iterate` returns `Union{Nothing, Tuple}`, we explicitly pass a `valid` flag to eliminate # the type instability inside the core `__inc` logic, and this gives better runtime performance. __inc(::Tuple{}, ::Tuple{}) = false, () - @inline function __inc(state::Tuple{Int}, indices::Tuple{<:OrdinalRange}) + @inline function __inc(state::Tuple{Int}, indices::Tuple{OrdinalRangeInt}) rng = indices[1] I = state[1] + step(rng) valid = __is_valid_range(I, rng) && state[1] != last(rng) return valid, (I, ) end - @inline function __inc(state, indices) + @inline function __inc(state::Tuple{Int,Int,Vararg{Int,N}}, indices::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt,N}}) where {N} rng = indices[1] I = state[1] + step(rng) if __is_valid_range(I, rng) && state[1] != last(rng) return true, (I, tail(state)...) end - valid, I = __inc(tail(state), tail(indices)) + t1, t2 = tail(state), tail(indices) + # avoid dynamic dispatch by telling the compiler relational invariants + valid, I = isa(t1, Tuple{Int}) ? __inc(t1, t2::Tuple{OrdinalRangeInt}) : __inc(t1, t2::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt}}) return valid, (first(rng), I...) end @@ -458,7 +463,7 @@ module IteratorsMD # Split out the first N elements of a tuple @inline function split(t, V::Val) - ref = ntuple(d->true, V) # create a reference tuple of length N + ref = ntuple(Returns(true), V) # create a reference tuple of length N _split1(t, ref), _splitrest(t, ref) end @inline _split1(t, ref) = (t[1], _split1(tail(t), tail(ref))...) @@ -505,20 +510,21 @@ module IteratorsMD # decrement post check to avoid integer overflow @inline __dec(::Tuple{}, ::Tuple{}) = false, () - @inline function __dec(state::Tuple{Int}, indices::Tuple{<:OrdinalRange}) + @inline function __dec(state::Tuple{Int}, indices::Tuple{OrdinalRangeInt}) rng = indices[1] I = state[1] - step(rng) valid = __is_valid_range(I, rng) && state[1] != first(rng) return valid, (I,) end - - @inline function __dec(state, indices) + @inline function __dec(state::Tuple{Int,Int,Vararg{Int,N}}, indices::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt,N}}) where {N} rng = indices[1] I = state[1] - step(rng) if __is_valid_range(I, rng) && state[1] != first(rng) return true, (I, tail(state)...) end - valid, I = __dec(tail(state), tail(indices)) + t1, t2 = tail(state), tail(indices) + # avoid dynamic dispatch by telling the compiler relational invariants + valid, I = isa(t1, Tuple{Int}) ? __dec(t1, t2::Tuple{OrdinalRangeInt}) : __dec(t1, t2::Tuple{OrdinalRangeInt,OrdinalRangeInt,Vararg{OrdinalRangeInt}}) return valid, (last(rng), I...) end @@ -685,10 +691,10 @@ checkindex(::Type{Bool}, inds::Tuple, I::CartesianIndices) = all(checkindex.(Boo # rather than returning N, it returns an NTuple{N,Bool} so the result is inferrable @inline index_ndims(i1, I...) = (true, index_ndims(I...)...) @inline function index_ndims(i1::CartesianIndex, I...) - (map(x->true, i1.I)..., index_ndims(I...)...) + (map(Returns(true), i1.I)..., index_ndims(I...)...) end @inline function index_ndims(i1::AbstractArray{CartesianIndex{N}}, I...) where N - (ntuple(x->true, Val(N))..., index_ndims(I...)...) + (ntuple(Returns(true), Val(N))..., index_ndims(I...)...) end index_ndims() = () @@ -698,7 +704,7 @@ index_ndims() = () @inline index_dimsum(::Colon, I...) = (true, index_dimsum(I...)...) @inline index_dimsum(::AbstractArray{Bool}, I...) = (true, index_dimsum(I...)...) @inline function index_dimsum(::AbstractArray{<:Any,N}, I...) where N - (ntuple(x->true, Val(N))..., index_dimsum(I...)...) + (ntuple(Returns(true), Val(N))..., index_dimsum(I...)...) end index_dimsum() = () @@ -822,7 +828,7 @@ uncolon(inds::Tuple{}, I::Tuple{Colon, Vararg{Any}}) = Slice(OneTo(1)) uncolon(inds::Tuple, I::Tuple{Colon, Vararg{Any}}) = Slice(inds[1]) ### From abstractarray.jl: Internal multidimensional indexing definitions ### -getindex(x::Number, i::CartesianIndex{0}) = x +getindex(x::Union{Number,Char}, ::CartesianIndex{0}) = x getindex(t::Tuple, i::CartesianIndex{1}) = getindex(t, i.I[1]) # These are not defined on directly on getindex to avoid @@ -1160,6 +1166,8 @@ their indices; any offset results in a (circular) wraparound. If the arrays have overlapping indices, then on the domain of the overlap `dest` agrees with `src`. +See also: [`circshift`](@ref). + # Examples ```julia-repl julia> src = reshape(Vector(1:16), (4,4)) diff --git a/base/multimedia.jl b/base/multimedia.jl index 45e6b9532e9fa..5d9e3e807d159 100644 --- a/base/multimedia.jl +++ b/base/multimedia.jl @@ -69,7 +69,7 @@ methods; for example, if the available MIME formats depend on the *value* of `x` julia> showable(MIME("text/plain"), rand(5)) true -julia> showable("img/png", rand(5)) +julia> showable("image/png", rand(5)) false ``` """ @@ -176,7 +176,7 @@ data except for a set of types known to be text data (possibly Unicode). julia> istextmime(MIME("text/plain")) true -julia> istextmime(MIME("img/png")) +julia> istextmime(MIME("image/png")) false ``` """ diff --git a/base/namedtuple.jl b/base/namedtuple.jl index 07c4735f08b28..9361fde52619b 100644 --- a/base/namedtuple.jl +++ b/base/namedtuple.jl @@ -194,8 +194,8 @@ _nt_names(::Type{T}) where {names,T<:NamedTuple{names}} = names hash(x::NamedTuple, h::UInt) = xor(objectid(_nt_names(x)), hash(Tuple(x), h)) +(<)(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = Tuple(a) < Tuple(b) isless(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = isless(Tuple(a), Tuple(b)) -# TODO: case where one argument's names are a prefix of the other's same_names(::NamedTuple{names}...) where {names} = true same_names(::NamedTuple...) = false @@ -267,7 +267,7 @@ merge(a::NamedTuple, b::NamedTuple{()}) = a merge(a::NamedTuple{()}, b::NamedTuple{()}) = a merge(a::NamedTuple{()}, b::NamedTuple) = b -merge(a::NamedTuple, b::Iterators.Pairs{<:Any,<:Any,<:Any,<:NamedTuple}) = merge(a, b.data) +merge(a::NamedTuple, b::Iterators.Pairs{<:Any,<:Any,<:Any,<:NamedTuple}) = merge(a, getfield(b, :data)) merge(a::NamedTuple, b::Iterators.Zip{<:Tuple{Any,Any}}) = merge(a, NamedTuple{Tuple(b.is[1])}(b.is[2])) diff --git a/base/number.jl b/base/number.jl index 142796d3903ac..8dfa56aa0f61a 100644 --- a/base/number.jl +++ b/base/number.jl @@ -25,6 +25,8 @@ isinteger(x::Integer) = true Return `true` if `x == zero(x)`; if `x` is an array, this checks whether all of the elements of `x` are zero. +See also: [`isone`](@ref), [`isinteger`](@ref), [`isfinite`](@ref), [`isnan`](@ref). + # Examples ```jldoctest julia> iszero(0.0) @@ -110,6 +112,8 @@ copy(x::Number) = x # some code treats numbers as collection-like Returns `true` if the value of the sign of `x` is negative, otherwise `false`. +See also [`sign`](@ref) and [`copysign`](@ref). + # Examples ```jldoctest julia> signbit(-4) @@ -131,6 +135,23 @@ signbit(x::Real) = x < 0 sign(x) Return zero if `x==0` and ``x/|x|`` otherwise (i.e., ±1 for real `x`). + +See also [`signbit`](@ref), [`zero`](@ref), [`copysign`](@ref), [`flipsign`](@ref). + +# Examples +```jldoctest +julia> sign(-4.0) +-1.0 + +julia> sign(99) +1 + +julia> sign(-0.0) +-0.0 + +julia> sign(0 + im) +0.0 + 1.0im +``` """ sign(x::Number) = iszero(x) ? x/abs(oneunit(x)) : x/abs(x) sign(x::Real) = ifelse(x < zero(x), oftype(one(x),-1), ifelse(x > zero(x), one(x), typeof(one(x))(x))) @@ -222,10 +243,18 @@ inv(x::Number) = one(x)/x Multiply `x` and `y`, giving the result as a larger type. +See also [`promote`](@ref), [`Base.add_sum`](@ref). + # Examples ```jldoctest -julia> widemul(Float32(3.), 4.) -12.0 +julia> widemul(Float32(3.0), 4.0) isa BigFloat +true + +julia> typemax(Int8) * typemax(Int8) +1 + +julia> widemul(typemax(Int8), typemax(Int8)) # == 127^2 +16129 ``` """ widemul(x::Number, y::Number) = widen(x)*widen(y) @@ -243,6 +272,8 @@ map(f, x::Number, ys::Number...) = f(x, ys...) Get the additive identity element for the type of `x` (`x` can also specify the type itself). +See also [`iszero`](@ref), [`one`](@ref), [`oneunit`](@ref), [`oftype`](@ref). + # Examples ```jldoctest julia> zero(1) @@ -280,6 +311,9 @@ should return an identity value of the same precision If you want a quantity that is of the same type as `x`, or of type `T`, even if `x` is dimensionful, use [`oneunit`](@ref) instead. +See also the [`identity`](@ref) function, +and `I` in [`LinearAlgebra`](@ref man-linalg) for the identity matrix. + # Examples ```jldoctest julia> one(3.7) diff --git a/base/operators.jl b/base/operators.jl index 010f5793fba06..3292ab8f7abe6 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -79,6 +79,9 @@ handle comparison to other types via promotion rules where possible. [`isequal`](@ref) falls back to `==`, so new methods of `==` will be used by the [`Dict`](@ref) type to compare keys. If your type will be used as a dictionary key, it should therefore also implement [`hash`](@ref). + +If some type defines `==`, [`isequal`](@ref), and [`isless`](@ref) then it should +also implement [`<`](@ref) to ensure consistency of comparisons. """ == @@ -90,6 +93,10 @@ and of missing values. `isequal` treats all floating-point `NaN` values as equal to each other, treats `-0.0` as unequal to `0.0`, and [`missing`](@ref) as equal to `missing`. Always returns a `Bool` value. +`isequal` is an equivalence relation - it is reflexive (`===` implies `isequal`), symmetric +(`isequal(a, b)` implies `isequal(b, a)`) and transitive (`isequal(a, b)` and +`isequal(b, c)` implies `isequal(a, c)`). + # Implementation The default implementation of `isequal` calls `==`, so a type that does not involve floating-point values generally only needs to define `==`. @@ -98,8 +105,12 @@ floating-point values generally only needs to define `==`. that `hash(x) == hash(y)`. This typically means that types for which a custom `==` or `isequal` method exists must -implement a corresponding `hash` method (and vice versa). Collections typically implement -`isequal` by calling `isequal` recursively on all contents. +implement a corresponding [`hash`](@ref) method (and vice versa). Collections typically +implement `isequal` by calling `isequal` recursively on all contents. + +Furthermore, `isequal` is linked with [`isless`](@ref), and they work together to +define a fixed total ordering, where exactly one of `isequal(x, y)`, `isless(x, y)`, or +`isless(y, x)` must be `true` (and the other two `false`). Scalar types generally do not need to implement `isequal` separate from `==`, unless they represent floating-point numbers amenable to a more efficient implementation than that @@ -118,6 +129,12 @@ true julia> isequal(0.0, -0.0) false + +julia> missing == missing +missing + +julia> isequal(missing, missing) +true ``` """ isequal(x, y) = x == y @@ -132,8 +149,8 @@ isequal(x::AbstractFloat, y::Real ) = (isnan(x) & isnan(y)) | signequal( """ isless(x, y) -Test whether `x` is less than `y`, according to a fixed total order. -`isless` is not defined on all pairs of values `(x, y)`. However, if it +Test whether `x` is less than `y`, according to a fixed total order (defined together with +[`isequal`](@ref)). `isless` is not defined on all pairs of values `(x, y)`. However, if it is defined, it is expected to satisfy the following: - If `isless(x, y)` is defined, then so is `isless(y, x)` and `isequal(x, y)`, and exactly one of those three yields `true`. @@ -185,7 +202,7 @@ largest values and `isgreater` defines a descending total order with `NaN` and !!! note Like `min`, `isgreater` orders containers (tuples, vectors, etc) - lexigraphically with `isless(y, x)` rather than recursively with itself: + lexicographically with `isless(y, x)` rather than recursively with itself: ```jldoctest julia> Base.isgreater(1, NaN) # 1 is greater than NaN @@ -319,7 +336,6 @@ a partial order. New numeric types with a canonical partial order should implement this function for two arguments of the new type. Types with a canonical total order should implement [`isless`](@ref) instead. -(x < y) | (x == y) # Examples ```jldoctest @@ -464,7 +480,7 @@ cmp(x::Integer, y::Integer) = ifelse(isless(x, y), -1, ifelse(isless(y, x), 1, 0 """ max(x, y, ...) -Return the maximum of the arguments. See also the [`maximum`](@ref) function +Return the maximum of the arguments (with respect to [`isless`](@ref)). See also the [`maximum`](@ref) function to take the maximum element from a collection. # Examples @@ -478,7 +494,7 @@ max(x, y) = ifelse(isless(y, x), x, y) """ min(x, y, ...) -Return the minimum of the arguments. See also the [`minimum`](@ref) function +Return the minimum of the arguments (with respect to [`isless`](@ref)). See also the [`minimum`](@ref) function to take the minimum element from a collection. # Examples @@ -492,7 +508,9 @@ min(x,y) = ifelse(isless(y, x), y, x) """ minmax(x, y) -Return `(min(x,y), max(x,y))`. See also: [`extrema`](@ref) that returns `(minimum(x), maximum(x))`. +Return `(min(x,y), max(x,y))`. + +See also [`extrema`](@ref) that returns `(minimum(x), maximum(x))`. # Examples ```jldoctest @@ -561,6 +579,8 @@ extrema(f, x::Real) = (y = f(x); (y, y)) The identity function. Returns its argument. +See also: [`one`](@ref), [`oneunit`](@ref), and [`LinearAlgebra`](@ref man-linalg)'s `I`. + # Examples ```jldoctest julia> identity("Well, what did you expect?") @@ -576,6 +596,8 @@ identity(x) = x xor(x::Integer) = x const ⊻ = xor +const ⊼ = nand +const ⊽ = nor # foldl for argument lists. expand fully up to a point, then # switch to a loop. this allows small cases like `a+b+c+d` to be managed @@ -586,7 +608,7 @@ afoldl(op, a) = a function afoldl(op, a, bs...) l = length(bs) i = 0; y = a; l == i && return y - #@nexprs 15 i -> (y = op(y, bs[i]); l == i && return y) + #@nexprs 31 i -> (y = op(y, bs[i]); l == i && return y) i = 1; y = op(y, bs[i]); l == i && return y i = 2; y = op(y, bs[i]); l == i && return y i = 3; y = op(y, bs[i]); l == i && return y @@ -602,12 +624,28 @@ function afoldl(op, a, bs...) i = 13; y = op(y, bs[i]); l == i && return y i = 14; y = op(y, bs[i]); l == i && return y i = 15; y = op(y, bs[i]); l == i && return y + i = 16; y = op(y, bs[i]); l == i && return y + i = 17; y = op(y, bs[i]); l == i && return y + i = 18; y = op(y, bs[i]); l == i && return y + i = 19; y = op(y, bs[i]); l == i && return y + i = 20; y = op(y, bs[i]); l == i && return y + i = 21; y = op(y, bs[i]); l == i && return y + i = 22; y = op(y, bs[i]); l == i && return y + i = 23; y = op(y, bs[i]); l == i && return y + i = 24; y = op(y, bs[i]); l == i && return y + i = 25; y = op(y, bs[i]); l == i && return y + i = 26; y = op(y, bs[i]); l == i && return y + i = 27; y = op(y, bs[i]); l == i && return y + i = 28; y = op(y, bs[i]); l == i && return y + i = 29; y = op(y, bs[i]); l == i && return y + i = 30; y = op(y, bs[i]); l == i && return y + i = 31; y = op(y, bs[i]); l == i && return y for i in (i + 1):l y = op(y, bs[i]) end return y end -typeof(afoldl).name.mt.max_args = 18 +typeof(afoldl).name.mt.max_args = 34 for op in (:+, :*, :&, :|, :xor, :min, :max, :kron) @eval begin @@ -676,7 +714,7 @@ julia> bitstring(Int8(3)) julia> bitstring(Int8(12)) "00001100" ``` -See also [`>>`](@ref), [`>>>`](@ref). +See also [`>>`](@ref), [`>>>`](@ref), [`exp2`](@ref), [`ldexp`](@ref). """ function <<(x::Integer, c::Integer) @_inline_meta @@ -783,6 +821,8 @@ end Remainder from Euclidean division, returning a value of the same sign as `x`, and smaller in magnitude than `y`. This value is always exact. +See also: [`div`](@ref), [`mod`](@ref), [`mod1`](@ref), [`divrem`](@ref). + # Examples ```jldoctest julia> x = 15; y = 4; @@ -792,6 +832,10 @@ julia> x % y julia> x == div(x, y) * y + rem(x, y) true + +julia> rem.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + -2 -1 0 -2 -1 0 1 2 0 1 2 ``` """ rem @@ -801,7 +845,10 @@ const % = rem div(x, y) ÷(x, y) -The quotient from Euclidean division. Computes `x/y`, truncated to an integer. +The quotient from Euclidean (integer) division. Generally equivalent +to a mathematical operation x/y without a fractional part. + +See also: [`cld`](@ref), [`fld`](@ref), [`rem`](@ref), [`divrem`](@ref). # Examples ```jldoctest @@ -813,6 +860,10 @@ julia> -5 ÷ 3 julia> 5.0 ÷ 2 2.0 + +julia> div.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + -1 -1 -1 0 0 0 0 0 1 1 1 ``` """ div @@ -824,7 +875,7 @@ const ÷ = div Modulus after flooring division, returning a value `r` such that `mod(r, y) == mod(x, y)` in the range ``(0, y]`` for positive `y` and in the range ``[y,0)`` for negative `y`. -See also: [`fld1`](@ref), [`fldmod1`](@ref). +See also [`fld1`](@ref), [`fldmod1`](@ref). # Examples ```jldoctest @@ -843,7 +894,7 @@ mod1(x::T, y::T) where {T<:Real} = (m = mod(x, y); ifelse(m == 0, y, m)) Flooring division, returning a value consistent with `mod1(x,y)` -See also: [`mod1`](@ref), [`fldmod1`](@ref). +See also [`mod1`](@ref), [`fldmod1`](@ref). # Examples ```jldoctest @@ -870,7 +921,7 @@ end Return `(fld1(x,y), mod1(x,y))`. -See also: [`fld1`](@ref), [`mod1`](@ref). +See also [`fld1`](@ref), [`mod1`](@ref). """ fldmod1(x, y) = (fld1(x, y), mod1(x, y)) @@ -914,6 +965,42 @@ julia> [1:5;] |> x->x.^2 |> sum |> inv """ |>(x, f) = f(x) +""" + f = Returns(value) + +Create a callable `f` such that `f(args...; kw...) === value` holds. + +# Examples + +```jldoctest +julia> f = Returns(42); + +julia> f(1) +42 + +julia> f("hello", x=32) +42 + +julia> f.value +42 +``` + +!!! compat "Julia 1.7" + Returns requires at least Julia 1.7. +""" +struct Returns{V} <: Function + value::V + Returns{V}(value) where {V} = new{V}(value) + Returns(value) = new{Core.Typeof(value)}(value) +end + +(obj::Returns)(args...; kw...) = obj.value +function show(io::IO, obj::Returns) + show(io, typeof(obj)) + print(io, "(") + show(io, obj.value) + print(io, ")") +end # function composition """ @@ -953,7 +1040,7 @@ julia> fs = [ julia> ∘(fs...)(3) 3.0 ``` -See also [`ComposedFunction`](@ref). +See also [`ComposedFunction`](@ref), [`!f::Function`](@ref). """ function ∘ end @@ -1013,6 +1100,8 @@ end Predicate function negation: when the argument of `!` is a function, it returns a function which computes the boolean negation of `f`. +See also [`∘`](@ref). + # Examples ```jldoctest julia> str = "∀ ε > 0, ∃ δ > 0: |x-y| < δ ⇒ |f(x)-f(y)| < ε" @@ -1033,6 +1122,8 @@ julia> filter(!isletter, str) A type representing a partially-applied version of the two-argument function `f`, with the first argument fixed to the value "x". In other words, `Fix1(f, x)` behaves similarly to `y->f(x, y)`. + +See also [`Fix2`](@ref Base.Fix2). """ struct Fix1{F,T} <: Function f::F @@ -1293,6 +1384,8 @@ julia> [1, 2] .∈ ([2, 3],) 0 1 ``` + +See also: [`insorted`](@ref), [`contains`](@ref), [`occursin`](@ref), [`issubset`](@ref). """ in diff --git a/base/options.jl b/base/options.jl index 9ef4f78e90824..16dc884e8651e 100644 --- a/base/options.jl +++ b/base/options.jl @@ -21,6 +21,7 @@ struct JLOptions code_coverage::Int8 malloc_log::Int8 opt_level::Int8 + opt_level_min::Int8 debug_level::Int8 check_bounds::Int8 depwarn::Int8 diff --git a/base/pair.jl b/base/pair.jl index 30fd91892ce4b..7481d50b7458b 100644 --- a/base/pair.jl +++ b/base/pair.jl @@ -23,7 +23,7 @@ Construct a `Pair` object with type `Pair{typeof(x), typeof(y)}`. The elements are stored in the fields `first` and `second`. They can also be accessed via iteration (but a `Pair` is treated as a single "scalar" for broadcasting operations). -See also: [`Dict`](@ref) +See also [`Dict`](@ref). # Examples ```jldoctest diff --git a/base/path.jl b/base/path.jl index 1a7c2dc55018d..013ed5db26a5a 100644 --- a/base/path.jl +++ b/base/path.jl @@ -159,7 +159,7 @@ julia> dirname("/home/myuser/") "/home/myuser" ``` -See also: [`basename`](@ref) +See also [`basename`](@ref). """ dirname(path::AbstractString) = splitdir(path)[1] @@ -181,15 +181,15 @@ julia> basename("/home/myuser/") "" ``` -See also: [`dirname`](@ref) +See also [`dirname`](@ref). """ basename(path::AbstractString) = splitdir(path)[2] """ splitext(path::AbstractString) -> (AbstractString, AbstractString) -If the last component of a path contains a dot, split the path into everything before the -dot and everything including and after the dot. Otherwise, return a tuple of the argument +If the last component of a path contains one or more dots, split the path into everything before the +last dot and everything including and after the dot. Otherwise, return a tuple of the argument unmodified and the empty string. "splitext" is short for "split extension". # Examples @@ -197,8 +197,11 @@ unmodified and the empty string. "splitext" is short for "split extension". julia> splitext("/home/myuser/example.jl") ("/home/myuser/example", ".jl") -julia> splitext("/home/myuser/example") -("/home/myuser/example", "") +julia> splitext("/home/myuser/example.tar.gz") +("/home/myuser/example.tar", ".gz") + +julia> splitext("/home/my.user/example") +("/home/my.user/example", "") ``` """ function splitext(path::String) @@ -251,16 +254,19 @@ function splitpath(p::String) return out end -joinpath(path::AbstractString)::String = path - if Sys.iswindows() -function joinpath(path::AbstractString, paths::AbstractString...)::String - result_drive, result_path = splitdrive(path) +function joinpath(paths::Union{Tuple, AbstractVector})::String + assertstring(x) = x isa AbstractString || throw(ArgumentError("path component is not a string: $(repr(x))")) - local p_drive, p_path - for p in paths - p_drive, p_path = splitdrive(p) + isempty(paths) && throw(ArgumentError("collection of path components must be non-empty")) + assertstring(paths[1]) + result_drive, result_path = splitdrive(paths[1]) + + p_path = "" + for i in firstindex(paths)+1:lastindex(paths) + assertstring(paths[i]) + p_drive, p_path = splitdrive(paths[i]) if startswith(p_path, ('\\', '/')) # second path is absolute @@ -296,8 +302,15 @@ end else -function joinpath(path::AbstractString, paths::AbstractString...)::String - for p in paths +function joinpath(paths::Union{Tuple, AbstractVector})::String + assertstring(x) = x isa AbstractString || throw(ArgumentError("path component is not a string: $(repr(x))")) + + isempty(paths) && throw(ArgumentError("collection of path components must be non-empty")) + assertstring(paths[1]) + path = paths[1] + for i in firstindex(paths)+1:lastindex(paths) + p = paths[i] + assertstring(p) if isabspath(p) path = p elseif isempty(path) || path[end] == '/' @@ -311,8 +324,12 @@ end end # os-test +joinpath(paths::AbstractString...)::String = joinpath(paths) + """ joinpath(parts::AbstractString...) -> String + joinpath(parts::Vector{AbstractString}) -> String + joinpath(parts::Tuple{AbstractString}) -> String Join path components into a full path. If some argument is an absolute path or (on Windows) has a drive specification that doesn't match the drive computed for @@ -328,6 +345,11 @@ letter casing, hence `joinpath("C:\\A","c:b") = "C:\\A\\b"`. julia> joinpath("/home/myuser", "example.jl") "/home/myuser/example.jl" ``` + +```jldoctest +julia> joinpath(["/home/myuser", "example.jl"]) +"/home/myuser/example.jl" +``` """ joinpath @@ -390,7 +412,19 @@ normpath(a::AbstractString, b::AbstractString...) = normpath(joinpath(a,b...)) Convert a path to an absolute path by adding the current directory if necessary. Also normalizes the path as in [`normpath`](@ref). """ -abspath(a::String) = normpath(isabspath(a) ? a : joinpath(pwd(),a)) +function abspath(a::String)::String + if !isabspath(a) + cwd = pwd() + a_drive, a_nodrive = splitdrive(a) + if a_drive != "" && lowercase(splitdrive(cwd)[1]) != lowercase(a_drive) + cwd = a_drive * path_separator + a = joinpath(cwd, a_nodrive) + else + a = joinpath(cwd, a) + end + end + return normpath(a) +end """ abspath(path::AbstractString, paths::AbstractString...) -> String @@ -505,12 +539,16 @@ function relpath(path::String, startpath::String = ".") curdir = "." pardir = ".." path == startpath && return curdir - path_drive, path_without_drive = splitdrive(path) - startpath_drive, startpath_without_drive = splitdrive(startpath) - path_arr = split(abspath(path_without_drive), path_separator_re) - start_arr = split(abspath(startpath_without_drive), path_separator_re) if Sys.iswindows() - lowercase(path_drive) != lowercase(startpath_drive) && return abspath(path) + path_drive, path_without_drive = splitdrive(path) + startpath_drive, startpath_without_drive = splitdrive(startpath) + isempty(startpath_drive) && (startpath_drive = path_drive) # by default assume same as path drive + uppercase(path_drive) == uppercase(startpath_drive) || return abspath(path) # if drives differ return first path + path_arr = split(abspath(path_drive * path_without_drive), path_separator_re) + start_arr = split(abspath(path_drive * startpath_without_drive), path_separator_re) + else + path_arr = split(abspath(path), path_separator_re) + start_arr = split(abspath(startpath), path_separator_re) end i = 0 while i < min(length(path_arr), length(start_arr)) diff --git a/base/pcre.jl b/base/pcre.jl index e52bea2869eb7..a8edaaa089c31 100644 --- a/base/pcre.jl +++ b/base/pcre.jl @@ -228,7 +228,10 @@ function substring_length_bynumber(match_data, number) s = RefValue{Csize_t}() rc = ccall((:pcre2_substring_length_bynumber_8, PCRE_LIB), Cint, (Ptr{Cvoid}, Cint, Ref{Csize_t}), match_data, number, s) - rc < 0 && error("PCRE error: $(err_message(rc))") + if rc < 0 + rc == ERROR_UNSET && return 0 + error("PCRE error: $(err_message(rc))") + end return Int(s[]) end diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index 429fa67b2a3ab..ea966c44efc38 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -24,7 +24,7 @@ Given an AbstractArray `A`, create a view `B` such that the dimensions appear to be permuted. Similar to `permutedims`, except that no copying occurs (`B` shares storage with `A`). -See also: [`permutedims`](@ref). +See also [`permutedims`](@ref), [`invperm`](@ref). # Examples ```jldoctest @@ -83,10 +83,10 @@ end """ permutedims(A::AbstractArray, perm) -Permute the dimensions of array `A`. `perm` is a vector specifying a permutation of length -`ndims(A)`. +Permute the dimensions of array `A`. `perm` is a vector or a tuple of length `ndims(A)` +specifying the permutation. -See also: [`PermutedDimsArray`](@ref). +See also [`permutedims!`](@ref), [`PermutedDimsArray`](@ref), [`transpose`](@ref), [`invperm`](@ref). # Examples ```jldoctest @@ -100,7 +100,7 @@ julia> A = reshape(Vector(1:8), (2,2,2)) 5 7 6 8 -julia> permutedims(A, [3, 2, 1]) +julia> permutedims(A, (3, 2, 1)) 2×2×2 Array{Int64, 3}: [:, :, 1] = 1 3 @@ -109,6 +109,16 @@ julia> permutedims(A, [3, 2, 1]) [:, :, 2] = 2 4 6 8 + +julia> B = randn(5, 7, 11, 13); + +julia> perm = [4,1,3,2]; + +julia> size(permutedims(B, perm)) +(13, 5, 11, 7) + +julia> size(B)[perm] == ans +true ``` """ function permutedims(A::AbstractArray, perm) @@ -253,6 +263,16 @@ end P end +function Base._mapreduce_dim(f, op, init::Base._InitialValue, A::PermutedDimsArray, dims::Colon) + Base._mapreduce_dim(f, op, init, parent(A), dims) +end + +function Base.mapreducedim!(f, op, B::AbstractArray{T,N}, A::PermutedDimsArray{T,N,perm,iperm}) where {T,N,perm,iperm} + C = PermutedDimsArray{T,N,iperm,perm,typeof(B)}(B) # make the inverse permutation for the output + Base.mapreducedim!(f, op, C, parent(A)) + B +end + function Base.showarg(io::IO, A::PermutedDimsArray{T,N,perm}, toplevel) where {T,N,perm} print(io, "PermutedDimsArray(") Base.showarg(io, parent(A), false) diff --git a/base/pointer.jl b/base/pointer.jl index 0813d0a0c9735..d5b4972cc7875 100644 --- a/base/pointer.jl +++ b/base/pointer.jl @@ -125,7 +125,7 @@ Convert a `Ptr` to an object reference. Assumes the pointer refers to a valid he Julia object. If this is not the case, undefined behavior results, hence this function is considered "unsafe" and should be used with care. -See also: [`pointer_from_objref`](@ref). +See also [`pointer_from_objref`](@ref). """ unsafe_pointer_to_objref(x::Ptr) = ccall(:jl_value_ptr, Any, (Ptr{Cvoid},), x) @@ -139,11 +139,11 @@ remains referenced for the whole time that the `Ptr` will be used. This function may not be called on immutable objects, since they do not have stable memory addresses. -See also: [`unsafe_pointer_to_objref`](@ref). +See also [`unsafe_pointer_to_objref`](@ref). """ function pointer_from_objref(@nospecialize(x)) @_inline_meta - typeof(x).mutable || error("pointer_from_objref cannot be used on immutable objects") + typeof(x).name.mutable || error("pointer_from_objref cannot be used on immutable objects") ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x) end diff --git a/base/process.jl b/base/process.jl index 0c7db8a405d20..e7a460b0e8ead 100644 --- a/base/process.jl +++ b/base/process.jl @@ -476,7 +476,7 @@ function test_success(proc::Process) #TODO: this codepath is not currently tested throw(_UVError("could not start process " * repr(proc.cmd), proc.exitcode)) end - return proc.exitcode == 0 && (proc.termsignal == 0 || proc.termsignal == SIGPIPE) + return proc.exitcode == 0 && proc.termsignal == 0 end function success(x::Process) diff --git a/base/promotion.jl b/base/promotion.jl index a6e6d8fdcac4e..43add6cbf5f62 100644 --- a/base/promotion.jl +++ b/base/promotion.jl @@ -5,7 +5,6 @@ """ typejoin(T, S) - Return the closest common ancestor of `T` and `S`, i.e. the narrowest type from which they both inherit. """ @@ -144,6 +143,17 @@ end Compute a type that contains both `T` and `S`, which could be either a parent of both types, or a `Union` if appropriate. Falls back to [`typejoin`](@ref). + +See instead [`promote`](@ref), [`promote_type`](@ref). + +# Examples +```jldoctest +julia> Base.promote_typejoin(Int, Float64) +Real + +julia> Base.promote_type(Int, Float64) +Float64 +``` """ function promote_typejoin(@nospecialize(a), @nospecialize(b)) c = typejoin(_promote_typesubtract(a), _promote_typesubtract(b)) @@ -191,6 +201,9 @@ tolerated; for example, `promote_type(Int64, Float64)` returns [`Float64`](@ref) even though strictly, not all [`Int64`](@ref) values can be represented exactly as `Float64` values. +See also: [`promote`](@ref), [`promote_typejoin`](@ref), [`promote_rule`](@ref). + +# Examples ```jldoctest julia> promote_type(Int64, Float64) Float64 @@ -254,6 +267,8 @@ promote_result(::Type{T},::Type{S},::Type{Bottom},::Type{Bottom}) where {T,S} = Convert all arguments to a common type, and return them all (as a tuple). If no arguments can be converted, an error is raised. +See also: [`promote_type`], [`promote_rule`]. + # Examples ```jldoctest julia> promote(Int8(1), Float16(4.5), Float32(4.1)) @@ -335,7 +350,7 @@ where usually `^ == Base.^` unless `^` has been defined in the calling namespace.) If `y` is a negative integer literal, then `Base.literal_pow` transforms the operation to `inv(x)^-y` by default, where `-y` is positive. - +# Examples ```jldoctest julia> 3^5 243 diff --git a/base/range.jl b/base/range.jl index 54aeef84cae19..8051b0cdb7ccb 100644 --- a/base/range.jl +++ b/base/range.jl @@ -705,7 +705,7 @@ function argmin(r::AbstractRange) elseif step(r) > 0 firstindex(r) else - first(searchsorted(r, last(r))) + lastindex(r) end end @@ -720,7 +720,7 @@ function argmax(r::AbstractRange) if isempty(r) throw(ArgumentError("range must be non-empty")) elseif step(r) > 0 - first(searchsorted(r, last(r))) + lastindex(r) else firstindex(r) end @@ -828,17 +828,7 @@ function getindex(r::AbstractUnitRange, s::AbstractUnitRange{T}) where {T<:Integ @boundscheck checkbounds(r, s) if T === Bool - if length(s) == 0 - return r - elseif length(s) == 1 - if first(s) - return r - else - return range(r[1], length=0) - end - else # length(s) == 2 - return range(r[2], length=1) - end + range(first(s) ? first(r) : last(r), length = Int(last(s))) else f = first(r) st = oftype(f, f + first(s)-1) @@ -857,17 +847,7 @@ function getindex(r::AbstractUnitRange, s::StepRange{T}) where {T<:Integer} @boundscheck checkbounds(r, s) if T === Bool - if length(s) == 0 - return range(first(r), step=one(eltype(r)), length=0) - elseif length(s) == 1 - if first(s) - return range(first(r), step=one(eltype(r)), length=1) - else - return range(first(r), step=one(eltype(r)), length=0) - end - else # length(s) == 2 - return range(r[2], step=one(eltype(r)), length=1) - end + range(first(s) ? first(r) : last(r), step=oneunit(eltype(r)), length = Int(last(s))) else st = oftype(first(r), first(r) + s.start-1) return range(st, step=step(s), length=length(s)) @@ -888,7 +868,7 @@ function getindex(r::StepRange, s::AbstractRange{T}) where {T<:Integer} return range(first(r), step=step(r), length=0) end else # length(s) == 2 - return range(r[2], step=step(r), length=1) + return range(last(r), step=step(r), length=1) end else st = oftype(r.start, r.start + (first(s)-1)*step(r)) @@ -910,7 +890,7 @@ function getindex(r::StepRangeLen{T}, s::OrdinalRange{S}) where {T, S<:Integer} return StepRangeLen{T}(first(r), step(r), 0, 1) end else # length(s) == 2 - return StepRangeLen{T}(r[2], step(r), 1, 1) + return StepRangeLen{T}(last(r), step(r), 1, 1) end else # Find closest approach to offset by s @@ -935,7 +915,7 @@ function getindex(r::LinRange{T}, s::OrdinalRange{S}) where {T, S<:Integer} return LinRange(first(r), first(r), 0) end else # length(s) == 2 - return LinRange(r[2], r[2], 1) + return LinRange(last(r), last(r), 1) end else vfirst = unsafe_getindex(r, first(s)) @@ -947,6 +927,14 @@ end show(io::IO, r::AbstractRange) = print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r))) show(io::IO, r::OneTo) = print(io, "Base.OneTo(", r.stop, ")") +function show(io::IO, r::StepRangeLen) + if step(r) != 0 + print(io, repr(first(r)), ':', repr(step(r)), ':', repr(last(r))) + else + # ugly temporary printing, to avoid 0:0:0 etc. + print(io, "StepRangeLen(", repr(first(r)), ", ", repr(step(r)), ", ", repr(length(r)), ")") + end +end function ==(r::T, s::T) where {T<:AbstractRange} isempty(r) && return isempty(s) @@ -1258,7 +1246,7 @@ function _define_range_op(@nospecialize f) r1l = length(r1) (r1l == length(r2) || throw(DimensionMismatch("argument dimensions must match: length of r1 is $r1l, length of r2 is $(length(r2))"))) - range($f(first(r1), first(r2)), step=$f(step(r1), step(r2)), length=r1l) + StepRangeLen($f(first(r1), first(r2)), $f(step(r1), step(r2)), r1l) end function $f(r1::LinRange{T}, r2::LinRange{T}) where T @@ -1294,7 +1282,7 @@ end Find `y` in the range `r` such that ``x ≡ y (mod n)``, where `n = length(r)`, i.e. `y = mod(x - first(r), n) + first(r)`. -See also: [`mod1`](@ref). +See also [`mod1`](@ref). # Examples ```jldoctest diff --git a/base/reduce.jl b/base/reduce.jl index 185a158893daa..6490358214c7e 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -237,7 +237,7 @@ foldr(op, itr; kw...) = mapfoldr(identity, op, itr; kw...) if ifirst == ilast @inbounds a1 = A[ifirst] return mapreduce_first(f, op, a1) - elseif ifirst + blksize > ilast + elseif ilast - ifirst < blksize # sequential portion @inbounds a1 = A[ifirst] @inbounds a2 = A[ifirst+1] @@ -249,7 +249,7 @@ foldr(op, itr; kw...) = mapfoldr(identity, op, itr; kw...) return v else # pairwise portion - imid = (ifirst + ilast) >> 1 + imid = ifirst + (ilast - ifirst) >> 1 v1 = mapreduce_impl(f, op, A, ifirst, imid, blksize) v2 = mapreduce_impl(f, op, A, imid+1, ilast, blksize) return op(v1, v2) @@ -518,6 +518,8 @@ for non-empty collections. !!! compat "Julia 1.6" Keyword argument `init` requires Julia 1.6 or later. +See also: [`reduce`](@ref), [`mapreduce`](@ref), [`count`](@ref), [`union`](@ref). + # Examples ```jldoctest julia> sum(1:20) @@ -529,7 +531,7 @@ julia> sum(1:20; init = 0.0) """ sum(a; kw...) = sum(identity, a; kw...) sum(a::AbstractArray{Bool}; kw...) = - kw.data === NamedTuple() ? count(a) : reduce(add_sum, a; kw...) + isempty(kw) ? count(a) : reduce(add_sum, a; kw...) ## prod """ @@ -572,6 +574,8 @@ for non-empty collections. !!! compat "Julia 1.6" Keyword argument `init` requires Julia 1.6 or later. +See also: [`reduce`](@ref), [`cumprod`](@ref), [`any`](@ref). + # Examples ```jldoctest julia> prod(1:5) @@ -806,6 +810,8 @@ Return the maximal element of the collection `itr` and its index or key. If there are multiple maximal elements, then the first one will be returned. Values are compared with `isless`. +See also: [`findmin`](@ref), [`argmax`](@ref), [`maximum`](@ref). + # Examples ```jldoctest @@ -863,6 +869,8 @@ Return the minimal element of the collection `itr` and its index or key. If there are multiple minimal elements, then the first one will be returned. `NaN` is treated as less than all other values except `missing`. +See also: [`findmax`](@ref), [`argmin`](@ref), [`minimum`](@ref). + # Examples ```jldoctest @@ -913,6 +921,8 @@ The collection must not be empty. Values are compared with `isless`. +See also: [`argmin`](@ref), [`findmax`](@ref). + # Examples ```jldoctest julia> argmax([8, 0.1, -9, pi]) @@ -950,7 +960,6 @@ julia> argmin(x -> -x^3 + x^2 - 10, -5:5) julia> argmin(acos, 0:0.1:1) 1.0 - ``` """ argmin(f, domain) = findmin(f, domain)[2] @@ -965,6 +974,8 @@ The collection must not be empty. `NaN` is treated as less than all other values except `missing`. +See also: [`argmax`](@ref), [`findmin`](@ref). + # Examples ```jldoctest julia> argmin([8, 0.1, -9, pi]) @@ -992,6 +1003,8 @@ If the input contains [`missing`](@ref) values, return `missing` if all non-miss values are `false` (or equivalently, if the input contains no `true` value), following [three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). +See also: [`all`](@ref), [`count`](@ref), [`sum`](@ref), [`|`](@ref), , [`||`](@ref). + # Examples ```jldoctest julia> a = [true,false,false,true] @@ -1028,6 +1041,8 @@ If the input contains [`missing`](@ref) values, return `missing` if all non-miss values are `true` (or equivalently, if the input contains no `false` value), following [three-valued logic](https://en.wikipedia.org/wiki/Three-valued_logic). +See also: [`all!`](@ref), [`any`](@ref), [`count`](@ref), [`&`](@ref), , [`&&`](@ref), [`allunique`](@ref). + # Examples ```jldoctest julia> a = [true,false,false,true] @@ -1167,6 +1182,8 @@ to start counting from and therefore also determines the output type. !!! compat "Julia 1.6" `init` keyword was added in Julia 1.6. +See also: [`any`](@ref), [`sum`](@ref). + # Examples ```jldoctest julia> count(i->(4<=i<=6), [2,3,4,5,6]) diff --git a/base/reducedim.jl b/base/reducedim.jl index 85807851cd23d..5851cfcc0cd1f 100644 --- a/base/reducedim.jl +++ b/base/reducedim.jl @@ -3,7 +3,7 @@ ## Functions to compute the reduced shape # for reductions that expand 0 dims to 1 -reduced_index(i::OneTo) = OneTo(1) +reduced_index(i::OneTo{T}) where {T} = OneTo(one(T)) reduced_index(i::Union{Slice, IdentityUnitRange}) = oftype(i, first(i):first(i)) reduced_index(i::AbstractUnitRange) = throw(ArgumentError( @@ -295,7 +295,7 @@ reducedim!(op, R::AbstractArray{RT}, A::AbstractArrayOrBroadcasted) where {RT} = """ mapreduce(f, op, A::AbstractArray...; dims=:, [init]) -Evaluates to the same as `reduce(op, map(f, A); dims=dims, init=init)`, but is generally +Evaluates to the same as `reduce(op, map(f, A...); dims=dims, init=init)`, but is generally faster because the intermediate array is avoided. !!! compat "Julia 1.2" @@ -590,6 +590,8 @@ Compute the maximum value of an array over the given dimensions. See also the [`max(a,b)`](@ref) function to take the maximum of two or more arguments, which can be applied elementwise to arrays via `max.(a,b)`. +See also: [`maximum!`](@ref), [`extrema`](@ref), [`findmax`](@ref), [`argmax`](@ref). + # Examples ```jldoctest julia> A = [1 2; 3 4] @@ -612,7 +614,7 @@ maximum(A::AbstractArray; dims) """ maximum(f, A::AbstractArray; dims) -Compute the maximum value from of calling the function `f` on each element of an array over the given +Compute the maximum value by calling the function `f` on each element of an array over the given dimensions. # Examples @@ -665,6 +667,8 @@ Compute the minimum value of an array over the given dimensions. See also the [`min(a,b)`](@ref) function to take the minimum of two or more arguments, which can be applied elementwise to arrays via `min.(a,b)`. +See also: [`minimum!`](@ref), [`extrema`](@ref), [`findmin`](@ref), [`argmin`](@ref). + # Examples ```jldoctest julia> A = [1 2; 3 4] @@ -687,7 +691,7 @@ minimum(A::AbstractArray; dims) """ minimum(f, A::AbstractArray; dims) -Compute the minimum value from of calling the function `f` on each element of an array over the given +Compute the minimum value by calling the function `f` on each element of an array over the given dimensions. # Examples @@ -760,7 +764,7 @@ all(A::AbstractArray; dims) """ all(p, A; dims) -Determine whether predicate p returns true for all elements along the given dimensions of an array. +Determine whether predicate `p` returns `true` for all elements along the given dimensions of an array. # Examples ```jldoctest @@ -832,7 +836,7 @@ any(::AbstractArray; dims) """ any(p, A; dims) -Determine whether predicate p returns true for any elements along the given dimensions of an array. +Determine whether predicate `p` returns `true` for any elements along the given dimensions of an array. # Examples ```jldoctest @@ -995,7 +999,7 @@ julia> findmin(A, dims=1) ([1.0 2.0], CartesianIndex{2}[CartesianIndex(1, 1) CartesianIndex(1, 2)]) julia> findmin(A, dims=2) -([1.0; 3.0], CartesianIndex{2}[CartesianIndex(1, 1); CartesianIndex(2, 1)]) +([1.0; 3.0;;], CartesianIndex{2}[CartesianIndex(1, 1); CartesianIndex(2, 1);;]) ``` """ findmin(A::AbstractArray; dims=:) = _findmin(A, dims) @@ -1042,7 +1046,7 @@ julia> findmax(A, dims=1) ([3.0 4.0], CartesianIndex{2}[CartesianIndex(2, 1) CartesianIndex(2, 2)]) julia> findmax(A, dims=2) -([2.0; 4.0], CartesianIndex{2}[CartesianIndex(1, 2); CartesianIndex(2, 2)]) +([2.0; 4.0;;], CartesianIndex{2}[CartesianIndex(1, 2); CartesianIndex(2, 2);;]) ``` """ findmax(A::AbstractArray; dims=:) = _findmax(A, dims) diff --git a/base/reflection.jl b/base/reflection.jl index bfed4154cd7d8..33327b64a6a2a 100644 --- a/base/reflection.jl +++ b/base/reflection.jl @@ -20,6 +20,8 @@ nameof(m::Module) = ccall(:jl_module_name, Ref{Symbol}, (Any,), m) Get a module's enclosing `Module`. `Main` is its own parent. +See also: [`names`](@ref), [`nameof`](@ref), [`fullname`](@ref), [`@__MODULE__`](@ref). + # Examples ```jldoctest julia> parentmodule(Main) @@ -94,6 +96,8 @@ are also included. As a special case, all names defined in `Main` are considered \"exported\", since it is not idiomatic to explicitly export names from `Main`. + +See also: [`@locals`](@ref Base.@locals), [`@__MODULE__`](@ref). """ names(m::Module; all::Bool = false, imported::Bool = false) = sort!(ccall(:jl_module_names, Array{Symbol,1}, (Any, Cint, Cint), m, all, imported)) @@ -150,7 +154,7 @@ function fieldname(t::DataType, i::Integer) end throw_need_pos_int(i) = throw(ArgumentError("Field numbers must be positive integers. $i is invalid.")) - t.abstract && throw_not_def_field() + t.name.abstract && throw_not_def_field() names = _fieldnames(t) n_fields = length(names)::Int i > n_fields && throw_field_access(t, i, n_fields) @@ -167,10 +171,15 @@ fieldname(t::Type{<:Tuple}, i::Integer) = Get a tuple with the names of the fields of a `DataType`. +See also [`propertynames`](@ref), [`hasfield`](@ref). + # Examples ```jldoctest julia> fieldnames(Rational) (:num, :den) + +julia> fieldnames(typeof(1+im)) +(:re, :im) ``` """ fieldnames(t::DataType) = (fieldcount(t); # error check to make sure type is specific enough @@ -284,9 +293,11 @@ macro locals() end """ - objectid(x) + objectid(x) -> UInt Get a hash value for `x` based on object identity. `objectid(x)==objectid(y)` if `x === y`. + +See also [`hash`](@ref), [`IdDict`](@ref). """ objectid(@nospecialize(x)) = ccall(:jl_object_id, UInt, (Any,), x) @@ -446,6 +457,8 @@ Return `true` iff value `v` is mutable. See [Mutable Composite Types](@ref) for a discussion of immutability. Note that this function works on values, so if you give it a type, it will tell you that a value of `DataType` is mutable. +See also [`isbits`](@ref), [`isstructtype`](@ref). + # Examples ```jldoctest julia> ismutable(1) @@ -458,7 +471,7 @@ true !!! compat "Julia 1.5" This function requires at least Julia 1.5. """ -ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).mutable) +ismutable(@nospecialize(x)) = (@_pure_meta; typeof(x).name.mutable) """ @@ -473,7 +486,7 @@ Determine whether type `T` was declared as a mutable type function ismutabletype(@nospecialize(t::Type)) t = unwrap_unionall(t) # TODO: what to do for `Union`? - return isa(t, DataType) && t.mutable + return isa(t, DataType) && t.name.mutable end @@ -489,7 +502,7 @@ function isstructtype(@nospecialize(t::Type)) # TODO: what to do for `Union`? isa(t, DataType) || return false hasfield = !isdefined(t, :types) || !isempty(t.types) - return hasfield || (t.size == 0 && !t.abstract) + return hasfield || (t.size == 0 && !t.name.abstract) end """ @@ -504,7 +517,7 @@ function isprimitivetype(@nospecialize(t::Type)) # TODO: what to do for `Union`? isa(t, DataType) || return false hasfield = !isdefined(t, :types) || !isempty(t.types) - return !hasfield && t.size != 0 && !t.abstract + return !hasfield && t.size != 0 && !t.name.abstract end """ @@ -519,6 +532,8 @@ This category of types is significant since they are valid as type parameters, may not track [`isdefined`](@ref) / [`isassigned`](@ref) status, and have a defined layout that is compatible with C. +See also [`isbits`](@ref), [`isprimitivetype`](@ref), [`ismutable`](@ref). + # Examples ```jldoctest julia> isbitstype(Complex{Float64}) @@ -533,7 +548,7 @@ isbitstype(@nospecialize(t::Type)) = (@_pure_meta; isa(t, DataType) && t.isbitst """ isbits(x) -Return `true` if `x` is an instance of an `isbitstype` type. +Return `true` if `x` is an instance of an [`isbitstype`](@ref) type. """ isbits(@nospecialize x) = (@_pure_meta; typeof(x).isbitstype) @@ -564,6 +579,8 @@ end Determine whether type `T` is a concrete type, meaning it could have direct instances (values `x` such that `typeof(x) === T`). +See also: [`isbits`](@ref), [`isabstracttype`](@ref), [`issingletontype`](@ref). + # Examples ```jldoctest julia> isconcretetype(Complex) @@ -606,7 +623,7 @@ function isabstracttype(@nospecialize(t)) @_pure_meta t = unwrap_unionall(t) # TODO: what to do for `Union`? - return isa(t, DataType) && t.abstract + return isa(t, DataType) && t.name.abstract end """ @@ -740,7 +757,7 @@ function fieldcount(@nospecialize t) end abstr = true else - abstr = t.abstract || (t.name === Tuple.name && isvatuple(t)) + abstr = t.name.abstract || (t.name === Tuple.name && isvatuple(t)) end if abstr throw(ArgumentError("type does not have a definite number of fields")) @@ -845,7 +862,7 @@ function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool= throw(ArgumentError("'debuginfo' must be either :source or :none")) end return map(method_instances(f, t)) do m - if generated && isgenerated(m) + if generated && hasgenerator(m) if may_invoke_generator(m) return ccall(:jl_code_for_staged, Any, (Any,), m)::CodeInfo else @@ -860,8 +877,8 @@ function code_lowered(@nospecialize(f), @nospecialize(t=Tuple); generated::Bool= end end -isgenerated(m::Method) = isdefined(m, :generator) -isgenerated(m::Core.MethodInstance) = isgenerated(m.def) +hasgenerator(m::Method) = isdefined(m, :generator) +hasgenerator(m::Core.MethodInstance) = hasgenerator(m.def::Method) # low-level method lookup functions used by the compiler @@ -898,15 +915,13 @@ end # high-level, more convenient method lookup functions # type for reflecting and pretty-printing a subset of methods -mutable struct MethodList +mutable struct MethodList <: AbstractArray{Method,1} ms::Array{Method,1} mt::Core.MethodTable end -length(m::MethodList) = length(m.ms) -isempty(m::MethodList) = isempty(m.ms) -iterate(m::MethodList, s...) = iterate(m.ms, s...) -eltype(::Type{MethodList}) = Method +size(m::MethodList) = size(m.ms) +getindex(m::MethodList, i) = m.ms[i] function MethodList(mt::Core.MethodTable) ms = Method[] @@ -927,6 +942,8 @@ A list of modules can also be specified as an array. !!! compat "Julia 1.4" At least Julia 1.4 is required for specifying a module. + +See also: [`which`](@ref) and `@which`. """ function methods(@nospecialize(f), @nospecialize(t), mod::Union{Tuple{Module},AbstractArray{Module},Nothing}=nothing) @@ -1262,19 +1279,23 @@ function print_statement_costs(io::IO, @nospecialize(tt::Type); maxcost = Core.Compiler.statement_costs!(cst, code.code, code, Any[match.sparams...], false, params) nd = ndigits(maxcost) println(io, meth) - IRShow.show_ir(io, code, (io, linestart, idx) -> (print(io, idx > 0 ? lpad(cst[idx], nd+1) : " "^(nd+1), " "); return "")) + irshow_config = IRShow.IRShowConfig() do io, linestart, idx + print(io, idx > 0 ? lpad(cst[idx], nd+1) : " "^(nd+1), " ") + return "" + end + IRShow.show_ir(io, code, irshow_config) println(io) end end print_statement_costs(args...; kwargs...) = print_statement_costs(stdout, args...; kwargs...) -function _which(@nospecialize(tt::Type), world=typemax(UInt)) +function _which(@nospecialize(tt::Type), world=get_world_counter()) min_valid = RefValue{UInt}(typemin(UInt)) max_valid = RefValue{UInt}(typemax(UInt)) match = ccall(:jl_gf_invoke_lookup_worlds, Any, (Any, UInt, Ptr{Csize_t}, Ptr{Csize_t}), - tt, typemax(UInt), min_valid, max_valid) + tt, world, min_valid, max_valid) if match === nothing error("no unique matching method found for the specified argument types") end @@ -1287,6 +1308,8 @@ end Returns the method of `f` (a `Method` object) that would be called for arguments of the given `types`. If `types` is an abstract type, then the method that would be called by `invoke` is returned. + +See also: [`parentmodule`](@ref), and `@which` and `@edit` in [`InteractiveUtils`](@ref man-interactive-utils). """ function which(@nospecialize(f), @nospecialize(t)) if isa(f, Core.Builtin) @@ -1631,6 +1654,8 @@ as well to get the properties of an instance of the type. of the documented interface of `x`. If you want it to also return "private" fieldnames intended for internal use, pass `true` for the optional second argument. REPL tab completion on `x.` shows only the `private=false` properties. + +See also: [`hasproperty`](@ref), [`hasfield`](@ref). """ propertynames(x) = fieldnames(typeof(x)) propertynames(m::Module) = names(m) @@ -1643,5 +1668,7 @@ Return a boolean indicating whether the object `x` has `s` as one of its own pro !!! compat "Julia 1.2" This function requires at least Julia 1.2. + +See also: [`propertynames`](@ref), [`hasfield`](@ref). """ hasproperty(x, s::Symbol) = s in propertynames(x) diff --git a/base/refpointer.jl b/base/refpointer.jl index 67cec0925ff58..725b2d05f95ee 100644 --- a/base/refpointer.jl +++ b/base/refpointer.jl @@ -117,7 +117,7 @@ convert(::Type{Ref{T}}, x::AbstractArray{T}) where {T} = RefArray(x, 1) function unsafe_convert(P::Union{Type{Ptr{T}},Type{Ptr{Cvoid}}}, b::RefArray{T})::P where T if allocatedinline(T) p = pointer(b.x, b.i) - elseif isconcretetype(T) && T.mutable + elseif isconcretetype(T) && T.name.mutable p = pointer_from_objref(b.x[b.i]) else # see comment on equivalent branch for RefValue diff --git a/base/refvalue.jl b/base/refvalue.jl index cf5f4e6b74d6f..69d9a31061724 100644 --- a/base/refvalue.jl +++ b/base/refvalue.jl @@ -38,7 +38,7 @@ isassigned(x::RefValue) = isdefined(x, :x) function unsafe_convert(P::Union{Type{Ptr{T}},Type{Ptr{Cvoid}}}, b::RefValue{T})::P where T if allocatedinline(T) p = pointer_from_objref(b) - elseif isconcretetype(T) && T.mutable + elseif isconcretetype(T) && T.name.mutable p = pointer_from_objref(b.x) else # If the slot is not leaf type, it could be either immutable or not. diff --git a/base/regex.jl b/base/regex.jl index a79f51995fab3..82e2042552ee4 100644 --- a/base/regex.jl +++ b/base/regex.jl @@ -145,6 +145,47 @@ in a string using an `AbstractPattern`. """ abstract type AbstractMatch end +""" + RegexMatch + +A type representing a single match to a `Regex` found in a string. +Typically created from the [`match`](@ref) function. + +The `match` field stores the substring of the entire matched string. +The `captures` field stores the substrings for each capture group, indexed by number. +To index by capture group name, the entire match object should be indexed instead, +as shown in the examples. +The location of the start of the match is stored in the `offset` field. +The `offsets` field stores the locations of the start of each capture group, +with 0 denoting a group that was not captured. + +This type can be used as an iterator over the capture groups of the `Regex`, +yielding the substrings captured in each group. +Because of this, the captures of a match can be destructured. +If a group was not captured, `nothing` will be yielded instead of a substring. + +Methods that accept a `RegexMatch` object are defined for [`iterate`](@ref), +[`length`](@ref), [`eltype`](@ref), [`keys`](@ref keys(::RegexMatch)), [`haskey`](@ref), and +[`getindex`](@ref), where keys are the the names or numbers of a capture group. +See [`keys`](@ref keys(::RegexMatch)) for more information. + +# Examples +```jldoctest +julia> m = match(r"(?\\d+):(?\\d+)(am|pm)?", "11:30 in the morning") +RegexMatch("11:30", hour="11", minute="30", 3=nothing) + +julia> hr, min, ampm = m; + +julia> hr +"11" + +julia> m["minute"] +"30" + +julia> m.match +"11:30" +``` +""" struct RegexMatch <: AbstractMatch match::SubString{String} captures::Vector{Union{Nothing,SubString{String}}} @@ -153,6 +194,28 @@ struct RegexMatch <: AbstractMatch regex::Regex end +""" + keys(m::RegexMatch) -> Vector + +Return a vector of keys for all capture groups of the underlying regex. +A key is included even if the capture group fails to match. +That is, `idx` will be in the return value even if `m[idx] == nothing`. + +Unnamed capture groups will have integer keys corresponding to their index. +Named capture groups will have string keys. + +!!! compat "Julia 1.6" + This method was added in Julia 1.6 + +# Examples +```jldoctest +julia> keys(match(r"(?\\d+):(?\\d+)(am|pm)?", "11:30")) +3-element Vector{Any}: + "hour" + "minute" + 3 +``` +""" function keys(m::RegexMatch) idx_to_capture_name = PCRE.capture_names(m.regex.regex) return map(eachindex(m.captures)) do i @@ -275,7 +338,7 @@ end """ match(r::Regex, s::AbstractString[, idx::Integer[, addopts]]) -Search for the first match of the regular expression `r` in `s` and return a `RegexMatch` +Search for the first match of the regular expression `r` in `s` and return a [`RegexMatch`](@ref) object containing the match, or nothing if the match failed. The matching substring can be retrieved by accessing `m.match` and the captured sequences can be retrieved by accessing `m.captures` The optional `idx` argument specifies an index at which to start the search. @@ -528,6 +591,8 @@ replace_err(repl) = error("Bad replacement string: $repl") function _write_capture(io, re::RegexAndMatchData, group) len = PCRE.substring_length_bynumber(re.match_data, group) + # in the case of an optional group that doesn't match, len == 0 + len == 0 && return ensureroom(io, len+1) PCRE.substring_copy_bynumber(re.match_data, group, pointer(io.data, io.ptr), len+1) diff --git a/base/reinterpretarray.jl b/base/reinterpretarray.jl index c49c566ae65e5..3fec3452def86 100644 --- a/base/reinterpretarray.jl +++ b/base/reinterpretarray.jl @@ -683,7 +683,7 @@ end @noinline function mapreduce_impl(f::F, op::OP, A::AbstractArrayOrBroadcasted, ifirst::SCI, ilast::SCI, blksize::Int) where {F,OP,SCI<:SCartesianIndex2{K}} where K - if ifirst.j + blksize > ilast.j + if ilast.j - ifirst.j < blksize # sequential portion @inbounds a1 = A[ifirst] @inbounds a2 = A[SCI(2,ifirst.j)] @@ -702,7 +702,7 @@ end return v else # pairwise portion - jmid = (ifirst.j + ilast.j) >> 1 + jmid = ifirst.j + (ilast.j - ifirst.j) >> 1 v1 = mapreduce_impl(f, op, A, ifirst, SCI(K,jmid), blksize) v2 = mapreduce_impl(f, op, A, SCI(1,jmid+1), ilast, blksize) return op(v1, v2) diff --git a/base/reshapedarray.jl b/base/reshapedarray.jl index d9a9f4eafaa80..671dd2d86a840 100644 --- a/base/reshapedarray.jl +++ b/base/reshapedarray.jl @@ -146,7 +146,7 @@ end # product of trailing dims into the last element rdims_trailing(l, inds...) = length(l) * rdims_trailing(inds...) rdims_trailing(l) = length(l) -rdims(out::Val{N}, inds::Tuple) where {N} = rdims(ntuple(i -> OneTo(1), Val(N)), inds) +rdims(out::Val{N}, inds::Tuple) where {N} = rdims(ntuple(Returns(OneTo(1)), Val(N)), inds) rdims(out::Tuple{}, inds::Tuple{}) = () # N == 0, M == 0 rdims(out::Tuple{}, inds::Tuple{Any}) = () rdims(out::Tuple{}, inds::NTuple{M,Any}) where {M} = () diff --git a/base/ryu/Ryu.jl b/base/ryu/Ryu.jl index 1d260fe9b3696..81d1c41f4c19f 100644 --- a/base/ryu/Ryu.jl +++ b/base/ryu/Ryu.jl @@ -64,7 +64,7 @@ Various options for the output format include: * `hash`: whether the decimal point should be written, even if no additional digits are needed for precision * `precision`: minimum number of significant digits to be included in the decimal string; extra `'0'` characters will be added for padding if necessary * `decchar`: decimal point character to be used - * `trimtrailingzeros`: whether trailing zeros should be removed + * `trimtrailingzeros`: whether trailing zeros of fractional part should be removed """ function writefixed(x::T, precision::Integer, diff --git a/base/ryu/exp.jl b/base/ryu/exp.jl index cf1fe23105b8c..30291212d014d 100644 --- a/base/ryu/exp.jl +++ b/base/ryu/exp.jl @@ -1,25 +1,16 @@ -@inline function writeexp(buf, pos, v::T, +function writeexp(buf, pos, v::T, precision=-1, plus=false, space=false, hash=false, expchar=UInt8('e'), decchar=UInt8('.'), trimtrailingzeros=false) where {T <: Base.IEEEFloat} @assert 0 < pos <= length(buf) startpos = pos x = Float64(v) - neg = signbit(x) + pos = append_sign(x, plus, space, buf, pos) + # special cases if x == 0 - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end buf[pos] = UInt8('0') pos += 1 - if precision > 0 + if precision > 0 && !trimtrailingzeros buf[pos] = decchar pos += 1 for _ = 1:precision @@ -41,16 +32,6 @@ buf[pos + 2] = UInt8('N') return pos + 3 elseif !isfinite(x) - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end buf[pos] = UInt8('I') buf[pos + 1] = UInt8('n') buf[pos + 2] = UInt8('f') @@ -70,16 +51,6 @@ end nonzero = false precision += 1 - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end digits = 0 printedDigits = 0 availableDigits = 0 @@ -213,7 +184,7 @@ roundPos = pos while true roundPos -= 1 - if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-') + if roundPos == (startpos - 1) || buf[roundPos] == UInt8('-') || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' ')) buf[roundPos + 1] = UInt8('1') e += 1 break diff --git a/base/ryu/fixed.jl b/base/ryu/fixed.jl index 4be1b3741832e..e0085f5c66dab 100644 --- a/base/ryu/fixed.jl +++ b/base/ryu/fixed.jl @@ -1,30 +1,18 @@ -@inline function writefixed(buf, pos, v::T, +function writefixed(buf, pos, v::T, precision=-1, plus=false, space=false, hash=false, decchar=UInt8('.'), trimtrailingzeros=false) where {T <: Base.IEEEFloat} @assert 0 < pos <= length(buf) startpos = pos x = Float64(v) - neg = signbit(x) + pos = append_sign(x, plus, space, buf, pos) + # special cases if x == 0 - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end buf[pos] = UInt8('0') pos += 1 - if precision > 0 + if precision > 0 && !trimtrailingzeros buf[pos] = decchar pos += 1 - if trimtrailingzeros - precision = 1 - end for _ = 1:precision buf[pos] = UInt8('0') pos += 1 @@ -40,16 +28,6 @@ buf[pos + 2] = UInt8('N') return pos + 3 elseif !isfinite(x) - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end buf[pos] = UInt8('I') buf[pos + 1] = UInt8('n') buf[pos + 2] = UInt8('f') @@ -68,16 +46,6 @@ m2 = (Int64(1) << 52) | mant end nonzero = false - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end if e2 >= -52 idx = e2 < 0 ? 0 : indexforexp(e2) p10bits = pow10bitsforindex(idx) @@ -101,9 +69,11 @@ buf[pos] = UInt8('0') pos += 1 end + hasfractional = false if precision > 0 || hash buf[pos] = decchar pos += 1 + hasfractional = true end if e2 < 0 idx = div(-e2, 16) @@ -166,11 +136,12 @@ dotPos = 1 while true roundPos -= 1 - if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) + if roundPos == (startpos - 1) || (buf[roundPos] == UInt8('-')) || (plus && buf[roundPos] == UInt8('+')) || (space && buf[roundPos] == UInt8(' ')) buf[roundPos + 1] = UInt8('1') if dotPos > 1 buf[dotPos] = UInt8('0') buf[dotPos + 1] = decchar + hasfractional = true end buf[pos] = UInt8('0') pos += 1 @@ -199,7 +170,7 @@ pos += 1 end end - if trimtrailingzeros + if trimtrailingzeros && hasfractional while buf[pos - 1] == UInt8('0') pos -= 1 end diff --git a/base/ryu/shortest.jl b/base/ryu/shortest.jl index 52502fecf9610..f95c09d235e6d 100644 --- a/base/ryu/shortest.jl +++ b/base/ryu/shortest.jl @@ -224,13 +224,11 @@ integer. If a `maxsignif` argument is provided, then `b < maxsignif`. return b, e10 end - -@inline function writeshortest(buf::Vector{UInt8}, pos, x::T, - plus=false, space=false, hash=true, - precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), - typed=false, compact=false) where {T} +function writeshortest(buf::Vector{UInt8}, pos, x::T, + plus=false, space=false, hash=true, + precision=-1, expchar=UInt8('e'), padexp=false, decchar=UInt8('.'), + typed=false, compact=false) where {T} @assert 0 < pos <= length(buf) - neg = signbit(x) # special cases if x == 0 if typed && x isa Float16 @@ -244,17 +242,7 @@ end buf[pos + 7] = UInt8('(') pos += 8 end - - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end + pos = append_sign(x, plus, space, buf, pos) buf[pos] = UInt8('0') pos += 1 if hash @@ -291,6 +279,7 @@ end end return pos elseif isnan(x) + pos = append_sign(x, plus, space, buf, pos) buf[pos] = UInt8('N') buf[pos + 1] = UInt8('a') buf[pos + 2] = UInt8('N') @@ -305,22 +294,20 @@ end end return pos + 3 + (typed && x isa Union{Float32, Float16} ? 2 : 0) elseif !isfinite(x) - if neg - buf[pos] = UInt8('-') - end - buf[pos + neg] = UInt8('I') - buf[pos + neg + 1] = UInt8('n') - buf[pos + neg + 2] = UInt8('f') + pos = append_sign(x, plus, space, buf, pos) + buf[pos] = UInt8('I') + buf[pos + 1] = UInt8('n') + buf[pos + 2] = UInt8('f') if typed if x isa Float32 - buf[pos + neg + 3] = UInt8('3') - buf[pos + neg + 4] = UInt8('2') + buf[pos + 3] = UInt8('3') + buf[pos + 4] = UInt8('2') elseif x isa Float16 - buf[pos + neg + 3] = UInt8('1') - buf[pos + neg + 4] = UInt8('6') + buf[pos + 3] = UInt8('1') + buf[pos + 4] = UInt8('6') end end - return pos + neg + 3 + (typed && x isa Union{Float32, Float16} ? 2 : 0) + return pos + 3 + (typed && x isa Union{Float32, Float16} ? 2 : 0) end output, nexp = reduce_shortest(x, compact ? 999_999 : nothing) @@ -336,16 +323,7 @@ end buf[pos + 7] = UInt8('(') pos += 8 end - if neg - buf[pos] = UInt8('-') - pos += 1 - elseif plus - buf[pos] = UInt8('+') - pos += 1 - elseif space - buf[pos] = UInt8(' ') - pos += 1 - end + pos = append_sign(x, plus, space, buf, pos) olength = decimallength(output) exp_form = true diff --git a/base/ryu/utils.jl b/base/ryu/utils.jl index 24e38a0a50241..352f8f19cb9be 100644 --- a/base/ryu/utils.jl +++ b/base/ryu/utils.jl @@ -195,6 +195,20 @@ Compute `(m * mul) >> j % 10^9` where `mul = mula + mulb<<64 + mulc<<128`, and ` return (v % UInt32) - UInt32(1000000000) * shifted end +@inline function append_sign(x, plus, space, buf, pos) + if signbit(x) && !isnan(x) # suppress minus sign for signaling NaNs + buf[pos] = UInt8('-') + pos += 1 + elseif plus + buf[pos] = UInt8('+') + pos += 1 + elseif space + buf[pos] = UInt8(' ') + pos += 1 + end + return pos +end + @inline function append_n_digits(olength, digits, buf, pos) i = 0 while digits >= 10000 diff --git a/base/set.jl b/base/set.jl index fb837fbf86166..0c8a8b95b10ce 100644 --- a/base/set.jl +++ b/base/set.jl @@ -17,6 +17,8 @@ Set() = Set{Any}() Construct a [`Set`](@ref) of the values generated by the given iterable object, or an empty set. Should be used instead of [`BitSet`](@ref) for sparse integer sets, or for sets of arbitrary objects. + +See also: [`push!`](@ref), [`empty!`](@ref), [`union!`](@ref), [`in`](@ref). """ Set(itr) = _Set(itr, IteratorEltype(itr)) @@ -105,6 +107,8 @@ as determined by [`isequal`](@ref), in the order that the first of each set of equivalent elements originally appears. The element type of the input is preserved. +See also: [`unique!`](@ref), [`allunique`](@ref). + # Examples ```jldoctest julia> unique([1, 2, 6, 2]) @@ -371,6 +375,8 @@ end Return `true` if all values from `itr` are distinct when compared with [`isequal`](@ref). +See also: [`unique`](@ref), [`issorted`](@ref). + # Examples ```jldoctest julia> a = [1; 2; 3] @@ -379,6 +385,9 @@ julia> a = [1; 2; 3] 2 3 +julia> allunique(a) +true + julia> allunique([a, a]) false ``` @@ -537,7 +546,7 @@ of the result will not include singleton types which are replaced with values of a different type: for example, `Union{T,Missing}` will become `T` if `missing` is replaced. -See also [`replace!`](@ref). +See also [`replace!`](@ref), [`splice!`](@ref), [`delete!`](@ref), [`insert!`](@ref). # Examples ```jldoctest diff --git a/base/shell.jl b/base/shell.jl index 48fcb4079bda0..99866c8010b0f 100644 --- a/base/shell.jl +++ b/base/shell.jl @@ -322,7 +322,7 @@ run(setenv(`cmd /C echo %cmdargs%`, "cmdargs" => cmdargs)) With an I/O stream parameter `io`, the result will be written there, rather than returned as a string. -See also: [`escape_microsoft_c_args`](@ref), [`shell_escape_posixly`](@ref) +See also [`escape_microsoft_c_args`](@ref), [`shell_escape_posixly`](@ref). # Example ```jldoctest @@ -376,7 +376,7 @@ It joins command-line arguments to be passed to a Windows C/C++/Julia application into a command line, escaping or quoting the meta characters space, TAB, double quote and backslash where needed. -See also: [`shell_escape_wincmd`](@ref), [`escape_raw_string`](@ref) +See also [`shell_escape_wincmd`](@ref), [`escape_raw_string`](@ref). """ function escape_microsoft_c_args(io::IO, args::AbstractString...) # http://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES diff --git a/base/show.jl b/base/show.jl index 278a5c96df615..fa69913ee1c3c 100644 --- a/base/show.jl +++ b/base/show.jl @@ -45,6 +45,7 @@ function show(io::IO, ::MIME"text/plain", f::Function) end show(io::IO, ::MIME"text/plain", c::ComposedFunction) = show(io, c) +show(io::IO, ::MIME"text/plain", c::Returns) = show(io, c) function show(io::IO, ::MIME"text/plain", iter::Union{KeySet,ValueIterator}) isempty(iter) && get(io, :compact, false) && return show(io, iter) @@ -583,6 +584,69 @@ function make_typealias(@nospecialize(x::Type)) end end +isgensym(s::Symbol) = '#' in string(s) + +function show_can_elide(p::TypeVar, wheres::Vector, elide::Int, env::SimpleVector, skip::Int) + elide == 0 && return false + wheres[elide] === p || return false + for i = (elide + 1):length(wheres) + v = wheres[i]::TypeVar + has_typevar(v.lb, p) && return false + has_typevar(v.ub, p) && return false + end + for i = 1:length(env) + i == skip && continue + has_typevar(env[i], p) && return false + end + return true +end + +function show_typeparams(io::IO, env::SimpleVector, orig::SimpleVector, wheres::Vector) + n = length(env) + elide = length(wheres) + function egal_var(p::TypeVar, @nospecialize o) + return o isa TypeVar && + ccall(:jl_types_egal, Cint, (Any, Any), p.ub, o.ub) != 0 && + ccall(:jl_types_egal, Cint, (Any, Any), p.lb, o.lb) != 0 + end + for i = n:-1:1 + p = env[i] + if p isa TypeVar + if i == n && egal_var(p, orig[i]) && show_can_elide(p, wheres, elide, env, i) + n -= 1 + elide -= 1 + elseif p.lb === Union{} && isgensym(p.name) && show_can_elide(p, wheres, elide, env, i) + elide -= 1 + elseif p.ub === Any && isgensym(p.name) && show_can_elide(p, wheres, elide, env, i) + elide -= 1 + end + end + end + if n > 0 + print(io, "{") + for i = 1:n + p = env[i] + if p isa TypeVar + if p.lb === Union{} && something(findfirst(@nospecialize(w) -> w === p, wheres), 0) > elide + print(io, "<:") + show(io, p.ub) + elseif p.ub === Any && something(findfirst(@nospecialize(w) -> w === p, wheres), 0) > elide + print(io, ">:") + show(io, p.lb) + else + show(io, p) + end + else + show(io, p) + end + i < n && print(io, ", ") + end + print(io, "}") + end + resize!(wheres, elide) + nothing +end + function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, wheres::Vector) if !(get(io, :compact, false)::Bool) # Print module prefix unless alias is visible from module passed to @@ -595,21 +659,19 @@ function show_typealias(io::IO, name::GlobalRef, x::Type, env::SimpleVector, whe end end print(io, name.name) - n = length(env) - n == 0 && return - - print(io, "{") - param_io = IOContext(io) - for i = 1:length(wheres) - p = wheres[i]::TypeVar - param_io = IOContext(param_io, :unionall_env => p) + isempty(env) && return + io = IOContext(io) + for p in wheres + io = IOContext(io, :unionall_env => p) end - for i = 1:n - p = env[i] - show(param_io, p) - i < n && print(io, ", ") + orig = getfield(name.mod, name.name) + vars = TypeVar[] + while orig isa UnionAll + push!(vars, orig.var) + orig = orig.body end - print(io, "}") + show_typeparams(io, env, Core.svec(vars...), wheres) + nothing end function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type)) @@ -642,12 +704,12 @@ function make_wheres(io::IO, env::SimpleVector, @nospecialize(x::Type)) return wheres end -function show_wheres(io::IO, env::Vector) - isempty(env) && return +function show_wheres(io::IO, wheres::Vector) + isempty(wheres) && return io = IOContext(io) - n = length(env) + n = length(wheres) for i = 1:n - p = env[i]::TypeVar + p = wheres[i]::TypeVar print(io, n == 1 ? " where " : i == 1 ? " where {" : ", ") show(io, p) io = IOContext(io, :unionall_env => p) @@ -857,7 +919,11 @@ function _show_type(io::IO, @nospecialize(x::Type)) push!(wheres, var) io = IOContext(io, :unionall_env => var) end - show(io, x) + if x isa DataType + show_datatype(io, x, wheres) + else + show(io, x) + end end show_wheres(io, wheres) end @@ -919,29 +985,23 @@ function show_type_name(io::IO, tn::Core.TypeName) nothing end -function show_datatype(io::IO, @nospecialize(x::DataType)) +function show_datatype(io::IO, @nospecialize(x::DataType), wheres::Vector=TypeVar[]) parameters = x.parameters::SimpleVector istuple = x.name === Tuple.name n = length(parameters) # Print homogeneous tuples with more than 3 elements compactly as NTuple{N, T} - if istuple && n > 3 && all(i -> (parameters[1] === i), parameters) - print(io, "NTuple{", n, ", ", parameters[1], "}") + if istuple + if n > 3 && all(@nospecialize(i) -> (parameters[1] === i), parameters) + print(io, "NTuple{", n, ", ", parameters[1], "}") + else + print(io, "Tuple{") + join(io, parameters, ", ") + print(io, "}") + end else show_type_name(io, x.name) - if (n > 0 || istuple) && x !== Tuple - # Do not print the type parameters for the primary type if we are - # printing a method signature or type parameter. - # Always print the type parameter if we are printing the type directly - # since this information is still useful. - print(io, '{') - for i = 1:n - p = parameters[i] - show(io, p) - i < n && print(io, ", ") - end - print(io, '}') - end + show_typeparams(io, parameters, unwrap_unionall(x.name.wrapper).parameters, wheres) end end @@ -956,9 +1016,22 @@ end show_supertypes(typ::DataType) = show_supertypes(stdout, typ) """ - @show + @show exs... + +Prints one or more expressions, and their results, to `stdout`, and returns the last result. -Show an expression and result, returning the result. See also [`show`](@ref). +See also: [`show`](@ref), [`@info`](@ref Logging), [`println`](@ref). + +# Examples +```jldoctest +julia> x = @show 1+2 +1 + 2 = 3 +3 + +julia> @show x^2 x/2; +x ^ 2 = 9 +x / 2 = 1.5 +``` """ macro show(exs...) blk = Expr(:block) @@ -1204,7 +1277,7 @@ const ExprNode = Union{Expr, QuoteNode, Slot, LineNumberNode, SSAValue, # IOContext(io, :unquote_fallback => false) tells show_unquoted to treat any # Expr whose head is :$ as if it is inside a quote, preventing fallback to the # "unhandled" case: this is used by print/string to be lawful to Rule 1 above. -# On the countrary, show/repr have to follow Rule 2, requiring any Expr whose +# On the contrary, show/repr have to follow Rule 2, requiring any Expr whose # head is :$ and which is not inside a quote to fallback to the "unhandled" case: # this is behavior is triggered by IOContext(io, :unquote_fallback => true) print( io::IO, ex::ExprNode) = (show_unquoted(IOContext(io, :unquote_fallback => false), ex, 0, -1); nothing) @@ -1404,8 +1477,8 @@ emphasize(io, str::AbstractString, col = Base.error_color()) = get(io, :color, f printstyled(io, str; color=col, bold=true) : print(io, uppercase(str)) -show_linenumber(io::IO, line) = print(io, "#= line ", line, " =#") -show_linenumber(io::IO, line, file) = print(io, "#= ", file, ":", line, " =#") +show_linenumber(io::IO, line) = printstyled(io, "#= line ", line, " =#", color=:light_black) +show_linenumber(io::IO, line, file) = printstyled(io, "#= ", file, ":", line, " =#", color=:light_black) show_linenumber(io::IO, line, file::Nothing) = show_linenumber(io, line) # show a block, e g if/for/etc @@ -2226,7 +2299,7 @@ function show_signature_function(io::IO, @nospecialize(ft), demangle=false, farg uwf = unwrap_unionall(f) parens = isa(f, UnionAll) && !(isa(uwf, DataType) && f === uwf.name.wrapper) parens && print(io, "(") - show(io, f) + print_within_stacktrace(io, f, bold=true) parens && print(io, ")") else if html @@ -2416,7 +2489,7 @@ function show(io::IO, src::CodeInfo; debuginfo::Symbol=:source) # TODO: static parameter values? # only accepts :source or :none, we can't have a fallback for default since # that would break code_typed(, debuginfo=:source) iff IRShow.default_debuginfo[] = :none - IRShow.show_ir(lambda_io, src, IRShow.__debuginfo[debuginfo](src)) + IRShow.show_ir(lambda_io, src, IRShow.IRShowConfig(IRShow.__debuginfo[debuginfo](src))) else # this is a CodeInfo that has not been used as a method yet, so its locations are still LineNumberNodes body = Expr(:block) @@ -2543,7 +2616,7 @@ function dump(io::IOContext, x::DataType, n::Int, indent) if x !== Any print(io, " <: ", supertype(x)) end - if n > 0 && !(x <: Tuple) && !x.abstract + if n > 0 && !(x <: Tuple) && !x.name.abstract tvar_io::IOContext = io for tparam in x.parameters # approximately recapture the list of tvar parameterization @@ -2709,6 +2782,9 @@ function array_summary(io::IO, a, inds) print(io, " with indices ", inds2string(inds)) end +## `summary` for Function +summary(io::IO, f::Function) = show(io, MIME"text/plain"(), f) + """ showarg(io::IO, x, toplevel) @@ -2772,7 +2848,7 @@ function showarg(io::IO, v::SubArray, toplevel) toplevel && print(io, " with eltype ", eltype(v)) return nothing end -showindices(io, ::Union{Slice,IdentityUnitRange}, inds...) = +showindices(io, ::Slice, inds...) = (print(io, ", :"); showindices(io, inds...)) showindices(io, ind1, inds...) = (print(io, ", ", ind1); showindices(io, inds...)) diff --git a/base/simdloop.jl b/base/simdloop.jl index e0b6d89d97277..29e2382cf39aa 100644 --- a/base/simdloop.jl +++ b/base/simdloop.jl @@ -8,7 +8,7 @@ export @simd, simd_outer_range, simd_inner_length, simd_index # Error thrown from ill-formed uses of @simd struct SimdError <: Exception - msg::AbstractString + msg::String end # Parse iteration space expression diff --git a/base/some.jl b/base/some.jl index 272ed0e00ce31..58280fe727352 100644 --- a/base/some.jl +++ b/base/some.jl @@ -64,18 +64,20 @@ Return `true` if `x === nothing`, and return `false` if not. !!! compat "Julia 1.1" This function requires at least Julia 1.1. + +See also [`something`](@ref), [`notnothing`](@ref), [`ismissing`](@ref). """ isnothing(x) = x === nothing """ - something(x, y...) + something(x...) Return the first value in the arguments which is not equal to [`nothing`](@ref), if any. Otherwise throw an error. Arguments of type [`Some`](@ref) are unwrapped. -See also [`coalesce`](@ref). +See also [`coalesce`](@ref), [`skipmissing`](@ref), [`@something`](@ref). # Examples ```jldoctest @@ -98,3 +100,46 @@ something() = throw(ArgumentError("No value arguments present")) something(x::Nothing, y...) = something(y...) something(x::Some, y...) = x.value something(x::Any, y...) = x + + +""" + @something(x...) + +Short-circuiting version of [`something`](@ref). + +# Examples +```jldoctest +julia> f(x) = (println("f(\$x)"); nothing); + +julia> a = 1; + +julia> a = @something a f(2) f(3) error("Unable to find default for `a`") +1 + +julia> b = nothing; + +julia> b = @something b f(2) f(3) error("Unable to find default for `b`") +f(2) +f(3) +ERROR: Unable to find default for `b` +[...] + +julia> b = @something b f(2) f(3) Some(nothing) +f(2) +f(3) + +julia> b === nothing +true +``` + +!!! compat "Julia 1.7" + This macro is available as of Julia 1.7. +""" +macro something(args...) + expr = :(nothing) + for arg in reverse(args) + expr = :((val = $arg) !== nothing ? val : $expr) + end + return esc(:(something(let val; $expr; end))) +end + diff --git a/base/sort.jl b/base/sort.jl index 6a3883215c0b4..0946eec516ef7 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -231,89 +231,59 @@ end function searchsortedlast(a::AbstractRange{<:Real}, x::Real, o::DirectOrdering)::keytype(a) require_one_based_indexing(a) - if step(a) == 0 - lt(o, x, first(a)) ? 0 : length(a) + f, h, l = first(a), step(a), last(a) + if lt(o, x, f) + 0 + elseif h == 0 || !lt(o, x, l) + length(a) else - n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a))) + n = round(Integer, (x - f) / h + 1) lt(o, x, a[n]) ? n - 1 : n end end function searchsortedfirst(a::AbstractRange{<:Real}, x::Real, o::DirectOrdering)::keytype(a) require_one_based_indexing(a) - if step(a) == 0 - lt(o, first(a), x) ? length(a) + 1 : 1 + f, h, l = first(a), step(a), last(a) + if !lt(o, f, x) + 1 + elseif h == 0 || lt(o, l, x) + length(a) + 1 else - n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a))) + n = round(Integer, (x - f) / h + 1) lt(o, a[n], x) ? n + 1 : n end end function searchsortedlast(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering)::keytype(a) require_one_based_indexing(a) - h = step(a) - if h == 0 - lt(o, x, first(a)) ? 0 : length(a) - elseif h > 0 && x < first(a) - firstindex(a) - 1 - elseif h > 0 && x >= last(a) - lastindex(a) - elseif h < 0 && x > first(a) - firstindex(a) - 1 - elseif h < 0 && x <= last(a) - lastindex(a) + f, h, l = first(a), step(a), last(a) + if lt(o, x, f) + 0 + elseif h == 0 || !lt(o, x, l) + length(a) else if o isa ForwardOrdering - fld(floor(Integer, x) - first(a), h) + 1 + fld(floor(Integer, x) - f, h) + 1 else - fld(ceil(Integer, x) - first(a), h) + 1 + fld(ceil(Integer, x) - f, h) + 1 end end end function searchsortedfirst(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering)::keytype(a) require_one_based_indexing(a) - h = step(a) - if h == 0 - lt(o, first(a), x) ? length(a)+1 : 1 - elseif h > 0 && x <= first(a) - firstindex(a) - elseif h > 0 && x > last(a) - lastindex(a) + 1 - elseif h < 0 && x >= first(a) - firstindex(a) - elseif h < 0 && x < last(a) - lastindex(a) + 1 + f, h, l = first(a), step(a), last(a) + if !lt(o, f, x) + 1 + elseif h == 0 || lt(o, l, x) + length(a) + 1 else if o isa ForwardOrdering - -fld(floor(Integer, -x) + Signed(first(a)), h) + 1 - else - -fld(ceil(Integer, -x) + Signed(first(a)), h) + 1 - end - end -end - -function searchsortedfirst(a::AbstractRange{<:Integer}, x::Unsigned, o::DirectOrdering)::keytype(a) - require_one_based_indexing(a) - if lt(o, first(a), x) - if step(a) == 0 - length(a) + 1 + cld(ceil(Integer, x) - f, h) + 1 else - min(cld(x - first(a), step(a)), length(a)) + 1 + cld(floor(Integer, x) - f, h) + 1 end - else - 1 - end -end - -function searchsortedlast(a::AbstractRange{<:Integer}, x::Unsigned, o::DirectOrdering)::keytype(a) - require_one_based_indexing(a) - if lt(o, x, first(a)) - 0 - elseif step(a) == 0 - length(a) - else - min(fld(x - first(a), step(a)) + 1, length(a)) end end @@ -337,6 +307,8 @@ according to the order specified by the `by`, `lt` and `rev` keywords, assuming is already sorted in that order. Return an empty range located at the insertion point if `a` does not contain values equal to `x`. +See also: [`insorted`](@ref), [`searchsortedfirst`](@ref), [`sort`](@ref), [`findall`](@ref). + # Examples ```jldoctest julia> searchsorted([1, 2, 4, 5, 5, 7], 4) # single match @@ -363,6 +335,8 @@ Return the index of the first value in `a` greater than or equal to `x`, accordi specified order. Return `length(a) + 1` if `x` is greater than all values in `a`. `a` is assumed to be sorted. +See also: [`searchsortedlast`](@ref), [`searchsorted`](@ref), [`findfirst`](@ref). + # Examples ```jldoctest julia> searchsortedfirst([1, 2, 4, 5, 5, 7], 4) # single match @@ -409,13 +383,14 @@ julia> searchsortedlast([1, 2, 4, 5, 5, 7], 0) # no match, insert at start """ searchsortedlast """ - insorted(a, x; by=, lt=, rev=false) + insorted(a, x; by=, lt=, rev=false) -> Bool Determine whether an item is in the given sorted collection, in the sense that it is [`==`](@ref) to one of the values of the collection according to the order specified by the `by`, `lt` and `rev` keywords, assuming that `a` is already -sorted in that order, see [`sort`](@ref) for the keywords. See also -[`in`](@ref). Returns a `Bool` value. +sorted in that order, see [`sort`](@ref) for the keywords. + +See also [`in`](@ref). # Examples ```jldoctest @@ -907,7 +882,7 @@ using the same keywords as [`sort!`](@ref). The permutation is guaranteed to be if the sorting algorithm is unstable, meaning that indices of equal elements appear in ascending order. -See also [`sortperm!`](@ref). +See also [`sortperm!`](@ref), [`partialsortperm`](@ref), [`invperm`](@ref), [`indexin`](@ref). # Examples ```jldoctest diff --git a/base/special/cbrt.jl b/base/special/cbrt.jl index 978f7cf89971e..9fda5c41fb09e 100644 --- a/base/special/cbrt.jl +++ b/base/special/cbrt.jl @@ -146,3 +146,20 @@ function cbrt(x::Union{Float32,Float64}) t = _approx_cbrt(x) return _improve_cbrt(x, t) end + +function cbrt(a::Float16) + if !isfinite(a) || iszero(a) + return a + end + x = Float32(a) + + # 5 bit approximation. Simpler than _approx_cbrt since subnormals can not appear + u = highword(x) & 0x7fff_ffff + v = div(u, UInt32(3)) + 0x2a5119f2 + t = copysign(fromhighword(Float32, v), x) + + # 2 newton iterations + t = 0.33333334f0 * (2f0*t + x/(t*t)) + t = 0.33333334f0 * (2f0*t + x/(t*t)) + return Float16(t) +end diff --git a/base/special/exp.jl b/base/special/exp.jl index 5dffcde385812..fd88eee3fc638 100644 --- a/base/special/exp.jl +++ b/base/special/exp.jl @@ -9,7 +9,7 @@ MAGIC_ROUND_CONST(::Type{Float32}) = 1.048576f7 MAX_EXP(n::Val{2}, ::Type{Float32}) = 128.0f0 MAX_EXP(n::Val{2}, ::Type{Float64}) = 1024.0 MAX_EXP(n::Val{:ℯ}, ::Type{Float32}) = 88.72284f0 -MAX_EXP(n::Val{:ℯ}, ::Type{Float64}) = 709.782712893384 +MAX_EXP(n::Val{:ℯ}, ::Type{Float64}) = 709.7827128933841 MAX_EXP(n::Val{10}, ::Type{Float32}) = 38.53184f0 MAX_EXP(n::Val{10}, ::Type{Float64}) = 308.25471555991675 @@ -198,91 +198,136 @@ end # # 2. Approximate b^r by 7th-degree minimax polynomial p_b(r) on the interval [-log(b,2)/2, log(b,2)/2]. # 3. Scale back: b^x = 2^N * p_b(r) - # For both, a little extra care needs to be taken if b^r is subnormal. # The solution is to do the scaling back in 2 steps as just messing with the exponent wouldn't work. -for (func, base) in (:exp2=>Val(2), :exp=>Val(:ℯ), :exp10=>Val(10)) - @eval begin - function ($func)(x::T) where T<:Float64 - N_float = muladd(x, LogBo256INV($base, T), MAGIC_ROUND_CONST(T)) - N = reinterpret(uinttype(T), N_float) % Int32 - N_float -= MAGIC_ROUND_CONST(T) #N_float now equals round(x*LogBo256INV($base, T)) - r = muladd(N_float, LogBo256U($base, T), x) - r = muladd(N_float, LogBo256L($base, T), r) - k = N >> 8 - jU, jL = table_unpack(N&255 +1) - small_part = muladd(jU, expm1b_kernel($base, r), jL) + jU - - if !(abs(x) <= SUBNORM_EXP($base, T)) - x >= MAX_EXP($base, T) && return Inf - x <= MIN_EXP($base, T) && return 0.0 - if k <= -53 - # The UInt64 forces promotion. (Only matters for 32 bit systems.) - twopk = (k + UInt64(53)) << 52 - return reinterpret(T, twopk + reinterpret(UInt64, small_part))*(2.0^-53) - end - end - twopk = Int64(k) << 52 - return reinterpret(T, twopk + reinterpret(Int64, small_part)) - end - function ($func)(x::T) where T<:Float32 - N_float = round(x*LogBINV($base, T)) - N = unsafe_trunc(Int32, N_float) - r = muladd(N_float, LogBU($base, T), x) - r = muladd(N_float, LogBL($base, T), r) - small_part = expb_kernel($base, r) - if !(abs(x) <= SUBNORM_EXP($base, T)) - x > MAX_EXP($base, T) && return Inf32 - x < MIN_EXP($base, T) && return 0.0f0 - if N<=Int32(-24) - twopk = reinterpret(T, (N+Int32(151)) << Int32(23)) - return (twopk*small_part)*(2f0^(-24)) - end - N == (exponent_max(T)+1) && return small_part * T(2.0) * T(2.0)^exponent_max(T) - end - twopk = reinterpret(T, (N+Int32(127)) << Int32(23)) - return twopk*small_part +@inline function exp_impl(x::Float64, base) + T = Float64 + N_float = muladd(x, LogBo256INV(base, T), MAGIC_ROUND_CONST(T)) + N = reinterpret(UInt64, N_float) % Int32 + N_float -= MAGIC_ROUND_CONST(T) #N_float now equals round(x*LogBo256INV(base, T)) + r = muladd(N_float, LogBo256U(base, T), x) + r = muladd(N_float, LogBo256L(base, T), r) + k = N >> 8 + jU, jL = table_unpack(N&255 + 1) + small_part = muladd(jU, expm1b_kernel(base, r), jL) + jU + + if !(abs(x) <= SUBNORM_EXP(base, T)) + x >= MAX_EXP(base, T) && return Inf + x <= MIN_EXP(base, T) && return 0.0 + if k <= -53 + # The UInt64 forces promotion. (Only matters for 32 bit systems.) + twopk = (k + UInt64(53)) << 52 + return reinterpret(T, twopk + reinterpret(UInt64, small_part))*(2.0^-53) end + #k == 1024 && return (small_part * 2.0) * 2.0^1023 + end + twopk = Int64(k) << 52 + return reinterpret(T, twopk + reinterpret(Int64, small_part)) +end +@inline function exp_impl_fast(x::Float64, base) + T = Float64 + N_float = muladd(x, LogBo256INV(base, T), MAGIC_ROUND_CONST(T)) + N = reinterpret(UInt64, N_float) % Int32 + N_float -= MAGIC_ROUND_CONST(T) #N_float now equals round(x*LogBo256INV(base, T)) + r = muladd(N_float, LogBo256U(base, T), x) + r = muladd(N_float, LogBo256L(base, T), r) + k = N >> 8 + jU = reinterpret(Float64, JU_CONST | (@inbounds J_TABLE[N&255 + 1] & JU_MASK)) + small_part = muladd(jU, expm1b_kernel(base, r), jU) + twopk = Int64(k) << 52 + return reinterpret(T, twopk + reinterpret(Int64, small_part)) +end - function ($func)(a::Float16) - T = Float32 - x = T(a) - N_float = round(x*LogBINV($base, T)) - N = unsafe_trunc(Int32, N_float) - r = muladd(N_float, LogB($base, Float16), x) - small_part = expb_kernel($base, r) - if !(abs(x) <= SUBNORM_EXP($base, T)) - x > MAX_EXP($base, T) && return Inf16 - N<=Int32(-24) && return zero(Float16) - end - twopk = reinterpret(T, (N+Int32(127)) << Int32(23)) - return Float16(twopk*small_part) +@inline function exp_impl(x::Float32, base) + T = Float32 + N_float = round(x*LogBINV(base, T)) + N = unsafe_trunc(Int32, N_float) + r = muladd(N_float, LogBU(base, T), x) + r = muladd(N_float, LogBL(base, T), r) + small_part = expb_kernel(base, r) + if !(abs(x) <= SUBNORM_EXP(base, T)) + x > MAX_EXP(base, T) && return Inf32 + x < MIN_EXP(base, T) && return 0.0f0 + if N <= Int32(-24) + twopk = reinterpret(T, (N+Int32(151)) << Int32(23)) + return (twopk*small_part)*(2f0^(-24)) end + N == 128 && return small_part * T(2.0) * T(2.0)^127 + end + twopk = reinterpret(T, (N+Int32(127)) << Int32(23)) + return twopk*small_part +end + +@inline function exp_impl_fast(x::Float32, base) + T = Float32 + N_float = round(x*LogBINV(base, T)) + N = unsafe_trunc(Int32, N_float) + r = muladd(N_float, LogBU(base, T), x) + r = muladd(N_float, LogBL(base, T), r) + small_part = expb_kernel(base, r) + twopk = reinterpret(T, (N+Int32(127)) << Int32(23)) + return twopk*small_part +end + +@inline function exp_impl(a::Float16, base) + T = Float32 + x = T(a) + N_float = round(x*LogBINV(base, T)) + N = unsafe_trunc(Int32, N_float) + r = muladd(N_float, LogB(base, Float16), x) + small_part = expb_kernel(base, r) + if !(abs(x) <= SUBNORM_EXP(base, T)) + x > MAX_EXP(base, T) && return Inf16 + N<=Int32(-24) && return zero(Float16) end + twopk = reinterpret(T, (N+Int32(127)) << Int32(23)) + return Float16(twopk*small_part) end + +for (func, fast_func, base) in ((:exp2, :exp2_fast, Val(2)), + (:exp, :exp_fast, Val(:ℯ)), + (:exp10, :exp10_fast, Val(10))) + @eval begin + $func(x::Union{Float16,Float32,Float64}) = exp_impl(x, $base) + $fast_func(x::Union{Float32,Float64}) = exp_impl_fast(x, $base) + end +end + @doc """ exp(x) -Compute the natural base exponential of `x`, in other words ``e^x``. +Compute the natural base exponential of `x`, in other words ``ℯ^x``. + +See also [`exp2`](@ref), [`exp10`](@ref) and [`cis`](@ref). # Examples ```jldoctest julia> exp(1.0) 2.718281828459045 + +julia> exp(im * pi) == cis(pi) +true ``` """ exp(x::Real) - """ exp2(x) Compute the base 2 exponential of `x`, in other words ``2^x``. +See also [`ldexp`](@ref), [`<<`](@ref). + # Examples ```jldoctest julia> exp2(5) 32.0 + +julia> 2^5 +32 + +julia> exp2(63) > typemax(Int) +true ``` """ exp2(x) @@ -296,6 +341,9 @@ Compute the base 10 exponential of `x`, in other words ``10^x``. ```jldoctest julia> exp10(2) 100.0 + +julia> 10^2 +100 ``` """ exp10(x) @@ -314,3 +362,106 @@ exp10(x) reinterpret(Float64, (exponent_bias(Float64) + (x % Int64)) << (significand_bits(Float64) % UInt)) end end + +# min and max arguments for expm1 by type +MAX_EXP(::Type{Float64}) = 709.7827128933845 # log 2^1023*(2-2^-52) +MIN_EXP(::Type{Float64}) = -37.42994775023705 # log 2^-54 +MAX_EXP(::Type{Float32}) = 88.72284f0 # log 2^127 *(2-2^-23) +MIN_EXP(::Type{Float32}) = -17.32868f0 # log 2^-25 +MAX_EXP(::Type{Float16}) = Float16(11.09) # log 2^15 *(2-2^-10) +MIN_EXP(::Type{Float16}) = -Float16(8.32) # log 2^-12 + +Ln2INV(::Type{Float64}) = 1.4426950408889634 +Ln2(::Type{Float64}) = -0.6931471805599453 +Ln2INV(::Type{Float32}) = 1.442695f0 +Ln2(::Type{Float32}) = -0.6931472f0 + +# log(.75) <= x <= log(1.25) +@inline function expm1_small(x::Float64) + p = evalpoly(x, (0.16666666666666632, 0.04166666666666556, 0.008333333333401227, + 0.001388888889068783, 0.00019841269447671544, 2.480157691845342e-5, + 2.7558212415361945e-6, 2.758218402815439e-7, 2.4360682937111612e-8)) + p2 = exthorner(x, (1.0, .5, p)) + return fma(x, p2[1], x*p2[2]) +end +@inline function expm1_small(x::Float32) + p = evalpoly(x, (0.16666666f0, 0.041666627f0, 0.008333682f0, + 0.0013908712f0, 0.0001933096f0)) + p2 = exthorner(x, (1f0, .5f0, p)) + return fma(x, p2[1], x*p2[2]) +end + +function expm1(x::Float64) + T = Float64 + if -0.2876820724517809 <= x <= 0.22314355131420976 + return expm1_small(x) + elseif !(abs(x)<=MIN_EXP(Float64)) + isnan(x) && return x + x > MAX_EXP(Float64) && return Inf + x < MIN_EXP(Float64) && return -1.0 + end + + N_float = muladd(x, LogBo256INV(Val(:ℯ), T), MAGIC_ROUND_CONST(T)) + N = reinterpret(UInt64, N_float) % Int32 + N_float -= MAGIC_ROUND_CONST(T) #N_float now equals round(x*LogBo256INV(Val(:ℯ), T)) + r = muladd(N_float, LogBo256U(Val(:ℯ), T), x) + r = muladd(N_float, LogBo256L(Val(:ℯ), T), r) + k = Int64(N >> 8) + jU, jL = table_unpack(N&255 +1) + p = expm1b_kernel(Val(:ℯ), r) + twopk = reinterpret(Float64, (1023+k) << 52) + twopnk = reinterpret(Float64, (1023-k) << 52) + k>=106 && return reinterpret(Float64, (1022+k) << 52)*(jU + muladd(jU, p, jL))*2 + k>=53 && return twopk*(jU + muladd(jU, p, (jL-twopnk))) + k<=-2 && return twopk*(jU + muladd(jU, p, jL))-1 + return twopk*((jU-twopnk) + fma(jU, p, jL)) +end + +function expm1(x::Float32) + x > MAX_EXP(Float32) && return Inf32 + x < MIN_EXP(Float32) && return -1f0 + if -0.2876821f0 <=x <= 0.22314355f0 + return expm1_small(x) + end + x = Float64(x) + N_float = round(x*Ln2INV(Float64)) + N = unsafe_trunc(UInt64, N_float) + r = muladd(N_float, Ln2(Float64), x) + hi = evalpoly(r, (1.0, .5, 0.16666667546642386, 0.041666183019487026, + 0.008332997481506921, 0.0013966479175977883, 0.0002004037059220124)) + small_part = r*hi + twopk = reinterpret(Float64, (N+1023) << 52) + return Float32(muladd(twopk, small_part, twopk-1.0)) +end + +function expm1(x::Float16) + x > MAX_EXP(Float16) && return Inf16 + x < MIN_EXP(Float16) && return Float16(-1.0) + x = Float32(x) + if -0.2876821f0 <=x <= 0.22314355f0 + return Float16(x*evalpoly(x, (1f0, .5f0, 0.16666628f0, 0.04166785f0, 0.008351848f0, 0.0013675707f0))) + end + N_float = round(x*Ln2INV(Float32)) + N = unsafe_trunc(UInt32, N_float) + r = muladd(N_float, Ln2(Float32), x) + hi = evalpoly(r, (1f0, .5f0, 0.16666667f0, 0.041665863f0, 0.008333111f0, 0.0013981499f0, 0.00019983904f0)) + small_part = r*hi + twopk = reinterpret(Float32, (N+Int32(127)) << Int32(23)) + return Float16(muladd(twopk, small_part, twopk-1f0)) +end + +""" + expm1(x) + +Accurately compute ``e^x-1``. It avoids the loss of precision involved in the direct +evaluation of exp(x)-1 for small values of x. +# Examples +```jldoctest +julia> expm1(1e-16) +1.0e-16 + +julia> exp(1e-16) - 1 +0.0 +``` +""" +expm1(x) diff --git a/base/special/hyperbolic.jl b/base/special/hyperbolic.jl index 1fee6e2879220..d84cadcb2b6f2 100644 --- a/base/special/hyperbolic.jl +++ b/base/special/hyperbolic.jl @@ -14,19 +14,6 @@ # is preserved. # ==================================================== -@inline function exthorner(x, p::Tuple) - # polynomial evaluation using compensated summation. - # much more accurate, especially when lo can be combined with other rounding errors - hi, lo = p[end], zero(x) - for i in length(p)-1:-1:1 - pi = p[i] - prod = hi*x - err = fma(hi, x, -prod) - hi = pi+prod - lo = fma(lo, x, prod - (hi - pi) + err) - end - return hi, lo -end # Hyperbolic functions # sinh methods @@ -63,6 +50,11 @@ function sinh_kernel(x::Float32) return Float32(res*x) end +@inline function sinh16_kernel(x::Float32) + res = evalpoly(x*x, (1.0f0, 0.16666667f0, 0.008333337f0, 0.00019841001f0, + 2.7555539f-6, 2.514339f-8, 1.6260095f-10)) + return Float16(res*x) +end function sinh(x::T) where T<:Union{Float32,Float64} # Method @@ -88,6 +80,14 @@ function sinh(x::T) where T<:Union{Float32,Float64} return copysign(T(.5)*(E - 1/E),x) end +function Base.sinh(a::Float16) + x = Float32(a) + absx = abs(x) + absx <= SINH_SMALL_X(Float32) && return sinh16_kernel(x) + E = exp(absx) + return Float16(copysign(.5f0*(E - 1/E),x)) +end + COSH_SMALL_X(::Type{T}) where T= one(T) function cosh_kernel(x2::Float32) @@ -112,7 +112,7 @@ function cosh(x::T) where T<:Union{Float32,Float64} # return cosh(x) = = (exp(x) + exp(-x))/2 # e) H_LARGE_X <= x # return cosh(x) = exp(x/2)/2 * exp(x/2) - # Note that this branch automatically deals with Infs and NaNs + # Note that this branch automatically deals with Infs and NaNs absx = abs(x) if absx <= COSH_SMALL_X(T) diff --git a/base/special/trig.jl b/base/special/trig.jl index 6ebfd2f2932aa..363bec0e62c8c 100644 --- a/base/special/trig.jl +++ b/base/special/trig.jl @@ -168,6 +168,8 @@ end Simultaneously compute the sine and cosine of `x`, where `x` is in radians, returning a tuple `(sine, cosine)`. + +See also [`cis`](@ref), [`sincospi`](@ref), [`sincosd`](@ref). """ function sincos(x::T) where T<:Union{Float32, Float64} if abs(x) < T(pi)/4 @@ -742,6 +744,8 @@ mulpi_ext(x::Real) = pi*x # Fallback sinpi(x) Compute ``\\sin(\\pi x)`` more accurately than `sin(pi*x)`, especially for large `x`. + +See also [`sind`](@ref), [`cospi`](@ref), [`sincospi`](@ref). """ function sinpi(x::T) where T<:AbstractFloat if !isfinite(x) @@ -863,6 +867,8 @@ where `x` is in radians), returning a tuple `(sine, cosine)`. !!! compat "Julia 1.6" This function requires Julia 1.6 or later. + +See also: [`cispi`](@ref), [`sincosd`](@ref), [`sinpi`](@ref). """ function sincospi(x::T) where T<:AbstractFloat if !isfinite(x) @@ -1069,6 +1075,8 @@ isinf_real(x::Number) = false sinc(x) Compute ``\\sin(\\pi x) / (\\pi x)`` if ``x \\neq 0``, and ``1`` if ``x = 0``. + +See also [`cosc`](@ref), its derivative. """ sinc(x::Number) = _sinc(float(x)) sinc(x::Integer) = iszero(x) ? one(x) : zero(x) @@ -1261,22 +1269,30 @@ end sincosd(::Missing) = (missing, missing) for (fd, f, fn) in ((:sind, :sin, "sine"), (:cosd, :cos, "cosine"), (:tand, :tan, "tangent")) - name = string(fd) - @eval begin - @doc """ - $($name)(x) - Compute $($fn) of `x`, where `x` is in degrees. """ ($fd)(z) = ($f)(deg2rad(z)) + for (fu, un) in ((:deg2rad, "degrees"),) + name = string(fd) + @eval begin + @doc """ + $($name)(x) + + Compute $($fn) of `x`, where `x` is in $($un). + If `x` is a matrix, `x` needs to be a square matrix. """ ($fd)(x) = ($f)(($fu).(x)) + end end end for (fd, f, fn) in ((:asind, :asin, "sine"), (:acosd, :acos, "cosine"), (:asecd, :asec, "secant"), (:acscd, :acsc, "cosecant"), (:acotd, :acot, "cotangent")) - name = string(fd) - @eval begin - @doc """ - $($name)(x) - Compute the inverse $($fn) of `x`, where the output is in degrees. """ ($fd)(y) = rad2deg(($f)(y)) + for (fu, un) in ((:rad2deg, "degrees"),) + name = string(fd) + @eval begin + @doc """ + $($name)(x) + + Compute the inverse $($fn) of `x`, where the output is in $($un). + If `x` is a matrix, `x` needs to be a square matrix. """ ($fd)(x) = ($fu).(($f)(x)) + end end end @@ -1286,5 +1302,5 @@ end Compute the inverse tangent of `y` or `y/x`, respectively, where the output is in degrees. """ -atand(y) = rad2deg(atan(y)) -atand(y, x) = rad2deg(atan(y,x)) +atand(y) = rad2deg.(atan(y)) +atand(y, x) = rad2deg.(atan(y,x)) diff --git a/base/stat.jl b/base/stat.jl index d3612b23a0fd1..e6adda11fef6f 100644 --- a/base/stat.jl +++ b/base/stat.jl @@ -187,7 +187,7 @@ julia> isdir("not/a/directory") false ``` -See also: [`isfile`](@ref) and [`ispath`](@ref). +See also [`isfile`](@ref) and [`ispath`](@ref). """ isdir(st::StatStruct) = filemode(st) & 0xf000 == 0x4000 @@ -216,7 +216,7 @@ true julia> close(f); rm("test_file.txt") ``` -See also: [`isdir`](@ref) and [`ispath`](@ref). +See also [`isdir`](@ref) and [`ispath`](@ref). """ isfile(st::StatStruct) = filemode(st) & 0xf000 == 0x8000 diff --git a/base/stream.jl b/base/stream.jl index 509bc9953add6..6cbd1d3b86a28 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -1127,7 +1127,7 @@ function _fd(x::Union{LibuvStream, LibuvServer}) return fd[] end -struct redirect_stdio <: Function +struct RedirectStdStream <: Function unix_fd::Int writable::Bool end @@ -1135,7 +1135,7 @@ for (f, writable, unix_fd) in ((:redirect_stdin, false, 0), (:redirect_stdout, true, 1), (:redirect_stderr, true, 2)) - @eval const ($f) = redirect_stdio($unix_fd, $writable) + @eval const ($f) = RedirectStdStream($unix_fd, $writable) end function _redirect_io_libc(stream, unix_fd::Int) posix_fd = _fd(stream) @@ -1154,7 +1154,7 @@ function _redirect_io_global(io, unix_fd::Int) unix_fd == 2 && (global stderr = io) nothing end -function (f::redirect_stdio)(handle::Union{LibuvStream, IOStream}) +function (f::RedirectStdStream)(handle::Union{LibuvStream, IOStream}) _redirect_io_libc(handle, f.unix_fd) c_sym = f.unix_fd == 0 ? cglobal(:jl_uv_stdin, Ptr{Cvoid}) : f.unix_fd == 1 ? cglobal(:jl_uv_stdout, Ptr{Cvoid}) : @@ -1164,7 +1164,7 @@ function (f::redirect_stdio)(handle::Union{LibuvStream, IOStream}) _redirect_io_global(handle, f.unix_fd) return handle end -function (f::redirect_stdio)(::DevNull) +function (f::RedirectStdStream)(::DevNull) nulldev = @static Sys.iswindows() ? "NUL" : "/dev/null" handle = open(nulldev, write=f.writable) _redirect_io_libc(handle, f.unix_fd) @@ -1172,13 +1172,13 @@ function (f::redirect_stdio)(::DevNull) _redirect_io_global(devnull, f.unix_fd) return devnull end -function (f::redirect_stdio)(io::AbstractPipe) +function (f::RedirectStdStream)(io::AbstractPipe) io2 = (f.writable ? pipe_writer : pipe_reader)(io) f(io2) _redirect_io_global(io, f.unix_fd) return io end -function (f::redirect_stdio)(p::Pipe) +function (f::RedirectStdStream)(p::Pipe) if p.in.status == StatusInit && p.out.status == StatusInit link_pipe!(p) end @@ -1186,9 +1186,9 @@ function (f::redirect_stdio)(p::Pipe) f(io2) return p end -(f::redirect_stdio)() = f(Pipe()) +(f::RedirectStdStream)() = f(Pipe()) -# Deprecate these in v2 (redirect_stdio support) +# Deprecate these in v2 (RedirectStdStream support) iterate(p::Pipe) = (p.out, 1) iterate(p::Pipe, i::Int) = i == 1 ? (p.in, 2) : nothing getindex(p::Pipe, key::Int) = key == 1 ? p.out : key == 2 ? p.in : throw(KeyError(key)) @@ -1204,6 +1204,8 @@ the pipe. !!! note `stream` must be a compatible objects, such as an `IOStream`, `TTY`, `Pipe`, socket, or `devnull`. + +See also [`redirect_stdio`](@ref). """ redirect_stdout @@ -1215,6 +1217,8 @@ Like [`redirect_stdout`](@ref), but for [`stderr`](@ref). !!! note `stream` must be a compatible objects, such as an `IOStream`, `TTY`, `Pipe`, socket, or `devnull`. + +See also [`redirect_stdio`](@ref). """ redirect_stderr @@ -1227,10 +1231,125 @@ Note that the direction of the stream is reversed. !!! note `stream` must be a compatible objects, such as an `IOStream`, `TTY`, `Pipe`, socket, or `devnull`. + +See also [`redirect_stdio`](@ref). """ redirect_stdin -function (f::redirect_stdio)(thunk::Function, stream) +""" + redirect_stdio(;stdin=stdin, stderr=stderr, stdout=stdout) + +Redirect a subset of the streams `stdin`, `stderr`, `stdout`. +Each argument must be an `IOStream`, `TTY`, `Pipe`, socket, or `devnull`. + +!!! compat "Julia 1.7" + `redirect_stdio` requires Julia 1.7 or later. +""" +function redirect_stdio(;stdin=nothing, stderr=nothing, stdout=nothing) + stdin === nothing || redirect_stdin(stdin) + stderr === nothing || redirect_stderr(stderr) + stdout === nothing || redirect_stdout(stdout) +end + +""" + redirect_stdio(f; stdin=nothing, stderr=nothing, stdout=nothing) + +Redirect a subset of the streams `stdin`, `stderr`, `stdout`, +call `f()` and restore each stream. + +Possible values for each stream are: +* `nothing` indicating the stream should not be redirected. +* `path::AbstractString` redirecting the stream to the file at `path`. +* `io` an `IOStream`, `TTY`, `Pipe`, socket, or `devnull`. + +# Examples +```julia +julia> redirect_stdio(stdout="stdout.txt", stderr="stderr.txt") do + print("hello stdout") + print(stderr, "hello stderr") + end + +julia> read("stdout.txt", String) +"hello stdout" + +julia> read("stderr.txt", String) +"hello stderr" +``` + +# Edge cases + +It is possible to pass the same argument to `stdout` and `stderr`: +```julia +julia> redirect_stdio(stdout="log.txt", stderr="log.txt", stdin=devnull) do + ... +end +``` + +However it is not supported to pass two distinct descriptors of the same file. +```julia +julia> io1 = open("same/path", "w") + +julia> io2 = open("same/path", "w") + +julia> redirect_stdio(f, stdout=io1, stderr=io2) # not suppored +``` +Also the `stdin` argument may not be the same descriptor as `stdout` or `stderr`. +```julia +julia> io = open(...) + +julia> redirect_stdio(f, stdout=io, stdin=io) # not supported +``` + +!!! compat "Julia 1.7" + `redirect_stdio` requires Julia 1.7 or later. +""" +function redirect_stdio(f; stdin=nothing, stderr=nothing, stdout=nothing) + + function resolve(new::Nothing, oldstream, mode) + (new=nothing, close=false, old=nothing) + end + function resolve(path::AbstractString, oldstream,mode) + (new=open(path, mode), close=true, old=oldstream) + end + function resolve(new, oldstream, mode) + (new=new, close=false, old=oldstream) + end + + same_path(x, y) = false + function same_path(x::AbstractString, y::AbstractString) + # if x = y = "does_not_yet_exist.txt" then samefile will return false + (abspath(x) == abspath(y)) || samefile(x,y) + end + if same_path(stderr, stdin) + throw(ArgumentError("stdin and stderr cannot be the same path")) + end + if same_path(stdout, stdin) + throw(ArgumentError("stdin and stdout cannot be the same path")) + end + + new_in , close_in , old_in = resolve(stdin , Base.stdin , "r") + new_out, close_out, old_out = resolve(stdout, Base.stdout, "w") + if same_path(stderr, stdout) + # make sure that in case stderr = stdout = "same/path" + # only a single io is used instead of opening the same file twice + new_err, close_err, old_err = new_out, false, Base.stderr + else + new_err, close_err, old_err = resolve(stderr, Base.stderr, "w") + end + + redirect_stdio(; stderr=new_err, stdin=new_in, stdout=new_out) + + try + return f() + finally + redirect_stdio(;stderr=old_err, stdin=old_in, stdout=old_out) + close_err && close(new_err) + close_in && close(new_in ) + close_out && close(new_out) + end +end + +function (f::RedirectStdStream)(thunk::Function, stream) stdold = f.unix_fd == 0 ? stdin : f.unix_fd == 1 ? stdout : f.unix_fd == 2 ? stderr : @@ -1243,6 +1362,7 @@ function (f::redirect_stdio)(thunk::Function, stream) end end + """ redirect_stdout(f::Function, stream) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index c9108966325f8..52c8f6591874f 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -35,8 +35,8 @@ model allows index arithmetic to work with out-of- bounds indices as intermediate values so long as one never uses them to retrieve a character, which often helps avoid needing to code around edge cases. -See also: [`codeunit`](@ref), [`ncodeunits`](@ref), [`thisind`](@ref), -[`nextind`](@ref), [`prevind`](@ref) +See also [`codeunit`](@ref), [`ncodeunits`](@ref), [`thisind`](@ref), +[`nextind`](@ref), [`prevind`](@ref). """ AbstractString @@ -62,8 +62,8 @@ julia> ncodeunits('∫'), ncodeunits('e'), ncodeunits('ˣ') (3, 1, 2) ``` -See also: [`codeunit`](@ref), [`checkbounds`](@ref), [`sizeof`](@ref), -[`length`](@ref), [`lastindex`](@ref) +See also [`codeunit`](@ref), [`checkbounds`](@ref), [`sizeof`](@ref), +[`length`](@ref), [`lastindex`](@ref). """ ncodeunits(s::AbstractString) @@ -77,7 +77,7 @@ limited to these three types, but it's hard to think of widely used string encodings that don't use one of these units. `codeunit(s)` is the same as `typeof(codeunit(s,1))` when `s` is a non-empty string. -See also: [`ncodeunits`](@ref) +See also [`ncodeunits`](@ref). """ codeunit(s::AbstractString) @@ -102,7 +102,7 @@ julia> typeof(a) UInt8 ``` -See also: [`ncodeunits`](@ref), [`checkbounds`](@ref) +See also [`ncodeunits`](@ref), [`checkbounds`](@ref). """ @propagate_inbounds codeunit(s::AbstractString, i::Integer) = typeof(i) === Int ? throw(MethodError(codeunit, (s, i))) : codeunit(s, Int(i)) @@ -118,8 +118,8 @@ In order for `isvalid(s, i)` to be an O(1) function, the encoding of `s` must be [self-synchronizing](https://en.wikipedia.org/wiki/Self-synchronizing_code). This is a basic assumption of Julia's generic string support. -See also: [`getindex`](@ref), [`iterate`](@ref), [`thisind`](@ref), -[`nextind`](@ref), [`prevind`](@ref), [`length`](@ref) +See also [`getindex`](@ref), [`iterate`](@ref), [`thisind`](@ref), +[`nextind`](@ref), [`prevind`](@ref), [`length`](@ref). # Examples ```jldoctest @@ -152,7 +152,7 @@ be iterated, yielding a sequences of characters. If `i` is out of bounds in `s` then a bounds error is raised. The `iterate` function, as part of the iteration protocol may assume that `i` is the start of a character in `s`. -See also: [`getindex`](@ref), [`checkbounds`](@ref) +See also [`getindex`](@ref), [`checkbounds`](@ref). """ @propagate_inbounds iterate(s::AbstractString, i::Integer) = typeof(i) === Int ? throw(MethodError(iterate, (s, i))) : iterate(s, Int(i)) @@ -183,7 +183,7 @@ isempty(s::AbstractString) = iszero(ncodeunits(s)::Int) function getindex(s::AbstractString, i::Integer) @boundscheck checkbounds(s, i) - @inbounds return isvalid(s, i) ? iterate(s, i)[1] : string_index_err(s, i) + @inbounds return isvalid(s, i) ? (iterate(s, i)::NTuple{2,Any})[1] : string_index_err(s, i) end getindex(s::AbstractString, i::Colon) = s @@ -375,8 +375,8 @@ value `0`. the string because it counts the value on the fly. This is in contrast to the method for arrays, which is a constant-time operation. -See also: [`isvalid`](@ref), [`ncodeunits`](@ref), [`lastindex`](@ref), -[`thisind`](@ref), [`nextind`](@ref), [`prevind`](@ref) +See also [`isvalid`](@ref), [`ncodeunits`](@ref), [`lastindex`](@ref), +[`thisind`](@ref), [`nextind`](@ref), [`prevind`](@ref). # Examples ```jldoctest @@ -676,13 +676,16 @@ cases where `v` contains non-ASCII characters.) # Examples ```jldoctest -julia> r = reverse("Julia") -"ailuJ" +julia> s = "Julia🚀" +"Julia🚀" -julia> for i in 1:length(r) - print(r[reverseind("Julia", i)]) +julia> r = reverse(s) +"🚀ailuJ" + +julia> for i in eachindex(s) + print(r[reverseind(r, i)]) end -Julia +Julia🚀 ``` """ reverseind(s::AbstractString, i::Integer) = thisind(s, ncodeunits(s)-i+1) @@ -692,7 +695,7 @@ reverseind(s::AbstractString, i::Integer) = thisind(s, ncodeunits(s)-i+1) Repeat a string `r` times. This can be written as `s^r`. -See also: [`^`](@ref :^(::Union{AbstractString, AbstractChar}, ::Integer)) +See also [`^`](@ref :^(::Union{AbstractString, AbstractChar}, ::Integer)). # Examples ```jldoctest @@ -707,7 +710,7 @@ repeat(s::AbstractString, r::Integer) = repeat(String(s), r) Repeat a string or character `n` times. This can also be written as `repeat(s, n)`. -See also: [`repeat`](@ref) +See also [`repeat`](@ref). # Examples ```jldoctest diff --git a/base/strings/io.jl b/base/strings/io.jl index 6003a6d503b90..4ed55f9f0a2bf 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -64,10 +64,10 @@ Hello, world julia> io = IOBuffer(); -julia> println(io, "Hello, world") +julia> println(io, "Hello", ',', " world.") julia> String(take!(io)) -"Hello, world\\n" +"Hello, world.\\n" ``` """ println(io::IO, xs...) = print(io, xs..., "\n") @@ -172,6 +172,8 @@ highly efficient, then it may make sense to add a method to `string` and define `print(io::IO, x::MyType) = print(io, string(x))` to ensure the functions are consistent. +See also: [`String`](@ref), [`repr`](@ref), [`sprint`](@ref), [`show`](@ref @show). + # Examples ```jldoctest julia> string("a", 1, true) @@ -188,6 +190,54 @@ print(io::IO, s::AbstractString) = for c in s; print(io, c); end write(io::IO, s::AbstractString) = (len = 0; for c in s; len += Int(write(io, c))::Int; end; len) show(io::IO, s::AbstractString) = print_quoted(io, s) +# show elided string if more than `limit` characters +function show( + io :: IO, + mime :: MIME"text/plain", + str :: AbstractString; + limit :: Union{Int, Nothing} = nothing, +) + # compute limit in default case + if limit === nothing + get(io, :limit, false) || return show(io, str) + limit = max(20, displaysize(io)[2]) + # one line in collection, seven otherwise + get(io, :typeinfo, nothing) === nothing && (limit *= 7) + end + + # early out for short strings + len = ncodeunits(str) + len ≤ limit - 2 && # quote chars + return show(io, str) + + # these don't depend on string data + units = codeunit(str) == UInt8 ? "bytes" : "code units" + skip_text(skip) = " ⋯ $skip $units ⋯ " + short = length(skip_text("")) + 4 # quote chars + chars = max(limit, short + 1) - short # at least 1 digit + + # figure out how many characters to print in elided case + chars -= d = ndigits(len - chars) # first adjustment + chars += d - ndigits(len - chars) # second if needed + chars = max(0, chars) + + # find head & tail, avoiding O(length(str)) computation + head = nextind(str, 0, 1 + (chars + 1) ÷ 2) + tail = prevind(str, len + 1, chars ÷ 2) + + # threshold: min chars skipped to make elision worthwhile + t = short + ndigits(len - chars) - 1 + n = tail - head # skipped code units + if 4t ≤ n || t ≤ n && t ≤ length(str, head, tail-1) + skip = skip_text(n) + show(io, SubString(str, 1:prevind(str, head))) + print(io, skip) # TODO: bold styled + show(io, SubString(str, tail)) + else + show(io, str) + end +end + # optimized methods to avoid iterating over chars write(io::IO, s::Union{String,SubString{String}}) = GC.@preserve s Int(unsafe_write(io, pointer(s), reinterpret(UInt, sizeof(s))))::Int @@ -251,15 +301,12 @@ IOBuffer(s::SubString{String}) = IOBuffer(view(unsafe_wrap(Vector{UInt8}, s.stri # join is implemented using IO """ - join([io::IO,] strings [, delim [, last]]) - -Join an array of `strings` into a single string, inserting the given delimiter (if any) between -adjacent strings. If `last` is given, it will be used instead of `delim` between the last -two strings. If `io` is given, the result is written to `io` rather than returned -as a `String`. + join([io::IO,] iterator [, delim [, last]]) -`strings` can be any iterable over elements `x` which are convertible to strings -via `print(io::IOBuffer, x)`. `strings` will be printed to `io`. +Join any `iterator` into a single string, inserting the given delimiter (if any) between +adjacent items. If `last` is given, it will be used instead of `delim` between the last +two items. Each item of `iterator` is converted to a string via `print(io::IOBuffer, x)`. +If `io` is given, the result is written to `io` rather than returned as a `String`. # Examples ```jldoctest @@ -270,15 +317,15 @@ julia> join([1,2,3,4,5]) "12345" ``` """ -function join(io::IO, strings, delim, last) +function join(io::IO, iterator, delim, last) first = true local prev - for str in strings + for item in iterator if @isdefined prev first ? (first = false) : print(io, delim) print(io, prev) end - prev = str + prev = item end if @isdefined prev first || print(io, last) @@ -286,19 +333,19 @@ function join(io::IO, strings, delim, last) end nothing end -function join(io::IO, strings, delim="") +function join(io::IO, iterator, delim="") # Specialization of the above code when delim==last, # which lets us emit (compile) less code first = true - for str in strings + for item in iterator first ? (first = false) : print(io, delim) - print(io, str) + print(io, item) end end -join(strings) = sprint(join, strings) -join(strings, delim) = sprint(join, strings, delim) -join(strings, delim, last) = sprint(join, strings, delim, last) +join(iterator) = sprint(join, iterator) +join(iterator, delim) = sprint(join, iterator, delim) +join(iterator, delim, last) = sprint(join, iterator, delim, last) ## string escaping & unescaping ## @@ -323,6 +370,8 @@ escaped by a prepending backslash (`\"` is also escaped by default in the first The argument `keep` specifies a collection of characters which are to be kept as they are. Notice that `esc` has precedence here. +See also [`unescape_string`](@ref) for the reverse operation. + !!! compat "Julia 1.7" The `keep` argument is available as of Julia 1.7. @@ -343,9 +392,6 @@ julia> escape_string(string('\\u2135','\\0')) # unambiguous julia> escape_string(string('\\u2135','\\0','0')) # \\0 would be ambiguous "ℵ\\\\x000" ``` - -## See also -[`unescape_string`](@ref) for the reverse operation. """ function escape_string(io::IO, s::AbstractString, esc=""; keep = ()) a = Iterators.Stateful(s) @@ -406,6 +452,8 @@ The following escape sequences are recognised: - Hex bytes (`\\x` with 1-2 trailing hex digits) - Octal bytes (`\\` with 1-3 trailing octal digits) +See also [`escape_string`](@ref). + # Examples ```jldoctest julia> unescape_string("aaa\\\\nbbb") # C escape sequence @@ -420,9 +468,6 @@ julia> unescape_string("\\\\101") # octal julia> unescape_string("aaa \\\\g \\\\n", ['g']) # using `keep` argument "aaa \\\\g \\n" ``` - -## See also -[`escape_string`](@ref). """ function unescape_string(io::IO, s::AbstractString, keep = ()) a = Iterators.Stateful(s) @@ -540,7 +585,7 @@ macro raw_str(s); s; end Escape a string in the manner used for parsing raw string literals. For each double-quote (`"`) character in input string `s`, this -function counts the number _n_ of preceeding backslash (`\\`) characters, +function counts the number _n_ of preceding backslash (`\\`) characters, and then increases there the number of backslashes from _n_ to 2_n_+1 (even for _n_ = 0). It also doubles a sequence of backslashes at the end of the string. @@ -550,7 +595,7 @@ string literals. (It also happens to be the escaping convention expected by the Microsoft C/C++ compiler runtime when it parses a command-line string into the argv[] array.) -See also: [`escape_string`](@ref) +See also [`escape_string`](@ref). """ function escape_raw_string(io, str::AbstractString) escapes = 0 @@ -622,6 +667,8 @@ end Remove leading indentation from string. +See also `indent` from the [`MultilineStrings` package](https://github.com/invenia/MultilineStrings.jl). + # Examples ```jldoctest julia> Base.unindent(" a\\n b", 2) @@ -630,8 +677,6 @@ julia> Base.unindent(" a\\n b", 2) julia> Base.unindent("\\ta\\n\\tb", 2, tabwidth=8) " a\\n b" ``` - -See also `indent` from the [`MultilineStrings` package](https://github.com/invenia/MultilineStrings.jl). """ function unindent(str::AbstractString, indent::Int; tabwidth=8) indent == 0 && return str diff --git a/base/strings/search.jl b/base/strings/search.jl index 51b23705671f7..ed5758aa68307 100644 --- a/base/strings/search.jl +++ b/base/strings/search.jl @@ -616,7 +616,7 @@ julia> occursin(r"a.a", "abba") false ``` -See also: [`contains`](@ref). +See also [`contains`](@ref). """ occursin(needle::Union{AbstractString,AbstractChar}, haystack::AbstractString) = _searchindex(haystack, needle, firstindex(haystack)) != 0 diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index 38ffacd8aa572..cf215849ab08c 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -283,7 +283,7 @@ isassigned(c) = UTF8PROC_CATEGORY_CN < category_code(c) <= UTF8PROC_CATEGORY_CO Tests whether a character is a lowercase letter (according to the Unicode standard's `Lowercase` derived property). -See also: [`isuppercase`](@ref). +See also [`isuppercase`](@ref). # Examples ```jldoctest @@ -307,7 +307,7 @@ islowercase(c::AbstractChar) = ismalformed(c) ? false : Bool(ccall(:utf8proc_isl Tests whether a character is an uppercase letter (according to the Unicode standard's `Uppercase` derived property). -See also: [`islowercase`](@ref). +See also [`islowercase`](@ref). # Examples ```jldoctest @@ -328,7 +328,7 @@ isuppercase(c::AbstractChar) = ismalformed(c) ? false : Bool(ccall(:utf8proc_isu Tests whether a character is cased, i.e. is lower-, upper- or title-cased. -See also: [`islowercase`](@ref), [`isuppercase`](@ref). +See also [`islowercase`](@ref), [`isuppercase`](@ref). """ function iscased(c::AbstractChar) cat = category_code(c) @@ -514,7 +514,7 @@ isxdigit(c::AbstractChar) = '0'<=c<='9' || 'a'<=c<='f' || 'A'<=c<='F' Return `s` with all characters converted to uppercase. -See also: [`lowercase`](@ref), [`titlecase`](@ref), [`uppercasefirst`](@ref). +See also [`lowercase`](@ref), [`titlecase`](@ref), [`uppercasefirst`](@ref). # Examples ```jldoctest @@ -529,7 +529,7 @@ uppercase(s::AbstractString) = map(uppercase, s) Return `s` with all characters converted to lowercase. -See also: [`uppercase`](@ref), [`titlecase`](@ref), [`lowercasefirst`](@ref). +See also [`uppercase`](@ref), [`titlecase`](@ref), [`lowercasefirst`](@ref). # Examples ```jldoctest @@ -551,7 +551,7 @@ which characters should be considered as word separators. See also [`uppercasefirst`](@ref) to capitalize only the first character in `s`. -See also: [`uppercase`](@ref), [`lowercase`](@ref), [`uppercasefirst`](@ref). +See also [`uppercase`](@ref), [`lowercase`](@ref), [`uppercasefirst`](@ref). # Examples ```jldoctest @@ -593,8 +593,8 @@ Return `s` with the first character converted to uppercase (technically "title case" for Unicode). See also [`titlecase`](@ref) to capitalize the first character of every word in `s`. -See also: [`lowercasefirst`](@ref), [`uppercase`](@ref), [`lowercase`](@ref), -[`titlecase`](@ref) +See also [`lowercasefirst`](@ref), [`uppercase`](@ref), [`lowercase`](@ref), +[`titlecase`](@ref). # Examples ```jldoctest @@ -615,8 +615,8 @@ end Return `s` with the first character converted to lowercase. -See also: [`uppercasefirst`](@ref), [`uppercase`](@ref), [`lowercase`](@ref), -[`titlecase`](@ref) +See also [`uppercasefirst`](@ref), [`uppercase`](@ref), [`lowercase`](@ref), +[`titlecase`](@ref). # Examples ```jldoctest diff --git a/base/strings/util.jl b/base/strings/util.jl index 140c5a31194f1..9bc043513deed 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -10,7 +10,7 @@ const Chars = Union{AbstractChar,Tuple{Vararg{AbstractChar}},AbstractVector{<:Ab Return `true` if `s` starts with `prefix`. If `prefix` is a vector or set of characters, test whether the first character of `s` belongs to that set. -See also [`endswith`](@ref). +See also [`endswith`](@ref), [`contains`](@ref). # Examples ```jldoctest @@ -30,7 +30,7 @@ startswith(str::AbstractString, chars::Chars) = !isempty(str) && first(str)::Abs Return `true` if `s` ends with `suffix`. If `suffix` is a vector or set of characters, test whether the last character of `s` belongs to that set. -See also [`startswith`](@ref). +See also [`startswith`](@ref), [`contains`](@ref). # Examples ```jldoctest @@ -77,6 +77,8 @@ Return `true` if `haystack` contains `needle`. This is the same as `occursin(needle, haystack)`, but is provided for consistency with `startswith(haystack, needle)` and `endswith(haystack, needle)`. +See also [`occursin`](@ref), [`in`](@ref), [`issubset`](@ref). + # Examples ```jldoctest julia> contains("JuliaLang is pretty cool!", "Julia") @@ -166,6 +168,8 @@ The call `chop(s)` removes the last character from `s`. If it is requested to remove more characters than `length(s)` then an empty string is returned. +See also [`chomp`](@ref), [`startswith`](@ref), [`first`](@ref). + # Examples ```jldoctest julia> a = "March" @@ -196,6 +200,8 @@ end Remove a single trailing newline from a string. +See also [`chop`](@ref). + # Examples ```jldoctest julia> chomp("Hello\\n") @@ -233,6 +239,8 @@ The default behaviour is to remove leading whitespace and delimiters: see The optional `chars` argument specifies which characters to remove: it can be a single character, or a vector or set of characters. +See also [`strip`](@ref) and [`rstrip`](@ref). + # Examples ```jldoctest julia> a = lpad("March", 20) @@ -265,6 +273,8 @@ The default behaviour is to remove trailing whitespace and delimiters: see The optional `chars` argument specifies which characters to remove: it can be a single character, or a vector or set of characters. +See also [`strip`](@ref) and [`lstrip`](@ref). + # Examples ```jldoctest julia> a = rpad("March", 20) @@ -296,6 +306,8 @@ The default behaviour is to remove leading and trailing whitespace and delimiter The optional `chars` argument specifies which characters to remove: it can be a single character, vector or set of characters. +See also [`lstrip`](@ref) and [`rstrip`](@ref). + !!! compat "Julia 1.2" The method which accepts a predicate function requires Julia 1.2 or later. @@ -595,15 +607,20 @@ replace(s::AbstractString, pat_f::Pair; count=typemax(Int)) = # hex <-> bytes conversion """ - hex2bytes(s::Union{AbstractString,AbstractVector{UInt8}}) + hex2bytes(itr) -Given a string or array `s` of ASCII codes for a sequence of hexadecimal digits, returns a +Given an iterable `itr` of ASCII codes for a sequence of hexadecimal digits, returns a `Vector{UInt8}` of bytes corresponding to the binary representation: each successive pair -of hexadecimal digits in `s` gives the value of one byte in the return vector. +of hexadecimal digits in `itr` gives the value of one byte in the return vector. -The length of `s` must be even, and the returned array has half of the length of `s`. +The length of `itr` must be even, and the returned array has half of the length of `itr`. See also [`hex2bytes!`](@ref) for an in-place version, and [`bytes2hex`](@ref) for the inverse. +!!! compat "Julia 1.7" + Calling hex2bytes with iterables producing UInt8 requires + version 1.7. In earlier versions, you can collect the iterable + before calling instead. + # Examples ```jldoctest julia> s = string(12345, base = 16) @@ -632,46 +649,64 @@ julia> hex2bytes(a) """ function hex2bytes end -hex2bytes(s::AbstractString) = hex2bytes(String(s)) -hex2bytes(s::Union{String,AbstractVector{UInt8}}) = hex2bytes!(Vector{UInt8}(undef, length(s) >> 1), s) +hex2bytes(s) = hex2bytes!(Vector{UInt8}(undef, length(s) >> 1), s) -_firstbyteidx(s::String) = 1 -_firstbyteidx(s::AbstractVector{UInt8}) = first(eachindex(s)) -_lastbyteidx(s::String) = sizeof(s) -_lastbyteidx(s::AbstractVector{UInt8}) = lastindex(s) +# special case - valid bytes are checked in the generic implementation +function hex2bytes!(dest::AbstractArray{UInt8}, s::String) + sizeof(s) != length(s) && throw(ArgumentError("input string must consist of hexadecimal characters only")) + + hex2bytes!(dest, transcode(UInt8, s)) +end """ - hex2bytes!(d::AbstractVector{UInt8}, s::Union{String,AbstractVector{UInt8}}) + hex2bytes!(dest::AbstractVector{UInt8}, itr) -Convert an array `s` of bytes representing a hexadecimal string to its binary +Convert an iterable `itr` of bytes representing a hexadecimal string to its binary representation, similar to [`hex2bytes`](@ref) except that the output is written in-place -in `d`. The length of `s` must be exactly twice the length of `d`. -""" -function hex2bytes!(d::AbstractVector{UInt8}, s::Union{String,AbstractVector{UInt8}}) - if 2length(d) != sizeof(s) - isodd(sizeof(s)) && throw(ArgumentError("input hex array must have even length")) - throw(ArgumentError("output array must be half length of input array")) - end - j = first(eachindex(d)) - 1 - for i = _firstbyteidx(s):2:_lastbyteidx(s) - @inbounds d[j += 1] = number_from_hex(_nthbyte(s,i)) << 4 + number_from_hex(_nthbyte(s,i+1)) +to `dest`. The length of `dest` must be half the length of `itr`. + +!!! compat "Julia 1.7" + Calling hex2bytes! with iterators producing UInt8 requires + version 1.7. In earlier versions, you can collect the iterable + before calling instead. +""" +function hex2bytes!(dest::AbstractArray{UInt8}, itr) + isodd(length(itr)) && throw(ArgumentError("length of iterable must be even")) + @boundscheck 2*length(dest) != length(itr) && throw(ArgumentError("length of output array must be half of the length of input iterable")) + iszero(length(itr)) && return dest + + next = iterate(itr) + @inbounds for i in eachindex(dest) + x,state = next::NTuple{2,Any} + y,state = iterate(itr, state)::NTuple{2,Any} + next = iterate(itr, state) + dest[i] = number_from_hex(x) << 4 + number_from_hex(y) end - return d + + return dest end -@inline number_from_hex(c) = - (UInt8('0') <= c <= UInt8('9')) ? c - UInt8('0') : - (UInt8('A') <= c <= UInt8('F')) ? c - (UInt8('A') - 0x0a) : - (UInt8('a') <= c <= UInt8('f')) ? c - (UInt8('a') - 0x0a) : +@inline number_from_hex(c::AbstractChar) = number_from_hex(Char(c)) +@inline number_from_hex(c::Char) = number_from_hex(UInt8(c)) +@inline function number_from_hex(c::UInt8) + UInt8('0') <= c <= UInt8('9') && return c - UInt8('0') + c |= 0b0100000 + UInt8('a') <= c <= UInt8('f') && return c - UInt8('a') + 0x0a throw(ArgumentError("byte is not an ASCII hexadecimal digit")) +end """ - bytes2hex(a::AbstractArray{UInt8}) -> String - bytes2hex(io::IO, a::AbstractArray{UInt8}) + bytes2hex(itr) -> String + bytes2hex(io::IO, itr) + +Convert an iterator `itr` of bytes to its hexadecimal string representation, either +returning a `String` via `bytes2hex(itr)` or writing the string to an `io` stream +via `bytes2hex(io, itr)`. The hexadecimal characters are all lowercase. -Convert an array `a` of bytes to its hexadecimal string representation, either -returning a `String` via `bytes2hex(a)` or writing the string to an `io` stream -via `bytes2hex(io, a)`. The hexadecimal characters are all lowercase. +!!! compat "Julia 1.7" + Calling bytes2hex with iterators producing UInt8 requires + version 1.7. In earlier versions, you can collect the iterable + before calling instead. # Examples ```jldoctest @@ -689,17 +724,19 @@ julia> bytes2hex(b) """ function bytes2hex end -function bytes2hex(a::Union{Tuple{Vararg{UInt8}}, AbstractArray{UInt8}}) - b = Base.StringVector(2*length(a)) - @inbounds for (i, x) in enumerate(a) +function bytes2hex(itr) + eltype(itr) === UInt8 || throw(ArgumentError("eltype of iterator not UInt8")) + b = Base.StringVector(2*length(itr)) + @inbounds for (i, x) in enumerate(itr) b[2i - 1] = hex_chars[1 + x >> 4] b[2i ] = hex_chars[1 + x & 0xf] end return String(b) end -function bytes2hex(io::IO, a::Union{Tuple{Vararg{UInt8}}, AbstractArray{UInt8}}) - for x in a +function bytes2hex(io::IO, itr) + eltype(itr) === UInt8 || throw(ArgumentError("eltype of iterator not UInt8")) + for x in itr print(io, Char(hex_chars[1 + x >> 4]), Char(hex_chars[1 + x & 0xf])) end end diff --git a/base/sysinfo.jl b/base/sysinfo.jl index 4c113971266d7..cdcb304271b5d 100644 --- a/base/sysinfo.jl +++ b/base/sysinfo.jl @@ -286,8 +286,8 @@ end Get the maximum resident set size utilized in bytes. See also: - - man page of getrusage(2) on Linux and FreeBSD. - - windows api `GetProcessMemoryInfo` + - man page of `getrusage`(2) on Linux and FreeBSD. + - Windows API `GetProcessMemoryInfo`. """ maxrss() = ccall(:jl_maxrss, Csize_t, ()) @@ -516,7 +516,7 @@ function which(program_name::String) program_path = joinpath(path_dir, pname) # If we find something that matches our name and we can execute if isfile(program_path) && isexecutable(program_path) - return realpath(program_path) + return program_path end end end diff --git a/base/task.jl b/base/task.jl index 8c9516fb39766..2c3e5c44e6d0b 100644 --- a/base/task.jl +++ b/base/task.jl @@ -77,9 +77,14 @@ function showerror(io::IO, ex::TaskFailedException, bt = nothing; backtrace=true end function show_task_exception(io::IO, t::Task; indent = true) - stack = catch_stack(t) + stack = current_exceptions(t) b = IOBuffer() - show_exception_stack(IOContext(b, io), stack) + if isempty(stack) + # exception stack buffer not available; probably a serialized task + showerror(IOContext(b, io), t.result) + else + show_exception_stack(IOContext(b, io), stack) + end str = String(take!(b)) if indent str = replace(str, "\n" => "\n ") @@ -157,7 +162,7 @@ end end elseif field === :backtrace # TODO: this field name should be deprecated in 2.0 - return catch_stack(t)[end][2] + return current_exceptions(t)[end][2] elseif field === :exception # TODO: this field name should be deprecated in 2.0 return t._isexception ? t.result : nothing @@ -417,6 +422,43 @@ macro async(expr) end end +""" + errormonitor(t::Task) + +Print an error log to `stderr` if task `t` fails. +""" +function errormonitor(t::Task) + t2 = Task() do + if istaskfailed(t) + local errs = stderr + try # try to display the failure atomically + errio = IOContext(PipeBuffer(), errs::IO) + emphasize(errio, "Unhandled Task ") + display_error(errio, current_exceptions(t)) + write(errs, errio) + catch + try # try to display the secondary error atomically + errio = IOContext(PipeBuffer(), errs::IO) + print(errio, "\nSYSTEM: caught exception while trying to print a failed Task notice: ") + display_error(errio, current_exceptions()) + write(errs, errio) + flush(errs) + # and then the actual error, as best we can + Core.print(Core.stderr, "while handling: ") + Core.println(Core.stderr, current_exceptions(t)[end][1]) + catch e + # give up + Core.print(Core.stderr, "\nSYSTEM: caught exception of type ", typeof(e).name.name, + " while trying to print a failed Task notice; giving up\n") + end + end + end + nothing + end + _wait2(t, t2) + return t +end + # Capture interpolated variables in $() and move them to let-block function _lift_one_interp!(e) letargs = Any[] # store the new gensymed arguments diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index f35cb37da990b..e66af69b3e82f 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -export threadid, nthreads, @threads +export threadid, nthreads, @threads, @spawn """ Threads.threadid() @@ -15,6 +15,10 @@ threadid() = Int(ccall(:jl_threadid, Int16, ())+1) Get the number of threads available to the Julia process. This is the inclusive upper bound on [`threadid()`](@ref). + +See also: `BLAS.get_num_threads` and `BLAS.set_num_threads` in the +[`LinearAlgebra`](@ref man-linalg) standard library, and `nprocs()` in the +[`Distributed`](@ref man-distributed) standard library. """ nthreads() = Int(unsafe_load(cglobal(:jl_n_threads, Cint))) @@ -114,6 +118,10 @@ The default schedule (used when no `schedule` argument is present) is subject to !!! compat "Julia 1.5" The `schedule` argument is available as of Julia 1.5. + +See also: [`@spawn`](@ref Threads.@spawn), [`nthreads()`](@ref Threads.nthreads), +[`threadid()`](@ref Threads.threadid), `pmap` in [`Distributed`](@ref man-distributed), +`BLAS.set_num_threads` in [`LinearAlgebra`](@ref man-linalg). """ macro threads(args...) na = length(args) diff --git a/base/threads_overloads.jl b/base/threads_overloads.jl index 3e6ad06760747..a0d4bbeda2288 100644 --- a/base/threads_overloads.jl +++ b/base/threads_overloads.jl @@ -35,7 +35,7 @@ function Threads.foreach(f, channel::Channel; # do `stop[] && break` after `f(item)` to avoid losing `item`. # this isn't super comprehensive since a task could still get # stuck on `take!` at `for item in channel`. We should think - # about a more robust mechanism to avoid dropping items. See also: + # about a more robust mechanism to avoid dropping items. See also # https://github.com/JuliaLang/julia/pull/34543#discussion_r422695217 stop[] && break end diff --git a/base/toml_parser.jl b/base/toml_parser.jl index c69096504df0b..8fcfc4ca0c29c 100644 --- a/base/toml_parser.jl +++ b/base/toml_parser.jl @@ -242,7 +242,7 @@ const err_message = Dict( ErrExpectedEqualAfterKey => "expected equal sign after key", ErrNoTrailingDigitAfterDot => "expected digit after dot", ErrOverflowError => "overflowed when parsing integer", - ErrInvalidUnicodeScalar => "invalid uncidode scalar", + ErrInvalidUnicodeScalar => "invalid unicode scalar", ErrInvalidEscapeCharacter => "invalid escape character", ErrUnexpectedEofExpectedValue => "unexpected end of file, expected a value" ) @@ -321,7 +321,7 @@ function Base.showerror(io::IO, err::ParserError) printstyled(io, " error: "; color=Base.error_color()) println(io, format_error_message_for_err_type(err)) # In this case we want the arrow to point one character - pos = err.pos + pos = err.pos::Int err.type == ErrUnexpectedEofExpectedValue && (pos += 1) str1, err1 = point_to_line(err.str, pos, pos, io) @static if VERSION <= v"1.6.0-DEV.121" @@ -751,7 +751,7 @@ isvalid_binary(c::Char) = '0' <= c <= '1' const ValidSigs = Union{typeof.([isvalid_hex, isvalid_oct, isvalid_binary, isdigit])...} # This function eats things accepted by `f` but also allows eating `_` in between -# digits. Retruns if it ate at lest one character and if it ate an underscore +# digits. Returns if it ate at lest one character and if it ate an underscore function accept_batch_underscore(l::Parser, f::ValidSigs, fail_if_underscore=true)::Err{Tuple{Bool, Bool}} contains_underscore = false at_least_one = false @@ -821,8 +821,6 @@ function parse_number_or_date_start(l::Parser) ate && return parse_int(l, contains_underscore) elseif accept(l, isdigit) return parse_local_time(l) - elseif peek(l) !== '.' - return ParserError(ErrLeadingZeroNotAllowedInteger) end end diff --git a/base/tuple.jl b/base/tuple.jl index d0b849f3a9803..ad08bf42f5e1a 100644 --- a/base/tuple.jl +++ b/base/tuple.jl @@ -104,12 +104,15 @@ state `itr_state`. Return a `Tuple`, if `collection` itself is a `Tuple`, a subt `AbstractVector`, if `collection` is an `AbstractArray`, a subtype of `AbstractString` if `collection` is an `AbstractString`, and an arbitrary iterator, falling back to `Iterators.rest(collection[, itr_state])`, otherwise. -Can be overloaded for user-defined collection types to customize the behavior of slurping -in assignments, like `a, b... = collection`. + +Can be overloaded for user-defined collection types to customize the behavior of [slurping +in assignments](@ref destructuring-assignment), like `a, b... = collection`. !!! compat "Julia 1.6" `Base.rest` requires at least Julia 1.6. +See also: [`first`](@ref first), [`Iterators.rest`](@ref). + # Examples ```jldoctest julia> a = [1 2; 3 4] @@ -186,6 +189,8 @@ safe_tail(t::Tuple{}) = () Return a `Tuple` consisting of all but the last component of `x`. +See also: [`first`](@ref), [`tail`](@ref Base.tail). + # Examples ```jldoctest julia> Base.front((1,2,3)) @@ -215,11 +220,17 @@ map(f, t::Tuple{Any, Any}) = (@_inline_meta; (f(t[1]), f(t[2]))) map(f, t::Tuple{Any, Any, Any}) = (@_inline_meta; (f(t[1]), f(t[2]), f(t[3]))) map(f, t::Tuple) = (@_inline_meta; (f(t[1]), map(f,tail(t))...)) # stop inlining after some number of arguments to avoid code blowup -const Any16{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any, - Any,Any,Any,Any,Any,Any,Any,Any,Vararg{Any,N}} -const All16{T,N} = Tuple{T,T,T,T,T,T,T,T, - T,T,T,T,T,T,T,T,Vararg{T,N}} -function map(f, t::Any16) +const Any32{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any, + Any,Any,Any,Any,Any,Any,Any,Any, + Any,Any,Any,Any,Any,Any,Any,Any, + Any,Any,Any,Any,Any,Any,Any,Any, + Vararg{Any,N}} +const All32{T,N} = Tuple{T,T,T,T,T,T,T,T, + T,T,T,T,T,T,T,T, + T,T,T,T,T,T,T,T, + T,T,T,T,T,T,T,T, + Vararg{T,N}} +function map(f, t::Any32) n = length(t) A = Vector{Any}(undef, n) for i=1:n @@ -235,7 +246,7 @@ function map(f, t::Tuple, s::Tuple) @_inline_meta (f(t[1],s[1]), map(f, tail(t), tail(s))...) end -function map(f, t::Any16, s::Any16) +function map(f, t::Any32, s::Any32) n = length(t) A = Vector{Any}(undef, n) for i = 1:n @@ -251,7 +262,7 @@ function map(f, t1::Tuple, t2::Tuple, ts::Tuple...) @_inline_meta (f(heads(t1, t2, ts...)...), map(f, tails(t1, t2, ts...)...)...) end -function map(f, t1::Any16, t2::Any16, ts::Any16...) +function map(f, t1::Any32, t2::Any32, ts::Any32...) n = length(t1) A = Vector{Any}(undef, n) for i = 1:n @@ -317,8 +328,8 @@ function _totuple(T, itr, s...) end # use iterative algorithm for long tuples -function _totuple(T::Type{All16{E,N}}, itr) where {E,N} - len = N+16 +function _totuple(T::Type{All32{E,N}}, itr) where {E,N} + len = N+32 elts = collect(E, Iterators.take(itr,len)) if length(elts) != len _totuple_err(T) @@ -342,15 +353,19 @@ end filter(f, xs::Tuple) = afoldl((ys, x) -> f(x) ? (ys..., x) : ys, (), xs...) # use Array for long tuples -filter(f, t::Any16) = Tuple(filter(f, collect(t))) +filter(f, t::Any32) = Tuple(filter(f, collect(t))) ## comparison ## -isequal(t1::Tuple, t2::Tuple) = (length(t1) == length(t2)) && _isequal(t1, t2) -_isequal(t1::Tuple{}, t2::Tuple{}) = true -_isequal(t1::Tuple{Any}, t2::Tuple{Any}) = isequal(t1[1], t2[1]) -_isequal(t1::Tuple, t2::Tuple) = isequal(t1[1], t2[1]) && _isequal(tail(t1), tail(t2)) -function _isequal(t1::Any16, t2::Any16) +isequal(t1::Tuple, t2::Tuple) = length(t1) == length(t2) && _isequal(t1, t2) +_isequal(::Tuple{}, ::Tuple{}) = true +function _isequal(t1::Tuple{Any,Vararg{Any,N}}, t2::Tuple{Any,Vararg{Any,N}}) where {N} + isequal(t1[1], t2[1]) || return false + t1, t2 = tail(t1), tail(t2) + # avoid dynamic dispatch by telling the compiler relational invariants + return isa(t1, Tuple{}) ? true : _isequal(t1, t2::Tuple{Any,Vararg{Any}}) +end +function _isequal(t1::Any32, t2::Any32) for i = 1:length(t1) if !isequal(t1[i], t2[i]) return false @@ -380,7 +395,7 @@ function _eq_missing(t1::Tuple, t2::Tuple) return _eq_missing(tail(t1), tail(t2)) end end -function _eq(t1::Any16, t2::Any16) +function _eq(t1::Any32, t2::Any32) anymissing = false for i = 1:length(t1) eq = (t1[i] == t2[i]) @@ -396,7 +411,7 @@ end const tuplehash_seed = UInt === UInt64 ? 0x77cfa1eef01bca90 : 0xf01bca90 hash(::Tuple{}, h::UInt) = h + tuplehash_seed hash(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h)) -function hash(t::Any16, h::UInt) +function hash(t::Any32, h::UInt) out = h + tuplehash_seed for i = length(t):-1:1 out = hash(t[i], out) @@ -417,7 +432,7 @@ function <(t1::Tuple, t2::Tuple) end return tail(t1) < tail(t2) end -function <(t1::Any16, t2::Any16) +function <(t1::Any32, t2::Any32) n1, n2 = length(t1), length(t2) for i = 1:min(n1, n2) a, b = t1[i], t2[i] @@ -444,7 +459,7 @@ function isless(t1::Tuple, t2::Tuple) a, b = t1[1], t2[1] isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2))) end -function isless(t1::Any16, t2::Any16) +function isless(t1::Any32, t2::Any32) n1, n2 = length(t1), length(t2) for i = 1:min(n1, n2) a, b = t1[i], t2[i] diff --git a/base/twiceprecision.jl b/base/twiceprecision.jl index 4df9c072f78ee..55cdc59371674 100644 --- a/base/twiceprecision.jl +++ b/base/twiceprecision.jl @@ -214,6 +214,14 @@ function TwicePrecision{T}(nd::Tuple{I,I}, nb::Integer) where {T,I} twiceprecision(TwicePrecision{T}(nd), nb) end +# Fix #39798 +# See steprangelen_hp(::Type{Float64}, ref::Tuple{Integer,Integer}, +# step::Tuple{Integer,Integer}, nb::Integer, +# len::Integer, offset::Integer) +function TwicePrecision{T}(nd::Tuple{Integer,Integer}, nb::Integer) where T + twiceprecision(TwicePrecision{T}(nd), nb) +end + # Truncating constructors. Useful for generating values that can be # exactly multiplied by small integers. function twiceprecision(val::T, nb::Integer) where {T<:IEEEFloat} @@ -673,7 +681,7 @@ end # range for rational numbers, start = start_n/den, stop = stop_n/den # Note this returns a StepRangeLen -_linspace(::Type{T}, start::Integer, stop::Integer, len::Integer) where {T<:IEEEFloat} = _linspace(T, start, stop, len, 1) +_linspace(::Type{T}, start::Integer, stop::Integer, len::Integer) where {T<:IEEEFloat} = _linspace(T, start, stop, len, one(start)) function _linspace(::Type{T}, start_n::Integer, stop_n::Integer, len::Integer, den::Integer) where T<:IEEEFloat len < 2 && return _linspace1(T, start_n/den, stop_n/den, len) start_n == stop_n && return steprangelen_hp(T, (start_n, den), (zero(start_n), den), 0, len, 1) diff --git a/base/util.jl b/base/util.jl index e91ab3780824f..503ba5c390e1c 100644 --- a/base/util.jl +++ b/base/util.jl @@ -67,7 +67,9 @@ Printing with the color `:nothing` will print the string without modifications. """ text_colors -function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol}, io::IO, args...; bold::Bool = false) +function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol}, io::IO, args...; + bold::Bool = false, underline::Bool = false, blink::Bool = false, + reverse::Bool = false, hidden::Bool = false) buf = IOBuffer() iscolor = get(io, :color, false)::Bool try f(IOContext(buf, io), args...) @@ -77,9 +79,22 @@ function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol} print(io, str) else bold && color === :bold && (color = :nothing) + underline && color === :underline && (color = :nothing) + blink && color === :blink && (color = :nothing) + reverse && color === :reverse && (color = :nothing) + hidden && color === :hidden && (color = :nothing) enable_ansi = get(text_colors, color, text_colors[:default]) * - (bold ? text_colors[:bold] : "") - disable_ansi = (bold ? disable_text_style[:bold] : "") * + (bold ? text_colors[:bold] : "") * + (underline ? text_colors[:underline] : "") * + (blink ? text_colors[:blink] : "") * + (reverse ? text_colors[:reverse] : "") * + (hidden ? text_colors[:hidden] : "") + + disable_ansi = (hidden ? disable_text_style[:hidden] : "") * + (reverse ? disable_text_style[:reverse] : "") * + (blink ? disable_text_style[:blink] : "") * + (underline ? disable_text_style[:underline] : "") * + (bold ? disable_text_style[:bold] : "") * get(disable_text_style, color, text_colors[:default]) first = true for line in split(str, '\n') @@ -94,18 +109,23 @@ function with_output_color(@nospecialize(f::Function), color::Union{Int, Symbol} end """ - printstyled([io], xs...; bold::Bool=false, color::Union{Symbol,Int}=:normal) + printstyled([io], xs...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Symbol,Int}=:normal) Print `xs` in a color specified as a symbol or integer, optionally in bold. `color` may take any of the values $(Base.available_text_colors_docstring) or an integer between 0 and 255 inclusive. Note that not all terminals support 256 colors. If the keyword `bold` is given as `true`, the result will be printed in bold. +If the keyword `underline` is given as `true`, the result will be printed underlined. +If the keyword `blink` is given as `true`, the result will blink. +If the keyword `reverse` is given as `true`, the result will have foreground and background colors inversed. +If the keyword `hidden` is given as `true`, the result will be hidden. +Keywords can be given in any combination. """ -printstyled(io::IO, msg...; bold::Bool=false, color::Union{Int,Symbol}=:normal) = - with_output_color(print, color, io, msg...; bold=bold) -printstyled(msg...; bold::Bool=false, color::Union{Int,Symbol}=:normal) = - printstyled(stdout, msg...; bold=bold, color=color) +printstyled(io::IO, msg...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = + with_output_color(print, color, io, msg...; bold=bold, underline=underline, blink=blink, reverse=reverse, hidden=hidden) +printstyled(msg...; bold::Bool=false, underline::Bool=false, blink::Bool=false, reverse::Bool=false, hidden::Bool=false, color::Union{Int,Symbol}=:normal) = + printstyled(stdout, msg...; bold=bold, underline=underline, blink=blink, reverse=reverse, hidden=hidden, color=color) """ Base.julia_cmd(juliapath=joinpath(Sys.BINDIR::String, julia_exename())) @@ -161,6 +181,7 @@ function julia_cmd(julia=joinpath(Sys.BINDIR::String, julia_exename())) opts.can_inline == 0 && push!(addflags, "--inline=no") opts.use_compiled_modules == 0 && push!(addflags, "--compiled-modules=no") opts.opt_level == 2 || push!(addflags, "-O$(opts.opt_level)") + opts.opt_level_min == 0 || push!(addflags, "--min-optlevel=$(opts.opt_level_min)") push!(addflags, "-g$(opts.debug_level)") if opts.code_coverage != 0 # Forward the code-coverage flag only if applicable (if the filename is pid-dependent) diff --git a/base/uuid.jl b/base/uuid.jl index 16ffdcefccc8d..ff4df68ddb7c8 100644 --- a/base/uuid.jl +++ b/base/uuid.jl @@ -31,6 +31,11 @@ end UInt128(u::UUID) = u.value +let + uuid_hash_seed = UInt === UInt64 ? 0xd06fa04f86f11b53 : 0x96a1f36d + Base.hash(uuid::UUID, h::UInt) = hash(uuid_hash_seed, hash(convert(NTuple{2, UInt64}, uuid), h)) +end + let @inline function uuid_kernel(s, i, u) _c = UInt32(@inbounds codeunit(s, i)) diff --git a/base/version.jl b/base/version.jl index 86343dcddabf4..77676f80e3676 100644 --- a/base/version.jl +++ b/base/version.jl @@ -107,10 +107,10 @@ end function tryparse(::Type{VersionNumber}, v::AbstractString) v == "∞" && return typemax(VersionNumber) - m = match(VERSION_REGEX, v) + m = match(VERSION_REGEX, String(v)::String) m === nothing && return nothing major, minor, patch, minus, prerl, plus, build = m.captures - major = parse(VInt, major) + major = parse(VInt, major::AbstractString) minor = minor !== nothing ? parse(VInt, minor) : VInt(0) patch = patch !== nothing ? parse(VInt, patch) : VInt(0) if prerl !== nothing && !isempty(prerl) && prerl[1] == '-' diff --git a/base/version_git.sh b/base/version_git.sh index d2ac9cb6058a7..c46021097995e 100644 --- a/base/version_git.sh +++ b/base/version_git.sh @@ -5,11 +5,11 @@ echo "# This file was autogenerated in base/version_git.sh" echo "struct GitVersionInfo" -echo " commit::AbstractString" -echo " commit_short::AbstractString" -echo " branch::AbstractString" +echo " commit::String" +echo " commit_short::String" +echo " branch::String" echo " build_number::Int" -echo " date_string::AbstractString" +echo " date_string::String" echo " tagged_commit::Bool" echo " fork_master_distance::Int" echo " fork_master_timestamp::Float64" diff --git a/base/weakkeydict.jl b/base/weakkeydict.jl index c7ec172af46aa..8e1a3d480b995 100644 --- a/base/weakkeydict.jl +++ b/base/weakkeydict.jl @@ -84,6 +84,8 @@ empty(d::WeakKeyDict, ::Type{K}, ::Type{V}) where {K, V} = WeakKeyDict{K, V}() IteratorSize(::Type{<:WeakKeyDict}) = SizeUnknown() islocked(wkh::WeakKeyDict) = islocked(wkh.lock) +lock(wkh::WeakKeyDict) = lock(wkh.lock) +unlock(wkh::WeakKeyDict) = unlock(wkh.lock) lock(f, wkh::WeakKeyDict) = lock(f, wkh.lock) trylock(f, wkh::WeakKeyDict) = trylock(f, wkh.lock) diff --git a/cli/Makefile b/cli/Makefile index e289ffc82aaa6..c38b9972a243b 100644 --- a/cli/Makefile +++ b/cli/Makefile @@ -70,7 +70,7 @@ $(BUILDDIR)/julia_res.o: $(JULIAHOME)/contrib/windows/julia.rc $(JULIAHOME)/VERS JLVER=`cat $(JULIAHOME)/VERSION` && \ JLVERi=`echo $$JLVER | perl -nle \ '/^(\d+)\.?(\d*)\.?(\d*)/ && \ - print int $$1,",",int $$2,",0,",int $$3'` && \ + print int $$1,",",int $$2,",",int $$3,",0"'` && \ $(CROSS_COMPILE)windres $< -O coff -o $@ -DJLVER=$$JLVERi -DJLVER_STR=\\\"$$JLVER\\\" EXE_OBJS += $(BUILDDIR)/julia_res.o EXE_DOBJS += $(BUILDDIR)/julia_res.o @@ -100,17 +100,10 @@ libjulia-debug: $(build_shlibdir)/libjulia-debug.$(SHLIB_EXT) ifeq ($(OS),WINNT) # On Windows we need to strip out exported functions from the generated import library. -# On i686, there's an extra underscore at the beginning -ifeq ($(ARCH),i686) -ABI_UNDERSCORE := _\#\# -else -ABI_UNDERSCORE := -endif -EXPORTED_FUNCS := $(shell echo -e "#include \"jl_exported_funcs.inc\"\n#define XX(x) $(ABI_UNDERSCORE)x\nJL_EXPORTED_FUNCS(XX)" | $(CPP) -I$(JULIAHOME)/src - | tail -n 1) -STRIP_EXPORTED_FUNCS := $(patsubst %,--strip-symbol=%,$(EXPORTED_FUNCS)) +STRIP_EXPORTED_FUNCS := $(shell $(CPP_STDOUT) -I$(JULIAHOME)/src $(SRCDIR)/list_strip_symbols.h) endif -$(build_shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_OBJS) | $(build_shlibdir) $(build_libdir) +$(build_shlibdir)/libjulia.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_OBJS) $(SRCDIR)/list_strip_symbols.h | $(build_shlibdir) $(build_libdir) @$(call PRINT_LINK, $(CC) $(call IMPLIB_FLAGS,$@.tmp) $(LOADER_CFLAGS) -DLIBRARY_EXPORTS -shared $(SHIPFLAGS) $(LIB_OBJS) -o $@ \ $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(RPATH_LIB) $(call SONAME_FLAGS,libjulia.$(JL_MAJOR_SHLIB_EXT))) @$(INSTALL_NAME_CMD)libjulia.$(SHLIB_EXT) $@ @@ -120,14 +113,13 @@ ifeq ($(OS), WINNT) @$(call PRINT_ANALYZE, $(OBJCOPY) $(build_libdir)/$(notdir $@).tmp.a $(STRIP_EXPORTED_FUNCS) $(build_libdir)/$(notdir $@).a && rm $(build_libdir)/$(notdir $@).tmp.a) endif -$(build_shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_DOBJS) | $(build_shlibdir) $(build_libdir) - @$(call PRINT_LINK, $(CC) $(call IMPLIB_FLAGS,$@.tmp) $(LOADER_CFLAGS) -DLIBRARY_EXPORTS -shared $(DEBUGFLAGS) $(LIB_DOBJS) -o $@.tmp \ +$(build_shlibdir)/libjulia-debug.$(JL_MAJOR_MINOR_SHLIB_EXT): $(LIB_DOBJS) $(SRCDIR)/list_strip_symbols.h | $(build_shlibdir) $(build_libdir) + @$(call PRINT_LINK, $(CC) $(call IMPLIB_FLAGS,$@.tmp) $(LOADER_CFLAGS) -DLIBRARY_EXPORTS -shared $(DEBUGFLAGS) $(LIB_DOBJS) -o $@ \ $(JLIBLDFLAGS) $(LOADER_LDFLAGS) $(RPATH_LIB) $(call SONAME_FLAGS,libjulia-debug.$(JL_MAJOR_SHLIB_EXT))) @$(INSTALL_NAME_CMD)libjulia-debug.$(SHLIB_EXT) $@.tmp ifeq ($(OS), WINNT) @$(call PRINT_ANALYZE, $(OBJCOPY) $(build_libdir)/$(notdir $@).tmp.a $(STRIP_EXPORTED_FUNCS) $(build_libdir)/$(notdir $@).a && rm $(build_libdir)/$(notdir $@).tmp.a) endif - @mv $@.tmp $@ ifneq ($(OS), WINNT) $(build_shlibdir)/libjulia.$(JL_MAJOR_SHLIB_EXT) $(build_shlibdir)/libjulia-debug.$(JL_MAJOR_SHLIB_EXT): $(build_shlibdir)/libjulia%.$(JL_MAJOR_SHLIB_EXT): \ diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000000000..4021aceb7d839 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,31 @@ +# cli and loader + +This directory contains the code used by the Julia loader, implementing the pieces necessary to isolate ourselves from the native dynamic loader enough to reimplement useful features such as RPATH across all platforms. +This loader comprises the `julia` executable and the `libjulia` library, which are responsible for setting things up such that `libjulia-internal` and any other internal dependencies can be reliably loaded. +The code is organized in three pieces: + +* `loader_exe.c` gets built into the main `julia` executable. It immediately loads `libjulia`. +* `loader_lib.c` gets built into the main `libjulia` shared library. This is the main entrypoint for the Julia runtime loading process, which occurs within `jl_load_repl()`. +* `trampolines/*.S`, which contains assembly definitions for symbol forwarding trampolines. These are used to allow `libjulia` to re-export symbols such that a C linker can use `libjulia` directly for embedding usecases. + +The main requirements of the loader are as follows: + +- **Isolation**: We need to be able to load our own copy of `libgcc_s.so`, etc... + On Linux/macOS, proper application of `RPATH` can influence the linker's decisions, however errant `LD_LIBRARY_PATH` entries or system libraries inserted into the build process can still interfere, not to mention Windows' lack of `RPATH`-like capabilities. + To address this, the loader is built as a stand-alone binary that does not depend on the large set of dependencies that `libjulia-internal` itself does, and manually `dlopen()`'s a list of dependencies using logic similar to that of an `RPATH`. +- **Compatibility**: We need to support embedding usecases without forcing embedders to care about all of these things. + For linking against the Julia runtime by simply providing `-ljulia` on the link line, we must ensure that all public interfaces, whether function symbols or data symbols, must be exported from `libjulia`. + This motivates our usage of function trampolines to re-export functions from `libjulia-internal`, and the reason why all public data symbols are defined within `libjulia`, then imported into `libjulia-internal` for initialization. +- **Flexibility**: We need to be able to make use of system libraries when requested to do so by the user at build time. + Currently, we embed the list of libraries to be `dlopen()`'ed within `libjulia` as a string (See the definition of `DEP_LIBS` in `Make.inc` and its usage in `loader_lib.c`). + This is flexible enough as we do not support changing this configuration at runtime, however in the future, we may need to add some simple parsing logic in `loader_lib.c` to inspect a `LocalPreferences.toml` and construct the list of libraries to load from that. +- **Speed**: This whole process should be fast, especially function trampolines. + To this end, we write everything in low-overhead assembly, borrowing inspiration from the PLT trampolines that the linker already generates when using dynamic libraries. + +## Public interface definition + +The public interface exported by `libjulia` is contained within `.inc` files stored in `src`; one for exported data symbols, [`src/jl_exported_data.inc`](../src/jl_exported_data.inc) and one for exported functions, [`src/jl_exported_funcs.inc`](../src/jl_exported_funcs.inc). +Adding entries to the data list will cause `libjulia` to generate a placeholder variable declaration. +Most symbols are declared to be of type `void *`, however for symbols that are of a different size, they are declared along with their type. +Adding entries to the function list will cause `libjulia` to generate a trampoline definition (using a trampoline according to the architecture of the target processor) and then at runtime, when `libjulia` has successfully loaded `libjulia-internal`, it will `dlsym()` that symbol from within `libjulia-internal` and set it as the target of the trampoline. +All initialization will occur automatically upon successful load of `libjulia`, so there is no need for user code to call an initialization before invoking typical `libjulia-internal` functions (although initialization of the runtime itself is still necessary, e.g. calling `jl_init()`). diff --git a/cli/jl_exports.h b/cli/jl_exports.h index 0d467a6528b75..35d2767726865 100644 --- a/cli/jl_exports.h +++ b/cli/jl_exports.h @@ -10,13 +10,19 @@ JL_EXPORTED_DATA_POINTERS(XX) #undef XX -// Define symbol data as `$type) $(name);` +// Define symbol data as `$(type) $(name);` #define XX(name, type) JL_DLLEXPORT type name; JL_EXPORTED_DATA_SYMBOLS(XX) #undef XX -// Define holder locations for function addresses as `const void * $(name)_addr` -#define XX(name) JL_HIDDEN const void * name##_addr; +// Declare list of exported functions (sans type) +#define XX(name) JL_DLLEXPORT void name(void); +typedef void (anonfunc)(void); +JL_EXPORTED_FUNCS(XX) +#undef XX + +// Define holder locations for function addresses as `const void * $(name)_addr = & $(name);` +#define XX(name) JL_HIDDEN anonfunc * name##_addr = (anonfunc*)&name; JL_EXPORTED_FUNCS(XX) #undef XX @@ -29,7 +35,7 @@ static const char *const jl_exported_func_names[] = { #undef XX #define XX(name) &name##_addr, -static const void ** jl_exported_func_addrs[] = { +static anonfunc **const jl_exported_func_addrs[] = { JL_EXPORTED_FUNCS(XX) NULL }; diff --git a/cli/list_strip_symbols.h b/cli/list_strip_symbols.h new file mode 100644 index 0000000000000..e1a96261fe05a --- /dev/null +++ b/cli/list_strip_symbols.h @@ -0,0 +1,7 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#include "jl_exported_funcs.inc" +#include "trampolines/common.h" +#define XX(x) --strip-symbol=CNAME(x) +JL_EXPORTED_FUNCS(XX) +#undef XX diff --git a/cli/loader_lib.c b/cli/loader_lib.c index 0249c11f3f6c3..f7858d9bc909f 100644 --- a/cli/loader_lib.c +++ b/cli/loader_lib.c @@ -130,7 +130,7 @@ JL_DLLEXPORT const char * jl_get_libdir() void * libjulia_internal = NULL; __attribute__((constructor)) void jl_load_libjulia_internal(void) { - // Only initalize this once + // Only initialize this once if (libjulia_internal != NULL) { return; } @@ -160,7 +160,12 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) { // Once we have libjulia-internal loaded, re-export its symbols: for (unsigned int symbol_idx=0; jl_exported_func_names[symbol_idx] != NULL; ++symbol_idx) { - (*jl_exported_func_addrs[symbol_idx]) = lookup_symbol(libjulia_internal, jl_exported_func_names[symbol_idx]); + void *addr = lookup_symbol(libjulia_internal, jl_exported_func_names[symbol_idx]); + if (addr == NULL || addr == *jl_exported_func_addrs[symbol_idx]) { + jl_loader_print_stderr3("ERROR: Unable to load ", jl_exported_func_names[symbol_idx], " from libjulia-internal"); + exit(1); + } + (*jl_exported_func_addrs[symbol_idx]) = addr; } } @@ -191,9 +196,9 @@ JL_DLLEXPORT int jl_load_repl(int argc, char * argv[]) { #endif // Load the repl entrypoint symbol and jump into it! - int (*entrypoint)(int, char **) = (int (*)(int, char **))lookup_symbol(libjulia_internal, "repl_entrypoint"); + int (*entrypoint)(int, char **) = (int (*)(int, char **))lookup_symbol(libjulia_internal, "jl_repl_entrypoint"); if (entrypoint == NULL) { - jl_loader_print_stderr("ERROR: Unable to find `repl_entrypoint()` within libjulia-internal!\n"); + jl_loader_print_stderr("ERROR: Unable to find `jl_repl_entrypoint()` within libjulia-internal!\n"); exit(1); } return entrypoint(argc, (char **)argv); diff --git a/cli/trampolines/common.h b/cli/trampolines/common.h index 743d697d2467b..06d7b9e236971 100644 --- a/cli/trampolines/common.h +++ b/cli/trampolines/common.h @@ -23,6 +23,9 @@ .ascii STR(-export:##I(name)); \ .ascii " "; \ .section .text +#elif defined(__ELF__) +#define DEBUGINFO(name) .type CNAME(name),@function +#define EXPORT(name) .size CNAME(name), . - CNAME(name) #else #define DEBUGINFO(name) #define EXPORT(name) diff --git a/cli/trampolines/trampolines_arm.S b/cli/trampolines/trampolines_arm.S index 1bb924168525b..f99b7820360b2 100644 --- a/cli/trampolines/trampolines_arm.S +++ b/cli/trampolines/trampolines_arm.S @@ -5,7 +5,7 @@ .global CNAME(name); \ .cfi_startproc; \ CNAME(name)##:; \ - ldr ip, CONCAT(.L,CNAME(name)); \ + ldr ip, CONCAT(.L,CNAMEADDR(name)); \ CONCAT(.L,CNAME(name)): ;\ add ip, pc, ip; \ ldr pc, [ip]; \ diff --git a/contrib/add_license_to_files.jl b/contrib/add_license_to_files.jl index eecca7dc3f464..c5aa0f49d99d3 100644 --- a/contrib/add_license_to_files.jl +++ b/contrib/add_license_to_files.jl @@ -20,7 +20,7 @@ const rootdirs = [ "../stdlib", ] -# to exculde whole sub directories +# to exclude whole sub directories const excludedirs = [ # see: https://github.com/JuliaLang/julia/pull/11073#issuecomment-98090053 "../base/ryu", diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 049506fd464c2..b5ded199688ee 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -141,7 +141,10 @@ if Artifacts !== nothing precompile_script *= """ using Artifacts, Base.BinaryPlatforms, Libdl artifacts_toml = abspath(joinpath(Sys.STDLIB, "Artifacts", "test", "Artifacts.toml")) - # cd(() -> (name = "HelloWorldC"; @artifact_str(name)), dirname(artifacts_toml)) + artifact_hash("HelloWorldC", artifacts_toml) + oldpwd = pwd(); cd(dirname(artifacts_toml)) + macroexpand(Main, :(@artifact_str("HelloWorldC"))) + cd(oldpwd) artifacts = Artifacts.load_artifacts_toml(artifacts_toml) platforms = [Artifacts.unpack_platform(e, "HelloWorldC", artifacts_toml) for e in artifacts["HelloWorldC"]] best_platform = select_platform(Dict(p => triplet(p) for p in platforms)) diff --git a/contrib/refresh_checksums.mk b/contrib/refresh_checksums.mk index da0c69eed5510..1ccbb16a9ba4f 100644 --- a/contrib/refresh_checksums.mk +++ b/contrib/refresh_checksums.mk @@ -19,7 +19,7 @@ CLANG_TRIPLETS=$(filter %-darwin %-freebsd,$(TRIPLETS)) NON_CLANG_TRIPLETS=$(filter-out %-darwin %-freebsd,$(TRIPLETS)) # These are the projects currently using BinaryBuilder; both GCC-expanded and non-GCC-expanded: -BB_PROJECTS=mbedtls libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib suitesparse openlibm blastrampoline +BB_PROJECTS=mbedtls libssh2 nghttp2 mpfr curl libgit2 pcre libuv unwind llvmunwind dsfmt objconv p7zip zlib libsuitesparse openlibm blastrampoline BB_GCC_EXPANDED_PROJECTS=openblas csl BB_CXX_EXPANDED_PROJECTS=gmp llvm clang llvm-tools # These are non-BB source-only deps @@ -47,7 +47,7 @@ endef # if $(3) is "assert", we set BINARYBUILDER_LLVM_ASSERTS=1 define checksum_dep checksum-$(1)-$(2)-$(3): - -$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/deps" $(call make_flags,$(1),$(2),$(3)) checksum-$(1) + -+$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/deps" $(call make_flags,$(1),$(2),$(3)) checksum-$(1) .PHONY: checksum-$(1)-$(2)-$(3) # Add this guy to his project target @@ -73,31 +73,40 @@ $(foreach project,$(BB_GCC_EXPANDED_PROJECTS),$(foreach triplet,$(TRIPLETS),$(fo $(foreach project,$(BB_CXX_EXPANDED_PROJECTS),$(foreach triplet,$(NON_CLANG_TRIPLETS),$(foreach cxxstring_abi,cxx11 cxx03,$(eval $(call checksum_dep,$(project),$(triplet)-$(cxxstring_abi)))))) $(foreach project,$(BB_CXX_EXPANDED_PROJECTS),$(foreach triplet,$(CLANG_TRIPLETS),$(eval $(call checksum_dep,$(project),$(triplet))))) -# Special libLLVM_asserts_jll targets +# Special libLLVM_asserts_jll/LLVM_assert_jll targets $(foreach triplet,$(NON_CLANG_TRIPLETS),$(foreach cxxstring_abi,cxx11 cxx03,$(eval $(call checksum_dep,llvm,$(triplet)-$(cxxstring_abi),assert)))) +$(foreach triplet,$(NON_CLANG_TRIPLETS),$(foreach cxxstring_abi,cxx11 cxx03,$(eval $(call checksum_dep,llvm-tools,$(triplet)-$(cxxstring_abi),assert)))) $(foreach triplet,$(CLANG_TRIPLETS),$(eval $(call checksum_dep,llvm,$(triplet),assert))) +$(foreach triplet,$(CLANG_TRIPLETS),$(eval $(call checksum_dep,llvm-tools,$(triplet),assert))) # External stdlibs checksum-stdlibs: - -$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/stdlib" checksumall + -+$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/stdlib" checksumall all: checksum-stdlibs .PHONY: checksum-stdlibs # doc unicode data checksum-doc-unicodedata: - -$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/doc" checksum-unicodedata + -+$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/doc" checksum-unicodedata all: checksum-doc-unicodedata .PHONY: checksum-doc-unicodedata # Special LLVM source hashes for optional targets checksum-llvm-special-src: - -$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/deps" USE_BINARYBUILDER_LLVM=0 DEPS_GIT=0 BUILD_LLDB=1 BUILD_LLVM_CLANG=1 BUILD_CUSTOM_LIBCXX=1 USECLANG=1 checksum-llvm + -+$(MAKE) $(QUIET_MAKE) -C "$(JULIAHOME)/deps" USE_BINARYBUILDER_LLVM=0 DEPS_GIT=0 BUILD_LLDB=1 BUILD_LLVM_CLANG=1 BUILD_CUSTOM_LIBCXX=1 USECLANG=1 checksum-llvm all: checksum-llvm-special-src .PHONY: checksum-llvm-special-src # merge substring project names to avoid races pack-checksum-llvm-tools: | pack-checksum-llvm +pack-checksum-llvm: | checksum-llvm-tools pack-checksum-csl: | pack-checksum-compilersupportlibraries +pack-checksum-compilersupportlibraries: | checksum-csl + +# We need to adjust to the fact that the checksum files are called `suitesparse` +pack-checksum-libsuitesparse: | pack-checksum-suitesparse + @# nothing to do but disable the prefix rule +pack-checksum-suitesparse: | checksum-libsuitesparse # define how to pack parallel checksums into a single file format pack-checksum-%: FORCE diff --git a/contrib/windows/build-installer.iss b/contrib/windows/build-installer.iss index 576f834bc3c91..4f5f0259d2f2c 100644 --- a/contrib/windows/build-installer.iss +++ b/contrib/windows/build-installer.iss @@ -2,10 +2,6 @@ #define AppName "Julia" #endif -#ifndef AppId -#define AppId "{{054B4BC6-BD30-45C8-A623-8F5BA6EBD55D}" -#endif - #ifndef DirName #define DirName AppName + "-" + AppVersion #endif @@ -14,6 +10,9 @@ #define AppMainExeName "bin\julia.exe" #define CurrentYear GetDateTimeString('yyyy', '', '') +#ifndef AppId +#define AppId DirName +#endif [LangOptions] @@ -61,7 +60,7 @@ AppName={#AppName} AppVersion={#AppVersion} AppPublisher=Julia Language AppPublisherURL=https://julialang.org -AppCopyright=Copyright 2009-{#CurrentYear}; Julia Langage +AppCopyright=Copyright 2009-{#CurrentYear}; Julia Language VersionInfoDescription=Julia Installer PrivilegesRequiredOverridesAllowed=commandline WizardStyle=modern @@ -104,7 +103,8 @@ Name: "addtopath"; Description: "Add {#AppName} to PATH"; GroupDescription: "{cm [Files] -Source: "{#SourceDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "{#SourceDir}\*"; Excludes: "{#AppMainExeName}"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; +Source: "{#SourceDir}\{#AppMainExeName}"; DestDir: "{app}\bin"; Flags: ignoreversion sign; [Icons] diff --git a/contrib/windows/julia.rc b/contrib/windows/julia.rc index afef95ca4af0b..9a82ee1083ad6 100644 --- a/contrib/windows/julia.rc +++ b/contrib/windows/julia.rc @@ -1,13 +1,13 @@ #include #include -1 VERSIONINFO +VS_VERSION_INFO VERSIONINFO FILEVERSION JLVER PRODUCTVERSION JLVER /* -FILEFLAGSMASK VS_FF_PRERELEASE -FILEFLAGS VS_FF_PRERELEASE +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS VER_PRIVATEBUILD */ -FILEOS VOS_DOS_WINDOWS32 +FILEOS VOS__WINDOWS32 FILETYPE VFT_APP BEGIN BLOCK "StringFileInfo" @@ -18,7 +18,7 @@ BEGIN VALUE "FileDescription", "Julia Programming Language" VALUE "FileVersion", JLVER_STR VALUE "InternalName", "julia" - VALUE "LegalCopyright", "(c) 2009-2020 Julia Language" + VALUE "LegalCopyright", "(c) 2009-2021 Julia Language" VALUE "OriginalFilename", "julia.exe" VALUE "ProductName", "Julia" VALUE "ProductVersion", JLVER_STR diff --git a/deps/Makefile b/deps/Makefile index cc5d7a05f3902..27b93f444580f 100644 --- a/deps/Makefile +++ b/deps/Makefile @@ -24,7 +24,7 @@ BUILDDIR := $(BUILDDIR)$(MAYBE_HOST) # if you are adding a new target, it can help to copy an similar, existing target # # autoconf configure-driven scripts: pcre unwind gmp mpfr patchelf libuv curl -# custom Makefile rules: openlibm dsfmt suitesparse-wrapper suitesparse lapack blastrampoline openblas utf8proc objconv libwhich +# custom Makefile rules: openlibm dsfmt libsuitesparse lapack blastrampoline openblas utf8proc objconv libwhich # CMake libs: llvm llvmunwind libgit2 libssh2 mbedtls # # downloadable via git: llvm-svn, libuv, libopenlibm, utf8proc, libgit2, libssh2 @@ -46,10 +46,6 @@ ifeq ($(USE_SYSTEM_CSL), 0) DEP_LIBS += csl endif -ifeq ($(USE_GPL_LIBS), 1) -DEP_LIBS += suitesparse-wrapper -endif - ifeq ($(USE_SYSTEM_LIBUV), 0) DEP_LIBS += libuv endif @@ -134,8 +130,8 @@ DEP_LIBS += mpfr endif ifeq ($(USE_GPL_LIBS), 1) -ifeq ($(USE_SYSTEM_SUITESPARSE), 0) -DEP_LIBS += suitesparse +ifeq ($(USE_SYSTEM_LIBSUITESPARSE), 0) +DEP_LIBS += libsuitesparse endif endif @@ -166,12 +162,24 @@ ifneq ($(OS), WINNT) DEP_LIBS += libwhich endif -# unlist targets that have not been converted to use the staged-install -DEP_LIBS_STAGED := $(DEP_LIBS) -DEP_LIBS_STAGED := $(filter-out csl,$(DEP_LIBS_STAGED)) -DEP_LIBS_STAGED := $(filter-out suitesparse,$(DEP_LIBS_STAGED)) -DEP_LIBS_STAGED := $(filter-out suitesparse-wrapper,$(DEP_LIBS_STAGED)) +# list all targets +DEP_LIBS_STAGED_ALL := llvm llvm-tools clang llvmunwind unwind libuv pcre \ + openlibm dsfmt blastrampoline openblas lapack gmp mpfr patchelf utf8proc \ + objconv mbedtls libssh2 nghttp2 curl libgit2 libwhich zlib p7zip csl \ + libsuitesparse +DEP_LIBS_ALL := $(DEP_LIBS_STAGED_ALL) +ifneq ($(USE_BINARYBUILDER_OPENBLAS),0) +DEP_LIBS_ALL := $(filter-out lapack,$(DEP_LIBS_ALL)) +endif + +ifeq ($(USE_BINARYBUILDER_LLVM),0) +DEP_LIBS_ALL := $(filter-out clang llvm-tools,$(DEP_LIBS_ALL)) +endif + +ifeq ($(USE_BINARYBUILDER_LIBSUITESPARSE),0) +DEP_LIBS_STAGED := $(filter-out libsuitesparse,$(DEP_LIBS_STAGED)) +endif ## Common build target prefixes @@ -183,21 +191,14 @@ compile: $(addprefix compile-, $(DEP_LIBS)) check: $(addprefix check-, $(DEP_LIBS)) fastcheck: $(addprefix fastcheck-, $(DEP_LIBS)) stage: $(addprefix stage-, $(DEP_LIBS_STAGED)) -install: $(addprefix install-, $(DEP_LIBS)) -cleanall: $(addprefix clean-, $(DEP_LIBS)) -distcleanall: $(addprefix distclean-, $(DEP_LIBS)) - rm -rf $(build_prefix) -getall: get-llvm get-libuv get-pcre get-openlibm get-dsfmt get-blastrampoline get-openblas get-lapack get-suitesparse get-unwind get-gmp get-mpfr get-patchelf get-utf8proc get-objconv get-mbedtls get-libssh2 get-nghttp2 get-curl get-libgit2 get-libwhich get-zlib get-p7zip get-csl - -# If we're building for MacOS, no matter what, `getall` should include `llvmunwind` -ifeq ($(OS),Darwin) -getall: get-llvmunwind -endif +install: version-check $(addprefix install-, $(DEP_LIBS)) +version-check: $(addprefix version-check-, $(DEP_LIBS_STAGED)) -# Same if we're building a purely-source archive, always include `llvmunwind` -ifeq ($(USE_BINARYBUILDER_LLVMUNWIND),0) -getall: get-llvmunwind -endif +uninstall: $(addprefix uninstall-, $(DEP_LIBS_STAGED_ALL)) +cleanall: $(addprefix clean-, $(DEP_LIBS_ALL)) +distcleanall: $(addprefix distclean-, $(DEP_LIBS_ALL)) + rm -rf $(build_prefix) +getall: $(addprefix get-, $(DEP_LIBS_ALL)) include $(SRCDIR)/csl.mk include $(SRCDIR)/llvm.mk @@ -209,7 +210,7 @@ include $(SRCDIR)/objconv.mk include $(SRCDIR)/blastrampoline.mk include $(SRCDIR)/openblas.mk include $(SRCDIR)/utf8proc.mk -include $(SRCDIR)/suitesparse.mk +include $(SRCDIR)/libsuitesparse.mk include $(SRCDIR)/unwind.mk include $(SRCDIR)/gmp.mk include $(SRCDIR)/mpfr.mk diff --git a/deps/SuiteSparse_wrapper.c b/deps/SuiteSparse_wrapper.c deleted file mode 100644 index fc8b612d7671b..0000000000000 --- a/deps/SuiteSparse_wrapper.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - SuiteSparse_wrapper.c: Changes made to this file in the Julia repo - in deps/SuiteSparse_wrapper.c should be also made in - Yggdrasil/S/SuiteSparse and vice versa. -*/ - -#include -#include - -extern size_t jl_cholmod_common_size(void) { - return sizeof(cholmod_common); -} - -extern size_t jl_cholmod_sizeof_long(void) { - return sizeof(SuiteSparse_long); -} - -extern int jl_cholmod_version(int *ver) { - if (ver != (int*) NULL) { - ver[0] = CHOLMOD_MAIN_VERSION; - ver[1] = CHOLMOD_SUB_VERSION; - ver[2] = CHOLMOD_SUBSUB_VERSION; - } - return CHOLMOD_VERSION; -} - -extern void jl_cholmod_common_offsets(size_t *vv) { - vv[0] = offsetof(cholmod_common, dbound); - vv[1] = offsetof(cholmod_common, maxrank); - vv[2] = offsetof(cholmod_common, supernodal_switch); - vv[3] = offsetof(cholmod_common, supernodal); - vv[4] = offsetof(cholmod_common, final_asis); - vv[5] = offsetof(cholmod_common, final_super); - vv[6] = offsetof(cholmod_common, final_ll); - vv[7] = offsetof(cholmod_common, final_pack); - vv[8] = offsetof(cholmod_common, final_monotonic); - vv[9] = offsetof(cholmod_common, final_resymbol); - vv[10] = offsetof(cholmod_common, prefer_zomplex); - vv[11] = offsetof(cholmod_common, prefer_upper); - vv[12] = offsetof(cholmod_common, print); - vv[13] = offsetof(cholmod_common, precise); - vv[14] = offsetof(cholmod_common, nmethods); - vv[15] = offsetof(cholmod_common, selected); - vv[16] = offsetof(cholmod_common, postorder); - vv[17] = offsetof(cholmod_common, itype); - vv[18] = offsetof(cholmod_common, dtype); -} diff --git a/deps/Versions.make b/deps/Versions.make index 9d19790e945e6..cb41d43622aed 100644 --- a/deps/Versions.make +++ b/deps/Versions.make @@ -15,7 +15,7 @@ CSL_JLL_NAME := CompilerSupportLibraries # Clang (paired with LLVM, only here as a JLL download) CLANG_JLL_NAME := Clang -CLANG_JLL_VER := 11.0.1+3 +CLANG_JLL_VER := 12.0.0+0 # DSFMT DSFMT_VER := 2.2.4 @@ -44,13 +44,14 @@ LIBUV_VER := 2 LIBUV_JLL_NAME := LibUV # LLVM -LLVM_VER := 11.0.1 -LLVM_ASSERT_JLL_VER := 11.0.1+3 +LLVM_VER := 12.0.0 +LLVM_ASSERT_JLL_VER := 12.0.0+0 LLVM_JLL_NAME := libLLVM # LLVM_tools (downloads LLVM_jll to get things like `lit` and `opt`) LLVM_TOOLS_JLL_NAME := LLVM -LLVM_TOOLS_JLL_VER := 11.0.1+3 +LLVM_TOOLS_JLL_VER := 12.0.0+0 +LLVM_TOOLS_ASSERT_JLL_VER := 12.0.0+0 # LLVM libunwind LLVMUNWIND_VER := 11.0.1 @@ -74,7 +75,7 @@ OBJCONV_JLL_NAME := Objconv OBJCONV_JLL_VER := 2.49.1+0 # blastrampoline -BLASTRAMPOLINE_VER := 3.0.2 +BLASTRAMPOLINE_VER := 3.0.4 BLASTRAMPOLINE_JLL_NAME := libblastrampoline # OpenBLAS @@ -97,8 +98,8 @@ PCRE_VER := 10.36 PCRE_JLL_NAME := PCRE2 # SuiteSparse -SUITESPARSE_VER := 5.8.1 -SUITESPARSE_JLL_NAME := SuiteSparse +LIBSUITESPARSE_VER := 5.10.1 +LIBSUITESPARSE_JLL_NAME := SuiteSparse # unwind UNWIND_VER := 1.3.2 diff --git a/deps/blastrampoline.version b/deps/blastrampoline.version index 905164db9e272..86d77ab5bf293 100644 --- a/deps/blastrampoline.version +++ b/deps/blastrampoline.version @@ -1,2 +1,2 @@ -BLASTRAMPOLINE_BRANCH=main -BLASTRAMPOLINE_SHA1=5882fdf6395afb1ed01a8a10db94b7b3cbd39e16 +BLASTRAMPOLINE_BRANCH=v3.0.4 +BLASTRAMPOLINE_SHA1=23de7a09bf354fe6f655c457bab5bf47fdd2486d diff --git a/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/md5 b/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/md5 deleted file mode 100644 index 58efffdca88d2..0000000000000 --- a/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -7e0ab65c9c6f9413a458ee77ad5e0b29 diff --git a/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/sha512 b/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/sha512 deleted file mode 100644 index c01000751dc6b..0000000000000 --- a/deps/checksums/Downloads-6bb83068bd796c4890baaeb39628ff79a4979374.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -b7961928dffd19fb4e5220da694260ae822e80b5ae39ad503f493dcd225f54bc50d4df1b2e833473a164dd42b89c710528d6c58c60f0997492f2551ae1eebaf4 diff --git a/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/md5 b/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/md5 new file mode 100644 index 0000000000000..3e5f8512f28d5 --- /dev/null +++ b/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/md5 @@ -0,0 +1 @@ +2f772706c50763c369486fa730fb6314 diff --git a/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/sha512 b/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/sha512 new file mode 100644 index 0000000000000..cae2e9b1fbbac --- /dev/null +++ b/deps/checksums/Downloads-c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71.tar.gz/sha512 @@ -0,0 +1 @@ +c18c87194f5c214c2a3caddc1e0b17924c3c1c7f6f1f711cd545af32736cedc612ee8056ad892d115042ba140d1c7cd8d1fbdd70203eb8995587e54842bb67a8 diff --git a/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/md5 b/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/md5 new file mode 100644 index 0000000000000..bf3e63240bbb4 --- /dev/null +++ b/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/md5 @@ -0,0 +1 @@ +1cf54106737f6481a64f8311ff32c822 diff --git a/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/sha512 b/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/sha512 new file mode 100644 index 0000000000000..060de26b7c765 --- /dev/null +++ b/deps/checksums/Pkg-6cf6b95e051d8ecde0424ff8bac022fee197c690.tar.gz/sha512 @@ -0,0 +1 @@ +aa4276a579852468db725748a05783fe81e2bb63c519e74eb0e0fc90fb1403f5d55e43e55878b52cb6a75bb6f930c409e9e5220907b007ec674fa00b86b2de85 diff --git a/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/md5 b/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/md5 deleted file mode 100644 index 8ff865fe02593..0000000000000 --- a/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -f70da472ebac16aaec6f38e69e49c6d7 diff --git a/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/sha512 b/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/sha512 deleted file mode 100644 index 84f9ae288d8a2..0000000000000 --- a/deps/checksums/Pkg-af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -83f6966bc5a55f80fce9899e8f48a0e26dae37d88a5819b1a67d81d2ab5bf57999acd1a42b2ca7366c428efb2a8661679820550df8d8f7a4a74f9a4406da096d diff --git a/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/md5 b/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/md5 new file mode 100644 index 0000000000000..234424096e008 --- /dev/null +++ b/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/md5 @@ -0,0 +1 @@ +62c5d890b62dc8825ff449dd229452b2 diff --git a/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/sha512 b/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/sha512 new file mode 100644 index 0000000000000..7833dea8238d1 --- /dev/null +++ b/deps/checksums/SuiteSparse-ec4b40ad9c0490ebf0969a41d4f880620db3f6f9.tar.gz/sha512 @@ -0,0 +1 @@ +b822f84edaab9dce301803510ac6e597fd135620685544aa9e8fbc0bbb140784fb00012e5ccfe4836b4dc39bd75f8be54c4e1fffc29696991e3d78855bc7617c diff --git a/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/md5 b/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/md5 new file mode 100644 index 0000000000000..30d64c2600751 --- /dev/null +++ b/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/md5 @@ -0,0 +1 @@ +e2b8b646355ba71a6e30dbe9c0fdc6ac diff --git a/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/sha512 b/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/sha512 new file mode 100644 index 0000000000000..be161a529bc83 --- /dev/null +++ b/deps/checksums/Tar-86825ecf1e8b6f57105bf0632e93c532cee200a4.tar.gz/sha512 @@ -0,0 +1 @@ +db66086d531bbf2210207449ac464d4e865562a849f8a4197feca4636c90ca577140977daf3d0fb4c4c61240866934a10ccc6120b7bc95b1a18ff16f9491aed9 diff --git a/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/md5 b/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/md5 deleted file mode 100644 index 5f1a8151702d6..0000000000000 --- a/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -8e142a0c1761068128b4ac229aae584d diff --git a/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/sha512 b/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/sha512 deleted file mode 100644 index 0c3dd7423504f..0000000000000 --- a/deps/checksums/Tar-ac4d442266a676ce2d1a43acb55fc07d1edc6566.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -d899b09c3ab4d94605297c716838f21dae7f1467b2785c9fff960ddad645161148fcdb2bc114e94da24f567098af4abce49960986f91eb26a2c234928fe6bdc9 diff --git a/deps/checksums/blastrampoline b/deps/checksums/blastrampoline index 02049d4752096..a9a564fc09042 100644 --- a/deps/checksums/blastrampoline +++ b/deps/checksums/blastrampoline @@ -1,34 +1,34 @@ -blastrampoline-5882fdf6395afb1ed01a8a10db94b7b3cbd39e16.tar.gz/md5/e0d62a761862e4331e39f3a863558b15 -blastrampoline-5882fdf6395afb1ed01a8a10db94b7b3cbd39e16.tar.gz/sha512/b0637d903183b42ad7fff0e7c6e2c9feda0082d31d6a86926586c56437fc91041b5fea2c4cd4f5b588e8f86e71fdbf4ac216fa6862a1df360faa77c8966e7b0e -libblastrampoline.v3.0.2+0.aarch64-apple-darwin.tar.gz/md5/4f7ba7d67f6fc8148f5be9f125b09628 -libblastrampoline.v3.0.2+0.aarch64-apple-darwin.tar.gz/sha512/e1b950317edbfa5fa91c343ff99b008db82f2a7f2c4a19a51b4c9b36faf8f9c1d11453d8b3234eb29ee30adeca10877098ce456d181b9c068ba086a59792165f -libblastrampoline.v3.0.2+0.aarch64-linux-gnu.tar.gz/md5/ba18ed1a8db10a2e630a8c09b4911af3 -libblastrampoline.v3.0.2+0.aarch64-linux-gnu.tar.gz/sha512/242bd84474827725f45faa1e52ecc1f8f1d9d0abd9fa8f0f994557d0a508b5959f10c098d9ede579f9421fa8c7559a9ab3ef01e71aa44fd1f691dc8f96d1f4bd -libblastrampoline.v3.0.2+0.aarch64-linux-musl.tar.gz/md5/6296dad440625727da3a167a4dcb9d14 -libblastrampoline.v3.0.2+0.aarch64-linux-musl.tar.gz/sha512/0f7975b008003575ba499b6c98ae2231d6bd5d3831f0b737ea0019b63d6ddb8bfd526350390a4727569181accd895e0f82f00c23cdb2aa11e5eafba046c1224a -libblastrampoline.v3.0.2+0.armv6l-linux-gnueabihf.tar.gz/md5/3dc56056be7f96e39a25bf1e2413e1f6 -libblastrampoline.v3.0.2+0.armv6l-linux-gnueabihf.tar.gz/sha512/e1c66d40ff078736502597cf2e06165741ac387d987b5c5c96053f632b74ee80bf0df0318da15f87833a9a096b36113b4bd882c4f4c90810a389015efb66a1d6 -libblastrampoline.v3.0.2+0.armv6l-linux-musleabihf.tar.gz/md5/fb2db3dfc963ac7fe78b738bfbc68d8a -libblastrampoline.v3.0.2+0.armv6l-linux-musleabihf.tar.gz/sha512/14878afb19bc1925e9d8f5d4586ce03c8b248bbf669e367b5114c3d289f99340c1cf002e5b030e4ca8272021c0173bc39faeddf3c4d8ce890590d94d28b73149 -libblastrampoline.v3.0.2+0.armv7l-linux-gnueabihf.tar.gz/md5/216eca57cb50379ec2766b59d66014b3 -libblastrampoline.v3.0.2+0.armv7l-linux-gnueabihf.tar.gz/sha512/478cac263aa42db5800d3d70efba81f3111ef371ba0f9940cc64a4a0b8306751ab4f517dc42a136b5c3e3a50cdf25ab0ad769e9eb854de812fba47e54f0c0f16 -libblastrampoline.v3.0.2+0.armv7l-linux-musleabihf.tar.gz/md5/6896c312111b20b6b9c45398991a4309 -libblastrampoline.v3.0.2+0.armv7l-linux-musleabihf.tar.gz/sha512/43241768dff5f3b4bec18ac72cfb328dc6498ddfb1b0ed98b5a2e4052ea7bb1d1e7a669910a1edb50fcb938dd460578bee268baf28a9eb69426c053259272a74 -libblastrampoline.v3.0.2+0.i686-linux-gnu.tar.gz/md5/9ab7739ae2816070d7bd57cacc2ae5b1 -libblastrampoline.v3.0.2+0.i686-linux-gnu.tar.gz/sha512/de747d285db84ccd5983e2acef4b98d03d209fe2454ac48142190be28db655c62e6c6d4041c56b227cae4f247276ad6f0491add09c07bc46dc4cb171030cff63 -libblastrampoline.v3.0.2+0.i686-linux-musl.tar.gz/md5/0621e71f25a3a69dc06acc845fb89999 -libblastrampoline.v3.0.2+0.i686-linux-musl.tar.gz/sha512/bb80afabf0525ab11beec9829097498a1501cd2f51d83f0599d17d40a684ec2ac3d7a61150cfec6b2464872184b435d0fd912fd6d4a4cd5d286a029a2633961d -libblastrampoline.v3.0.2+0.i686-w64-mingw32.tar.gz/md5/a03bd4ea83d040dfc3658be3bf089210 -libblastrampoline.v3.0.2+0.i686-w64-mingw32.tar.gz/sha512/0585aad4e9fd0b2722ed3b4693b41ceeeef18b34f00246f98352556ff17e1213342f457916a5fcf53d0d87a93be1ad22af17c9d4a3b1fec80ad21ef964cde1db -libblastrampoline.v3.0.2+0.powerpc64le-linux-gnu.tar.gz/md5/89ac3a8c5b0fb9b02b14d61f7b8e5055 -libblastrampoline.v3.0.2+0.powerpc64le-linux-gnu.tar.gz/sha512/3f0bf8921a8574cbea0d4a3a7e9a521b9e318acfbe0476b01e4266a9c674995f8ad9d21a05976b65c04dce99afd2d96d50d8a3da0ca53ce3cf843e78a7d19871 -libblastrampoline.v3.0.2+0.x86_64-apple-darwin.tar.gz/md5/0da14952e48c982321a63a0877b4a685 -libblastrampoline.v3.0.2+0.x86_64-apple-darwin.tar.gz/sha512/8aa97721c77a310864632c54a46768ad62507a40c1dc36fc240bf409cc25db3b443270b3cdbce6a7794bc6e59e492220adb69d90a2804c32d0d7a41a7712366a -libblastrampoline.v3.0.2+0.x86_64-linux-gnu.tar.gz/md5/a8884383157ee9dc33f8d885510d806a -libblastrampoline.v3.0.2+0.x86_64-linux-gnu.tar.gz/sha512/5f0d8a2d36778c08b46769f4eeae2bad03c0763dd84c94531911e5979eecad816b198ee3cadf0d03d4339bcbef28ed5d20e2799d00f13b0bc818f94fb7521675 -libblastrampoline.v3.0.2+0.x86_64-linux-musl.tar.gz/md5/1f59ccb2555dd76d92f4d779029bfccc -libblastrampoline.v3.0.2+0.x86_64-linux-musl.tar.gz/sha512/c631648a90306d11aa80880ed857de7cdc40d354f9a26979e71fbc44fa5517596a68af53f651a683307fb8112abd439b335ad1df18c0301afc7f7f24f380a97a -libblastrampoline.v3.0.2+0.x86_64-unknown-freebsd.tar.gz/md5/2dfab8bbdcfcdb02f1bacac6c2317587 -libblastrampoline.v3.0.2+0.x86_64-unknown-freebsd.tar.gz/sha512/d93b277a51e43d150d1af781ddc122a8e093450a83ce376a37e1f32d0eaf382a6a852722181a11765cfbbd514287854937eab88e9bb09688da0d323ede46e1b3 -libblastrampoline.v3.0.2+0.x86_64-w64-mingw32.tar.gz/md5/e233f526a30b02d8d486918607af44d6 -libblastrampoline.v3.0.2+0.x86_64-w64-mingw32.tar.gz/sha512/25ca3feb99157f80dc45661319a2c5a00ea7943830905d7530a9053b89d47e4e4c4efbe7b374bf9b7e7c44774fc2b2061c4b2b7f09f6cc3e14aa1867039f15be +blastrampoline-23de7a09bf354fe6f655c457bab5bf47fdd2486d.tar.gz/md5/0c8016a6e30bc2237184b816b613d11c +blastrampoline-23de7a09bf354fe6f655c457bab5bf47fdd2486d.tar.gz/sha512/7b7dbb101cf05ac833a8e5b09f1eec8eb99f0caafbe80075751a5f7e0bfe03a3b19d11d3507dadd13f503cfa9fc1a6cd53f3461af7d5afb39ca385a0ee26120b +libblastrampoline.v3.0.4+0.aarch64-apple-darwin.tar.gz/md5/0ea485b558637933f039d8793b3aa6c6 +libblastrampoline.v3.0.4+0.aarch64-apple-darwin.tar.gz/sha512/bc7d4edd90f0f01cbc23cdce38bf3fa550ce988790fc63d8c84951b884465cc4f2d591d91a119e5cf8ce6b3161da6e09dc3689d52b4e71175be0d21afba00319 +libblastrampoline.v3.0.4+0.aarch64-linux-gnu.tar.gz/md5/a175724976338ad493b200194687f63a +libblastrampoline.v3.0.4+0.aarch64-linux-gnu.tar.gz/sha512/30164779760514f0395daad24e9c4c457b1428f9532a47c1d5cc64c5843f3c392505825c70fdd6f0953c4b064b1a9fdb0834d4901b88244f1b31b49cb9baacdf +libblastrampoline.v3.0.4+0.aarch64-linux-musl.tar.gz/md5/f73b62096c9b3a128749179be29e2503 +libblastrampoline.v3.0.4+0.aarch64-linux-musl.tar.gz/sha512/7cb42503ad8d7103c1187e8ee163324cf28c54b38dde535f7ca5e1ef7c29be187a11d10cc451baebf74327d48010bb6b6638fcf5c31418f47f853bbea2d8b7f6 +libblastrampoline.v3.0.4+0.armv6l-linux-gnueabihf.tar.gz/md5/436323431e54429f35128f6f404771bf +libblastrampoline.v3.0.4+0.armv6l-linux-gnueabihf.tar.gz/sha512/760a5c35c17c70f5ae0d8cb543a982435f999662382d78070cc2b16f11000ed03e5de60944da67f959ef978f35bb033981a0a65460dddfd0f9bc146ff34e4e87 +libblastrampoline.v3.0.4+0.armv6l-linux-musleabihf.tar.gz/md5/370ba82c807bb041d7f015b4f5ee8c48 +libblastrampoline.v3.0.4+0.armv6l-linux-musleabihf.tar.gz/sha512/79be4403f2c3afd58103a6bb14bf42087f3c9b6737ece01d6abc339844d6b4b5f3e42ab6dd9d418e7f949cd2c1bbd8b934193763c1eb261298d9a0ce04c82019 +libblastrampoline.v3.0.4+0.armv7l-linux-gnueabihf.tar.gz/md5/3ea77545ee850be82d497753360671b7 +libblastrampoline.v3.0.4+0.armv7l-linux-gnueabihf.tar.gz/sha512/4dd1562f003c846fb84454ad2f6a0d6ae02d9662974d360d2d5ce6422a2c22d1f80e84ca500571cf391689d614c352288e1e4ef51392eb8438990a0ed96e66ae +libblastrampoline.v3.0.4+0.armv7l-linux-musleabihf.tar.gz/md5/b12cdf35ebe3eaa4c71db76be589d860 +libblastrampoline.v3.0.4+0.armv7l-linux-musleabihf.tar.gz/sha512/b389958b71c0e31d60c69492055c2fe3eb6cb1c2ae1e99c55fee7768dd1c40c07b8d25c6525fddb60806c4d98731a20f851c790ddb3c6030f16a82a9c89b3336 +libblastrampoline.v3.0.4+0.i686-linux-gnu.tar.gz/md5/078924f3c57310602aca1ac0063236ac +libblastrampoline.v3.0.4+0.i686-linux-gnu.tar.gz/sha512/7c37fff276943d32a7dfa9beb819569000ffb067b53a3dffa1752a9f40b29a10f87193ea5fb49d8fa3ac17a812a9c897c3fe8f89294e9aed1bac6bb3cf87eaac +libblastrampoline.v3.0.4+0.i686-linux-musl.tar.gz/md5/eb7c4a8454e9e5bdf84d8ce36dc6c6ed +libblastrampoline.v3.0.4+0.i686-linux-musl.tar.gz/sha512/01580512c9d7827ac0218ca43a546e595da0c2588b0dd60a7538b7c3e91ffce9aba3572eb5b682caa6f159b3453954169fc3a17f440a5a3057ad31c8094105f3 +libblastrampoline.v3.0.4+0.i686-w64-mingw32.tar.gz/md5/ce9c539cd80f4ed80a76fdff81a5d8ee +libblastrampoline.v3.0.4+0.i686-w64-mingw32.tar.gz/sha512/0fb5452b3ee1d9a78f74ad5a95bca1049b903f37eb6b64f47479592d87a24e2b12d1838a7f2c5b3cede7d5e4c5d76f599cf47cfc7559f7ef01ba34acbf60a832 +libblastrampoline.v3.0.4+0.powerpc64le-linux-gnu.tar.gz/md5/10239f0598e486969d882001c458a148 +libblastrampoline.v3.0.4+0.powerpc64le-linux-gnu.tar.gz/sha512/85bf61041c7c1e7efa6405c16892dac342a88f94a3c8a03696044ddf32a65e94217bfa09165cf532f2adbea3c8ee9ed3ecdf7401d5d3d4a886c29879fb6c4116 +libblastrampoline.v3.0.4+0.x86_64-apple-darwin.tar.gz/md5/a6dec79d2442617c03a32b69a2a5b1bf +libblastrampoline.v3.0.4+0.x86_64-apple-darwin.tar.gz/sha512/493b522b86568b82e3011518bdfd234d3a1f04fecd687f2a44d3a6037ff00d45e122d700ad41b434c3aeab2f9668f04afcc999236958e137fe1ab8660187a719 +libblastrampoline.v3.0.4+0.x86_64-linux-gnu.tar.gz/md5/69fa36c363904e71dc7bd5c08a63c0a8 +libblastrampoline.v3.0.4+0.x86_64-linux-gnu.tar.gz/sha512/c5563205653fc2d8c3efbf1449d3777a202e902f611febf5d8973a8b6247e6229cb9e3c30d9dd84d0bcafaa0ea9b85f433d6b0806e1e755c8ec3ba51e2efa125 +libblastrampoline.v3.0.4+0.x86_64-linux-musl.tar.gz/md5/32f12ef8e1ad8b8ed4338bb5666c10ae +libblastrampoline.v3.0.4+0.x86_64-linux-musl.tar.gz/sha512/dce53f14bbcab1fd4c1836308b13fc38de6043f62fe74fcada894a725efad520153375bebdea8a48b8ae9edfb813c2f03ec194361f4556e6ed51238fbe8919ae +libblastrampoline.v3.0.4+0.x86_64-unknown-freebsd.tar.gz/md5/75dfdd1264f58b8ef43021bdd0ff6656 +libblastrampoline.v3.0.4+0.x86_64-unknown-freebsd.tar.gz/sha512/9a14a89c82a93e23dbbf226cfe58bca2847a3eb66a9e2f552dc1598d721b837ed8ce3f9bc617266591872169dcd3728ff7ab251882de4230d6ce00c6f791c821 +libblastrampoline.v3.0.4+0.x86_64-w64-mingw32.tar.gz/md5/3bf231ab990147d315ed6c243e35135b +libblastrampoline.v3.0.4+0.x86_64-w64-mingw32.tar.gz/sha512/9ae053f60060dccf78c2d77716d0dc8d6720799e2d92410e0de1412c1c7ddaf8523405994a9f0949c795da2d68f85056e851e17f3fd0a2f2aa4dc0be32f9caf7 diff --git a/deps/checksums/clang b/deps/checksums/clang index 3e438a189a575..7dec72fad1db5 100644 --- a/deps/checksums/clang +++ b/deps/checksums/clang @@ -1,58 +1,58 @@ -Clang.v11.0.1+3.aarch64-apple-darwin.tar.gz/md5/55c50726cd43c1b49a222ec92ea05431 -Clang.v11.0.1+3.aarch64-apple-darwin.tar.gz/sha512/009b29068af7d8a008e34853faa3ce1e20817d3a7975fe4ca5657d1303e546410c903af345356fb94c88f8e95474895e68414a5a04096b2e9bdeed732780637e -Clang.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/md5/e5d8d1d5364dba4c5891c9a127ee358d -Clang.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/sha512/a5efd0a4c0b05ab6ac55081a28cace0cffcd3eefeaa872d239711f667425808f29939c90a327bbf8664d2d065d1b807ed802c161599b7fbda29f554ba9148b48 -Clang.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/md5/67716fd169ad7cb464a576cc10d42ad0 -Clang.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/sha512/5780d34b24fc786406f4f4f814ee6b8bf6366964d7252b61ea7dd3a09283ffb266270d76c2580ca1285a753d68922cd42d2d75b9527d331747325c22224536b7 -Clang.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/md5/77e3d4ff674493fda7958b9ad950e934 -Clang.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/sha512/813a0cac9ae4972fe426451b9fa0d640f25ff5edfe22624a621cbbe737f7977259d062710f44475139c8298265336fcc67fc28dc7eeddd95039bef44dc080ac4 -Clang.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/md5/e53b1db80024cc3a1152d7694291cbbd -Clang.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/sha512/f6b9c15655ca8bb54cd568728fe5ac33df62abbf07029816e892b0483afbb5adc69fde1789b90687137be491fa0351fa5806cf6d869232b3cbb4b42e1f7a5a64 -Clang.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/7ae72cb4b33be0250402f29217e32c53 -Clang.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/1b85e78a78c2bd437c3b21855bb36f8200543d0daa3c2d7be68d5c75ee06a74534e9b8b80ac6048fe05c426e441af3ff019076bf2d045152eb142d7d5769b525 -Clang.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/b83a93c3da36d8eb469f5fd39e8bcb9d -Clang.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/9aab7d5f9be0ce1580ed9d3b3c4da0bff1fff7094794d58620e1fb646ac7733708162f69ad281cd441c4cbbec8985c9906887f4979e5a5ebec8a05c6be06c91e -Clang.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/md5/ea570204363ae3b62965a000e6a3948e -Clang.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/21c9a1418029d5ca0d3d16e943914d8a4932bdbaee1152f74af681349abaebfe4d87a2f51ff06196cea59363b3bec706c629d61f5a37cf0e75cd645fed2ae835 -Clang.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/md5/63130e9a585a747e8f8e31a1b71a27b8 -Clang.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/27f3f72afa62b4f6c8e80d5934cc17119336c65ee070f05d98182e7e83fd02f0ab439a924165c7e6a414409eb2d2044ddf778c0e3e7a6994643b5d0d8b3e2ab9 -Clang.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/0d85a6ace70f1295202ba1c50c5948f4 -Clang.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/574c289c06283e8c2530e64bafb5ff606c27e76a2577acf84112e1ee9b8a3b299abde1e68dfd92700fa472dd6032af02399cca8b436136a5642ce545272398f2 -Clang.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/595279b252dbab5d6411db0d6a514985 -Clang.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/6a1e55e09cfc2325772f11a67f3e7e43872ce07fcceea6852649635778bd472e3e9e6cd0e7e2bf5dbefa1bf0862bae478329b8aedb48b4d7d8cf6ea074e98ce8 -Clang.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/md5/6f973ced20fd2dabf60b12b5ff3b0cb7 -Clang.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/dfc77ef9b13111d5b2d6cdd4d27b0df086ee7a79b535bfc2dcbcc5d9014d0cb0f583c792f812100d64eeadf938645ebe3af72d2df45b396b15b3bc54a0dc3d40 -Clang.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/md5/f96d5a441a56ee914372249fa0cb83e7 -Clang.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/dc2f4afbad26afe4eb43054c70674674a1258f6a1bb17ebd989179336e3de119b976c3429880b3e614668ec5da6c9401346c0fdb8fb45311e818a948c5a2e851 -Clang.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/md5/7f18573c99258f1887aba30228bab25e -Clang.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/sha512/6fa4296f59515ca058d2012ab200e65d4c1f130f40b7a3796d4237f6bf9a72f0a3872bbf83ef1865e7c1cdb75de9c5dd3385a64c55be6741fdb91bd5ef00c6de -Clang.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/md5/dd8333ce489719b53cf4f83300ec5c91 -Clang.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/sha512/356497a88871fa9a725d0206b09462cf4af96cb866724e7c9ca7a7060bea62a6b39426cb2a17d000d17b04052cc78893008c78b1a1c3cf30d6f84f10cda73fd6 -Clang.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/md5/f82aa0d21872e9b50ef238d004ff28d3 -Clang.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/sha512/a2c216727acf6a42c5b914321541a752cdc3cc0b64ae39d1ede1588935ef9d8a4678e5d6f61b2bc1df96a1b4d63812c14e5e6adec7f2babc3175ebfb72421334 -Clang.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/md5/3317c99fba259bddb9f351e79564c831 -Clang.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/sha512/bda2aa0decf76b787986a9a308a3832856cce9545b2c75da49193f23e64ac00dd839d243aa85737f28288c284b9770c1f5408deb4e5440293262d14df2ec759c -Clang.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/md5/826749b99dc7b5f24bac5d0531e84468 -Clang.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/sha512/e15ba270c2ad915be5d0072830b97e4d66daa2e18b3ba4db8f9687633c3ef0dfc1ee312f4fbdd1c921374709f68cb1b4bc9e58b9ffcbdd200c1eb665fa9a595b -Clang.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/md5/2f217eae89b066e190243b1c120cc46a -Clang.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/sha512/526846408cced1707b85f1e40796eb1607d47fb1509435fe7e28368a74e84fa56276aaf9fcab47664615cfe4349c7af3b1ad9995126e888e9002e1a4d20cb1cd -Clang.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/md5/6b6472551ff2e00249fb39ce80df330d -Clang.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/1d2780eb20c2f43659ab2502ff88334a7bf827bb533d37de058e524e9fee9a8ace431761495e93dc9564c80e94aa569066c235bc958cf893c4de5249c4a12676 -Clang.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/md5/74cdafebc133bc54bffabb40547622db -Clang.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/afcad373d30eb465964e17e70b66fd3ea72c1565b1bceb811d82188368a788fdf6a18e388be6d329d9a632f68890d26b878ac0e107ec975b93fc1aec81bab89e -Clang.v11.0.1+3.x86_64-apple-darwin.tar.gz/md5/a4cb1dfe2b86f24b52d730835f8ee31c -Clang.v11.0.1+3.x86_64-apple-darwin.tar.gz/sha512/4526942c33bb4789d3b5975023abdff81d747ecc26b9863c7ea61f87550506d2102a8f83e21085ebbc743ba2be8ddb2b6d4e12a65c9a58e02f6254a335d934f2 -Clang.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/md5/b9bd14c451a9e8efd28c916a85cdb442 -Clang.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/sha512/7cf7ba37c600669f12a74e6760ee5b166b6de4f7e817b9ddf133275a242335ed9a460c226a3f4102cec47bb552d8258b34cf3cedd35b16756f1efb5a3608250e -Clang.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/md5/9e930813e07758c80ca7a1575886afc7 -Clang.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/sha512/e0dce74b7377256fa65f1e6ce461ef5a6424b6ddb157be36393cd8038153afbecf460c966979e267d1de5cb0ed4509a093ed58210eb3cb69391d16b938a4e7a4 -Clang.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/md5/6e345f292464e430d3408826d0ce9573 -Clang.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/sha512/f802e46a46a2946641f07b8b2ef41fee8efbe98e13d23a8ee01047831992b6f115d157520e44879978e27e994da4b63c1a09e6ace63b7c1a1f6351ec04c4885d -Clang.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/md5/ec61190097b601446985c96ca3ffc58e -Clang.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/sha512/00de2b64bda05e27f5129d5702894823517f5da01a42892ee20f69e55b6004b0c1020ecb941330243a565048ed249d827612dc3ce69687401c731ac168566049 -Clang.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/md5/dac3f7585db42a3e8eae4d563abc5d68 -Clang.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/sha512/082ff3234db9b36346553b5c97d5b7dd55f7458aa4f1f1d358e4d4ee2c7805525514c18c35d319a22c56e6c3bfdd4160ff0a2157f24e1123c5879d167f1a2d13 -Clang.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/md5/81aa45c118d96afe17accb9a0e02ea49 -Clang.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/sha512/240979d6e958ad75b6100b5a4fe650c21076dd06b8c9ff13fa397b34bf9816d2d8b8c3ed6040235ef82d11d885cfbda20e5500af3ba3034442744d201264acb0 -Clang.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/md5/b1695d5e231249c07b5cd9d868b6434d -Clang.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/sha512/24a33877f7b97a67cd8acc21ce23d31802bea13f416b5bbf28c262277f4a9e8f6a2cdee642d4d49b7d9b7948bc538f3b1bacb259ab0298e58db910044ebcceaf +Clang.v12.0.0+0.aarch64-apple-darwin.tar.gz/md5/980c74812ecb2910ce5ff89f50adeb4e +Clang.v12.0.0+0.aarch64-apple-darwin.tar.gz/sha512/3d732de9268f4ee3550cb8cd25547025f0c3c2b42733da68570ba40906aac590c51de8819f1643d40f3c2310f666eb1d5adff6beaf1a811e1358f71a2b2e693e +Clang.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/md5/4cb0061a62021a9f2e8c4c38cc116a32 +Clang.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/sha512/628844979ab97b7e95578cc6a2f01be4853e2e451321baa209d8ef80a3a77f58403f8c905e89ac48570daeae72b10a5dd21de948cc3e886918eec67f87168d2c +Clang.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/md5/98216114af0c5080f2054012986df84a +Clang.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/sha512/8f615879985a7840b0c1dec53aaa4f77025464cc32594e3dfd7148ce36201cf0221641fc6de867f605b784d98a2ab360c1aabf1bb98d77363e35d6225f4bce17 +Clang.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/md5/f9ac91da205acb64c95dace753035a45 +Clang.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/sha512/91739206d79d6c75586289205a40c71b922cd42c96564c174b0707a7cc136e77cfbeadbee820ec7ab0e0bfc36f481b88818d3579a205b2d6ae65d7701eb817e6 +Clang.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/md5/7679a6f941daada0225667c017fe50c6 +Clang.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/sha512/aa1532188095bb73dfcea86dc5965302b6a3099c4c95787c0b3ab01ca5c53c7a533325308af6c109d1aa50f69153c57fd5e502f41f2af41dbcf3b039d5f1defa +Clang.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/01056c4c0a86f8684643a06fefa92f27 +Clang.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/bff88b75e7214135cd6c9e797c47cc5dc2d3f2b9bd8e3cf9f1c7ade3bcb205ca916b63b5c6f2067f4de306dddc4efef36c9089a49562c8d656b95d45c957cfd9 +Clang.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/88e9b5fde388021ef88896d39968b3fe +Clang.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/aa5ab4375f532629b22a81d927a23bab60c819ae16982a1dc797a043fd3622d2b5a9c0e4f3195d2974df3383438a844c276efe3a60fee1c99ec7d3a10064cd45 +Clang.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/md5/4415d5e19f1e4bf2719b4851ca428ea1 +Clang.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/200d43017d05ca59374950b557eadb5f2630bf70378a2970dbac4da2ada8e2428c786b9f3c1a2774ed863baf34d8ac667c294c2bb46e51125c40a3aa0125b596 +Clang.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/md5/c8b618d1fb0685f0023c3440918923a0 +Clang.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/4b85961d98cd47105cb88a187ac52072af7af27c81defa35b2bbf36a0841c0d7745a294373fde503989bfc22245ba45a1c9d253e7bda5a28381dd6ab9b677238 +Clang.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/d6d6a8fb56ca4e44304310f5ce7e14cd +Clang.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/dd3a039d3a3099fd8e0f135443ed9145891179437dcc1cd851da3b54d4815058190e2f6ede97d2f0357629e0d173395a86537732b0354bc87ae5815638d402ca +Clang.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/f0431cd3ad402d8faec1efcddd7f7fef +Clang.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/0d5e7b96a15db5bd09457aa27aefd05b8f530ff348956ce1699503a03adfd6abec84fee080aa5cac54a7d4eca42730f7f9cd6b13c23e3b13f4d2392f08fcf688 +Clang.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/md5/1579ee70c12a5c38f84e9c52610b196b +Clang.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/91841937b8c1e3dc4c223a4dae48e7d4fa307df2cc692e512c469994bfabcba897078bc95c4141e5384f53be31d160ee750b60382005d7e5acf99532f47b4566 +Clang.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/md5/75aaeadab3001679561ebd56193cd90c +Clang.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/7096f0bdb478c2cd76cee8f3ea47ecf8565af0702901f5c6351233458d2c66d3ea61e3f065ae9e90960dc7e0bd6fa1a0c6d160934fe409a663e4eefa23e6c5d6 +Clang.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/md5/987c4b1b50d9bb56e598839e383f79b9 +Clang.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/sha512/e3b827ce6f250a2264700991720585b154bba9c6713da7fa619a5e9e0829c7b02b909e3f73ab9149f58de2e27566a7d47723043d6de5fd027b1233452bd1d2f9 +Clang.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/md5/e8297a60b87199cab225418ec49503ae +Clang.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/sha512/9b341cdd57982d269df2d8158a5101f451f09031e1e784b593c78aa272c392eb7328b1c328a2f29d494b5ad4ef1e1ef96d01772f176be6395a8503f983e18d56 +Clang.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/md5/46f27859be1f7e162499e846d9532a37 +Clang.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/sha512/5173beba0ba2423c978cc3663e3b6673752efaef34547efe1e1015a18bc5cb1129ebdec3dacbe9894832601d87efffbebb263790d88ae198cd985636cba3fdfe +Clang.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/md5/00ef76971a4783c7e63a86ccae8b15b3 +Clang.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/sha512/f5e5f89f541df4b1da164392da0ea5397be62138e203f321b0b771942646530acdc621ca36a6e6c15df32c0d722fe9b0b5845c7ac58bf24966ae503979a6e8c8 +Clang.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/md5/8761cdd4810ffe1b3eb3537fb3e03218 +Clang.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/sha512/e5f011a2f74a032ef0ac429acc615b02d3d6bc07271acf2279afd947c1151914533456cf5b111ae7f4c868f7ee739ccd9623ce3ca2850b3cda3db53bfddc8aac +Clang.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/md5/0048f8c3014f9baf26e9d4e10ea2a893 +Clang.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/sha512/9ac2b0e47d86877bb47f5ff1bb7cfef3c0dcbeb813c770c29e2fac232cab0c06f39b5b2fad15d975d50a9590e9cce3c251e3a3c6ebd87b0656c93ed14a08c901 +Clang.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/md5/b5833c865313b442da0b8bbe47a7ec51 +Clang.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/ef2c7cef9703248a0d09ae0a2b1d09496575411d6a846557a47628c9471824ec6f8b9ec361bb0c6bfe1ad5c27c1160900638b185cd46f21ad0eaf341e9caf600 +Clang.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/md5/e76c4776341d23d2f87d87f2f9b32acd +Clang.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/e855521dfa1fb07fdbfb3afec0bf27d346bcf316c68dd0b3898ecee9d2e79f02d7bae9763e1c046b9ef6730458b40bdf35f737d0bece9a965c68223c6e1ada96 +Clang.v12.0.0+0.x86_64-apple-darwin.tar.gz/md5/d2522f901fe5fc2f1dc4c9d3c0a82e29 +Clang.v12.0.0+0.x86_64-apple-darwin.tar.gz/sha512/3efb4423573861ecdeaf0a82e7c15c1cc767016ceb9e9a5132a7ecdc2075bc0d8e8326d6bf9e02b649b6c324319fcea471d0e1727e595515488be7b39cfd07d1 +Clang.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/md5/88488b8e890dc41c7c6ac19d1b405a6f +Clang.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/sha512/dff87a31cc19147c9105ecff15cc0cc671a0f683b6dd3d86446b6a53c745256ebd1a951d0b83e26ad2e29aef6bb044b6c00d30c4647a3eaa0cad45fc1fb70f20 +Clang.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/md5/1b5bde42bd922cbcc06ffaa5c96f3664 +Clang.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/sha512/af499fc2aa6b35cb67414782a9cdb9e21dfafb2d5678c7ba9f95bbd92650c8b7f90879f86ba55b445ce4a42947ec495c1a6fdd6e768742bf8c3cba7552e2bd4e +Clang.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/md5/a3922ad0741b490daa6e21b91056324f +Clang.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/sha512/257732327901f32d3baa7e1fc202f266e578b5bb9d929949a900505b664213c9c8c132b109ee93f96c37bde3c4d2c7b806a45f44e93f55af1973fbe45c47c621 +Clang.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/md5/42a813253b2f820bfc4328c55687b096 +Clang.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/sha512/ab4843e2d252f1ad6435d506483c29c752573b6be70c363a3207e8a45d09850f2cec5381ac5491694e69ede5cf0b102f61e5f54d7bce81b049bfce9b6552e194 +Clang.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/md5/b17ec22a9dbb88dcf956ccfbb62f6609 +Clang.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/sha512/d885e4a50e6f57b8314752a590d5ae72b78eec3feb838ad1a66116cc2fb1b4254b77ab36bb86de416ad93e58dc2d60086eaed27ed29399f200355191daf43123 +Clang.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/819b09f861dde64cde72c061feeb1baf +Clang.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/4f2e8c402e2a184f115311f129fe731b6445422cfcf7ffb9b1ae577e9588f5d0de040ba6c3eac3263fd3d51cbf10ab822bed24be0a3d8766084adc23c04b082b +Clang.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/080587a6f5a463efc06362d40730334e +Clang.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/46e47a06c996094b385b5939e73ac831a0c08da7e113683433e0e559a5627c43242311be0d6f2ba992d65bc3b5edfab3045b1d06ef26f6b87045c14111845260 diff --git a/deps/checksums/compilersupportlibraries b/deps/checksums/compilersupportlibraries index 8ad65ac42987a..deacc52a102a3 100644 --- a/deps/checksums/compilersupportlibraries +++ b/deps/checksums/compilersupportlibraries @@ -1,92 +1,92 @@ -CompilerSupportLibraries.v0.4.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/df1bb35cddff18f4512b57a2b36a6be7 -CompilerSupportLibraries.v0.4.0+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/d01fb4077b97d10d5b4c7567146d82d7e6a45a57296cae14e97fe3d4174083553d9318a0ad75bd492315fa9ee213bcf04cb3841c2a6302f87fc8a377e756f459 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/81e354bb883997335f1945cffd493978 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/5c1f79488019d9bf46906e5e921ccf0118b762baf522b02314177ce81ccfb839e75226802c844462dc9a70aaca609b465348e43297b918deb9c4d3c8e36a6b94 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/c9de5672d1e67cd2541eb8ae25188573 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/30381588684a1fe4818ef6e2d0e3dcf44f0dbf81fcb63a043b9c8e4b3a34e6b7b09511e94c3eeb5004ca45a17b9fd0b7e102bb0176672fef09f1b940edf15a03 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/b2f930fd61a2c22895f3102f950df915 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/89e3103c28429d4c9a020be7b0ed9b374bc48d2971671904e889a57a9bb9b8c81011b20143c0152814d1191d246d144242e4c71cbd45a3c4bf50ebd0ab967b15 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/be7aa1b8f769bcee21a615d4819f00f6 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/3404792c4bd24499fd83f7140c392fff7ac5360eb55ea580808d051f9bfc9c9f9e7b59be25ada594d71e3d94610fc4eb397daee6d84fa6bf4c988f6881e19c33 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/22e9e895ca30837fa5165bbf4b74e482 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/04600705e907ca1ea4a203d5e696171bae4777c4c9534f4ae3d20525d39be60de1916a2d0b12b7e710d144ac47b2472754e1b3e01295fb43934e6ed8c9201766 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/6a2518ceb9c3e57fabf0db12090a0872 -CompilerSupportLibraries.v0.4.0+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/19222a3dcbf9afbdf43192943a0a7ad9cbf4762c1a681567cbbf6093866e44465ff566a10595220c9366d92dde43dcba84d41c240e2192da042ddfeff3e9f1a4 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/96f355abd8fd31d6522c6d7d5b259971 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/1fd436c9e4d15ff199fa60fd9b715c16effbdb6c15f86b86e9b2dbfca70136da71a4a491caa2650eb415fc32620b40295729a6b375efe1a08f9c34cbbc317949 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/1aae7c2cdaf1ba04b9bad8119224eb24 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/913defbddb5d5069f1d8b9a1a4a5c2e325538baeb0203756cc91de45fb52b21defc7cbdca6f454803f792dba895ae146009d667ed508727f4aea627dc1ae419f -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/f1c35daa5d66fae11adcf6385ab6e095 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/6a7a9ef08709ce5c805ea19fc33bee65b85ee576cae747327eeb12f0950dfca4b871a0e9799d4961e5d703a0a6e116145542078d124258ab3a949957e368173b -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/fe30bb318b88b3270e92d3d8f84abb5f -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/d54f5e0c7780a8557b889b3fa5d2fcca639521d00d624a0a4a3f4a46b854a3615989040f122243f5dfa266d8f6ce700bcffc9ed1653f86eb8279d5c31b67c6f3 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/489e4a98eadee286d3c32ed08ba2b5a1 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/b4589dddadd17ba1ac3e086a9312db3301e5d828b4c17e9e8db3ed018eba4757c84282dd78b2b2c84f978fa9154c9f46f9e3f1e711207eb19ca0f834239b835d -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/cf0e32142c441673680d55b7c547a629 -CompilerSupportLibraries.v0.4.0+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/698af44f897dfb0682b49532666896b2d3430f1a172921f9184e17404e714448899a227882f8375193d0a0476a777754e7f679bc0dea987ad185eafad30eca0b -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/16897e51e3a1d61d1b9a7abd6e728d2a -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/3a9a56d80c1ba1eca7bee4156a7d56938564c27366a51395d6c8f74c3bb500b0b374deed3fc1efc75942e6a66dc354808a6c7a66d1952eba9dc81c9e0fb8cc69 -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/840d73fbd5ec7fe94708cd8179ccefbc -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/dcf7834d1f2b67356baedf0d3eeba4f5d3e62e0fd475ba3329668e18608fe1493fba07c9737bc4474e8276b09c6c73c76dcd6fde44d96149b740398c218a3432 -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/50a06e1bc8a8442c7a1369bc837ce504 -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/868970d00f5387f42a632c5fdbedc3e9135b6723ce3b1ae1735fd51a4a1faf91ab5fae94bc99c37aee75d9cc9547a7259cba584d95e0971ef97605592effeb39 -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/9998e35984f1c3b54b45dd8a4af2145a -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/2e653f25d5652003d2cfceae4d786187ea3911caff8555d9f4e10e0ad60d237afc18fdc5247804e3347825682e6e347a92b70699ba73bf497ec414467f1cfccf -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/64ac31833d8d69b57b6acb1767cf110c -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/31c762e0c5d8a0652fda77e10eb5d195d8e27e8cce9e020d8c186aa904e55687cf2e090e0eec55aa6e5e885fe165c099d05c93efb45d83fcd438f7f996a131ba -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/805a1d491313c87632b6e4527e499129 -CompilerSupportLibraries.v0.4.0+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/72d7e5387e3f1fb69f7d0ce51fed36cdd794b5c284dc9514c93e26458df860f83ca4581f4f6f53e838b26ed3563248c0beea7e8e2020e16d30a965e8d1f4de63 -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran3.tar.gz/md5/48eff236a6aedae30f871e9e5d1c14a6 -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/b913aaca516fcad91f11f4f797810d8f5fb240d92e428607ef982558f8e74a1dbdec3eee5983a5f0b7bfa9e6e750f724de4193b007fbfabfaf6705bd4b0fa523 -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran4.tar.gz/md5/6b377e6b8a2b120acbd24319dfef4efc -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/65248ec4ac7997faeeb4abba9a79b0707dab9d0dffaff293039f7c0886f972d1e118738e37c4e2168228de11b498be58bff996a3a335b9ad2799146f593106e8 -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran5.tar.gz/md5/964ce992265ecac408cfea1e7fbf434b -CompilerSupportLibraries.v0.4.0+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/c100995a619ea04361bba6de3e460b22a9187af61fc02d8c3f94191cf71f73e9ff2409d87078e34655be6aa352f75f395e419860b6dca976cb665caa20e31fbc -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran3.tar.gz/md5/3a1dab532cd7222708d27d1cab9428a1 -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran3.tar.gz/sha512/836acc03a34cb48b079ac2c8b397a03d01c1dad522a6be5c3ad81da98ee0979b981b14184f08e7308bdc69bc17bcd897d400853b0e6ce9a7821f9ab3c6a6890d -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran4.tar.gz/md5/7bae09d4f9460ae491605f6642c3f1dc -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran4.tar.gz/sha512/fb5bad1260aa3ad1ee135120ce0cfda4034380d85970c458a6dbac9cd24e3a7b996bffae8ccfcbd30223273e766c3a7d5945ea42c5237811a2b4af1db5027e09 -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran5.tar.gz/md5/c7e7cdd660accdeda123685c7691429a -CompilerSupportLibraries.v0.4.0+0.i686-linux-musl-libgfortran5.tar.gz/sha512/7015eb83612711a93dda9ae5fa709f74e72b33922e7f48ae98e8bc4798b8057ee315a65a27c2ab041623775407d37c686f4b3d64e1af27df6a32fd4d0edd5441 -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/2dcabd868fe7ddb4edd29078b840c093 -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/a70e6ee8cf73aacf0cbc7b4ac5f17b8e6914e93b106caba907c5ce8f2ab24fbf28ef50b60548ff6bd8e47461ec971a4f2c7519ffe0c13893ae48e4d6bbfd6a49 -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/0097f1075086376188cf594276edb421 -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/47cee1709879bea6a7d537a31438b39b5baf19b94a7575e7ae2a2271174884f484069c24d8e1dc927f3cc89f2007c5c1037b4c76e1747a1f9512d5055e30900f -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/e00d8689da404039de3956327e5e1abf -CompilerSupportLibraries.v0.4.0+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/24efa7cc047c9ebc7f9bb99c844691fc78333a8e78f11da4a0d8ef58e98cf64da20198fe97b735443220ef6860e9618b9e1bedfdf38b2e134d9366db4ae9da4e -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/118fede168fbaa2433c10c725ee445cf -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/447f0f4eaa72531c6118f65268d1e505323a210e04213358942b58a8a34f4e20c39306ac7d89f06e51df57265b04a1d0d4dad6c141b590cbd3389573ede0de8b -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/262d162451ffc50c25cf599285555c47 -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/137afd852f57a3b4d56f7ddf1ce2f7a3386bdb26d7e577e91af8d95e1fa08c2eb43623925158248f2b43df346cf2e87f308305087e3a3473eb6a0526ee259a5f -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/d3b8e3b11b74d1cac626ccab59e652b1 -CompilerSupportLibraries.v0.4.0+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/fcb110fa7b7966840a00f5fab2968d543d1c15354222ef6e693197797c337a3b9586caa66db7042280ebb46de51adf4903cb21c79b4cd1179f5aa1d4082e270b -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/1f593b25ca831267c4e02555304e447a -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/94b502cb4c02bdc1dda87e3608d9807925002eac68883c26cf27e358d48eff41fda0832fb6118c750a1386192e27bd6a0c14c9510d114edbf43efdc2e5bd1c13 -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/a23d18444255c8ebf5253dbd470169ab -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/50737af89141a126766829fafe19599e1dc645d8669cb10f05111aa4c031f3fffecdb9ec98dd4ac9fab541d5947582b284d650f86c3116db12c10387be42eff6 -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/dbc289277a5b2a960111e2a5eefa7f0c -CompilerSupportLibraries.v0.4.0+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/4affcc86a550400f5fefb0337a1d245849ecf7fdd305790197c60112a0d1e096fffdc4ac140a82952abf6eab220e8c631c392b8903ea586b5c0345c65c9116f7 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/dfc62f03e7b65447ed877a9eaa537e07 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/f782f5a7c87924e134778ce9f7f98f0d48f4626f8b7b371a5c7799cf5bc7ea3cd6cdf275769dfc2b9dc2da82181e49b9d77833ff5241d2600d58c9bfd78a189c -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/6e46faded79b17c6b77846fbf2e5119f -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/6cafdf6d79bc8a7125857c148282384477720038293ccae83dc9065f8457ee28d516468bf9c96320086c9f2dbefb6f57ce77a952bc105de2b67e47fb0b0b8a1c -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/68d2354ca386ba9ec4e98504fff2f222 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/ed3d1c0cbd34f62abd41694fc73ac38a34bc19674526e41090f66aaeeafe87cad382a5b17cfe8a622079571d646735d273249acd108bec9a1f42c195da98403b -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/ed7a41374016ffe35c8068b2090fb66f -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/a8089a9704b8ac0b7c8de2f329f4eaabca5daa508e015cfc6a1fb668e78167463a30d9c96f23e2a518dc8b730fe606253c360a13689fc6a098dd18ad61ce1fc7 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/1f425bdb591db55d4a821a3b83a1fed1 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/24a1d1fb3d388eff2521c7b0eafafe76b29c3571b784af1dcc0ff8ea2781aa81b26fcdd03a0a1efaba9a913b6b67ece29c3c867a3cc93dfe46eecb3fdd2ef5be -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/6c19ee02d1bf8be22d65155d0d430946 -CompilerSupportLibraries.v0.4.0+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/aaaaf2a731e9009171a555b66fd2b662e2bfb207ecf84cb54138c770bba0e8e5910190a7a279b1d1d6058645a2f0d8bbca92ce9ca39753cc14c886a7189431fa -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/6c9beb8a213ccae10713d336e4c48c1b -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/da25d33a824e71d254492c891cad0a0fd9e472e5320403830a4bf8c0f175f531775b4e468832c702edf1e46dac68725e04ccdcf8914ac6fa60b27cec45d5aa1e -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/dba2d41d040bba44d9a7767d4fb6c329 -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/16f9ec8a9897832b3a7408e192f9d0af222f369f33e5a698fd92f54f3c4326f0632f1e8ffb6757b6969d5a18f594f8f0e70457f8bb78a7740b8b26daf22171e4 -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/1dd16d636fc9a87668a9c6ad2abc1a93 -CompilerSupportLibraries.v0.4.0+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/6a2deb304127c06baf260e2614bdd1d397fff3bc0b11c192ed0e43b3681af805dc5f17d84ff4836b108be65f879743a13b49122015d5f343f5ff3c895bf46de8 -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/2edeb2d7edbd955a43ca3efc8830e292 -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/a89faa9dbac9ddb3544a743c61636a77ada4af5fb637f9391187fdcde293d766deee7a60a878a53a08eae6f35e4b64b981c0ec5a39a2038299549c07e0bcca10 -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/50d2b57735d2cba4a5411414a2e26e6d -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/f6db77083655181c0c28c2056962559ac5e77e6869dc990ba21e5d0c265d7705c482088587f6871dff1142c4a6ccc12ed24329f6c1f99146bf43f176dffbe28a -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/b1479d5d095e9f2b198e48ff24f0a0f9 -CompilerSupportLibraries.v0.4.0+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/a37fcc95658e91a820d6a4d13b51cf8ee6820b62142686ced67768d8f03eb09bd8cc3d0e7afc16abdde4a4fa764ece7bd92b8951cac06ad817e7ad13eaa784e2 +CompilerSupportLibraries.v0.4.3+0.aarch64-apple-darwin-libgfortran5.tar.gz/md5/36348c1087386681380589f7fdbd383a +CompilerSupportLibraries.v0.4.3+0.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/e3dd3c93a855a85f02190659fdc9f41e96332b74577c67a149f78c35ebc2bb193bb4c156104d4bf24ca278f5b8621e944807a554153721bb5d0f22b8e9069fc1 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran3.tar.gz/md5/b9d432c6639d30f1c63e9a234c1f10b7 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/f208fb24fb34e82a60fc37ae3acfca6a1cac7201b8b8daf29c3ac98e607d9eb94a51fe92c54fde287359a7398b4646e8df98bf359f7acd1eacf25b1b5ea16456 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran4.tar.gz/md5/37ccf8848bdee5445d002b889e54bca5 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/0b29ef79bf8b238d9778d72f0e404145536933d9f9185f2cc1e917b3ec7cb8cfaa33ff664837e9e8e6ec28a3612ebd9cb226c0938954594849b4267514b27be3 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran5.tar.gz/md5/bde8da82e00ed6375716bbcba6b04c3b +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/7d50d91d4b6430154ae037fe54eb8b321e57c4ef1f7740ce0633416d8e39e133d3049a36481fba8ea689fdbf8ee8750c99578f7ef287736476bd39e5b05793e9 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran3.tar.gz/md5/b58108feab2a1d546fc2c3184233da69 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran3.tar.gz/sha512/4079e9a5548426863bf610a1287f4e0c41fb701af95be66db12a805686cc89b6d3baf9ab203dd6ac7429bff8d1352bcd80dde7adf22bfae20688fd8a17dfe457 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran4.tar.gz/md5/00ab7379109240a211f492dbae4d31c8 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran4.tar.gz/sha512/d2d5e7165566fcaf38f97fedd78cb7c6df475a01dec262643c79a0d310ebde4b64f670ad92104ae5e7bb8b1004d211c8f7d2bd4df05b87ddd188db62b11325c4 +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran5.tar.gz/md5/ee7881127866d50c9d1fc76ef0ac50be +CompilerSupportLibraries.v0.4.3+0.aarch64-linux-musl-libgfortran5.tar.gz/sha512/8f622cbac6777cf14d98a6cfcea38d42296f9f93b7202eee501c9fcf02f112ca2833dc9c034beb0b79aacc85bef9d57a26ee672716ca50b8353e3d17da298ecb +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/fe4c403eedb9dca880961501834bdc8f +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/de829db62f7e28b425ac04d883db62e45f346e2e115d364a6f9ace29681a73422109bab7239014b51e6174cbd6141902ee65868a5cd2c6836d2db43b07c7ec3f +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/670dbd3088ccb46830d80edd4c64143e +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/43a419548597d2624c68504c405da1104007b80f49189dddef5f2abb0a7cbe404af80172d69d7b8b2dea516fa4bf429a73068de2959266f1bc796868ac926682 +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/00a9ea852c32c503e405389cb322827b +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/741c34b253f4c785b1092333d9060aea71b73879bed96da0f964dda1d1367032f133abde335cc7917c2e04c8cae4c3e110a249518d5305d8a4752cdea7d3aada +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/7b4528e842d27c849b6bc0443255f974 +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/8dc362faaded886ca1bf7c48f43847cdc4f6685e29b0468809d254ff44121061c49d962a33e37acde9ab00b258636a77213ded1f8570ad2543dfb0097f3a7cc7 +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/a8d66ecf146c17a5af2f7a6c4c75dc9c +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/4fc7590050d18a3cff6cad29bdaed3ae1aad72a7bed3e69a14b726309cdd5631ba903998ae042a488c815f9668567cbbb2e779eb44c13fca1aee47f93bbaaad0 +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/4405f621357e9bc3178ceb24337385b6 +CompilerSupportLibraries.v0.4.3+0.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/0c8eeda7d94c551e90cefc6ef5c41fa1d79776abd87f1e739e17b8507ae966c0a6aed10bf466f37c34e29e38fe5bd25d542829e25269adf971c0e8a9d640dfb0 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/2a37fb150af0438cbe768e8c479ff893 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/d0f577f4bfa76c349f188e4573644a82a749f9e5c3293246de0347fda866c9a1610fe9f3383ef54ac1bcee774f2a557aa1c67cbfe76580313cd5f9a231df05fd +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/f7bc21abc374654421385f27d653f3e6 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/fe55de45a99817cbd7a4ac69b87744acd9804d159b9b9144ce24d401742c87b9621a388614da32dac00f6b5e78037cef88d37c2b14308b6c94f951aacb176e94 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/022cb4d36156bf257fc57a50124cdfcd +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/f12af33831b91fff66e5ab2964aa4fe520e3063e148a794d9840ed4f526e6741555350e5d6dffe7857c733d2f405e1db81949d1e24a42425c521b1dd71539ec3 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/b99d07c03c91c9d2186999bc924eb4d3 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/6ded3253561e5fa0c93712a2a86efbc5b1bbdca26f2170876e855400978674910c43dba6dfe992537ce90db66e40b618a7fdc3753abae67940ac46175bbbf9b7 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/c1d701eee76fd974ece928cb3e1a85f2 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/ad338863ddbe47ec579636dc6ce155b47b701b9d47c8f0bca93918af18e8df6da6ddf65a2e2042fb79b335d1df07549addb2e794cf1e8f41d6fb518259a6dcd9 +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/0fa43aa26c3f5a717945659ad00ad96a +CompilerSupportLibraries.v0.4.3+0.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/387a676e4e79a5f783c3797dab0ab4a9ba3b469b66d008bbe3262751e94316b0f7ae6987db212f763be47e9cb5202b1a6740b3f419818b30c2f1251bf0b305fa +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran3.tar.gz/md5/e8360ca87e6f9d7e512d20fd0669ea70 +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran3.tar.gz/sha512/6441bfbd93ae4edad1cc1e7d8adedeff85bc7749bf68b802f4316117e81938fdec35620264627fca367ff2182b503dd97235f7871dc79e70cdb0b86712d570e8 +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran4.tar.gz/md5/088a85ce5999f373ead5f43e7bece97a +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran4.tar.gz/sha512/c3d75384c93afabb2eff3f84a13df8b7ecf535e8f786c5fcea78ee1902fb052854acbfdf9fda5d558ca19f285883836e6827acdb042a9d50ca65d5d0823e44e5 +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran5.tar.gz/md5/97ddfc865ec5218c7d2d092f65de71b1 +CompilerSupportLibraries.v0.4.3+0.i686-linux-gnu-libgfortran5.tar.gz/sha512/2328f3fd706078125badd6294159d860b2349203b85d77f2ecae914f3a41a99951021ab1124a40c358ea82352f6778a87f8094b039679356965fc4c8bb48beb4 +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran3.tar.gz/md5/479a7a80865c38795cc4454dacebead6 +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran3.tar.gz/sha512/cb4c79f6e5e9129b3d99f3f0ac17f395d696b9f354df966faebc27f6ea120a8592548a59e5f7a7ad124583d23c93d621f00069a4af07a4b41a4a1f474bded4e0 +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran4.tar.gz/md5/03e4d7d3189be081e4b56cdfcd439b5f +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran4.tar.gz/sha512/6c3f3b9fcad535a5e071853540b4b8689cde976a375b9406c93734e37d412f86069c8133ef85898efedd3b8fab0477d51f9ae681dabb00a66ec3f213e042bf82 +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran5.tar.gz/md5/6b20e61bf6eef2bd8587d93bcbdf8ac2 +CompilerSupportLibraries.v0.4.3+0.i686-linux-musl-libgfortran5.tar.gz/sha512/2f7b0c63773f7c5e8bad43041ec30e727dffb665f4371c7ec5619648644c9ecc085674a15f0df20e5399d25d84bc8e49ce0cd29a5a438e7a828000395e0928eb +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran3.tar.gz/md5/185a1f5582eede2e71bc6664294fe368 +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran3.tar.gz/sha512/cc54dc1e1fe10374fd62d7e3a6159024dbb9638b90014e9cf6168ed63ee1b64f7a52f8c851315a340e5327513dfe939b3b04035631cdb251ec2232f8ba381d8a +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran4.tar.gz/md5/ec4d496e9c5f3e806d78c30bb92f4324 +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran4.tar.gz/sha512/4917f4755c3ccf223491d75baf729677d51abae00a66f7a66439b45169283aa86070bb314ae9256525de4b422b7213de9d087d0dba9a821caa71ec346f1138ed +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran5.tar.gz/md5/4080d550f9a31d084c59195a98b6ed7b +CompilerSupportLibraries.v0.4.3+0.i686-w64-mingw32-libgfortran5.tar.gz/sha512/6048b61a476905469e46c4e15a7067f0f39451c7374e981212cc9d2a66bdcbd7f0503d9eef731bfbe10b174d76937d7fa349f079a652587fecdfb2c6d59a1a1e +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/30bd967c069fbc73dc653f2ac9d55b6c +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/e16e77c72e3dd3399240bfcd72123da4540016eb91f10bd6015f0e6e58b397677b685c143527f5827423e7abb15abf5e461e3b74fccdb07dfdece2f0cb361912 +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/073a8be233fae3c6b453684de7e51ea7 +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/3fda4c515131c75181c662fa4d5fd538a0c8e257673edca7f94c46509c641d4720c130cffa37512bea0a215b6a9952735acbe359fb38e8e341822545021d88dc +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/4853c451821303959723f541434a7d1c +CompilerSupportLibraries.v0.4.3+0.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/539a6b7626883d54b7661db6fcad1b7390ce37ab406a88065b8c24786353725f8cd972cbc29d07e71c9fefcb126239c8a63583626a0b8298c04b34de47bb9248 +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran3.tar.gz/md5/889855efa0450aa975166803fa775686 +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/8162aebac8f13264cebdbc8359f4823f25cd28c76812df8687b5801b6e133206b514cbad5d5ff0d6fbb584eecd82038049c5a965637b43a5d12f77ad386addc8 +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran4.tar.gz/md5/ed9f7aee0565904a8cbd5cc26df37a9d +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/e93bd2a9e4e2c358f46f756f15d9765ef5aef44e5ee2adbfb23e971f380052f4ad5e4569fc5932b6250a40e204253e70966a6554c30c0251f1d5406babdac837 +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran5.tar.gz/md5/6757ed75b520bfd1f6edf55f01f7d1af +CompilerSupportLibraries.v0.4.3+0.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/5f50c9df89ebd5a8b2c6a97e99b8340b0e63e4f689e3062a32474fdd6dd33f160647ae1a2ba96a30abac1bfbbd730be9824dcf4b05a4c327c0ad60c9b96f889f +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran3.tar.gz/md5/954ffb60eb3cba5d7d02d3cf31fc3c75 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/199738c5e226565230368e38183de6af66ac1decc880cb28e072aeba097b8c060a6ee51d755072d66fe955a6621d183f28de364f7d57f372c8ad7585e30cded9 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran4.tar.gz/md5/02c5342c240220803dea5edaa6aa03c0 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/c752b742d7aa39b7ac2297c8f4bae066c6c8217cb717cb7f913aa045b402350325e8ac96b0656404e39a891c825c57e18e5dc9325a954c7e64d98ece776293cd +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran5.tar.gz/md5/5b2ca9ee08026e2ab9d24d18bb631ede +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/f98aed5aec767e1145b4f19515c99927e30790f577494e6d439c7f1a24f7e8e2acb977945f616abeceb614776e329f1a1f852edc1ade9de78a0c94f619046e40 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran3.tar.gz/md5/6e5a0d8521b560e79cb5d5caffa4c675 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran3.tar.gz/sha512/7079605d315f45ebbd2a517b2aad38b226b574ee3f892a20efe02b8336654c84139a810820734456fcf6bb5bcc8fdd9408e783d1dfa2aa25168ec3e9b3e57785 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran4.tar.gz/md5/dde75524ca38581b671d21c7ccc12c6d +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran4.tar.gz/sha512/ae229ccbb704da44f911704ee0700fe3e01730c9a5e7519dbf41c9e1aaf6d3f594678055845430e9c9d9b3ea974d1437fe2d84ae89f2886512c4569b9659a5dd +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran5.tar.gz/md5/1d13546f090e9e068540d5ca42f193f2 +CompilerSupportLibraries.v0.4.3+0.x86_64-linux-musl-libgfortran5.tar.gz/sha512/cd8a4a83a2f09f9b18baa719b0ed13e9eefbee765bce326854e29ca76075e18401b9052d70b13461f16b08219707237aba7e7857aec28d417bd5dddf4eea9dda +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/6987269d8385d6b5716f075ab51ad5a9 +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/0b5efa2c22c9be737a1396d10779fbbb91acd8662a6d419ba76d98b380b5c9cef977ac2d60e27c844d3c5f083fe4b59a6419675d09b8bd3e5b2fefc74ac09e0e +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/d430f7c46b66121833622ed58694368f +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/fc3c7bbf2c3730b68780950e4055491639d8874dc4b8509898722a4e7a06341cc43dbd7ed371e89f2a0cd11b515b0901a803f93349039b2c21aff6e453bca669 +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/557985cb8720a3995482e13c319678fc +CompilerSupportLibraries.v0.4.3+0.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/4d2b6b4431456e8067fd09b092617887277b4da3dc6e030d8091e7a9331c5fa73483f72626f6f06b3a749804b8060fc6ec8e592ecf87a3b1fcef96f5fc267c7d +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/aa27b022d98f489fb21c6d9a05b913a0 +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/13d0f7e243674034b1d41a7020db58df6932a9a3d9a9ba450e1b673f5e56ff984ab68af8a3bf5a14590bfa43661a20d88a781d67009e3af9f60c15bf32e56196 +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/7b381af909065da2da0e8eb035fffb47 +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/c35170eea5174360ebe795ccb79fe4d6c9dca288d8f751e731dcaaf26866172372b5919393a965e18ba1aa553b6f420ca8d8db32b8d38aebd226906e18b7a4d9 +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/8b4d1ee5add108fc05879fd0102cf34b +CompilerSupportLibraries.v0.4.3+0.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/23c7bd53523d8380491b97cd57083956b55273b8d6aebef2e1b5c80ce8593cfe3eab5ff50b6a417b974996673fdfb810ed2fc28798bba42ce59cfe6284b1ef8f diff --git a/deps/checksums/csl b/deps/checksums/csl deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/deps/checksums/gmp b/deps/checksums/gmp index db01480b953d0..da510e3dc2388 100644 --- a/deps/checksums/gmp +++ b/deps/checksums/gmp @@ -1,3 +1,5 @@ +gmp-6.2.1.tar.bz2/md5/28971fc21cf028042d4897f02fd355ea +gmp-6.2.1.tar.bz2/sha512/8904334a3bcc5c896ececabc75cda9dec642e401fb5397c4992c4fabea5e962c9ce8bd44e8e4233c34e55c8010cc28db0545f5f750cbdbb5f00af538dc763be9 GMP.v6.2.1+0.aarch64-apple-darwin.tar.gz/md5/e805c580078e4d6bcaeb6781cb6d56fa GMP.v6.2.1+0.aarch64-apple-darwin.tar.gz/sha512/62435e80f5fa0b67e2788c8bfc3681426add7a9b2853131bbebe890d1a2d9b54cebaea0860f6ddd0e93e1ae302baba39851d5f58a65acf0b2a9ea1226bb4eea4 GMP.v6.2.1+0.aarch64-linux-gnu-cxx03.tar.gz/md5/5384d6ba6fd408bc71c2781b643cd59a @@ -56,5 +58,3 @@ GMP.v6.2.1+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/1499a265b438cf5169286c1830eb573 GMP.v6.2.1+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/d2e6fe76abe0a0cb1a7445ea93cd5bd0bf9f729aec8df9c76d06a1f6f5e67cce442be69b66950eb33aa22cfda2e5a308f2bade64018a27bebfcb4b7a97e1d047 GMP.v6.2.1+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/fdb4187f617511d8eb19f67f8499a8d0 GMP.v6.2.1+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/bb6d8ead1c20cffebc2271461d3787cfad794fee2b32e23583af6521c0667ed9107805268a996d23d6edcab9fe653e542a210cab07252f7713af0c23feb76fb3 -gmp-6.2.1.tar.bz2/md5/28971fc21cf028042d4897f02fd355ea -gmp-6.2.1.tar.bz2/sha512/8904334a3bcc5c896ececabc75cda9dec642e401fb5397c4992c4fabea5e962c9ce8bd44e8e4233c34e55c8010cc28db0545f5f750cbdbb5f00af538dc763be9 diff --git a/deps/checksums/libgit2 b/deps/checksums/libgit2 index 0603b2ab9a662..6d836e4a4501c 100644 --- a/deps/checksums/libgit2 +++ b/deps/checksums/libgit2 @@ -1,3 +1,5 @@ +libgit2-7f4fa178629d559c037a1f72f79f79af9c1ef8ce.tar.gz/md5/c6a819fb0bf924df61e1595624a0988a +libgit2-7f4fa178629d559c037a1f72f79f79af9c1ef8ce.tar.gz/sha512/3de9c042115b309dae3b8e0008edf2e762addd90a7bdb54b3cf634811271ab9dbfea35656650eb53a3faec73caf33ed199fb885ec21f611c79d909d9f4fe48c5 LibGit2.v1.2.3+0.aarch64-apple-darwin.tar.gz/md5/0eb4d35fa6078de8da3dc79a420d5bc5 LibGit2.v1.2.3+0.aarch64-apple-darwin.tar.gz/sha512/aff23e9d56827be54d8f515489eed92d9cb4d9a1b69c12bbee44fa1343ebc906b38b082c11e6ecb227d256de5cba19b2f3a03c022b88809a33c225c34db08f7c LibGit2.v1.2.3+0.aarch64-linux-gnu.tar.gz/md5/f2f31aa978e43aa68a0e73107067c7cd @@ -30,5 +32,3 @@ LibGit2.v1.2.3+0.x86_64-unknown-freebsd.tar.gz/md5/e1623fd3f8f564085d47ec650a40e LibGit2.v1.2.3+0.x86_64-unknown-freebsd.tar.gz/sha512/295d55b78b21ef1c2ba471c8b5618b168dd633e986db9e1ec3e9630e352446ab18e8fd0992010b6afdd922463bb285bc45885a8b35a502d574553fe61c1f7b9f LibGit2.v1.2.3+0.x86_64-w64-mingw32.tar.gz/md5/c845901c4d9dc145f76469d45abad934 LibGit2.v1.2.3+0.x86_64-w64-mingw32.tar.gz/sha512/21951f3bc902f30b8cc75c3af233aa7fe8457e412e7758d556bf71de149c7f2325a5c4c204a7a462cc6a61b3dcb90f0d25e684ffd8617b0a1505a1d31cf2f69a -libgit2-7f4fa178629d559c037a1f72f79f79af9c1ef8ce.tar.gz/md5/c6a819fb0bf924df61e1595624a0988a -libgit2-7f4fa178629d559c037a1f72f79f79af9c1ef8ce.tar.gz/sha512/3de9c042115b309dae3b8e0008edf2e762addd90a7bdb54b3cf634811271ab9dbfea35656650eb53a3faec73caf33ed199fb885ec21f611c79d909d9f4fe48c5 diff --git a/deps/checksums/llvm b/deps/checksums/llvm index 69bacfdf5a928..aa0124f257b44 100644 --- a/deps/checksums/llvm +++ b/deps/checksums/llvm @@ -1,176 +1,234 @@ -libLLVM_assert.v11.0.1+3.aarch64-apple-darwin.tar.gz/md5/1468270825363bffb3d99d3ca9216d7d -libLLVM_assert.v11.0.1+3.aarch64-apple-darwin.tar.gz/sha512/b94c1273553204440b5f51a3b1fa8c96ad8eae2090e50c3cf10fed44f960e5d0a6c95d967b7e006f842d550cc59b06ed8585962399772e1c2d6d1e6cf7686567 -libLLVM_assert.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/md5/5ea96996524ebc1c69794d7e9ba2b252 -libLLVM_assert.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/sha512/8fd7d5debae5277a5d099c24c195ed1c110f95169bc05ebe42fbb697683f2012a95507b682dd978a25918582dcfd548233d26a3e74a3098e85758dd63b5ba98e -libLLVM_assert.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/md5/49e5dedbdcad40a5966aca51c8913d3b -libLLVM_assert.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/sha512/107a57a298416760c2f806901080963c2b1b3d09f16bef698db6e28b084c36f86796956deff096b4e014a61b29319e1fe1ed95f6a807ab3f1a6350288f85160a -libLLVM_assert.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/md5/7d594f4af283181513816fe50d299861 -libLLVM_assert.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/sha512/f074bca4a57c827c16558783b7efe8d31f12d4a0500a374ed9303a4beba2e848343d9d66da4bd0643c8df10004a6b7a9074a0f99bdba6e2b7eae939a892c7a0f -libLLVM_assert.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/md5/1328f6c829ddc5361e5217aa9d2ba1f0 -libLLVM_assert.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/sha512/238fc6e8eeed72f6fc23b9ea5e9083b8812447799fbb73ba13b2613c6ae0d35cdd8835276e8c9e34450d8c682121cf28601dbc6ce6c160ccabe7c36043441d78 -libLLVM_assert.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/f863e9b6afea27c93b04575194bd83b7 -libLLVM_assert.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/deb3d89d5cdfdeee2a8665d79e2cf77dca693c66bdfd5e10fdba9cb54cefce27a85aed76804ade511a65aff5e1a99f66748b827253ffdaca6c5c55c5947e4d5d -libLLVM_assert.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/0fc8a804ddcb6bebc2ca285697427a60 -libLLVM_assert.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/8cc0f98bc20bcaa47a6c6e28a559018b572b27c2c3507554abd2d5a09ecc36219881ab391625f47a581cf7a569534b693760abbe3b31a31b111c3a751051bc55 -libLLVM_assert.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/md5/eaf1aa0154ba5906a48848b1fd4770da -libLLVM_assert.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/e4531b5eb09be3ac6440e32dcface0360cc75595da00fa1bd178306e9780bd26eb7413a705d4b49d3d7eafd8f403a448bad9aae40bad56fb40bbea8db75e5f06 -libLLVM_assert.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/md5/57307cc154a85a84297f94f71593829d -libLLVM_assert.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/c8c8d35982a7df99ec468b688dee8ccf627512c6f009aea27cbd7fc8d350bcb915136753c18fc1a0ebcf621d9540d1995fae3f7532c31dfe70f1b3ea07275695 -libLLVM_assert.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/701b49c22b69b6e4a91cc1559b3b2622 -libLLVM_assert.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/1173b249d04df31a3d17e120666953654ce3274b749e137a24e137faa28b424a3a60bff9bf3c23f8299cdcb6b77fcf883b60654abced4b854e6080788a4093ea -libLLVM_assert.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/e781f504156bdf748cbebbae86173fcf -libLLVM_assert.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/572d0eadc5f3c495aef529d03fe3a3f890cac655fb7b8fc7dba92943023355a4494f72a2de5bb302756d5bbc36658b32babe4efdeca2f85f0b9f244f3c5e650e -libLLVM_assert.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/md5/b460698fc6f652366a0b869bfb2b1646 -libLLVM_assert.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/00f3caefa2885be6550f20a86048057b6beb17044ea822ffa9fb9df65c848eb7ffafbac4f6546ca16a1dfc344cfb851b7d42cc3a7f3f8a2b19a5044748a6f64e -libLLVM_assert.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/md5/b4f0efa367651e7e37976cb7052eda02 -libLLVM_assert.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/5af81df4c76dad4ab5387e3006f350f9387dbda5b131adb2b75669dde284a281af34f041dd00a0e8b6e0e8e92e7e4138fec5f83a6e2fc82fca8c3c6a637900a1 -libLLVM_assert.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/md5/ee47fdaec1107506ace19f70d090622f -libLLVM_assert.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/sha512/32c7702bc599f06be6c5403574b1cece6d07b2c9787bd3b08e73a3746a187956609f2b7cdf0c673fbdd3105030138cf0c622a08e59f4180cea5109cc486fc570 -libLLVM_assert.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/md5/d6a47e2c969aed82c377f42248b54b75 -libLLVM_assert.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/sha512/c95f7e895832deed7d99155ada1df46e1dd1e43dd24fb8aaf94e4109f301b8163b8c8f83f3a2fd65d7b445e4d194f456e2cdd93ba36ed70ac4131c805a0c89e0 -libLLVM_assert.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/md5/158ce4bcdb7cdf26faad269a6133e2eb -libLLVM_assert.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/sha512/f19f556f25e602da754e666476686411d484297cbe1d51f8d21e167feb241c44e1b94d502b4984649340c515dcf38a53be9d949805c29ca0e959101900f68fc7 -libLLVM_assert.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/md5/fe72914bc292072e1f474ffb41e01a99 -libLLVM_assert.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/sha512/87a300e6928b69a4ddc59a375a9c172cbef82dd14ee101ac97ea1a652e1e4cb69d8c1ba61f4e4c2889884c58a571a257cd3390a504ceb88b0cb4a514143541b8 -libLLVM_assert.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/md5/309fdd429e740941e0deab08f1043c5b -libLLVM_assert.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/sha512/b01bcb83a6ef208692bd26899e7e75177f6bd619afeae0dc46217ece0f79bd81d2f07fedf70084478fe1f8abcc2d031a0ea06b55ac55a34f3facabb38a2a993f -libLLVM_assert.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/md5/a9ee212809e891f147916cb6568f8b0e -libLLVM_assert.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/sha512/927a010c326dac7faa4ce822b7ed01048b825a8050ae03d11963a864bf8f70b810e58985d37ec04cb69e7ca5c8a4956438f8c5f50dc8af90dc00bb10c0b6dd28 -libLLVM_assert.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/md5/6a2f2cd6cad70e27029f4a7c78196589 -libLLVM_assert.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/77bee805988a0df69cda34c5196f29234d5e4c7cf55da2154fd5a4f431123cfa3ef870a7ee10dd773eeb446647f500edca844cc89d1fc39d04caea6be58ce6a1 -libLLVM_assert.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/md5/f780073977fddf46200103b476ba4176 -libLLVM_assert.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/40107288f36fe50e8f60fcd7b18a9058f36a6794cf8e8f06328437fb77f0890e1b890aba7f931329d98219faaf922dc14474f66340e6a70b8309f171e2bbc901 -libLLVM_assert.v11.0.1+3.x86_64-apple-darwin.tar.gz/md5/db4d528b06836c46d46755fc93cceaea -libLLVM_assert.v11.0.1+3.x86_64-apple-darwin.tar.gz/sha512/cb62a0db35f0f1cc4723c2313eed265c4e11dc6b225d5b30afd7e2aae0c79b0dc23558640a409862a31ccbe337e4c6e4c1a35f3c93251a1c714dedf5f4637716 -libLLVM_assert.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/md5/b00cef3645e589cb217d8df10173124c -libLLVM_assert.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/sha512/4de8fd6f90a5f85278c1045731e71855969b615e228a6b63bf53c84b145c3d8db4a7fc236301249e6ac195ee13fe62b0c23dee1c50c968ba74a1f9857e5ae3d8 -libLLVM_assert.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/md5/d326d3cd8918ef4abf4aa26a93f77310 -libLLVM_assert.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/sha512/ae49a764b848d179d8799793a79ba3cf03ece82d84e4d26b1f48256ce159984b1c54439db1f7b928f0526a85fb3b11021e9620104ae0404b7b85824aeb59d42f -libLLVM_assert.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/md5/10f34bf03747a92e6cdb6ed206b21724 -libLLVM_assert.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/sha512/ed06c31ae0024e60f7ac3a77dcde37e8aa545b280e0aef669edd6cf3f060b6acb90072c488f91a44bab6e573a3e50576a4b0a11f12596a63729a46547a7276af -libLLVM_assert.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/md5/55ad55e3e093d1a3c32775036c68f629 -libLLVM_assert.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/sha512/d1a30dd14b64c49397c45b2e53aa6099585ef22014fd9091dda39a7ccf03c78b85b018f3844c90c56aff47c6725bc5dfd73b5e6402ea13f73109aea6debaa276 -libLLVM_assert.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/md5/7d88bc9491b83793e39f494f45b7e636 -libLLVM_assert.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/sha512/c6065593e89f861661ec9c1fb35e416496e79e9e0f56e5ed4b7ba9fbf8b236716ff7733bb60b5de8942b6f9aca5705e0236e7fcbedb24109767fc12c29542d01 -libLLVM_assert.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/md5/a012e6c9829ec51f260bbdedb20a2863 -libLLVM_assert.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/sha512/24dc81297cab5d7eafa47de5d0ab5ca0b3da3ffd032de94488c81556d5ebaec850884dd561e14de98fa7dc0104d45acdd0298e0b0339dbb7351a9dbaa32320f5 -libLLVM_assert.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/md5/bc0f8437c9f2aba1a7e696cafd3b4618 -libLLVM_assert.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/sha512/ac640918e72b169fffd4a43f1453965ea0ba734c582c3f6b04cd6f020b032b4745ed79208a43ba1c1f700f0122596466da4ed881a89a67f6df3a62141dab9f04 -libLLVM.v11.0.1+3.aarch64-apple-darwin.tar.gz/md5/7b2400d9ae3ed7a9091011b7951c8ce7 -libLLVM.v11.0.1+3.aarch64-apple-darwin.tar.gz/sha512/9078fc8c24d1749b303f5c7843bbb6b5322080e4adfca0b96d7757454783617253dfcee07f24d1adaf3768563d298029a69bb75d39dc0701d024c27c66e50fd3 -libLLVM.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/md5/712ea06bba40025d5ad86229585e1eb9 -libLLVM.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/sha512/6260d68dd30f8950370db956dc85ad9ba1e474e9c27781ca2640d8d669d3fe34fdf2e020922e4f11d88c4394bb1e72f81f211e656684682207418b954f78102b -libLLVM.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/md5/941dc9c8a4d11cd7cc0bf5edb47ae822 -libLLVM.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/sha512/0ae65d99a49713aaace58e31f539c07727c34f30e089134c64b96b35dd061f44fd9889372364b1c9a36fe295a005160210cdfdf937c23e834ffa1b4260c6705b -libLLVM.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/md5/1bf46309788bf2827e337376a7a7355a -libLLVM.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/sha512/86dcde04d89730219b22dd67ee113942ef689125cfa6d3c5294387561b7771caf948e889a0cc93128159427704500c793b62e6a6cd39a372ff6be735fbb0fdf6 -libLLVM.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/md5/09e727bddee3132c944ed1404c421c2c -libLLVM.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/sha512/00a5f853557ca1f65fc807d3109357b211ba1935de66e2d3b59c8e00b4837c04b2ea72d6c6417a8fd788835938abaa8a4fed9e36d3f9cc009260150417465d72 -libLLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/46e656d8225b534bfcc01f7ceb8592cd -libLLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/325f4d521fed87fa75b296dfc8ea83e4fe5b04e8902f66d15d2f020b5b32236184a7b31a92eb5e0acc9597b1a21f94e6b4101f9844615767b03e6c2782c08760 -libLLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/26c52c856334ed443dadb7874a808946 -libLLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/e1bc796fcaa258e8c650c83c0b533f95bfc932c389d0ea507fbfecfd1d8829e746d53377508f909971d83b4247a0b31c31d2d1106cedc84234536ac19d2dc37e -libLLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/md5/c223e17dc0eb63e02625ed269b5c4064 -libLLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/90d29712769299ff526c7c7a4307bff6e519e1e5d991b4bf4279f5231263eae6103f0887ed2310c45052c904cb05d5b059ecc3ae0d124540fb0886f8c9cbf61c -libLLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/md5/54def908d9d9d93e0c16770344761dc3 -libLLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/d89b9ef23fd2bc0f974e343cf4254747a4ca2918bdcd9080846a56f2580626b80c7fe326488083e57330d857227e7bdd43455fd5f6c9dc90fdd0f9eda3c751c0 -libLLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/c927115d9435d5712dfd6aec848404b6 -libLLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/53050300ce37e79900677b3a447570b19518bc3ab0d13958274544686bba378742d7c6ad87b850a63f825a5fbeca0287f8b67332adc81962911e43cf952c9806 -libLLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/3dcfb85331c0bb7184bc10403a22447d -libLLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/9615b09038238a1cdabe1638a5550feb8498c9889cd805c5876350d7d5185a4ba467f2a97d2c4e192adfb59cfea76afb109e3c9687de183951a535b6b8271d5f -libLLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/md5/8b918180fafba11ae565771ed6839d6b -libLLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/29bf5de468872c0eb90603d2981e891536da58d60bfb2d0c095dbd9ad7c3390276117164077bb89f95ed3cb21a03c0e1245c4a92cd46bc9ed25e4204fdc69e8d -libLLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/md5/3f7054e973baa77535629c08f7b22cab -libLLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/e10819701d77d14bf28bae2fbd69ea03007ee6cce1d6c54e9dbbbcc5dca8d6c2351ee21007ba19da827c445626f5b4bb7e345d54971ba1a35e04278ed9d9b83c -libLLVM.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/md5/16c1530e3df1d137674503bf02423ffd -libLLVM.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/sha512/8284f5a7cf1f0fa8664031e16ebc12b7d5131de8efc7bc9e77fdf33a084294e40917f723ba9b9f56384f527ffb7bf4c7f04a2dff8953d25a2f473c90322f61d2 -libLLVM.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/md5/81670b1d368e9791705b71ae56373952 -libLLVM.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/sha512/dc0525dd275492ccd24533b89aa91a85660cb30cc3eb22f3c6fb10c854c890b5103048c802e06566aaf60d70bb00806ccd0552945573b78cc797295918968fca -libLLVM.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/md5/827cfc808c50b301c1645a21327692bf -libLLVM.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/sha512/dc504771c7cb465e40e4f6ce4b62b1f5114018209010e7bb199c2753438c1c78534d1aae39246d06fdca96f799b20c89e20a51cbf06a9ba318d0ff827d3a8519 -libLLVM.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/md5/fdb9e3d33d3b0e2051548d6a55d03daf -libLLVM.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/sha512/2cdf2fd7706c4e4ad80b12f6fc77a0389d4d015e3550c346f17fa0905dea058eccdd8e5b167477ff8ffb74cd1fe673af5c7ae5a13404da0b59232cb0e66669b7 -libLLVM.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/md5/f486dfa62a336cd7d9e1b00602fc1177 -libLLVM.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/sha512/8264c0cbd63fc4dc17472526723ce6ce4072b276d06a95156a259f8f2b2524e1ac6c5ca768a974f8f1b65bd0674336f7922225d4be5edb90680e549774f7d05e -libLLVM.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/md5/fbf1949afaa7e4d14722fc21c3dc7892 -libLLVM.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/sha512/3c897e31218f1975456d2769678f99c14b6308a464beea2fa6a4f534f355b5e9a7ef51c3f5fb0f44123ccb3c4854b906b96bb35a9ec01e1a1f39df903fadb30f -libLLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/md5/2e82ea13c59bf22f085768766d6dd8a4 -libLLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/664323d8461e5c64e26d8fb84d3d4bc68a8bc2020b3b397545aa651bfdc0539b83ca2c9bec80314322ce821ff225ae48e96521e23b159a684e74a244bb02bb72 -libLLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/md5/04f3934d4421e452673e015dbbe052e7 -libLLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/b8a0a8b6c56dc0ad4b6e179efc8461e69e01e69de8dc02b46644f74dcb859a5d6ae293b38b2091298e5024b7bbef041cb5332b095e6a3be9e44fcb8c21b54353 -libLLVM.v11.0.1+3.x86_64-apple-darwin.tar.gz/md5/487f852d540a46d03a804318067cab8b -libLLVM.v11.0.1+3.x86_64-apple-darwin.tar.gz/sha512/9158b5c8cfcc3dd75d835d6fae6b026bd57aaa60e8685d0777de8b31c5b644b40ac470a38632f6b0aa5eed85e1d001d3789a7f2989530f03f5e8dd95b947223e -libLLVM.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/md5/6f73bcabc8c748b997ce2d9433e7c910 -libLLVM.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/sha512/3152c54501343e575dccb928e55f2624340cf53e84dd67cc606e8a6ec18bd3b8c4121089962fd99af54acaab70279172b65aa35fb7ee50b53cc83db188febc07 -libLLVM.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/md5/4036faca6177ec29d38ae3d93e0a757a -libLLVM.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/sha512/0875703148d4f3056731247a6395c268e7a34edb5b25c9e1cddf507c13afd2f03d261088129fe822028a02e34842e41c48eda20b572b33d714d17b5b7c6f549b -libLLVM.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/md5/b1aa10a625f7e069023e10fed0ce6ff9 -libLLVM.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/sha512/b196521d0fcb830f137d4d67526a3fb46ae0f7591f290e3e0e45c7d2d412518d6b29e005edb38fc5d56b987f5f47f7bd272addfe0cfb1a9e41752f028bd0750f -libLLVM.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/md5/154eb676aa0b1fefe0f4bc2418deedc7 -libLLVM.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/sha512/91a79167fd025092a8f36cc37909a2b3f2591cb2f00809a6846e7abb8a41aa1c2f0f0c1e29d4365266c79c3cbacdce2325b58d09b1250806ea8f9e031a7b4c75 -libLLVM.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/md5/1a566cbd9e79eacfc7a76ac3defc4b6e -libLLVM.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/sha512/535a4e7c665d34e59b5490066373ce21c400001ed86e38b4f5ec7de9ea758b91fc58dadadb239213c4e27185eff33a29466250d978d3dbfa08e794f50ca6c3d7 -libLLVM.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/md5/97e8cfab218937f77421285f0dab30ad -libLLVM.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/sha512/cd514c19006f4f997b8530109a8b2f0099df1e0af7c0e5fe85dea65b01056cfd2b959190e17a3da8a3a223c59859aadd7486d1b6a71ab3207242e9bea891d546 -libLLVM.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/md5/f4ab87e307e014acf4600dc0a1d8120f -libLLVM.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/sha512/a44840a51cad8a7d0db296a3f3613372562c3c5464bb2f1a8e0352d9e521bcaa83053a70d0e369d75718cdd142584f24bd727b6717401174a270835ab40205a1 -llvm-11.0.1.src.tar.xz/md5/6ec7ae9fd43da9b87cda15b3ab9cc7af -llvm-11.0.1.src.tar.xz/sha512/b42c67ef88e09dd94171f85cdf49a421a15cfc82ff715c7ce6de22f98cefbe6c7cdf6bf4af7ca017d56ecf6aa3e36df3d823a78cf2dd5312de4301b54b43dbe8 -LLVM.v11.0.1+3.aarch64-apple-darwin.tar.gz/md5/181e555215a01db6017bef6b75b857f6 -LLVM.v11.0.1+3.aarch64-apple-darwin.tar.gz/sha512/7940b4494e5806319d013feb42771884c320b964fc674abfd8979169fe32bfbfa03558195e520a108fd645a4c7a06ef918d59cd411dbd086b6a46f80e5ff2c9c -LLVM.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/md5/b02bb670ea84bcca20f318ffb26a79fd -LLVM.v11.0.1+3.aarch64-linux-gnu-cxx03.tar.gz/sha512/f05004c2fd6fbfdfe502e4f83babb7c29f9863e900e711c86023e878808eb1a31ff0285c3288a616a2dbecd7dfe3036fdf4465a64633af723f10c2fce68aa84d -LLVM.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/md5/9aae2250dca2c2e8aa305d0175596fbd -LLVM.v11.0.1+3.aarch64-linux-gnu-cxx11.tar.gz/sha512/0ca30244061b3bd6f0b0a6bbbf61fc40b02db00b3e9bca4aa79013ac12137aa7e872ba7113c6bad3ca08225431a9d9a4d2267852606e8360b866e5752f027965 -LLVM.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/md5/f3c3b9667ec2ab3dd9f3663859a0a736 -LLVM.v11.0.1+3.aarch64-linux-musl-cxx03.tar.gz/sha512/5b1abc1967009154a71fc43813a80d37e1c8531575938b2682212478b51591def16a7141292844568ce65f76bc686a7e9f7a4d77b9311a57226ccd43d8494d48 -LLVM.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/md5/98505793b877160dfc7466284fea9e71 -LLVM.v11.0.1+3.aarch64-linux-musl-cxx11.tar.gz/sha512/90a0b9d8da40eaf29d9d7448a3611ee264eb90cd947fa68a6e5e2757d580e82bfbe8ffe3d31c2c2f1eade66d2d4b69a7dd79830b813b62ac7bba289281325559 -LLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/fdc1abc12cf08fae3d4e110976e5967e -LLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/6157dec83258fff29d54fe2f3783a7975a4487a5bc1b98f8355054970ad958eb26ee11f7a2f60c5ab8ae5c8e799275fc712051b00039a14febd0db66520d29b8 -LLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/2c492cfd7cac00863fe373f8d91ce84c -LLVM.v11.0.1+3.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/654e9842373cb52114407340f8cf4c5954966ba677cae9aa085e22a3ed167bb1670286f3f3dcb6798913fee45937da0327817a97f48db021d997c22862b039ef -LLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/md5/81b6c3bcb6b5e595f5fc12aee8596bfb -LLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/8360352c772c69f9cd9469b41ee7494534248ae0480f7661f9303747cb3a87e26d5659fbf32d7dd11ba70b4f24812cf94dacd7565b92b42c9d63da388b8e93e0 -LLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/md5/c9559f735a8419e77a874dd75451d726 -LLVM.v11.0.1+3.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/64cb59c966a1f42d1f31e32cf584602cd1a6a3bb5c3d805197c8e3cd96ebfc1ad3959bf52be2767d88110fe0025307f1e1982e9029630dd5438e94886da21366 -LLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/bacdfbffc987ab1e4e0a023c4f1cb636 -LLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/d9f772a958ff3621f10bc562833a7121a4b3c3aec8d8d03694554714dd54537aa89af0e080f16ffdcf965ae33bd1bb05d9659beeaa86ffb7e553a4202b924a0f -LLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/018802fd42e68b24459c4040df0019cc -LLVM.v11.0.1+3.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/ddcf9f104f47485cea67d0e5862393c2161e6aaf2e1cced1b0600b5b2dfb3c35895d00e47349de298cc9164665cc8cc8af3249997b716872fe23bb58bb1ea370 -LLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/md5/dc1ccc83441df682b09624bf7047aaf9 -LLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/b717137c831f698cd9b3339e5beb0a2e9d6fd8c59961f91d70b8e76d8b1ef7bd9ef610a49d02d45bd6e7130262f37601a780e33509b78e2b1caafd40eeead7d1 -LLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/md5/74749fde3378518041fcae2e447370ea -LLVM.v11.0.1+3.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/b60715831b4583679455ceffe82acc19ef6c7fe3798b02f3df8a08a129a4f80fbfd7ab59c663db4f4418285dc3551e536c3edda2e24310d10cecdd89596588fd -LLVM.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/md5/0d403181fae7d966c536ee0cd6e39c12 -LLVM.v11.0.1+3.i686-linux-gnu-cxx03.tar.gz/sha512/71728fdc4b559df058d9ddc6dcd1dfae4d2dc854e2038ba14baef62e1cba7f3e2c7565fd2942b069690497989e846d0b5a572e0bbea8de7873752e43bc6827c5 -LLVM.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/md5/791e288d0acc976ddf18776540b21ca2 -LLVM.v11.0.1+3.i686-linux-gnu-cxx11.tar.gz/sha512/49dc3c9a2952f928d51c0af64c9f87b441c05a3f7c497be7564052936bb44c4e5dbc05dca3b69d9123d784647f6ca1c528ece5bc11ad39059fb8d465582ff394 -LLVM.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/md5/da303f41ec8ad7329e826a5e94af8889 -LLVM.v11.0.1+3.i686-linux-musl-cxx03.tar.gz/sha512/39deaf22f9e5c2422eefaea6d64c8d78d3235385edb43ce050f8f34c5c9d128c7b155adb2af5c1f0653f92932324f9a8a564df6dc97009402842e98b4b9a17de -LLVM.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/md5/3c5c77b8534eb0756c112193e4028838 -LLVM.v11.0.1+3.i686-linux-musl-cxx11.tar.gz/sha512/9b00f22b169f17f1766e40da5a7aee602cf0b1f34ae97cdd02f59f3f7613f192dfa6a0235764a175efe4cf1ddcc1850d37052ea45e16947f0d1ad79deb6812d9 -LLVM.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/md5/757aab5c47122ed033f987847a95ec0c -LLVM.v11.0.1+3.i686-w64-mingw32-cxx03.tar.gz/sha512/de54c3f21959ebcb081601deb01bbbafe415b05cc7240fce230483b2901d77f89575a74384fb55c919bfe25a8ca8cde2f2e0c6f4f6a809fc73499f4752f2043a -LLVM.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/md5/c7f3d289428d68802eaea4cae65e043c -LLVM.v11.0.1+3.i686-w64-mingw32-cxx11.tar.gz/sha512/54fcb15fd2019dc0f5c3db10c24c9d21d8159e923b215dd000d6107a136b69ff240bc447b2a280a023f25e98880a86ea89cd42e1e3caacabeb59a4ba18b96d32 -LLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/md5/a3032d9310fdfcea2c0e6aa2cc27fe49 -LLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/a8f8c4739b17f902f08307dc2f154ebe90a229299d476d8723cffe504cdfa91a8c36aadab4c12c1db4ea8cc056de17b66e68e1f086ad5d30d5f2edcc53da2337 -LLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/md5/ba581dd66006b02e1e7643b93af14499 -LLVM.v11.0.1+3.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/8037109625c8cab5e310ff95aa852bd792b35f04b6830870962add89caaf0efbe001d08d6f870044e998a7b14216700a806eb132daadc5c4accd77baeebfb15e -LLVM.v11.0.1+3.x86_64-apple-darwin.tar.gz/md5/9d9c737b6e98a41086a1802283730757 -LLVM.v11.0.1+3.x86_64-apple-darwin.tar.gz/sha512/b24025364052233f977c17bb5f9675b4404fb4b197f35752a8a2591ac9786eb8aa5b4053ca4269e6c4de9daf401f88b0361880c3b3201be2db91626f9cad9030 -LLVM.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/md5/ef4535f1aaa5867e9dc4401e894086eb -LLVM.v11.0.1+3.x86_64-linux-gnu-cxx03.tar.gz/sha512/a1d7e4bdc72f33ec669023c89d4dcba8bd4b644e7c38e27784ab0f052e8efc08cb0cb89c38d5ee471961c8c8bfd6eaecc89898e70093a494f6cc53b9a36652eb -LLVM.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/md5/bcae5538b46ba7241b429dd568faa1b7 -LLVM.v11.0.1+3.x86_64-linux-gnu-cxx11.tar.gz/sha512/f336e5d7d007298027efe39a9b50afb32376d1361622097fac6a0530ce8a834f0cfb6d8abf05cf964bb5159b0864bedac978fb95031cb84672e0bc0b037d03aa -LLVM.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/md5/353ba4a877af02d2a986cb4917fc6cbc -LLVM.v11.0.1+3.x86_64-linux-musl-cxx03.tar.gz/sha512/ea038f9a12a84df32e62d877320eb041d2363b1714ded05508b1fdfb2a874a6964114833a7435feaad1040fd31a533acd29e48731f49e8df3b60fcea04f565fc -LLVM.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/md5/81d43dea36a9e2ba628263b1af36461b -LLVM.v11.0.1+3.x86_64-linux-musl-cxx11.tar.gz/sha512/a99b2dbdaf55cd36e8ead346fc7fae4ecd430cb98895343d6a409d0ea95406836048638dd5ab73129a2b2a637abd1e997515d8de1e9e5e8449e0f9d747773d4c -LLVM.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/md5/0f83ccf57dcb7814976a57c42c91c454 -LLVM.v11.0.1+3.x86_64-unknown-freebsd.tar.gz/sha512/06c3a97b6ec4f9095e8e978ccab0e65e03d26f99d90485c7893b6a41a53a4e5a8e8e531592e20f9d73a1100fe87f7fad793dc6cd19b09ae0bdaec5c362b7b4ac -LLVM.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/md5/8db6882c343f0ff1ed3137c1a17a1676 -LLVM.v11.0.1+3.x86_64-w64-mingw32-cxx03.tar.gz/sha512/a3fbc239389eaae152f4a21e5b50b6afd09adeb75d8e32754dfba5da3815991dd05ef5c403ef9539bdd47cad3f9b2c7066a61e3f40243f7bd237a7480172be86 -LLVM.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/md5/bee41a179343b54359aba1b159110a39 -LLVM.v11.0.1+3.x86_64-w64-mingw32-cxx11.tar.gz/sha512/3db19d091bd52cfc2018a25f28bf7714f6337bd93b24349ad90d2954f60317189e5e65241ff114c9f7cd15933b685f0a4a193d45daf21af593fe2890ab98843e +libLLVM_assert.v12.0.0+0.aarch64-apple-darwin.tar.gz/md5/1e5a6d26e657b2900c9c3914dfbad9e9 +libLLVM_assert.v12.0.0+0.aarch64-apple-darwin.tar.gz/sha512/e2846fa7e2503309dfb57159acbf8ca5836fffb1a2a81fc60e88743d13eb67491c5a8977bc3dce7d75de799ff9bb963029abb23dec5450085e480940bd3f4bbb +libLLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/md5/9b6a0cf448686b657caffe308a8512fa +libLLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/sha512/151f3c29ea0f21f6a4d4be8b127aad2cdfd0b97ed3f8cf8d518be28f2b3fdaaff29eac04b57b5a5ce0aa3ce137e1afc2fec2e619ea2dd119520ae815e0e064c1 +libLLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/md5/8b4eab1d6ec21bf412a3ca8eaba04f3d +libLLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/sha512/13009a160683ab073a0a3e089f17d006b1d74273a65b51d16f4e731b47352c972ea0487a79e02084c4f4f72f61bbd1f169b7bbdacb6974e5fa53944d444ec290 +libLLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/md5/d1e35884644357a76dd4fa6f7429bccf +libLLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/sha512/d0918e7886c9ff6771d3ff809a25a56a7a2154b4713ed2f47f3e0b75748524f5465fa742c771e1fb954e3757a3341ca3f5e8f659225e0edb49f0c50b9dec995f +libLLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/md5/ab814bef54de513926548605795ee56b +libLLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/sha512/18aa8f235963f24ff15854708418640eae32c061b663574391d8c70880926a9ea6038cd2d875ee616fc5b247aae6503c6bbe09738d5fd0b65ca92e976057c8f6 +libLLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/6fd292d8e348f895efc567a566a36a98 +libLLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/1b03e5de348c9f563fc31c2325817380df6b995a5f352effd434f786f760612ea53efbae2ddc37251b3dcef73eea88c71869a197006ecd0ec6f860ffdacca5ec +libLLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/7377e0370c12506893231c4d8e1a28bd +libLLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/c91aa4226f065c62cf16f9815b0cd34548dfff38cb1a05e0e122ff659c3db2ad6d28d83d9d7ec4d28227b2a5de1d2b48812e50f6af838e69eedbbd8cc153f131 +libLLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/md5/faa491409f4e9d822e9e34f6f2db36ad +libLLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/a07245c310755567e9e33b26c0f0282eae40abf1a1a1c22a77b6412709b191433ec497e16662f229558e49089d68a1c904cd282c548c02370ed902f544eb5cd5 +libLLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/md5/b42b08d46b64df98e3ab493341ac015a +libLLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/da2bd53fab48f8b46971639d6ed81b9e57467a6c4a7a3a63984c08f1b799f7352352ba28892a7789811879e3740073487b885d9974b6285fd03da16edca24f2b +libLLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/52e678465021c06611f86411a8f41e9e +libLLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/01964e97bb231899b6064734f756d8099bf141674ed6d231108dbb6c901f3079444cd620493b0ea7e8bf1fbd2899f288ed02df3c855e5af87d7db93a9fd60108 +libLLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/c5a5977de4429a0a38e4cf025d57660a +libLLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/a5e4aed882ca2cbf0a8a8ff5b0c8e4eaadeaf7491ea1887ee5fae628a5d46906e7d480b784b1d1fd190c921cecebcaa243ff39df5a1776a82abcfe4095bf3d07 +libLLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/md5/bb83098ced1081fa0c06ddb84b6cf0fa +libLLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/e217bb8fe434954191b2b2f0a00d6e32e39557b9ff95a2417a13f3a6a25f2266c180e66c98495b1946171d1652ca62689140814d5337e0e00b4abc15179f2879 +libLLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/md5/77161f57a346fc7f6b9aa1d36db55879 +libLLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/e53440cacd74eb6eb48e4de0b720df177bb9b8c90e682685efcf65f98bc4bc6f990c60ccdb426e85a80db8005dbad1efa5be69e2dc326953d1c0177734f6a84b +libLLVM_assert.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/md5/33deaff11953a1f1f78658461010b258 +libLLVM_assert.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/sha512/61383ed8e872e21c3419d64928e29c3f1e074c03973ee456062ef774b71cb27785afa47c641ce9db14a144fb66a7f8c53215448721c49ebf3b37674ed04a75e7 +libLLVM_assert.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/md5/65f47baee13c6e2cd9f0f3cd95bd724d +libLLVM_assert.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/sha512/6f814647393445c5a6ec05cd8c89a3ad106bde4a2197ee0a8bd8e64f1575245d695a01bcfb02861ad452f7d881114a5fb4ab145aa2211b42fc34b07ffec2ccbe +libLLVM_assert.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/md5/107c0e969aac6bc376588481f3ab4748 +libLLVM_assert.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/sha512/aaf8677bdf4fdf5751a0133c00dfefb28cdf5076d62d749d9bb81f29af2a3f35438b3c4c0aa71fc87214670bb63a2428712a1c07fc46dae217cdef27b9b0c550 +libLLVM_assert.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/md5/b6f7084de25b6b49631a2f2aba8da96e +libLLVM_assert.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/sha512/75f91fd66da8d1e041c9ed0e8fd69ece5601d909caf10eaf30992b6eb5b743653d97648766fe0782862dc0891a234f3aef05df3b6c04848d4371addbae8bb419 +libLLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/md5/c36270a831b06d5b3654ec7a9fd35b09 +libLLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/sha512/25a095c12ac43dc36fd32b0ceacf9bc10b240a360a45fa0b0fdde367a40dc22a83bb3a6267426c0c02f14f221046c0b453417eae4cc0539ca116149f8ea480ef +libLLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/md5/8f0c51901b55ff5374c25a0e9bdeae99 +libLLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/sha512/a1387d07d63d0e33632bf77702271bf624fa29bd8e689054d3f71734451d39ef09abb9fb63f78cb6aa1f6f5bbe54737f72740aeb63a94fc6876a600ede5ed159 +libLLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/md5/9a456e2d31115b296b212305988cbf0a +libLLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/9c93bbdf9b9d11654aa134cdd7b50198a7b49e86148ba3257cf6cb1003fe9d22f568e45ed5b26f4e0db7fb3128f57dadbef9f4494827c66b2957988305aa9b20 +libLLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/md5/efe3eec267a6224e5e8f1458be4fcda6 +libLLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/d5e90b29242b6aeab8b4ec6d37938a5ab15e1b1546f87f795d45b8f9a1520d24408e8b2c3a26cfb4b61c6d3228f98d490e2a0abf375b8afec0fd0e866a833197 +libLLVM_assert.v12.0.0+0.x86_64-apple-darwin.tar.gz/md5/475530f8b87ac033069c4073ba25f62c +libLLVM_assert.v12.0.0+0.x86_64-apple-darwin.tar.gz/sha512/ae46db3687de3bca657968624d95ec3afed99fc3d07271681ae9cc587baed2b391c17b4b0905cb4da3727a44c7698b248dced4b44c688242042c096f9b2c2a46 +libLLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/md5/888d7bd8ceb30a482438d0fa7526d6a5 +libLLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/sha512/b494736aa3c4378bccc5f72db20fdbc488bb383ec4f569be18848fe1aa712aa6dcd00df1a8c651ed266981e70f4f1e9ba2bf04cc410ef02140f988c21dc9730c +libLLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/md5/7fb8dee0396a2ef772612de81c4ce222 +libLLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/sha512/ce1bcc5465e61944c4720f615de3bc234d2d2a3d8fed986aa919ba1840c0fa9a8ff4b7e5fd1f8e063bbd153ca1977718a91ac2e1ab2623a4b744d8ca98c3191a +libLLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/md5/ae631966f7a9f28ff105ae2c5c9b45e2 +libLLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/sha512/da3c1b1335f891b1121fa5f1f8fa4d9705c2bfcc3d98f80ef86f453e4db2d7e4c391b462ff471a87a01403558f81241aff7fbb8f7a05d815b5e15099877f9f3c +libLLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/md5/a4f21af04ce1407eb8d16e9b4704bfd5 +libLLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/sha512/bc6ada66aecb448f28f61f261d0e7cc009643ec0582c46ab7756e09bb4ba2ffecea8883213e6605144084abbeb1e12ccaf6e2a15b1797151a6aa0522453c0af5 +libLLVM_assert.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/md5/0fee3ab691bab69b30f3ce5721c871db +libLLVM_assert.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/sha512/4b9adee9596d37b336434a74e3aa007f83afeeeccbeaa16c942dc117f2990d1485887860eae7eee74aec2b4bea0f674aa3c6abbe621ddc26a76697e7ab1be986 +libLLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/2dcc9f9c8e8ea1c96b19d48e9c4da039 +libLLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/86a518a72558cae62e2b393503bf34e768d5999d2b773b22ae5cffdd6a413780fd8afcb88d8862a62529f3f3238eb50dd5d1210814d417beb01814bbdc029540 +libLLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/0392a6e2b4d2ea9177d57ed1c6758344 +libLLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/e0306b68650e758121a577133321d07fe42d6e1ff5a1b4fa5ae91d522e0a196f63d0a8465005e8d49a39c3182c1f86be8f79ae3c5da1943b1c5ad3b45dbb90a7 +libLLVM.v12.0.0+0.aarch64-apple-darwin.tar.gz/md5/758342103dc72bef1e97045b61326c12 +libLLVM.v12.0.0+0.aarch64-apple-darwin.tar.gz/sha512/38632deb61b0bdcc509b6781ee8981697e2ed68ddf9c874328b8de613621fbdc04dcd8e8f7e839812ff3b553c8ace00c32bf391b1cd7bd01359df0223400b49f +libLLVM.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/md5/e46e23c1cb0116a64d4c6c362f36c273 +libLLVM.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/sha512/2f3a8870ccc0a2b9f8a0a1a46a1e3add68e412ca63b5dd2f3179d5c3f20c1c387d93493b4e3523fa1ecfaf676ec13fe8b97908e26d079ee140e24a03ae4138e3 +libLLVM.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/md5/6b29c384991d030f0192cc21d8ba6b07 +libLLVM.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/sha512/c4f90df89d6315b93f574f0149c8b66185252770d7580a96728dabf9b4a3a66abf6f534b528540ddde791e6719e97857069c8b5154bcb134369253be3d51c052 +libLLVM.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/md5/d00dd86e4a94b22976c8674d42eb9830 +libLLVM.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/sha512/7bc5e67ddc45a481ed3349098e581eb8db65b4408478db44b053850b9e534b9ffde27674ec22f3600a794a7a5d334d649907205d58016e6984ae2b8ec675959c +libLLVM.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/md5/f44c529d8c9afb2c6a5c555bb6a38177 +libLLVM.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/sha512/1c6c7320495d822f4e9ef209f726ef9793d130b28416b8ca7b60d124e5ea54d6a92d73596ae33078b00e863026196177f9ae291a338d00378169f4f0199f8fb3 +libLLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/a49912cfcf61750103f740d60de921bc +libLLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/3f4d803d5eb62ec23558c739d3afa8bcaa7cf371171019950548d46a07e2e9be771ed1a135995960d7e8b344cd149abe4f50b547889a5b7d30a5fc97a80e6f33 +libLLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/18b0841f11b5d3b8bd30c6a6711f3e84 +libLLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/e891c7d7188593b1c99b8e84ed8b0d9430367886eb1e06923675f666bb206649f570b818080598cca21603693241b8f8474e268a3ddbc5e85cf2640a7648a57a +libLLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/md5/d0f7682d75992f21e9f4583632af01e5 +libLLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/8f14d78b55a923e497fc72866850ec227ced1f600eae5b1f8060adf25dcc8382ebb4992474a1557b411f010e2fcd356168f2ada79b867ed5afeb82ec4a3fc30e +libLLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/md5/4b4030175961593cea3d63219cb2a5bc +libLLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/d3348b34db7e51c66c29e7ec835c5b8287a7f6f4abed97cbd2cae0b9ce6f975aee1e1eadea7e281cb6ac180de209deee277e1b7c2553b67dbf3faf5b0c00d96e +libLLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/25a752523cef3c8a0630ca80bc612251 +libLLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/ea8257ca590509ff1fe3c1b8379305be067c257e812269ee4af5df35cca1176400e85502b17cedab20e879e082f4bdfb8fe1dd34d83e786afe1c9914931c61df +libLLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/09971322fd89c0b1102fdfffaec53721 +libLLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/6b5b7169c96e7b7510a6b084af0d36b893a46a1c2c4a966e89f23878ac2e9eafbe3c21c062eed818f200c9eb2083261ba4ee76786af5ceb5f05621f79548ee7d +libLLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/md5/a7dd5765f7e530a40b72f44b5dfb8b38 +libLLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/c4b119dd79a810001b81b4eb103013b8d7fb8443c060becc3900e6f7379b91e38b70aedeab980062ee53ddec04592aa6790c62bfc59c556423edf9b94218d060 +libLLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/md5/f61a1d6e04a4c5c00bb0d31e997184bf +libLLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/831dbd3e5e16d4fe6c38fef6f2656f54b3532fac1c1c05121d0d35d6c9de328cd06329ab85f100975097211586bd1fcc3249f8e77661941c9746843d2adb0a6b +libLLVM.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/md5/4e368d4b4901825f115a3e58483036e1 +libLLVM.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/sha512/0211a7213e1d5dddc64be17c39b330b12d7361613e0a798d007bde9d3f4f3fb7259df8212c1809a45759118ab36af4bae0c1f35a66e88a4195c899a6341c21ba +libLLVM.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/md5/cacce4ec7289a2a86e9bcc91580a4a5f +libLLVM.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/sha512/04d71994344fdbf60f01128e8c8fe3c5f940ea3bd72a5eff154d913298893bb73b399eeef1240bab779ba477a02b8ddb647068c76946fcb35f9a530d7fecccea +libLLVM.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/md5/c242c47e4047bad01c15142eb6623fa6 +libLLVM.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/sha512/225b9ea08454ebd5b24ac1d4442023d21f4727072baa16730b23d71d0dfd1be713bb992868038f8e982af590f499bf6d2b4e64bd3cbff537fa41c1f8d271eb32 +libLLVM.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/md5/7843fcb202beb55d6aa87600a6d60342 +libLLVM.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/sha512/d8c9f6f865e2f1058bd0d3f5b04a799483f1a94336ec82161a8c26e8bf5070b714663cf5d62733c9d4006b9a6e145873a31198e780632f039dc43a980216407e +libLLVM.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/md5/ea045ca69935f5035071be6ae719ee7d +libLLVM.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/sha512/06a9b4f762bc08c827ec2d8bc6ff26ebe7af6c8d049bd1015f5d006d7927f7c6ec5d1310b0e74da59994b10c866d2e3358717e36d398d3c01a53455f5f94eaee +libLLVM.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/md5/cbb10916045594f8c509d158bc9eba2d +libLLVM.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/sha512/7ae2b3dc6e54bff8db71ab3208cf7d28a4c35819528d6cde17530e8a5509501d7aff18a75e851d93cb2682b0996d78f00e09db6ac11c2bd9bd57d349af8a3c14 +libLLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/md5/f59fa032a3f5d8fda741a7fb2c7908ea +libLLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/bac6f46e34660cf8b231a1d68eeaedc82f77518296cad4aa6d54ed3661c45c02b3d442e30c37c8b4b8cd0e0701a5ba49b080ffc842e6b58f6f19375250978231 +libLLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/md5/92f7fc40a1ffb473046d5493b329fa69 +libLLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/1f0256620164ee67b6936fc2005a66dba889dae4c0f92b16fa33fc6a3b4146ad1b119db8569a50b1716e2464b0e4def09cc68cb81aff96c234717e507d64b3ac +libLLVM.v12.0.0+0.x86_64-apple-darwin.tar.gz/md5/de7a0f428a9d6c53feb42cf1224744d1 +libLLVM.v12.0.0+0.x86_64-apple-darwin.tar.gz/sha512/f9f7adb7e80d2192692fae80909bd2a87d5a471cfbcab6e335750011b77abae89dbb2b5a81151bbc34739ee3828e3e84a844b46fbc63c279710f3e12c0369642 +libLLVM.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/md5/38dec37c1b969bd38739dcc88c795ede +libLLVM.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/sha512/9b0afbe6119925a6a2d7f03208ef4676209e6c6532c78f0badd87564636bc417058097c2038108d6aecf399ae5ed3a8629d75a00f36277a7e97483da92a5c963 +libLLVM.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/md5/68ef2be45e6228a974215cf76c630a8f +libLLVM.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/sha512/a8e48578b6ccdce02b3e03d7c20de8df90ab40ac99a029169c8dd15907e41b917579bcb0f677dafcf039f95c9be0395b2ee5503ac6e20d9ef62517b5a213f521 +libLLVM.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/md5/8422319066043fc91f69795c10e085ac +libLLVM.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/sha512/e072e786f4ed2a891b251e43f6b62f6916c3f2d88afdde12a132a468f77281fe6b52438862cec25726a501ae76ee5d9e920fd5a2a8c2ede91999958c157134b8 +libLLVM.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/md5/1251650b38740bcf2203ef52a9dc07fe +libLLVM.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/sha512/afa9b543a1930440b7e82aec6ff82549de6e1fcf88fa24c20e541ca66843bbf471f30fecc6af5e4e514cf383e91834c0cbbf231f0d97f2af9a99122ba13a6477 +libLLVM.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/md5/673870380f49f24097e9aa040bbae2b2 +libLLVM.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/sha512/88ba49a5063fe67bc91906d2b7d2044238faaa7a1ff52e10625f49d79a9d986de3b3a09b32e76f38f8bdeefadadab233ad8510881ed6ea7c4925b5d6c7396ed1 +libLLVM.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/6ff0f20bad03e04ea511fbe99a4a8c87 +libLLVM.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/b0496090fe91b7d8485883b3643f170c4a5533bd6bd388ddbb04e189d0073e44ccb31caa2cdbdff49f430c1180dd8c0d1fbffdd2fee83e5be52aaf362c0cd178 +libLLVM.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/1de026b6896ee464493d0b760c938faf +libLLVM.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/113ff6c2a706bbd334fd6882f56d1238fe0decd3e80b528166500ac5f831bb321d078b48ebb1883ed0ca5ea22516a9b3ca49fb32cc21b03fa985ddf69208deaa +llvm-12.0.0.src.tar.xz/md5/ceab21c9081e122a88d82216a80d0dc0 +llvm-12.0.0.src.tar.xz/sha512/ec17153ef774a1e08085763bda7d0dfce6802fbaa17e89831695ce1b2eb015a6c2aebfaa9fe7985a83b9c51bd75d40bb4f1fc706dc16d4c0dc2b2722a1d8a24e +LLVM_assert.v12.0.0+0.aarch64-apple-darwin.tar.gz/md5/9c1db1cec729fc7f9b65a135290ba820 +LLVM_assert.v12.0.0+0.aarch64-apple-darwin.tar.gz/sha512/684f8fb95bb99fc672d9ecbac831f3d6a68e906c8f0050bdeaac522f8b3ccedf8e54dd23667de3fd0c03f241471df221cd0a965036411b523b0e4016be89e896 +LLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/md5/1e84cba3d675739d2064ace317e8852a +LLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/sha512/2bd3cac963c0b54d23b1471f26b892c95400c2adea45be4a40dace6a0a456297c44c5edc2aba7d977c6afee1b8ca41c43171b8d99e04fa223ba9df877b8ec614 +LLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/md5/16a1d1b3006b5181e3b27c01775865b2 +LLVM_assert.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/sha512/6c34f0d2d30965a1b826edf98031cbe96cb480998816d351eb2e361acd868d35c11249da0a9273469aadb7f55851e97cbfdd1f5536fc9d7310410c192a592a23 +LLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/md5/b43babd0f88939f70f24d6ba6c42d93f +LLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/sha512/5aa5c686ed1d75bfff26deed4975eee7eeace2516c93e2d2a88c86d2f88e67f894f24d777d3891dcf962281794143eaca720eaa8dd9c774da3b69346beb50a04 +LLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/md5/ad72b54cbca417fb2fcbc22885315c51 +LLVM_assert.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/sha512/f2d7ddbecc040c8ceb4fffe0240a15a8b18b697ad605fc8c29e16f8502e72e9e8281bac4634e84f95d86ea5cc3abd4fd0fc437b3ee986027bfca6b6efbf39d54 +LLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/176daaa135bdae4140cd64699500af7a +LLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/c08598773fdb8cbfeeb4e8b6802f90b0139b89e50d7434a7976c36416a2378db7873f49f81810204291c9edae72d82f3716b61df36411b0639b148fc838095fe +LLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/68c15927b4db3e2507b89e82f3332757 +LLVM_assert.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/e8598844215ed87fe6a1be05465e80100f433d649b4fabeace1de111626577a5747fc27b109de532c024cbd3f3e8261df0d4bd0eeffdc1928354f1ebf501ebcb +LLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/md5/94cb1baaef471aaa4e07a2a0367caca9 +LLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/bb440e622e2da9f194a2804933131cdc4c084dd27567276e90a6638d6bb15d726abbb40bfbcb81d9934ae2472f1267068bf4f40043e7c928d12316eda66e4806 +LLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/md5/1fb3a0ac1d0511ebd20f9520050a5f1e +LLVM_assert.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/5453dd469aaaee937d2a89c03fc382c52dcc1742070e6310f2394d4753fdde32bf91fc51e078d2aa00f3bf78cb73ba4e5721e008f84428e1269549af04689368 +LLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/c6c7d20f7bae0e4dd52b538bdb0ab1ce +LLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/cc1f792fa7dbb91470106d84c168c3d5e3c519079c8514039fbda8692f987ac994b1cf8d6b96995f47ab32ff55cff42bf53d278a78b21378ebea9c03f1b53d43 +LLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/c2fe748bb8e95fc1c22585109c372a37 +LLVM_assert.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/f94a13e0da4a51b4e3f3697ce88ff2ab7d41918e2d25894cb6e41622be9f3c888d6715574e8cbafc3a20bfcc2164a1c9b417c2c66bc420b445e11c5265a96f7f +LLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/md5/ad087a60c33f5eda018ab8e2966bbfa8 +LLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/d0a4d1eb39491eff08c2991f8876a4e097071b337c4a5ddc783c51a1fa109810db67c5edd2e9b6dbef7e7fadc78224ab45864bee8e9b9e35f0325e49bfdcb6b5 +LLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/md5/0015dc719aed7ac0ce2bd16f11bcf53c +LLVM_assert.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/de224f36068bce30adb7472e40d0b3ba3e3fe739fe9ed62ddec825fa922bdd075dc081401cd55abd14a303551ff5a047cc98b2a077f367c105953c8e27764d86 +LLVM_assert.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/md5/f9ed12bd7fe3e616016b81bd3c56caa7 +LLVM_assert.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/sha512/9287a724fc4b0a0c098a71c4ff4aaf50c3ca79120e13b3ce718c206a0dab1f239137175e6e8b46559fecb373650ddd8224e04194042eb62c974ebce84ace6ebd +LLVM_assert.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/md5/04dd433225feb65b499bee9b93698265 +LLVM_assert.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/sha512/2e1d1d9f5ded294890f37dc8c2449d9d66541d242d3aea76f3f170cb319be20b3f7d5a296c0631b6a8b713627c8f952c07de9151e88e1ef4ecb9a6f622595cb6 +LLVM_assert.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/md5/2cbf070301e7ca4a54ddfbd4420f18ae +LLVM_assert.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/sha512/5a7a2212d0e99130b9f2dca5311e2ac14622976f8d129b120754df9c130047369e2bc57757e8b0bd48430c0637dd886fc85b2143e233d503cb4c92b6bf9735b5 +LLVM_assert.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/md5/ec1eefe92eb1a0ffc08c2761f6bd0ac3 +LLVM_assert.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/sha512/6e54c1eaa55aef60c8a98e3870c1e18392a862b79cb482cc92e7346918cbf886f0845c6bcb0e75dade163bdf60b86d6888dbba30eb088ff0d4cac04624abb2db +LLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/md5/9b282bc5b379138b634613dc27451588 +LLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/sha512/7969075ec1f8a367bf14cc19185bd1ac66631ddfe8faec955969600cc5e3548a82f2775271cdac71807df7f0fe38106bc6ba28b60514c9461513e9cb9e39de59 +LLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/md5/c2af10728a4cdca9223f2769a5b41572 +LLVM_assert.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/sha512/4ed5303b5bb58fc6fba82c260f368398ba7df17ec9cec8e1ce9fe5f608e19c67cecb62043cc8e20599210d6c438e2d29381ec9d3a8bcdeb11b7676022f21664e +LLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/md5/b8d7c5bc69c532251738e123124a046f +LLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/82bff8f8afe76ab38300a9e7fcba93ee07191230c1b2a0ee5bc98c6a1c94899a3da6eafd113ce7d938c27881f2af571534586e4adcdd1ca51ecd399fe56cd484 +LLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/md5/defb081814ccc0cd6732ae3e3cde034d +LLVM_assert.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/5dd21608cc271d9a4d065bb336301d0e797cc40ed7fdae3a4370b7ef0f93d868e784e8c79ef37ec33b057a2eb86d07720bd0d7c178c9c28f4368724a5d0783d2 +LLVM_assert.v12.0.0+0.x86_64-apple-darwin.tar.gz/md5/212f317b4d01dd033e1eaada7076bfb2 +LLVM_assert.v12.0.0+0.x86_64-apple-darwin.tar.gz/sha512/19a222b4d1a239219498d5a4d67142047e00746ff6548c7adaac40196cc1b3088e320f26fc8c12b2ad41eed37d6dc3738af61a1dcbb81ac42f28e6bba0da1d54 +LLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/md5/5afaaaba76df2d7d5a1c50d51ef45ef2 +LLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/sha512/2bf44283938600faa845b0b8b48f08d1826f80e48264fdc95ec828593afa8e592e0e697cd5b9e4ef959200a776ef3f85cf9c35e98fc908f526e082d4c4b4b340 +LLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/md5/aa41affb6459858a9beabf583842134b +LLVM_assert.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/sha512/3b35ed3bad9c7e88c3d937548bf9af24b270c1faf4aae9ecaaaef8000b02ef17f90d425f7506a9716c1aaf3c7247472d2098ab7ecbdb4010f478602a2ba9c5ff +LLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/md5/0429e7474dc3d250b0fc8772beed5b5e +LLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/sha512/13c180d03d337e911769793bd4624b75be846fb67d71aa0f0ff837c232e14d5d016aaa2fa2b986676297f3bbcc2599f104ebf4877e7110f92888e5c4d95f9ee9 +LLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/md5/e4403471e47034e849cc66610724cd50 +LLVM_assert.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/sha512/957df75539a723b680173d823bf96e542dc4cffb4b05b64783a9d60f0f0bafc1b0d1113fb9c4ae25ffe7e36c4764804a2f98fd9cc2468e2af3f1fa0e77929788 +LLVM_assert.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/md5/070bd8e25a76b980564f9160bdaa66f3 +LLVM_assert.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/sha512/c7c03229c34dbb715e2c59ce3c9d404f5b6a337506952bbee594c2109a0824c4962575f8ae9801a89a30d5569a85f05e4c1c4fd231ecdfe36d3ca7488799d3c5 +LLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/1b7726c382c08e3e24fc1ec35b8c015c +LLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/029c084d83ee049f45b1026757d631751cd2edc6c7e10deeec398baab792e8cce366fad5c971a120154ed2b6cd28b6659090dee7402e8f904bf43371b4170048 +LLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/2c6d5945a5ee5b4d216acc6fdf22b54a +LLVM_assert.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/f086e0c58eff5560c23bb9444270005407e66afeb969b4e5bfb1eb041a3479939ada7014c696e1dc50b0aa2717928887d434941d5266bf16264375dd3acfb67d +LLVM.v12.0.0+0.aarch64-apple-darwin.tar.gz/md5/8837684991656303d1ccd1da16cef6ab +LLVM.v12.0.0+0.aarch64-apple-darwin.tar.gz/sha512/de2a74fc6c305a8353168ab7e5849706e29fd4b66936bf4a8b6b9cf9dbaa2b7c30a30c118cf59f1421eaa399e7b5a7efa52ccb9ee4c2ce55c7afb9ceb2050a23 +LLVM.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/md5/4597b32ca87cbab6ca3de44ad0ff33d9 +LLVM.v12.0.0+0.aarch64-linux-gnu-cxx03.tar.gz/sha512/648233efb5037da8928e6d584ce7c0176fd41fd3ab66ffc36bc15fa0829bf4b19d554fdbfe7ad6d1fce28be5d66ee3e650871f4ca0973afeebb19ca4aa0cc596 +LLVM.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/md5/fa65be0be8c747801bf518e036d6b87e +LLVM.v12.0.0+0.aarch64-linux-gnu-cxx11.tar.gz/sha512/cb9d926450b9e2d805ed3cde63db738eb4bfa2073382f52acdece2ca46019da0205b305db10af8feb96832016b0d10ad766e37b7f986541ef07b3877526a745c +LLVM.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/md5/d8ada1b149428e1b363a3776208778c0 +LLVM.v12.0.0+0.aarch64-linux-musl-cxx03.tar.gz/sha512/5cbb49cfa03aef5f455a282dd76a7943d0a791bc3e2818d0e8bdebe3b072202a35d1a37119bf2fbb8082f18af99c1aa935b1f07b7a8a6ec3d0fdf05d7d7d0f1d +LLVM.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/md5/f7af27355d90e71ed8d3b643ea058801 +LLVM.v12.0.0+0.aarch64-linux-musl-cxx11.tar.gz/sha512/27043b1229ae05e4502eff589a04469ede3f4b701aa62d33f69c9cb57ec5c84ecd1c1a312a3853b27a6f32281c41b62098b623a6a592671a7f53947eac7d955f +LLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/md5/0f19ff6eb5d6874f386a55dd903a3808 +LLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx03.tar.gz/sha512/fc57dc902c574701555a86b404fa07ba676252b405cfc130fe253adc7bba7518ebeb6e984846f1a75fc192292fb5f546c3269960419351991aef74adfe6ce30b +LLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/md5/bb054c404683edecdcaa8b4e6c5d1969 +LLVM.v12.0.0+0.armv6l-linux-gnueabihf-cxx11.tar.gz/sha512/10de5dbad00bd92e47c6a77d249e45ceae2cb790893c6472e91a8ce9d8f3f03f736f598d9930bf6bb53411f490f971559b281ef38b0cc953ff3aab766ff20cbc +LLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/md5/81c6b866133c044922149e8da3330234 +LLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx03.tar.gz/sha512/b56ba063e89320a72e4db45e1ea31ea5f2238d3f317f3c8ea042a36b312f9c4a02eeb9da722cf34aac0e7d703c66d996b0f2c0c8b0e61b38e1e10d7c6a872270 +LLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/md5/0cf3669c60ccb6304566a612ec84dd96 +LLVM.v12.0.0+0.armv6l-linux-musleabihf-cxx11.tar.gz/sha512/a9b91abbcb1130e3bf83ffffa7c74e74a663f12fd79c1429f804af5d2a6dc71863bd387a080153fb241488baf9d0c9a3c317c92c7c95553fafb6714463b65e4e +LLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/md5/971bdc3c1e5f200d6d5e0791de47fc8c +LLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx03.tar.gz/sha512/71d50e5852892a8777076022dbe615c49363bd2321975a0fe93202a93518a9064c805966eb2b09783fb2679b589059e8673072fccbcf2110584b25e4174db365 +LLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/md5/2352473188a90f6b1df3613ff9f162ee +LLVM.v12.0.0+0.armv7l-linux-gnueabihf-cxx11.tar.gz/sha512/6f0e5a8eaf0d7976d31648370423caf9518f44182cd45fe7732d918d4cb2fcf302a5e1deb0856beed3064230e41581441a2ca339db7412a636c930e20bc8fefd +LLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/md5/6e9d5b4cda3fc8faf5d3b82d384e69c5 +LLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx03.tar.gz/sha512/ea0ebee79f685ea25d2be85656ae21cf18dac72874342ff960b6fbdc89c60383a2d6af8f36d14621cbc9bd534cbeb0f8a58c791c724e5469aa48d50606c2c08c +LLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/md5/4ab6e621226d158701368af6af0b8c1b +LLVM.v12.0.0+0.armv7l-linux-musleabihf-cxx11.tar.gz/sha512/3ead9d5227bfae81251d5327c98e28a4f888206176835626e24603fa2638354f4bd0f9880fdd14919091c756a9ee5d0901d76af8555b67094cdf7b6094fb2afa +LLVM.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/md5/799676b765c76572ec4217fea32a569f +LLVM.v12.0.0+0.i686-linux-gnu-cxx03.tar.gz/sha512/6a712ae86de5bacacbf805f9f53e7274a9f25c8b0dec28cbad756e6ac3e190ff1e6576a1d132659208f114cd36703bff0f049180b5e1ae7a49e05175db1689a4 +LLVM.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/md5/a14269eaee410d35904760ee26029a13 +LLVM.v12.0.0+0.i686-linux-gnu-cxx11.tar.gz/sha512/bc5208ed6d365da10e7c9f9b4a771cab0ec7f2d340e8c35184e80ab093b7b79fc8e2735e6baf7fde6e7f4910d0fa893012c3635291528a0575ccfeae5a2baece +LLVM.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/md5/8c01b166aeddb75916a24b5bc4a5288d +LLVM.v12.0.0+0.i686-linux-musl-cxx03.tar.gz/sha512/51b6436452cc3dafdd0bdd03852a3ba131740b8bc701abd50d5123d08ff04b8be03051192fff26ccc4c446a3d1b08981fb66619c080d9450e52071dde62fa31a +LLVM.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/md5/b95bf3b5d2a0db37ff16fa6dceb4c55f +LLVM.v12.0.0+0.i686-linux-musl-cxx11.tar.gz/sha512/9fe5a3c4fc758c25eae7fa8886607e8cd926f6d15d65fa1dd2f745a38d885eaf248c2c199cee73bfd25bd98e65392dfde2004a9c63c061aa2c7d8a465b469b0c +LLVM.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/md5/f714f857ac90c159a390d6f5d761e067 +LLVM.v12.0.0+0.i686-w64-mingw32-cxx03.tar.gz/sha512/4befbb7f17f717669eb670cb18b9e60026c84722e0b8d7b4cc91e27c8c05b27d7b04b50b2ef20ffaf30cfb785f951836d08ec824f6b8fa95ff6b30d21c252212 +LLVM.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/md5/9648a00d069ed91628d0214366df6477 +LLVM.v12.0.0+0.i686-w64-mingw32-cxx11.tar.gz/sha512/a5fa4c4015e1ad450767f694cf0ce701aff5c3a20916745f60ad788f933029418b8303dccfe818be482862fb59bc889d8c4c0ffa3f8104a1f957a8f5578bb442 +LLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/md5/1b05656cd5ea85d90c0ff7e0f3d2bb09 +LLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx03.tar.gz/sha512/070628a05d0beb3efb12831725db2da0b55910180290842b63373a39a73e305a6c87b91615ef7f31dd771813e32d6d93b6260a2200ed62ca14c04bf713d775c3 +LLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/md5/0c41e6d77cea62b37d2b04cea3e3e865 +LLVM.v12.0.0+0.powerpc64le-linux-gnu-cxx11.tar.gz/sha512/ec6c2a9e4de3921a2237ae0deefeef084713a0e8afdac63bc82a6ec4954ded1935696ada3e452d8c3929320d33a7ee6a861f3ad969e740e313639f72eaa33678 +LLVM.v12.0.0+0.x86_64-apple-darwin.tar.gz/md5/d716a03e7300f2c8b6cfd157baf82841 +LLVM.v12.0.0+0.x86_64-apple-darwin.tar.gz/sha512/be4bc5164d80db972cd4c0ce7e4325ad058243cc27850ca288635d191c0ac3b3428217623a01a312cfe4700a2af014eca03e06f4a345f52b5308185a38a2de65 +LLVM.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/md5/c4ef15b188097912a8893395e079d6fa +LLVM.v12.0.0+0.x86_64-linux-gnu-cxx03.tar.gz/sha512/2f06bfddbb907de527517b4a455bb7398b36a7bf9f72fcad778f2586425cbe90be9b3eb9d1cc03ff6b7e5fa6d04a0a06988aa9d2003e748163a7e7460102ced7 +LLVM.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/md5/3ec8ed370b0995c3fb3062768d9211c1 +LLVM.v12.0.0+0.x86_64-linux-gnu-cxx11.tar.gz/sha512/6e2414c5c4cc2696c951b928253bbed88b576d207772c2f14e483aa4f84fe16d0b8731c955ba7680596d29b5339f4ef90d1a2f8edac1a196b22923af09f6cbd1 +LLVM.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/md5/a186e057c1141e7efe465be3c07a167a +LLVM.v12.0.0+0.x86_64-linux-musl-cxx03.tar.gz/sha512/5e88b8a5a79889a7d402af9c49a1b7743dafc3572161b3137060066c5de18d48f7e6f6abc837ec1e794e22bb6dee3dd1663526c31b852be48c2c3f9d0ab85505 +LLVM.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/md5/ae4a90d5826c5b3db4085c90f91a42f5 +LLVM.v12.0.0+0.x86_64-linux-musl-cxx11.tar.gz/sha512/5bf3edbd72f86401d0f63803dbb0ef0ba9a835bd8cb9cece09e54807c0966d75b0ba68b6a0b337e40f8f754c04e0b6e95565baa4320a47a2b7f9d69c1e45de61 +LLVM.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/md5/1f3679db43d3b4b2fd2b2a4a8f92ddce +LLVM.v12.0.0+0.x86_64-unknown-freebsd.tar.gz/sha512/5ae1316d5327177975fcb7d4342760b66ba6bf7f38b90cdc04f77a00cb5d924b2dd041c1f354b9855001fae01b8cb301b486ee16db7daf4d0c41fcdf3e78fe39 +LLVM.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/md5/441c0fc39bd0db777bf1c4a05a00d7eb +LLVM.v12.0.0+0.x86_64-w64-mingw32-cxx03.tar.gz/sha512/7cd2556e0a7d6a9ee93cc23ee5e755d7f777edad22b838867d25c00c742e4591dcad40496388a149b54df25aa5697aa025d49a061614ea6d20c67f29ac66a484 +LLVM.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/md5/62f73d2ba5ccae272f6d85c6477d78e9 +LLVM.v12.0.0+0.x86_64-w64-mingw32-cxx11.tar.gz/sha512/a0f47a38994632c36502ec2f1b1d32f3f3c487062c7d47c38318ec6e85eb802a0e9d331b9743611eac86ef6d90c02960a6604f892aa295a88688905af6907b34 diff --git a/deps/checksums/openblas b/deps/checksums/openblas index 722bd059bfd85..ad67b3b6a2fc6 100644 --- a/deps/checksums/openblas +++ b/deps/checksums/openblas @@ -1,94 +1,94 @@ -OpenBLAS.v0.3.13+3.aarch64-apple-darwin-libgfortran5.tar.gz/md5/8604b202881c267dc73330e81722c2d4 -OpenBLAS.v0.3.13+3.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/9adc2e3234d3eeb6b0d970498b4b80427b32252fb76f9b28245c84a589cb20349dde2ff2822a26302bbb97ddcfbfa4ffbf98d6881f3c1684a6acce1fe3c3bd8f -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran3.tar.gz/md5/33e09a2f2d4abac4b272faff4d85ff23 -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/e3faf2f1de1244a6715c2cca032944b2ed0ff03c43bc617d5243738b3b02e4a87c93545beae7d3d5fae829389b20b303c2f3c59617031b3858438b03e19e1182 -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran4.tar.gz/md5/e3f9326cbcf0c1475c3b15498ce7dbc9 -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/fcb338fbf314e9421c711d84078948829936c710335e210d9f5d5a9c3e281f37d50abd6912543857ab325b8d6af7cef3266ea7ef3b74eb46b63b59ccb0c34882 -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran5.tar.gz/md5/b60363440ca1f92ec312bb0f3be60f08 -OpenBLAS.v0.3.13+3.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/45be2d0259ddd67c1f7b53d60dd3af74cb51f2bd83aa308a14e03488452563d0099521101d37ba37e44e1f80981608f1cc8f05539e90b3b7bb53735098b49bee -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran3.tar.gz/md5/f3d5076cc0d15a7516dfcb94214b91e5 -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran3.tar.gz/sha512/6015eb06ce1bb9b63434cd1561e9866a89b30afb104300089b0745a7beabc390415b033f317d687e10894c0b5f73794798ca50d2eeb27e10d03ce5eb4808682e -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran4.tar.gz/md5/579def3457520102a98d4114686b2a19 -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran4.tar.gz/sha512/c8887e1f0331cee22c02e96fa829f82f9fa571f97fcaacee5714da113345ef779c987e4565a09ab84104db7fb08ae741cee118da7e05ee86ebe72c55d36ed245 -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran5.tar.gz/md5/ba72ad025cbf670c15ce092403d6a40c -OpenBLAS.v0.3.13+3.aarch64-linux-musl-libgfortran5.tar.gz/sha512/ba1fbb3e70d63490cc94502651babd71c88f0aa430a334308e9abe5f3fdcb41ba1652fd9cfedb88ba19da460589318bae816f50e8fad917d87f3542d9e15e71b -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/998bcfd194dc81449e7cfdd553128547 -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/34e7730cf5dd58887566890a5ca7571989be29c0d824b6374ff6a06db20218945c868e8b224e9fa8dfc2388e9d3f9f1bba051202cb2ebcf5f0c37d985433d0d9 -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/6d3548f1992a6104e2a929b726b9d4e1 -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/ae7604b788ac0a1210be4c8cfdd1428426c8d8c13839fb2a970c3f3265daa978487c2bd572d83ff926a13f0f01afe49aa8230452002242622e915990b20856f3 -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/f9001a75f9b953bcc80be5b2a429d31b -OpenBLAS.v0.3.13+3.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/8afec322b5922242e225273ec4787a98e1fde9f6c9ebb785fa0e1a579327d7e9a3f7095f0891f4da83e0e75b63224d812984f62930310a27b9da95bdfb883028 -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/daa9a1fb3c4424688b46aec8fd4cee51 -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/6fb73a80b571c2f40a39f512b0626da62a6e10b1ded8e6f816796a9121a03ce84dd1a6a852a89d7815edf867332c60d03843030405d8d5ec0bc4be5e4b5034af -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/a01df5e91de4c24963367ffcfc12dc49 -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/893a5ad53ec1d5d0917b95ea424936778276db7bacfd7f807551de299ad5b886552fe681ea374043156daf763434d78129e5e8e783ef56d360651de8f610b1e5 -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/9d32ba768cb1f3723153a0921f83ddd2 -OpenBLAS.v0.3.13+3.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/1b7b22c5d5827ea542e1a275af1807303614f62c50a3f799ddd099e8546adf7c75ee7771fe627904c28d78bd1ed2a9ee16f11e1e63e2e02567ab725a5b4a723e -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/9471ef8b127fae0d7cd76a876da0e2f1 -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/53e83a7f1abcb2465d2440e6ffcc8981b67908d1920bdd627fa7d09e78388a0d90d6e06881f2f8b187755ca61a144f95e0839358b1890d914b117e13701dc00e -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/4d9125d5a35b37b5bf411257748209b2 -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/419f20c048c2a60b1f75ea095ede7c7079a4711e07850612b916d395b9b9e7014c01328269a13b1025718f7e2fa8f384343d5797e78941b091f806711800ac59 -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/b05d4c436a309f862f0345e6d770e712 -OpenBLAS.v0.3.13+3.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/e136fe5ca3016715d657f792a832099f4e4b8f29b7e5e18b83b4706c9e1f421c9457f50dbf99b940b9663f3316677796eb38c6c391ed2135f308bee1ac59389f -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/a9c01d75a82bad9cdb640402dcad81d9 -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/6143d3e2fc094d837c6d37047496aa3a4f4c5d01f3fb72e47c681c144b6af02c6b0310932910c0f3aac9a7e19c2bc0c14e0f792fc2e9193aaa1448bce6ccb84d -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/c59422761f5b7d9696a4c1c505787f41 -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/22984386ea44e0e07889d89208556cc65af038b34e95f199aacb1499dc7c1e8086c7e2c05179bbd9723f0e40e791a348bbb8db6634c954efe7f79e4676fe36f2 -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/29e90223144b14a357f42e44724c11d8 -OpenBLAS.v0.3.13+3.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/37b36ce6fe8fd14df505da7a0f57bdf5884fe5b030902a95794923a69d30eba7bc93a2da662db5648aa90bc95a88bd95625b3eb2e90a67fc9349f8f0e930ef64 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran3.tar.gz/md5/28791e1d052d430c42220c18b0d6df61 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran3.tar.gz/sha512/679d10e7ae4c2a8d38943ef20eb075ed9bc2ecb74dd4fb8e476c67b07659ce2fab39fb3bd30034dd7ed2d4d4103597a394e868642a92095de00188e373e38cd7 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran4.tar.gz/md5/ca5dca3237f0b718e8f8603c3cb1e472 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran4.tar.gz/sha512/914ab098759866ab3cd368b136ca6d2382a597ef426422314229a5f39344530e7c89f248c011eb183b8bde68e8d2dbd51ed7d0b6b1438c63322a100470378271 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran5.tar.gz/md5/d0fdd71df8ad278b1054fe2a2e133807 -OpenBLAS.v0.3.13+3.i686-linux-gnu-libgfortran5.tar.gz/sha512/5c0cbbe3992b60a5c51760257f2eebf54113db0ad93de3c8f5f9ed1aa64ccb2a5485ccfea9e127ca473d910cddccaa5e278f93c90328fe770c78557c46f7d57b -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran3.tar.gz/md5/215c7e2db8890d637cc63707b13dc0c6 -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran3.tar.gz/sha512/710e60446d05ad5f61e24f14769144ee621729973769f1e970df2fe330f821379af549f9dfbac6bb5034477443c063e0f7bcfe7cfe848f37ea4a9e44fc0af602 -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran4.tar.gz/md5/27a879f4c90c1509365f7b4712ac7313 -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran4.tar.gz/sha512/188fe3ad0b214d4b75f53f63c39183e609f34f8e0d70cce221bd46d3fac659318479413d65f66238f01c4d3c699224ac5d0e007bbfd27bdea527d36a37c22017 -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran5.tar.gz/md5/83547926ba627e621437f7843a8ddac7 -OpenBLAS.v0.3.13+3.i686-linux-musl-libgfortran5.tar.gz/sha512/425e8534e5efdf1c6e10ba63ead9e57e687f0a61892d64de0a36f0beaf845cbd9ad914d564fba5d57a343316c5e6d768af991a15c40cad0b0d00304f4d05f6b8 -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran3.tar.gz/md5/6f1994558d66532e3723d5a4d0bb01ad -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran3.tar.gz/sha512/52de4b2a43e512496a14c8d01987df0d75f78eef9ae273dace45ede477a04ee47ad70535566dd50bf9ea0c752625f8ad57e70d7dbee8f4e123fdb08fd4729b7b -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran4.tar.gz/md5/4a74f60ac55729a0a94d3f664a42ea59 -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran4.tar.gz/sha512/94d77add6def979b01da61026994174f0b9f4a6a4f3d57a3994fcc4091e69b6dcb5dca004ca75fa7fc93ca256847094c99eb97b5ccf274d6412608f0ccd06c2b -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran5.tar.gz/md5/6e01d0fb2859715b6821d216431325af -OpenBLAS.v0.3.13+3.i686-w64-mingw32-libgfortran5.tar.gz/sha512/667ee31f42614a6e99ffbc67668a320aba2b315684c812c3dda18929f2dc1199c56b39cbf012970950a5e5ac12b6f3d4ad6cf126448074b6b0fbe5dd665ce915 -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/e117edbb8c90a7d998c45a6764dc4354 -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/906f73b660439e0f453bd81d6b32cd59f954556a202d1ff7fc28c44d0b3eccfeb94f926eb91515b7b2047c342c152de25d007e3dc5d9b5646368d35c8d491cc7 -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/9c2d20df24b2fbe8a46bff4c2892be4f -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/916340447ef790e0fc80a37ad6b1bc173bcda7176204dac70a62d49176b08a2d90862cbe9587c6704548cdce71f41424d35746e2e73fea19841d26da02afd233 -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/8bbad84a47b5aa9ef3ac7621b5faa190 -OpenBLAS.v0.3.13+3.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/35fadabc402fd38fdcabf91da9d22745d92fe25d434276f79075ed0574ffe6a55964a77a8f50a22a0e5d0aaffbee17b1d5e415d7fd7f4b3f0b09fed3b64256b6 -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran3.tar.gz/md5/0813317427a6a7a49306b0e448c5a5fb -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/50686a37ff7511e786e8544b64d94c02a84f95d75e3dfb477aa3e504c6404ca9e3679add9a8491228e62343cd8e493933399dec654b016b431127171bf94cbcc -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran4.tar.gz/md5/ab6bd7d9c409102bf586a8aed4ebd13a -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/bd9d1d1901004f775df626fb640d8631ccb4de985b5964fe62cf0058e419184f2d9250e20c6341add1add892d2011e0d21d3823536a2b647f7ca78f60db489c8 -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran5.tar.gz/md5/e369283ebd3ebd30fa05204ca53a5cf7 -OpenBLAS.v0.3.13+3.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/24d19a0fc08421493713e3a61b7c9519346d8237e0f74f74fe98bd34cdd0031d084cef7d46f43c53bfb7f24bf7e7bd0899f03df7dd167c4762b0f9c3d4173289 -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran3.tar.gz/md5/8a4063223249acc7be6b0fff2e7204b7 -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/13ca28a88c9f5e61f1716a7244b9085b3e463a658bc414b2d3a16413ab448799081a3d92c7e67c71b702ab5337b5c9399f9a070c0e38d5ceb06526d4739129cf -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran4.tar.gz/md5/84cba3ec45759145675c96c269e48240 -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/a66872e004eeabedc3963d9cb341df2ceb46da66f97a6103fedc7b900adff9b63503b2fed87565cdb972112d881cf668a72a4a666fb16e75abaaee3e8df720d3 -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran5.tar.gz/md5/f71a6b64bca5a25132db4626749020bd -OpenBLAS.v0.3.13+3.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/03a0315a48aaa4424adebc6670e1ec1c2819836eccfb8b8f327f66d8ec482b4ab45b76f1fe8cc6eefe408b33106fa0389690457e047ebbb08c1c8aa66281e87b -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran3.tar.gz/md5/98baf7e5285880268bdf86d5c4fe694b -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran3.tar.gz/sha512/263f4d98fc89c8d7593707b10859c369bf72bd80aeff26f2f7e9484b4360c9faa28ace33ae3cd5a5f0c4870d59c8412e9be3fac212af5c17689bd609d2054481 -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran4.tar.gz/md5/6113194122b3fce00fe129af2ae48526 -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran4.tar.gz/sha512/fd2b93ded2be5a2850cdfe55a02465f41b0bf1f8b5a0d7341ea475de08f870c45ee320d15492a526fd6f4490e2b944898c974a0dcc1a0294e3e585593e4ad734 -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran5.tar.gz/md5/902b38c5eba17b699763936f6f7c4875 -OpenBLAS.v0.3.13+3.x86_64-linux-musl-libgfortran5.tar.gz/sha512/34eeaa9cc9fb7e9b1a2151f98b6d2bf36a6c0edc87e02fd3aa322547be4ea195f2c1739b90a9027dfbc9512f4af9e8d76e6d78c1a1f8cce9173aebcedf47c550 -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/7b01325206d4e9ebc9d8169ab19cafa0 -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/81a34637bd98073e64ecd11682e2ecfa7906f1032cb2549ea72adc83d471790baf3b6c43f6247a33469c7c275fe444f488f0a04139d131fb4a52919a25f05ab0 -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/6df828a5f9cb90e6d897e7934a6d447c -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/5a703ce4e1360ec76c782237e827cd99ad65696a659cfd1dbeb9ad8d1b751c4943e3edde4c53c2f1c17afdcde83bdfae60f6116a3602a96129f16f77e2faf5bc -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/2c9cb0175741399c21f7a685795833b3 -OpenBLAS.v0.3.13+3.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/6f4b51bfa30310c85c813b03e6fa44acae7479935cb9fdc977286519bb00b3860f1ea502a3c2072884739dd108103dcfb9ee167a9d31d1b31fca7f087fc7dc7e -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/ed4b72c7f57927c3b89efcbd7e9bb21b -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/c6663ec291ad053523f6a1d4c5fcbed83c7a412f534db90e0f690582e5ec19c7bcc65c903322e7e2a75a453caf5cdd9251ba7a83de5d44b8cd45ca022c6f7fdb -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/960dca2ea7e3d72ddbe918ed61787f25 -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/a78af513c6b6b5a0fd7fa5f5b5c598d4724025eb12e57653559c772092095b0c8b2e50ea174205d28aef9c3c503999674882c3771f02a2683bdfa62abb1f4474 -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/d3a0f811ae8e70033c9c75c9684dba2e -OpenBLAS.v0.3.13+3.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/0db4a8aba989d291b9ffbb8856f0922b38f84e6d321ef9ffdb56b455dacbf32252109c505e8f1d37f7e75c20d839ae3490a9353bbcfaefe7bab7fbef3b0a0c1f openblas-d2b11c47774b9216660e76e2fc67e87079f26fa1.tar.gz/md5/d50510c8b60b477b1ece4abafe66bf4d openblas-d2b11c47774b9216660e76e2fc67e87079f26fa1.tar.gz/sha512/95ce349353bea5e9c30455410b92fa9ebc833e58163a53a65b396c76fddf19147a323a3c69eea5892354488c67b027e20dc9b03754a0988f3bc8a4e9ad446b8b +OpenBLAS.v0.3.13+5.aarch64-apple-darwin-libgfortran5.tar.gz/md5/bd8b87e018af8cf4da8440d9c2d7ea4b +OpenBLAS.v0.3.13+5.aarch64-apple-darwin-libgfortran5.tar.gz/sha512/b066b590037a2ac6e8cd859ec642a330b4d058b60da2d071353c6dbe7691a8bb31a13fe36a03be3f1db5066ddd636c39911cb827aecb3811b5ff47de6ba3d3d3 +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran3.tar.gz/md5/0bfab1cdeab001382fbc6216a509532f +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran3.tar.gz/sha512/6137d4e861e61ad4ec6e871e7d24bf30979f701e27517b4b93cfea6230f34b70860d2bad8c8adadf426efce49d3348c1970d3bc85072c99aa255fcd6032450c0 +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran4.tar.gz/md5/ca0a14f775d18ef9313fc5a3d1ba36ad +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran4.tar.gz/sha512/74eb80e9f81519c514ddc09940c3ac6d79788ee0de3384e10039f836b806a7d4e521b25095606c366af1b84ef05aea47f6a6e9fb437b3297a4594c3507b36fc3 +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran5.tar.gz/md5/ad2976c0c5e7d5aa9b8d87cc23e9650d +OpenBLAS.v0.3.13+5.aarch64-linux-gnu-libgfortran5.tar.gz/sha512/2eda1e20468ea51d8196e8d2063cd709579aef33dd180957adf749e6a460330d47561b368885444be8a5eaca8c711058769fb8ebdcb9d7e5d7f55649e74c3677 +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran3.tar.gz/md5/9f102704c8730df892ca4cb75d78d2a7 +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran3.tar.gz/sha512/07345f12b03c004ec84e92ba2e4685478e09e13348b6a6c4faf41ddea7ec2bc11e9fbb2234865b931be880ff5a056f4ffa21d01706af46ce983597bddb56f340 +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran4.tar.gz/md5/3d6132e2ec95f7c5d952e512b095abeb +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran4.tar.gz/sha512/b7b4c62ae8040b9290487f3399fdf6fff40c5172e8830d46e7c2d35f1eeae90c54d3a93d297d8e3bb70c8e251cb7ab83fee454b3876443d97cedd8c566325d88 +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran5.tar.gz/md5/8a6e784e1194eee29bc0077b9d9c431d +OpenBLAS.v0.3.13+5.aarch64-linux-musl-libgfortran5.tar.gz/sha512/732cfbf3663717aedb70b9b14041b520a0281e3a8597018205a0dd96d89fc8f307bcb9ed1158da50bf643af6f1518e1cb7c1734ac7966611a4a6e181f1f3ec80 +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran3.tar.gz/md5/64ef9d054ac9090d44c250d5ac773a71 +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran3.tar.gz/sha512/92cace617a0ca6c06fea90848a1b8d5719e5f7ef62112b2c0ffdd34199e3153759a57c8cdd3f26893d880ddb5db2cf9e57963d758a9dc2d8cad3346cf6b5caae +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran4.tar.gz/md5/d9d069d165541e1717e0f4bd2cd7018f +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran4.tar.gz/sha512/6b640b432ff56495610555f6f4cec897c25898e8625f8028dc11e3400bf099533e4a88628de85a852c6c10e76e8defd69cd3b6b5b53a072362fab38dfafebd08 +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran5.tar.gz/md5/d557c68c9d6e619f240239c1e3bdda6f +OpenBLAS.v0.3.13+5.armv6l-linux-gnueabihf-libgfortran5.tar.gz/sha512/a9ee8ed000eb862bc10578526f311cd578d2cb59976b404d370150b97e84348b094852fae000dba4aa83d88b45bd50129da661cde7a1f8120dd1e29db66342cd +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran3.tar.gz/md5/7570b2ae804f57605715f31ca5144ce2 +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran3.tar.gz/sha512/87f169e260093a9652a299ae9b042fab015a21b67bae285bd425bd02471ebe41634f843be18bb4d8cb2fbe2f2ffb062b7de63148ed64fe66f4ba48dd622dd615 +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran4.tar.gz/md5/d2959f5bcb95f9ce759da9941b89dafc +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran4.tar.gz/sha512/dd4b0572c5165e511537f223e2bd2ff9b9c3f9ea241e8fe5c2863064f9dde37245c0e6cb331cd3ac6f02f15b4708bf53dcdd98daeb17f50eecb3abfbfb17a954 +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran5.tar.gz/md5/aa42183091223699052c4011b546f399 +OpenBLAS.v0.3.13+5.armv6l-linux-musleabihf-libgfortran5.tar.gz/sha512/b465abdcf5e876f2faa091927bd40da8a3c99a64d13ebbb1154a9c5d73652791db1b58564ea7bb0b0801af0ff239c8f3530c7784b91c6e2d770258108458c9fc +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran3.tar.gz/md5/9ddcfad4d2a2678acad7af0bd802ab94 +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran3.tar.gz/sha512/6803844189ae00891559ad0dc624e8253c05c0a27b8bf589539164dacb5251f22e6829fade408d1f64e39dd0979fb0be0993da4c96ae91e76e962e9f0f023de2 +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran4.tar.gz/md5/91d4df8a78d2f6295cdd597ff6f3beea +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran4.tar.gz/sha512/670d8bd3e49fc53d68dba3675f1962a01bbb396fe4e36b5169016f61fe4f8528876d0ed88ed4830714029e73e62b49cafbae2ad384eebf90eee1e6f558abd514 +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran5.tar.gz/md5/d08af1ab6eac6b37a9565080d9179616 +OpenBLAS.v0.3.13+5.armv7l-linux-gnueabihf-libgfortran5.tar.gz/sha512/12f2e08fa4c5d040f0992ba99fd19342d27999ffbdd3df4a1b2981a852caf7148b9b6d17747a61a961da427840f77c8867ed82df6a8fe395e54e92f68739afd0 +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran3.tar.gz/md5/db725dfb473c4cda573950b955415102 +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran3.tar.gz/sha512/d9be3863df5dd3ea5282a52489814db24f1a53fc76aaf323aaf6034637053b490dd927b37e71f29ad68cc4a825982d7e846ebe7fc5206d68ba2a74e411afb493 +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran4.tar.gz/md5/8668cfc1158871e4815fc0e169cabcf3 +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran4.tar.gz/sha512/6b345f776f853df1c69f73afeb67e35dc7c928ade07b24b561d238fdde2270c054083b7a3e216ec20071f34fa945141fc5b38af84ce42e57cf9e3a0f1bfea4cd +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran5.tar.gz/md5/00a1d20c390ea1eb8d1005ec9c26e809 +OpenBLAS.v0.3.13+5.armv7l-linux-musleabihf-libgfortran5.tar.gz/sha512/2d0e0880e36be4761f61b27da16b644cb097012ed2b03141b1646f0b1ceed6176030cfb31a45e7a0d5ded99a2d6a8e472bf2e2c5f5e4260ed997e9e88cdc1b70 +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran3.tar.gz/md5/8d67cca00f231c01330b993f1c2b9b39 +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran3.tar.gz/sha512/abbd1b89f7a40b1b72aa9b0a9d57688e5d6d385029e7e2016d31eda866898c42686f1ad1a47d69213c7e79e0e85c1ab74dc5eb467eb07c286ef3153a7dd33113 +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran4.tar.gz/md5/9473d3d6bd2ff41ce7a9bd70077aa884 +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran4.tar.gz/sha512/3a3da3b01dad7b0171e1ecc18bf274a2c9043c756b06da0f140db68342d8fcbd9afcfd1b1b05aa9d3f3c8fa4ce1915ed25dc38671adcf98fef969a106e49470c +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran5.tar.gz/md5/d64ccb11a8ea4c4dba5778f754e3e8f5 +OpenBLAS.v0.3.13+5.i686-linux-gnu-libgfortran5.tar.gz/sha512/8b4759484d705aae68d65a0785af9788c86d3766285c6fe3985837b9320f864be32f09e98707fa6d8614a702d44154019818fa4c44bafb9c54828e25555a4ac2 +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran3.tar.gz/md5/02c1652b95583156ea798d0e0241b979 +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran3.tar.gz/sha512/c9c7ed980170e5b4c23684d3979a972c47ed06c19ef582cbee7130b84511ca110af3408ae5b161162552a55611d7de6007c2a1d6adb4f872f1ccec4f6a3d38cd +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran4.tar.gz/md5/92a0082208291ead889f38ee4eeda56e +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran4.tar.gz/sha512/68cab863ca08fcde9aa75ccf8f34c49bdc4ff48089c982f2c00506765c7d37beaeddfb65e7d31847f1c61ef6390f6ce6fe307c7cf069ef7189ec55d38a56ddd3 +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran5.tar.gz/md5/60e2bb9badf6121387d87bd8b88a63e9 +OpenBLAS.v0.3.13+5.i686-linux-musl-libgfortran5.tar.gz/sha512/13f7aaa870e9d7811ee79f1b8133345e0aa0d0bf4ad20d39acb43723b2bda1b11efaa2c6fec3cd8e2bc83b411be926fa74b39a8fcab1af92ccd0665435b22007 +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran3.tar.gz/md5/f9e29157a222ec195f5d42dbe0472f8d +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran3.tar.gz/sha512/a3b0875554a063a966e03d4a2f3d2dfecd44b049b93a9b627aa0491b70fbe4d1ba04f8b939dd402e22fa6f650cc1d0bf0d5375c4453bf3b8f6a097ec8faf3993 +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran4.tar.gz/md5/ada7c84a9ba17f2af1e54afb65d51790 +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran4.tar.gz/sha512/0ca3f30c5c56c1d3da850f2c077ed76ea27782013d3a5b5253879ed55078a2435d862278bb5021def8d52e4bc2cbd202ba9d8a8f676afef14bac56cd2d5a6f5a +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran5.tar.gz/md5/42944f897776c8f0034fc31d74d1babe +OpenBLAS.v0.3.13+5.i686-w64-mingw32-libgfortran5.tar.gz/sha512/bb3823fc50440a4a3b6624bfd12b9c1018220345ee3a3d7a7f7b84c75812c8f97bd1403aa88754155b3aa52fa0e70435eebea171969f8c4a79b76c582266a764 +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran3.tar.gz/md5/238e8a32a24c6ffb6881866182588846 +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran3.tar.gz/sha512/9da4452924a8513f5f40c1c9350fdda30833a7ac9755421363e74f557944a5022df98881ccb1f9c468481550f8e4cc894d3963df57371a4d8c0dd0ee8cb1de70 +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran4.tar.gz/md5/6d27131cf20d9172ee8486776a768ec1 +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran4.tar.gz/sha512/a10ecd91b98cf33e5541b64a5e4cd26cb7738d751f7c40c8e0ad337214ac9c15101f012c37ac9724c5414bea8f1bec5342c33e9ed1f7ae5f3e3a90e29cada89d +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran5.tar.gz/md5/35d5f8477ea0ac0ce609785811d04164 +OpenBLAS.v0.3.13+5.powerpc64le-linux-gnu-libgfortran5.tar.gz/sha512/77148afb919ece259c35e383e432cebabb65651fdcce00f8f15ec9d8f8805ea0a5615258b400f7ce73ed44405cd9f671b87c8aa015df4c7d417f9b2ee89e06dc +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran3.tar.gz/md5/5b8910928fdf38f2dca382a3ca583414 +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran3.tar.gz/sha512/65303a748366432ac1723009abdcd51674af2e6452522a813b32bd928bbae44de96c9e7279b9cf8e403fdb5adc8a323b1e383275ec5162aaca957fa9e7983116 +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran4.tar.gz/md5/a62af36a018e5e695476bedeb189db4c +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran4.tar.gz/sha512/594cd0536a3200bc452a7c1e26e0f179ba75f86f0ccd17ebc0816ff6bdd70ef4d367c6e68d173fa220cb092c4c65f0ceceaf55aa783032e28c465c060ead63d5 +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran5.tar.gz/md5/aedbf36e1e5e4aff51c7188c9d52c7f6 +OpenBLAS.v0.3.13+5.x86_64-apple-darwin-libgfortran5.tar.gz/sha512/504afca82f8f30b7a93f0fc9fd9fdb2dbcb74b058fde3c3633b2462deb8b45f4c2f4caca5abf644196ac534799e07e1b7b55ce92ba395ff8e851c27d26113a42 +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran3.tar.gz/md5/9fc6ee1c8399a399dc5e6039bd99a3be +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran3.tar.gz/sha512/83896931f1e1f21a3c46a420238d4db2d633402cd72bb15f24d00359d7ff27cfd21f1e51a2e1e1cc95c90cf14ca6181060681784e14ae41d06857e5c732427fe +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran4.tar.gz/md5/e2c0cf837ba543048e66563f339ba674 +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran4.tar.gz/sha512/e63eb5501daadf460288aaab8d75ecfe4c321f775c25bf77836a0fb20cdd98f81adb8660e2b9465278fb0f002ed397f07399a93299b4373d571017511f474637 +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran5.tar.gz/md5/3301d928cce10270fe57dd9e1a83b9cc +OpenBLAS.v0.3.13+5.x86_64-linux-gnu-libgfortran5.tar.gz/sha512/2e2db27c44ca65b428cb081a0f6ad441cba91ac67e7309007870e4811398038bd0fc6db494d200cfa14b624797835fdf4f08fb21a34e3a61ca013e64e259fc9a +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran3.tar.gz/md5/384fbb41d82460762349990c60900fc2 +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran3.tar.gz/sha512/05dceac3d28ab52d5becf51bca4b6696848902e70c44cbc3cc237fe761dea92b44d82b463671cd656ea0b82628c4c4eb7f2cf136f9c653e594bb8f349b46850f +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran4.tar.gz/md5/04e92d94fa5190e6915ff739a723ab54 +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran4.tar.gz/sha512/c49f57d5d35adae65db8a5bb6829b2d3fa806c2232698796d1a7769845f122b1d34a5aa409199fd514364a99d854fa8f8369b0f7445a3a22a828d997a8d9e487 +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran5.tar.gz/md5/26f0bb722acde07d05ea1c35cd976781 +OpenBLAS.v0.3.13+5.x86_64-linux-musl-libgfortran5.tar.gz/sha512/29ba655390118eadd760c2e46a0ad4dd8ed6776a8185e3a6acb5b3fa3542b454f7caf3d3b183ec04ad8cecde774e182d4400be875ff349b00880352a4e4dcc32 +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran3.tar.gz/md5/0d08d7b22e4d6d6a844653718a6beb35 +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran3.tar.gz/sha512/08625e91f84243317e881a798e5c0c9f59ac19ec46c592d15ea105d1c24634fa17e66cfb9ac98a87a1bef14d3f550d278cde31e2cc62855288eb027778044a6f +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran4.tar.gz/md5/5a2484aaedea160beafa0ae928f98bce +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran4.tar.gz/sha512/c5561a01275430fa6361da34f11f0478b343946c08428617d106e36e8ba1514b59628ad2fd798fdd78c0ed79e0d0014da8b08166182bcf88044dedd3357c5026 +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran5.tar.gz/md5/c6f17657a15f180dfe9d911c0b41a244 +OpenBLAS.v0.3.13+5.x86_64-unknown-freebsd-libgfortran5.tar.gz/sha512/3dc411b0914734ec10d89d6acbb5ed70fc80ad8fc48fbdfa8c56dd209cb4c1251060b441d420bf2deb9cc81dc07605fc4036d7ae37d786a1069716f9bbb5870d +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran3.tar.gz/md5/5e1451e34917819fa100a92dffeafea5 +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran3.tar.gz/sha512/eea215ae37897fd03e0acd7b32547d33ee880ee000836632be637d503159bce5d8093a34d588ad4e9b9fa9b75ecebfeb09f633a8266db202076a4eda57be954b +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran4.tar.gz/md5/a34a631f7c912ef84ac9a53720b8f2b4 +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/78ceb1b14d89fb8ada27a1ce195d9e011a592c41079a7790df8cb9c88df57c798883967ee47ecd633d1eb281d3b751e3e41e4a0394b37d9ef511ec032d2ce299 +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/fbfdf0d564cb892aa7d62f9874aad2d7 +OpenBLAS.v0.3.13+5.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/361d1e38445cad0ccd15bb886c7c3a45655ccd83b621cb8d7a50cc5061a05ade9d797f9011894ceede9c782f210c8f320eb1803b4d4620db6087d1bb6e192160 diff --git a/deps/checksums/pcre b/deps/checksums/pcre index 05a06f9844ddf..f7e1fa0c1a3ba 100644 --- a/deps/checksums/pcre +++ b/deps/checksums/pcre @@ -1,3 +1,5 @@ +pcre2-10.36.tar.bz2/md5/bd7e7421ff3fa2e2d5429229ecfad095 +pcre2-10.36.tar.bz2/sha512/fc2a920562c80c3d31cedd94028fab55314ae0fb168cac7178f286c344a11fc514939edc3b83b8e0b57c872db4e595fd5530fd1d4b8c779be629553e9ec965a3 PCRE2.v10.36.0+2.aarch64-apple-darwin.tar.gz/md5/12ac3bee39df3a79f868f6463964953b PCRE2.v10.36.0+2.aarch64-apple-darwin.tar.gz/sha512/a1a1312931deb7f742f80886188babcf9c179ed3f156626fb23d92633fde896d1ee9b2d72cd99ae4a1f8048971b6d939e9b0b10c455d4eeec24b265968593486 PCRE2.v10.36.0+2.aarch64-linux-gnu.tar.gz/md5/32240ccddee3040aeedcbe69ea52fcad @@ -30,5 +32,3 @@ PCRE2.v10.36.0+2.x86_64-unknown-freebsd.tar.gz/md5/97410029c0b6ed5f7fb0d14e1f121 PCRE2.v10.36.0+2.x86_64-unknown-freebsd.tar.gz/sha512/229e910759da2959ddef83ca89e05a050c266b8e755c85dfce6a786658be541911c3b78a0fca7dfdee1b41fbbdccf57da75cf9fe45fd2821dba8d2aaeabfd538 PCRE2.v10.36.0+2.x86_64-w64-mingw32.tar.gz/md5/39827564bca329768e0380bd79b869fe PCRE2.v10.36.0+2.x86_64-w64-mingw32.tar.gz/sha512/4579049b99fca3334d726b0ca1f07524d1643a758e375b5b02b8f294ba7d9c2a4130da1a1523de29033233a8848105b3cb660e15bb4a759593405d805ee99883 -pcre2-10.36.tar.bz2/md5/bd7e7421ff3fa2e2d5429229ecfad095 -pcre2-10.36.tar.bz2/sha512/fc2a920562c80c3d31cedd94028fab55314ae0fb168cac7178f286c344a11fc514939edc3b83b8e0b57c872db4e595fd5530fd1d4b8c779be629553e9ec965a3 diff --git a/deps/checksums/suitesparse b/deps/checksums/suitesparse index 98bf43c0c3a92..25123ba015294 100644 --- a/deps/checksums/suitesparse +++ b/deps/checksums/suitesparse @@ -1,34 +1,34 @@ -SuiteSparse-5.8.1.tar.gz/md5/c414679bbc9432a3def01b31ad921140 -SuiteSparse-5.8.1.tar.gz/sha512/3d986157acd39968216880c2de30c54d72e0addd7318a04948c1b842ad9c876bcde32f292504d4540a4baa998a368dfc0db000606a2d00f61760a92d5b8c1cb8 -SuiteSparse.v5.8.1+0.aarch64-apple-darwin.tar.gz/md5/57fa5164c7ee989ff95571037c0dfcc0 -SuiteSparse.v5.8.1+0.aarch64-apple-darwin.tar.gz/sha512/a12ac3ec77ac0b78595bc247a4fc37b9136e9a5095abf061b3fade60130b153d61b5a3c602be87c7334660b67f3539075975a9d4a1545d8ee5fd62c734941032 -SuiteSparse.v5.8.1+0.aarch64-linux-gnu.tar.gz/md5/a932269a0fb499d931867acc9505e49b -SuiteSparse.v5.8.1+0.aarch64-linux-gnu.tar.gz/sha512/2983c095533f7d8c2fa81779bf907e9024b1bfef58e934a4d524d767911a41f3006babc20530b3b23854d87adce02eb5e7e8a98d4ad3d853b03abc64cd8d5e6b -SuiteSparse.v5.8.1+0.aarch64-linux-musl.tar.gz/md5/ccc8c1b5378f208374c45ceb6c2b38a1 -SuiteSparse.v5.8.1+0.aarch64-linux-musl.tar.gz/sha512/eb357385de23ce864dc15892100372075aeb2ea2dcdc091a24d746d22278593391ff30cfb94b4c68ab66b03414f13b50614312f46b27f972b977541050b96630 -SuiteSparse.v5.8.1+0.armv6l-linux-gnueabihf.tar.gz/md5/ed3ea07e0996126bfac86e3abee78fb5 -SuiteSparse.v5.8.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/d9de5fb0c0627376d0145ef238a1910f8b0d2037180dcf32caf2bae32600521641abcf20d24d725326fa9bbb52581bb6a4bfaccad292de875cef54b3d721d733 -SuiteSparse.v5.8.1+0.armv6l-linux-musleabihf.tar.gz/md5/a71b0a47cbc98144f52229e10f4cd20d -SuiteSparse.v5.8.1+0.armv6l-linux-musleabihf.tar.gz/sha512/1c61f4ec94ea8adbd2aef50a6f42dd767325400579ff91019c7a5d2555fac5abf17a05201b22b1ff389ce795267daffbef2d961eb46125348ad64032133797b9 -SuiteSparse.v5.8.1+0.armv7l-linux-gnueabihf.tar.gz/md5/bd585f667a26df26db98ffab82d3e40f -SuiteSparse.v5.8.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/1a7b1d0fb7cc5c308a10384a8a8c48cb789ab40d31693722feb01d14ee2781cacc74f0d3082f2e7149805d303002e05e70ca7c9ce715fdc93cbfdc92b84ff03f -SuiteSparse.v5.8.1+0.armv7l-linux-musleabihf.tar.gz/md5/960379f40ad66b94004c7201a0a0bd13 -SuiteSparse.v5.8.1+0.armv7l-linux-musleabihf.tar.gz/sha512/99745a0f4422f9ecb86a6c246cf0a1e5f02151adb5f17b600515b7fa220cdb3e7d709f769270af1665d693955500e27e0662ea97069affe209c4a50e4381ec92 -SuiteSparse.v5.8.1+0.i686-linux-gnu.tar.gz/md5/55ad27f4ac55e6c759160742904958ae -SuiteSparse.v5.8.1+0.i686-linux-gnu.tar.gz/sha512/84b14edf20a9fa9be0fec034866bf469ae7b07924e28fee6d5c4fa5c70826b4ac68c0c7abd5496b76f342c93d1b85f2c2f601ede71c5fba484f6776aa0ad04ab -SuiteSparse.v5.8.1+0.i686-linux-musl.tar.gz/md5/db6ec8eb4aee46f158abe36e593d9c20 -SuiteSparse.v5.8.1+0.i686-linux-musl.tar.gz/sha512/9ecdd62891730f9b587a3f6debfc859c51bc1e6fc7a925339442f25c9c9be587e5df90572f87236fc79302dd2435990d6d054a494ff3498fb31d83b0be11d0f9 -SuiteSparse.v5.8.1+0.i686-w64-mingw32.tar.gz/md5/379dbd76bc5b33b2f00e25b93f15d7c1 -SuiteSparse.v5.8.1+0.i686-w64-mingw32.tar.gz/sha512/91b4a4b3d5fd710510bba2ffa7b19bdf2860fb4f6c1946dcb421e4143097e7b77ee3bc780ed89726152f2c5e72d4e897e5eaa152b1d97176ed9d0e4fb2cdb6c6 -SuiteSparse.v5.8.1+0.powerpc64le-linux-gnu.tar.gz/md5/13e5e383de77448d7fca6802a27e2fc9 -SuiteSparse.v5.8.1+0.powerpc64le-linux-gnu.tar.gz/sha512/412611fd82923e042001774cbc7951e8d6777843b308f6b25cf361c05b44d1dafc1639e7526b0871ec637f15ac8fcd247e9201ba0d75bfe0bf0900a9dace1001 -SuiteSparse.v5.8.1+0.x86_64-apple-darwin.tar.gz/md5/d266370cc574c8ca8b2b8a94d6b877f4 -SuiteSparse.v5.8.1+0.x86_64-apple-darwin.tar.gz/sha512/2377d662f91d01229e3c44ec1c5624b6361e823ff90d625acc3bab8f68ada1b3b7b67f4e56c8896f890e5780bd2fcb494b5a1f91c9c7803715eac2a2a4bb938f -SuiteSparse.v5.8.1+0.x86_64-linux-gnu.tar.gz/md5/2545d16665a42f36fbbad9198a9668e5 -SuiteSparse.v5.8.1+0.x86_64-linux-gnu.tar.gz/sha512/66cf497a002b566a681531873da0b5dc3b4f79414068b7ae53845325afb2f56a55069ff5ba5f47de0eb961af4df18cf8495019150f163213d32aa5b12c511ce3 -SuiteSparse.v5.8.1+0.x86_64-linux-musl.tar.gz/md5/8a8ade173d751514e03a6987aee56ca1 -SuiteSparse.v5.8.1+0.x86_64-linux-musl.tar.gz/sha512/7393063fd2f88bf5dbe1378d6d34206bde446f1ed971d2dd334c3cca96075334f4f8ca69f7d406d532a631fd8a76d739df27dab7928e596a1d38ba9c96fbc9d6 -SuiteSparse.v5.8.1+0.x86_64-unknown-freebsd.tar.gz/md5/674bbae00649ff495aed5fb57de80966 -SuiteSparse.v5.8.1+0.x86_64-unknown-freebsd.tar.gz/sha512/4a1ee55b55149549cbe022b3354bb136b7bfbbbcef8254c2ec91aad8c921c689dbedd208003c8805c320e5d3319e9b36945c117eaac4a634f31e76ff3e579f3d -SuiteSparse.v5.8.1+0.x86_64-w64-mingw32.tar.gz/md5/f52e3758656acf8a4342f8a34584c266 -SuiteSparse.v5.8.1+0.x86_64-w64-mingw32.tar.gz/sha512/a9a335bae4b588147bf11b301d11e4d3663011c3f7bd449382b09bba3eeb108501ef1244477f11c408d463bc61c2eff613a182bcc56ff2acae630d84483bb724 +SuiteSparse-5.10.1.tar.gz/md5/68bb912f3cf3d2b01f30ebafef690302 +SuiteSparse-5.10.1.tar.gz/sha512/8f85c6d63b76cba95707dfa732c51200df7794cb4c2599dbd92100475747b8d02b05089a47096e85c60b89bc852a8e768e0670f24902a82d29494a80ccf2bb5f +SuiteSparse.v5.10.1+0.aarch64-apple-darwin.tar.gz/md5/b9392f8e71c0c40d37489e7b2071c5ad +SuiteSparse.v5.10.1+0.aarch64-apple-darwin.tar.gz/sha512/109d67cb009e3b2931b94d63cbdaaee29d60dc190b731ebe3737181cd48d913b8a1333043c67be8179c73e4d3ae32ed1361ab4e34312c0f42e4b29f8a7afda3e +SuiteSparse.v5.10.1+0.aarch64-linux-gnu.tar.gz/md5/1b2651ede4a74cd57f65505a65093314 +SuiteSparse.v5.10.1+0.aarch64-linux-gnu.tar.gz/sha512/753f986a749d139f9a6baedac059d8ed8efdd716ed28eacdbf00e6ebe863b4e17467f01a9693dcb39571d38b4b5c4c1375dbb790b88a7e704116e3fe83f7ff3e +SuiteSparse.v5.10.1+0.aarch64-linux-musl.tar.gz/md5/051ff9bbbc95c57d58563df8a2c8eedd +SuiteSparse.v5.10.1+0.aarch64-linux-musl.tar.gz/sha512/855979ed8d6290c529d9c9e82944fb15c88f9d9d8da7db1fa2fc34efb0ed985fc6554312882107f26956f2a18ae985918909cd834e068b874906c21a0f53b6c9 +SuiteSparse.v5.10.1+0.armv6l-linux-gnueabihf.tar.gz/md5/dbc5fb4844077084663612af26e180ce +SuiteSparse.v5.10.1+0.armv6l-linux-gnueabihf.tar.gz/sha512/b906f7275ab58006acd52927e7e04c79eec59b5f28e9d7e5d5b8556c0eedd54cfff87e494373702c205afa2384ee6b0f2bb5e811fd440b1b50d5c9eee1b47b99 +SuiteSparse.v5.10.1+0.armv6l-linux-musleabihf.tar.gz/md5/7770d256e76d5ce1484c3781508cc3ed +SuiteSparse.v5.10.1+0.armv6l-linux-musleabihf.tar.gz/sha512/4f1d46cc8da5a7eff665b4bb96f9e21319f39231f98a6164d8c3d654d5b6f93c3e4477f55a39a80b7f8125a78d690cc5a1cc58f29143ba4c109a4182d7fa2110 +SuiteSparse.v5.10.1+0.armv7l-linux-gnueabihf.tar.gz/md5/ee1fa978bcfb264842749f915bbefd77 +SuiteSparse.v5.10.1+0.armv7l-linux-gnueabihf.tar.gz/sha512/9592a42f6474fd89eea1144f62ecc2a23796ad251173a9c36ccbc9bc18dd88687ce49f51528974f56b5652e2ab15f0aa41634513f2cc0b3c54259de3b68350bd +SuiteSparse.v5.10.1+0.armv7l-linux-musleabihf.tar.gz/md5/30f708421b92158c7741c82576e9047b +SuiteSparse.v5.10.1+0.armv7l-linux-musleabihf.tar.gz/sha512/d8793d48757dbb62aa7a21c215b6d6e63a26ce4ba740f1f7f42a3e485ad3d9628744f021ad9cc96e29c8c88bfb2f02ea92865c26b971ca739d3c05c7f28875d9 +SuiteSparse.v5.10.1+0.i686-linux-gnu.tar.gz/md5/9018b6168b9a687bab0c9a9cbf45afba +SuiteSparse.v5.10.1+0.i686-linux-gnu.tar.gz/sha512/308a92f441af6855517c40c6871b4935251677c05cc082c21fd1249e0137b635fa524f60cad61c7524026301a6de7ffea0ad1f4b9a4d9d6e3ced3f332a6719d4 +SuiteSparse.v5.10.1+0.i686-linux-musl.tar.gz/md5/99143f8d6de4f071ffa19942252b6dec +SuiteSparse.v5.10.1+0.i686-linux-musl.tar.gz/sha512/9fb719fffea03296dfac8bc221bafc3ed8f7791749eca6c4b00265994de1be5d242e7e5184693603c745b39c4538feb11ab283204e0e33df2745f904cf0c7252 +SuiteSparse.v5.10.1+0.i686-w64-mingw32.tar.gz/md5/d049c943fbda2c8380dea33e16569275 +SuiteSparse.v5.10.1+0.i686-w64-mingw32.tar.gz/sha512/174768464432b991ecff88d5e5126caca83672fb5173115de59bc2387ef8aa75a56d3e84957fce625fabaf50ba462549f2ea828aea7258be7513835b7fea2e31 +SuiteSparse.v5.10.1+0.powerpc64le-linux-gnu.tar.gz/md5/f01f7e134f8ee77849f3a46e773c1ff2 +SuiteSparse.v5.10.1+0.powerpc64le-linux-gnu.tar.gz/sha512/dc0339f2b35f05d49fbd1dcf1822c774a07af122fabc8e00eb7435dc53fcf82b3c1ec24e2bb41b1a58d3f8ab8903830eb7ece19dc6fce3f5e73d90a3dc3c4194 +SuiteSparse.v5.10.1+0.x86_64-apple-darwin.tar.gz/md5/02975a8670660c5e79eab0a70b051a0b +SuiteSparse.v5.10.1+0.x86_64-apple-darwin.tar.gz/sha512/e55685ed7a63318c5baa326795503f13f031e0a617c045c972d5c89252ab51e7325e2b0425ca10dfbd59e79c5b4200545f5a4944fddd376e7610b6ebf74ded14 +SuiteSparse.v5.10.1+0.x86_64-linux-gnu.tar.gz/md5/6c111d315fb25c529710722bd5ae6af0 +SuiteSparse.v5.10.1+0.x86_64-linux-gnu.tar.gz/sha512/c971aed91bd695a0f7f735f58ddcb075d32b9522a8a50a30ad383ba5ce2c8e572fec97644e6cb85745206f4e5da72d7865d9a9724eb63ce3c04e90a4eedc90c9 +SuiteSparse.v5.10.1+0.x86_64-linux-musl.tar.gz/md5/7c98daf0edfad31764c3078e6351b521 +SuiteSparse.v5.10.1+0.x86_64-linux-musl.tar.gz/sha512/2c4b3cae1bd8d1ce62dae6aeca3ffbf90c26a1b01c0da4fb7761d6fe4293b8fad0b6fbfd5f930cefe6ccaef7546a482022ff2f50dc59ecf17c5c0dfc6a5961f5 +SuiteSparse.v5.10.1+0.x86_64-unknown-freebsd.tar.gz/md5/aeca88a7bc3f9d239c61084996ce9182 +SuiteSparse.v5.10.1+0.x86_64-unknown-freebsd.tar.gz/sha512/0bee1ee07c3883fe28dd322c40195be9adb757d6dab3eb1730d7b0ff65dd4517520047696ccdda4ca618e671d898cdb45b787094594e142cb4b176549a74200b +SuiteSparse.v5.10.1+0.x86_64-w64-mingw32.tar.gz/md5/63e449554eee134757e3d50ca8b5f47d +SuiteSparse.v5.10.1+0.x86_64-w64-mingw32.tar.gz/sha512/95b58df4fe7520e2b526f9e3b199253909992789cd24ecca814ddb9a0c0bb37ff93c1de40239e5295a8503613cdb2431a87f0a70a3d657d94d4661f1778797f2 diff --git a/deps/csl.mk b/deps/csl.mk index 095d4ceec4a1e..423201cbb5a0c 100644 --- a/deps/csl.mk +++ b/deps/csl.mk @@ -19,48 +19,34 @@ $$(build_shlibdir)/$(1): | $$(build_shlibdir) [ -n "$$$${SRC_LIB}" ] && cp $$$${SRC_LIB} $$(build_shlibdir) endef -ifeq ($(OS),WINNT) -define gen_libname -$$(if $(2),lib$(1)-$(2).$(SHLIB_EXT),lib$(1).$(SHLIB_EXT)) -endef -else ifeq ($(OS),Darwin) -define gen_libname -$$(if $(2),lib$(1).$(2).$(SHLIB_EXT),lib$(1).$(SHLIB_EXT)) -endef -else -define gen_libname -$$(if $(2),lib$(1).$(SHLIB_EXT).$(2),lib$(1).$(SHLIB_EXT)) -endef -endif - # libgfortran has multiple names; we're just going to copy any version we can find # Since we're only looking in the location given by `$(FC)` this should only succeed for one. -$(eval $(call copy_csl,$(call gen_libname,gfortran,3))) -$(eval $(call copy_csl,$(call gen_libname,gfortran,4))) -$(eval $(call copy_csl,$(call gen_libname,gfortran,5))) +$(eval $(call copy_csl,$(call versioned_libname,libgfortran,3))) +$(eval $(call copy_csl,$(call versioned_libname,libgfortran,4))) +$(eval $(call copy_csl,$(call versioned_libname,libgfortran,5))) # These are all libraries that we should always have -$(eval $(call copy_csl,$(call gen_libname,quadmath,0))) -$(eval $(call copy_csl,$(call gen_libname,stdc++,6))) -$(eval $(call copy_csl,$(call gen_libname,ssp,0))) -$(eval $(call copy_csl,$(call gen_libname,atomic,1))) -$(eval $(call copy_csl,$(call gen_libname,gomp,1))) +$(eval $(call copy_csl,$(call versioned_libname,libquadmath,0))) +$(eval $(call copy_csl,$(call versioned_libname,libstdc++,6))) +$(eval $(call copy_csl,$(call versioned_libname,libssp,0))) +$(eval $(call copy_csl,$(call versioned_libname,libatomic,1))) +$(eval $(call copy_csl,$(call versioned_libname,libgomp,1))) ifeq ($(OS),WINNT) # Windwos has special gcc_s names ifeq ($(ARCH),i686) -$(eval $(call copy_csl,$(call gen_libname,gcc_s_sjlj,1))) +$(eval $(call copy_csl,$(call versioned_libname,libgcc_s_sjlj,1))) else -$(eval $(call copy_csl,$(call gen_libname,gcc_s_seh,1))) +$(eval $(call copy_csl,$(call versioned_libname,libgcc_s_seh,1))) endif else -$(eval $(call copy_csl,$(call gen_libname,gcc_s,1))) +$(eval $(call copy_csl,$(call versioned_libname,libgcc_s,1))) endif # winpthread is only Windows, pthread is only others ifeq ($(OS),WINNT) -$(eval $(call copy_csl,$(call gen_libname,winpthread,1))) +$(eval $(call copy_csl,$(call versioned_libname,libwinpthread,1))) else -$(eval $(call copy_csl,$(call gen_libname,pthread,0))) +$(eval $(call copy_csl,$(call versioned_libname,libpthread,0))) endif get-csl: diff --git a/deps/libsuitesparse.mk b/deps/libsuitesparse.mk new file mode 100644 index 0000000000000..42ae7807bb4ec --- /dev/null +++ b/deps/libsuitesparse.mk @@ -0,0 +1,112 @@ +## LIBSUITESPARSE ## + +ifeq ($(USE_BLAS64), 1) +UMFPACK_CONFIG := -DLONGBLAS='long long' +CHOLMOD_CONFIG := -DLONGBLAS='long long' +SPQR_CONFIG := -DLONGBLAS='long long' +UMFPACK_CONFIG += -DSUN64 +CHOLMOD_CONFIG += -DSUN64 +SPQR_CONFIG += -DSUN64 +endif + +# Disable linking to libmetis +CHOLMOD_CONFIG += -DNPARTITION + +ifneq ($(USE_BINARYBUILDER_LIBSUITESPARSE), 1) + +LIBSUITESPARSE_PROJECTS := AMD BTF CAMD CCOLAMD COLAMD CHOLMOD LDL KLU UMFPACK RBio SPQR +LIBSUITESPARSE_LIBS := $(addsuffix .*$(SHLIB_EXT)*,suitesparseconfig amd btf camd ccolamd colamd cholmod klu ldl umfpack rbio spqr) + +SUITE_SPARSE_LIB := $(LDFLAGS) -L"$(abspath $(BUILDDIR))/SuiteSparse-$(LIBSUITESPARSE_VER)/lib" +ifeq ($(OS), Darwin) +SUITE_SPARSE_LIB += $(RPATH_ESCAPED_ORIGIN) +endif +LIBSUITESPARSE_MFLAGS := CC="$(CC)" CXX="$(CXX)" F77="$(FC)" AR="$(AR)" RANLIB="$(RANLIB)" BLAS="-L$(build_shlibdir) -lblastrampoline" LAPACK="-L$(build_shlibdir) -lblastrampoline" \ + LDFLAGS="$(SUITE_SPARSE_LIB)" CFOPENMP="" CUDA=no CUDA_PATH="" \ + UMFPACK_CONFIG="$(UMFPACK_CONFIG)" CHOLMOD_CONFIG="$(CHOLMOD_CONFIG)" SPQR_CONFIG="$(SPQR_CONFIG)" +ifeq ($(OS),WINNT) +LIBSUITESPARSE_MFLAGS += UNAME=Windows +else +LIBSUITESPARSE_MFLAGS += UNAME=$(OS) +endif + +$(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz: | $(SRCCACHE) + $(JLDOWNLOAD) $@ https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v$(LIBSUITESPARSE_VER).tar.gz + +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/source-extracted: $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz + $(JLCHECKSUM) $< + mkdir -p $(dir $@) + $(TAR) -C $(dir $@) --strip-components 1 -zxf $< + echo 1 > $@ + +checksum-libsuitesparse: $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz + $(JLCHECKSUM) $< + +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/SuiteSparse-shlib.patch-applied: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/source-extracted + cd $(dir $@) && patch -p1 < $(SRCDIR)/patches/SuiteSparse-shlib.patch + echo 1 > $@ +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/SuiteSparse-shlib.patch-applied + +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled: | $(build_prefix)/manifest/blastrampoline + +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/source-extracted + $(MAKE) -C $(dir $<)SuiteSparse_config library config $(LIBSUITESPARSE_MFLAGS) + $(INSTALL_NAME_CMD)libsuitesparseconfig.$(SHLIB_EXT) $(dir $<)lib/libsuitesparseconfig.$(SHLIB_EXT) + for PROJ in $(LIBSUITESPARSE_PROJECTS); do \ + $(MAKE) -C $(dir $<)$${PROJ} library $(LIBSUITESPARSE_MFLAGS) || exit 1; \ + $(INSTALL_NAME_CMD)lib`echo $${PROJ} | tr A-Z a-z`.$(SHLIB_EXT) $(dir $<)lib/lib`echo $${PROJ} | tr A-Z a-z`.$(SHLIB_EXT) || exit 1; \ + done + echo 1 > $@ + +ifeq ($(OS),WINNT) +LIBSUITESPARSE_SHLIB_ENV:=PATH="$(abspath $(dir $<))lib:$(build_bindir):$(PATH)" +else +LIBSUITESPARSE_SHLIB_ENV:=LD_LIBRARY_PATH="$(build_shlibdir)" +endif +$(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-checked: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled + for PROJ in $(LIBSUITESPARSE_PROJECTS); do \ + $(LIBSUITESPARSE_SHLIB_ENV) $(MAKE) -C $(dir $<)$${PROJ} default $(LIBSUITESPARSE_MFLAGS) || exit 1; \ + done + echo 1 > $@ + +UNINSTALL_suitesparse := $(LIBSUITESPARSE_VER) manual_suitesparse $(LIBSUITESPARSE_LIBS) + +$(build_prefix)/manifest/libsuitesparse: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled | $(build_prefix)/manifest $(build_shlibdir) + for lib in $(LIBSUITESPARSE_LIBS); do \ + cp -a $(dir $<)lib/lib$${lib} $(build_shlibdir) || exit 1; \ + done + #cp -a $(dir $<)lib/* $(build_shlibdir) + #cp -a $(dir $<)include/* $(build_includedir) + echo $(UNINSTALL_libsuitesparse) > $@ + +clean-libsuitesparse: uninstall-libsuitesparse + -rm $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled + -rm -fr $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/lib + -rm -fr $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/include + -$(MAKE) -C $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER) clean + +distclean-libsuitesparse: + -rm -rf $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz \ + $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER) + +get-libsuitesparse: $(SRCCACHE)/SuiteSparse-$(LIBSUITESPARSE_VER).tar.gz +extract-libsuitesparse: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/source-extracted +configure-libsuitesparse: extract-libsuitesparse +compile-libsuitesparse: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-compiled +fastcheck-libsuitesparse: #none +check-libsuitesparse: $(BUILDDIR)/SuiteSparse-$(LIBSUITESPARSE_VER)/build-checked +install-libsuitesparse: $(build_prefix)/manifest/libsuitesparse + +else # USE_BINARYBUILDER_LIBSUITESPARSE + +$(eval $(call bb-install,libsuitesparse,LIBSUITESPARSE,false)) + +# libsuitesparse depends on blastrampoline +compile-libsuitesparse: | $(build_prefix)/manifest/blastrampoline +endif + +define manual_libsuitesparse +uninstall-libsuitesparse: + -rm $(build_prefix)/manifest/libsuitesparse + -rm $(addprefix $(build_shlibdir)/lib,$3) +endef diff --git a/deps/llvm.mk b/deps/llvm.mk index 461f04b6b2503..c436a1a08a78c 100644 --- a/deps/llvm.mk +++ b/deps/llvm.mk @@ -457,77 +457,6 @@ $$(LLVM_BUILDDIR_withtype)/build-compiled: $$(LLVM_SRC_DIR)/$1.patch-applied LLVM_PATCH_PREV := $$(LLVM_SRC_DIR)/$1.patch-applied endef -ifeq ($(LLVM_VER_SHORT),8.0) -$(eval $(call LLVM_PATCH,llvm-D27629-AArch64-large_model_6.0.1)) -$(eval $(call LLVM_PATCH,llvm8-D34078-vectorize-fdiv)) -$(eval $(call LLVM_PATCH,llvm-7.0-D44650)) # mingw32 build fix -$(eval $(call LLVM_PATCH,llvm-6.0-DISABLE_ABI_CHECKS)) -$(eval $(call LLVM_PATCH,llvm7-D50010-VNCoercion-ni)) -$(eval $(call LLVM_PATCH,llvm-8.0-D50167-scev-umin)) -$(eval $(call LLVM_PATCH,llvm7-windows-race)) -$(eval $(call LLVM_PATCH,llvm-D57118-powerpc)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm-exegesis-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm-test-plugin-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm-8.0-D66401-mingw-reloc)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm7-revert-D44485)) -$(eval $(call LLVM_PATCH,llvm-8.0-D63688-wasm-isLocal)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D55758-tablegen-cond)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D59389-refactor-wmma)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D59393-mma-ptx63-fix)) # remove for 9.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D66657-codegen-degenerate)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D71495-vectorize-freduce)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D75072-SCEV-add-type)) -$(eval $(call LLVM_PATCH,llvm-8.0-D65174-limit-merge-stores)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-julia-tsan-custom-as)) -endif # LLVM_VER 8.0 - -ifeq ($(LLVM_VER_SHORT),9.0) -$(eval $(call LLVM_PATCH,llvm-D27629-AArch64-large_model_6.0.1)) -$(eval $(call LLVM_PATCH,llvm8-D34078-vectorize-fdiv)) -$(eval $(call LLVM_PATCH,llvm-7.0-D44650)) # mingw32 build fix -$(eval $(call LLVM_PATCH,llvm-6.0-DISABLE_ABI_CHECKS)) -$(eval $(call LLVM_PATCH,llvm9-D50010-VNCoercion-ni)) -$(eval $(call LLVM_PATCH,llvm-exegesis-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm-test-plugin-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm7-revert-D44485)) -$(eval $(call LLVM_PATCH,llvm-8.0-D66657-codegen-degenerate)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-8.0-D71495-vectorize-freduce)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-D75072-SCEV-add-type)) -$(eval $(call LLVM_PATCH,llvm-9.0-D65174-limit-merge-stores)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm9-D71443-PPC-MC-redef-symbol)) # remove for 10.0 -$(eval $(call LLVM_PATCH,llvm-9.0-D78196)) # remove for 11.0 -$(eval $(call LLVM_PATCH,llvm-julia-tsan-custom-as)) -$(eval $(call LLVM_PATCH,llvm-9.0-D85499)) # landed as D85553 -$(eval $(call LLVM_PATCH,llvm-D80101)) # remove for LLVM 12 -$(eval $(call LLVM_PATCH,llvm-D84031)) # remove for LLVM 12 -$(eval $(call LLVM_PATCH,llvm-rGb498303066a6-gcc11-header-fix)) # remove for LLVM 12 -endif # LLVM_VER 9.0 - -ifeq ($(LLVM_VER_SHORT),10.0) -$(eval $(call LLVM_PATCH,llvm-D27629-AArch64-large_model_6.0.1)) -$(eval $(call LLVM_PATCH,llvm8-D34078-vectorize-fdiv)) -$(eval $(call LLVM_PATCH,llvm-7.0-D44650)) # mingw32 build fix -$(eval $(call LLVM_PATCH,llvm-6.0-DISABLE_ABI_CHECKS)) -$(eval $(call LLVM_PATCH,llvm9-D50010-VNCoercion-ni)) -$(eval $(call LLVM_PATCH,llvm-exegesis-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm-test-plugin-mingw)) # mingw build -$(eval $(call LLVM_PATCH,llvm7-revert-D44485)) -$(eval $(call LLVM_PATCH,llvm-D75072-SCEV-add-type)) -$(eval $(call LLVM_PATCH,llvm-10.0-PPC_SELECT_CC)) # delete for LLVM 11 -$(eval $(call LLVM_PATCH,llvm-10.0-PPC-LI-Elimination)) # delete for LLVM 11 -$(eval $(call LLVM_PATCH,llvm-julia-tsan-custom-as)) -$(eval $(call LLVM_PATCH,llvm-D80101)) # remove for LLVM 12 -$(eval $(call LLVM_PATCH,llvm-D84031)) # remove for LLVM 12 -$(eval $(call LLVM_PATCH,llvm-10-D85553)) # remove for LLVM 12 -$(eval $(call LLVM_PATCH,llvm-10-r_aarch64_prel32)) # remove for LLVM 11 -$(eval $(call LLVM_PATCH,llvm-10-r_ppc_rel)) # remove for LLVM 11 -$(eval $(call LLVM_PATCH,llvm-10-unique_function_clang-sa)) -ifeq ($(BUILD_LLVM_CLANG),1) -$(eval $(call LLVM_PATCH,llvm-D88630-clang-cmake)) -endif -$(eval $(call LLVM_PATCH,llvm-rGb498303066a6-gcc11-header-fix)) # remove for LLVM 12 -endif # LLVM_VER 10.0 - ifeq ($(LLVM_VER_SHORT),11.0) ifeq ($(LLVM_VER_PATCH), 0) $(eval $(call LLVM_PATCH,llvm-D27629-AArch64-large_model_6.0.1)) # remove for LLVM 12 @@ -561,7 +490,7 @@ $(eval $(call LLVM_PATCH,llvm-11-ppc-half-ctr)) # remove for LLVM 12 $(eval $(call LLVM_PATCH,llvm-11-ppc-sp-from-bp)) # remove for LLVM 12 $(eval $(call LLVM_PATCH,llvm-rGb498303066a6-gcc11-header-fix)) # remove for LLVM 12 $(eval $(call LLVM_PATCH,llvm-11-D94813-mergeicmps)) -$(eval $(call LLVM_PATCH,llvm-11-D94980-CTR-half)) +$(eval $(call LLVM_PATCH,llvm-11-D94980-CTR-half)) # remove for LLVM 12 $(eval $(call LLVM_PATCH,llvm-11-D94058-sext-atomic-ops)) # remove for LLVM 12 $(eval $(call LLVM_PATCH,llvm-11-D96283-dagcombine-half)) # remove for LLVM 12 $(eval $(call LLVM_PROJ_PATCH,llvm-11-AArch64-FastIsel-bug)) @@ -570,6 +499,20 @@ $(eval $(call LLVM_PROJ_PATCH,llvm-11-D97571-AArch64-loh)) # remove for LLVM 13 $(eval $(call LLVM_PROJ_PATCH,llvm-11-aarch64-addrspace)) # remove for LLVM 13 endif # LLVM_VER 11.0 +ifeq ($(LLVM_VER_SHORT),12.0) +$(eval $(call LLVM_PATCH,llvm7-revert-D44485)) # Needs upstreaming +$(eval $(call LLVM_PATCH,llvm-12-D75072-SCEV-add-type)) +$(eval $(call LLVM_PATCH,llvm-julia-tsan-custom-as)) +ifeq ($(BUILD_LLVM_CLANG),1) +$(eval $(call LLVM_PATCH,llvm-D88630-clang-cmake)) +endif +$(eval $(call LLVM_PATCH,llvm-11-D93154-globalisel-as)) +$(eval $(call LLVM_PATCH,llvm-11-D94813-mergeicmps)) +$(eval $(call LLVM_PROJ_PATCH,llvm-11-AArch64-FastIsel-bug)) +$(eval $(call LLVM_PATCH,llvm-12-D97435-AArch64-movaddrreg)) +$(eval $(call LLVM_PROJ_PATCH,llvm-11-D97571-AArch64-loh)) # remove for LLVM 13 +$(eval $(call LLVM_PROJ_PATCH,llvm-11-aarch64-addrspace)) # remove for LLVM 13 +endif # LLVM_VER 12.0 # Add a JL prefix to the version map. DO NOT REMOVE ifneq ($(LLVM_VER), svn) @@ -610,7 +553,7 @@ LLVM_INSTALL = \ cp -r $$(LLVM_SRC_DIR)/utils/lit $2$$(build_depsbindir)/ && \ $$(CMAKE) -DCMAKE_INSTALL_PREFIX="$2$$(build_prefix)" -P cmake_install.cmake ifeq ($(OS), WINNT) -LLVM_INSTALL += && cp $2$$(build_shlibdir)/LLVM.dll $2$$(build_depsbindir) +LLVM_INSTALL += && cp $2$$(build_shlibdir)/libLLVM.dll $2$$(build_depsbindir) endif ifeq ($(OS),Darwin) # https://github.com/JuliaLang/julia/issues/29981 @@ -657,10 +600,14 @@ else # USE_BINARYBUILDER_LLVM ifeq ($(LLVM_ASSERTIONS), 1) LLVM_JLL_DOWNLOAD_NAME := libLLVM_assert LLVM_JLL_VER := $(LLVM_ASSERT_JLL_VER) +LLVM_TOOLS_JLL_DOWNLOAD_NAME := LLVM_assert +LLVM_TOOLS_JLL_VER := $(LLVM_TOOLS_ASSERT_JLL_VER) endif $(eval $(call bb-install,llvm,LLVM,false,true)) $(eval $(call bb-install,clang,CLANG,false,true)) $(eval $(call bb-install,llvm-tools,LLVM_TOOLS,false,true)) +install-clang install-llvm-tools: install-llvm + endif # USE_BINARYBUILDER_LLVM diff --git a/deps/patches/SuiteSparse-winclang.patch b/deps/patches/SuiteSparse-winclang.patch deleted file mode 100644 index 8bfb64dc27839..0000000000000 --- a/deps/patches/SuiteSparse-winclang.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- SuiteSparse_config/SuiteSparse_config.h 2015-07-15 03:26:41.000000000 +0000 -+++ SuiteSparse_config/SuiteSparse_config.h 2016-07-01 00:55:57.157465600 +0000 -@@ -54,7 +54,11 @@ - #ifdef _WIN64 - - #define SuiteSparse_long __int64 -+#ifdef _MSVC_VER - #define SuiteSparse_long_max _I64_MAX -+#else -+#define SuiteSparse_long_max LLONG_MAX -+#endif - #define SuiteSparse_long_idd "I64d" - - #else diff --git a/deps/patches/llvm-10-r_aarch64_prel32.patch b/deps/patches/llvm-10-r_aarch64_prel32.patch deleted file mode 100644 index 7236574b3311d..0000000000000 --- a/deps/patches/llvm-10-r_aarch64_prel32.patch +++ /dev/null @@ -1,66 +0,0 @@ -From c530dd687328d4208f91e62b600d25ec6e7f0f39 Mon Sep 17 00:00:00 2001 -From: Fangrui Song -Date: Fri, 17 Jul 2020 23:49:15 -0700 -Subject: [PATCH 2/2] [RelocationResolver] Support R_AARCH64_PREL32 - -Code from D83800 by Yichao Yu ---- - llvm/lib/Object/RelocationResolver.cpp | 6 ++++++ - llvm/test/DebugInfo/AArch64/eh-frame.ll | 21 +++++++++++++++++++++ - 2 files changed, 27 insertions(+) - create mode 100644 llvm/test/DebugInfo/AArch64/eh-frame.ll - -diff --git llvm/lib/Object/RelocationResolver.cpp llvm/lib/Object/RelocationResolver.cpp -index eedb236f83d..80339ebf7b9 100644 ---- llvm/lib/Object/RelocationResolver.cpp -+++ llvm/lib/Object/RelocationResolver.cpp -@@ -62,6 +62,8 @@ static bool supportsAArch64(uint64_t Type) { - switch (Type) { - case ELF::R_AARCH64_ABS32: - case ELF::R_AARCH64_ABS64: -+ case ELF::R_AARCH64_PREL32: -+ case ELF::R_AARCH64_PREL64: - return true; - default: - return false; -@@ -74,6 +76,10 @@ static uint64_t resolveAArch64(RelocationRef R, uint64_t S, uint64_t A) { - return (S + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_AARCH64_ABS64: - return S + getELFAddend(R); -+ case ELF::R_AARCH64_PREL32: -+ return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF; -+ case ELF::R_AARCH64_PREL64: -+ return S + getELFAddend(R) - R.getOffset(); - default: - llvm_unreachable("Invalid relocation type"); - } -diff --git llvm/test/DebugInfo/AArch64/eh-frame.ll llvm/test/DebugInfo/AArch64/eh-frame.ll -new file mode 100644 -index 00000000000..9651159271e ---- /dev/null -+++ llvm/test/DebugInfo/AArch64/eh-frame.ll -@@ -0,0 +1,21 @@ -+; RUN: llc -filetype=obj -mtriple=aarch64 %s -o %t.o -+; RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=REL32 -+; RUN: llvm-dwarfdump --eh-frame %t.o 2>&1 | FileCheck %s -+ -+; REL32: R_AARCH64_PREL32 .text 0x0 -+; REL32-NEXT: R_AARCH64_PREL32 .text 0x4 -+ -+; CHECK-NOT: warning: -+; CHECK: FDE cie=00000000 pc=00000000...00000004 -+;; TODO Take relocation into consideration -+; CHECK: FDE cie=00000000 pc=00000000...00000004 -+ -+define void @foo() { -+entry: -+ ret void -+} -+ -+define void @bar() { -+entry: -+ ret void -+} --- -2.28.0 - diff --git a/deps/patches/llvm-10-r_ppc_rel.patch b/deps/patches/llvm-10-r_ppc_rel.patch deleted file mode 100644 index f86ee75bb845e..0000000000000 --- a/deps/patches/llvm-10-r_ppc_rel.patch +++ /dev/null @@ -1,116 +0,0 @@ -From b7f604447cbd76c803ccff5c0ff1b699b9c1504e Mon Sep 17 00:00:00 2001 -From: Fangrui Song -Date: Fri, 17 Jul 2020 23:29:50 -0700 -Subject: [PATCH 1/2] [RelocationResolver] Support R_PPC_REL32 & - R_PPC64_REL{32,64} - -This suppresses `failed to compute relocation: R_PPC_REL32, Invalid data was encountered while parsing the file` -and its 64-bit variants when running llvm-dwarfdump on a PowerPC object file with .eh_frame - -Unfortunately it is difficult to test the computation: -DWARFDataExtractor::getEncodedPointer does not use the relocated value -and even if it does, we need to teach llvm-dwarfdump --eh-frame to do -some linker job to report a reasonable address. ---- - llvm/lib/Object/RelocationResolver.cpp | 20 +++++++++++-- - llvm/test/DebugInfo/PowerPC/eh-frame.ll | 39 +++++++++++++++++++++++++ - 2 files changed, 57 insertions(+), 2 deletions(-) - create mode 100644 llvm/test/DebugInfo/PowerPC/eh-frame.ll - -diff --git llvm/lib/Object/RelocationResolver.cpp llvm/lib/Object/RelocationResolver.cpp -index 31478be7899..eedb236f83d 100644 ---- llvm/lib/Object/RelocationResolver.cpp -+++ llvm/lib/Object/RelocationResolver.cpp -@@ -131,6 +131,8 @@ static bool supportsPPC64(uint64_t Type) { - switch (Type) { - case ELF::R_PPC64_ADDR32: - case ELF::R_PPC64_ADDR64: -+ case ELF::R_PPC64_REL32: -+ case ELF::R_PPC64_REL64: - return true; - default: - return false; -@@ -143,6 +145,10 @@ static uint64_t resolvePPC64(RelocationRef R, uint64_t S, uint64_t A) { - return (S + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_PPC64_ADDR64: - return S + getELFAddend(R); -+ case ELF::R_PPC64_REL32: -+ return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF; -+ case ELF::R_PPC64_REL64: -+ return S + getELFAddend(R) - R.getOffset(); - default: - llvm_unreachable("Invalid relocation type"); - } -@@ -238,12 +244,22 @@ static uint64_t resolveX86(RelocationRef R, uint64_t S, uint64_t A) { - } - - static bool supportsPPC32(uint64_t Type) { -- return Type == ELF::R_PPC_ADDR32; -+ switch (Type) { -+ case ELF::R_PPC_ADDR32: -+ case ELF::R_PPC_REL32: -+ return true; -+ default: -+ return false; -+ } - } - - static uint64_t resolvePPC32(RelocationRef R, uint64_t S, uint64_t A) { -- if (R.getType() == ELF::R_PPC_ADDR32) -+ switch (R.getType()) { -+ case ELF::R_PPC_ADDR32: - return (S + getELFAddend(R)) & 0xFFFFFFFF; -+ case ELF::R_PPC_REL32: -+ return (S + getELFAddend(R) - R.getOffset()) & 0xFFFFFFFF; -+ } - llvm_unreachable("Invalid relocation type"); - } - -diff --git llvm/test/DebugInfo/PowerPC/eh-frame.ll llvm/test/DebugInfo/PowerPC/eh-frame.ll -new file mode 100644 -index 00000000000..3a8f7df6b61 ---- /dev/null -+++ llvm/test/DebugInfo/PowerPC/eh-frame.ll -@@ -0,0 +1,39 @@ -+; RUN: llc -filetype=obj -mtriple=powerpc %s -o %t32.o -+; RUN: llvm-readobj -r %t32.o | FileCheck %s --check-prefix=PPC_REL -+; RUN: llvm-dwarfdump --eh-frame %t32.o 2>&1 | FileCheck %s --check-prefix=PPC -+ -+; PPC_REL: R_PPC_REL32 .text 0x0 -+; PPC_REL-NEXT: R_PPC_REL32 .text 0x4 -+ -+; PPC-NOT: warning: -+; PPC: FDE cie=00000000 pc=00000000...00000004 -+;; TODO Take relocation into consideration -+; PPC: FDE cie=00000000 pc=00000000...00000004 -+ -+; RUN: llc -filetype=obj -mtriple=ppc64 %s -o %t64.o -+; RUN: llvm-readobj -r %t64.o | FileCheck %s --check-prefix=PPC64_REL -+; RUN: llvm-dwarfdump --eh-frame %t64.o 2>&1 | FileCheck %s --check-prefix=PPC64 -+ -+; PPC64_REL: R_PPC64_REL32 .text 0x0 -+; PPC64_REL-NEXT: R_PPC64_REL32 .text 0x10 -+ -+; PPC64-NOT: warning: -+; PPC64: FDE cie=00000000 pc=00000000...00000010 -+; PPC64: FDE cie=00000000 pc=00000000...00000010 -+ -+; RUN: llc -filetype=obj -mtriple=ppc64le -code-model=large %s -o %t64l.o -+; RUN: llvm-readobj -r %t64l.o | FileCheck %s --check-prefix=PPC64L_REL -+; RUN: llvm-dwarfdump --eh-frame %t64l.o 2>&1 | FileCheck %s --check-prefix=PPC64 -+ -+; PPC64L_REL: R_PPC64_REL64 .text 0x0 -+; PPC64L_REL-NEXT: R_PPC64_REL64 .text 0x10 -+ -+define void @foo() { -+entry: -+ ret void -+} -+ -+define void @bar() { -+entry: -+ ret void -+} --- -2.28.0 - diff --git a/deps/patches/llvm-10.0-PPC-LI-Elimination.patch b/deps/patches/llvm-10.0-PPC-LI-Elimination.patch deleted file mode 100644 index f47a2c97f0e37..0000000000000 --- a/deps/patches/llvm-10.0-PPC-LI-Elimination.patch +++ /dev/null @@ -1,161 +0,0 @@ -From 5423496713e84dea2650e1703821de620f934573 Mon Sep 17 00:00:00 2001 -From: Nemanja Ivanovic -Date: Thu, 9 Apr 2020 21:34:30 -0500 -Subject: [PATCH] [PowerPC] Bail out of redundant LI elimination on an implicit - kill - -The transformation currently does not differentiate between explicit -and implicit kills. However, it is not valid to later simply clear -an implicit kill flag since the kill could be due to a call or return. - -Fixes: https://bugs.llvm.org/show_bug.cgi?id=45374 ---- - .../lib/Target/PowerPC/PPCPreEmitPeephole.cpp | 10 ++ - .../remove-redundant-li-skip-imp-kill.mir | 114 ++++++++++++++++++ - 2 files changed, 124 insertions(+) - create mode 100644 llvm/test/CodeGen/PowerPC/remove-redundant-li-skip-imp-kill.mir - -diff --git llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp -index a4b4bf2973d..4ea714ff15f 100644 ---- llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp -+++ llvm/lib/Target/PowerPC/PPCPreEmitPeephole.cpp -@@ -109,6 +109,16 @@ namespace { - // Track the operand that kill Reg. We would unset the kill flag of - // the operand if there is a following redundant load immediate. - int KillIdx = AfterBBI->findRegisterUseOperandIdx(Reg, true, TRI); -+ -+ // We can't just clear implicit kills, so if we encounter one, stop -+ // looking further. -+ if (KillIdx != -1 && AfterBBI->getOperand(KillIdx).isImplicit()) { -+ LLVM_DEBUG(dbgs() -+ << "Encountered an implicit kill, cannot proceed: "); -+ LLVM_DEBUG(AfterBBI->dump()); -+ break; -+ } -+ - if (KillIdx != -1) { - assert(!DeadOrKillToUnset && "Shouldn't kill same register twice"); - DeadOrKillToUnset = &AfterBBI->getOperand(KillIdx); -diff --git llvm/test/CodeGen/PowerPC/remove-redundant-li-skip-imp-kill.mir llvm/test/CodeGen/PowerPC/remove-redundant-li-skip-imp-kill.mir -new file mode 100644 -index 00000000000..78091d027ce ---- /dev/null -+++ llvm/test/CodeGen/PowerPC/remove-redundant-li-skip-imp-kill.mir -@@ -0,0 +1,114 @@ -+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -+# RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown -run-pass \ -+# RUN: ppc-pre-emit-peephole %s -o - | FileCheck %s -+--- | -+ ; ModuleID = 'a.ll' -+ source_filename = "a.ll" -+ target datalayout = "e-m:e-i64:64-n32:64" -+ -+ ; Function Attrs: nounwind -+ define dso_local signext i32 @b(i32 signext %a, i32* nocapture %b) local_unnamed_addr #0 { -+ entry: -+ %call = tail call signext i32 @g(i32 signext %a) -+ store i32 %call, i32* %b, align 4 -+ %call1 = tail call signext i32 @g(i32 signext %a) -+ ret i32 %call1 -+ } -+ -+ ; Function Attrs: nounwind -+ declare signext i32 @g(i32 signext) local_unnamed_addr #0 -+ -+ ; Function Attrs: nounwind -+ declare void @llvm.stackprotector(i8*, i8**) #0 -+ -+ attributes #0 = { nounwind } -+ -+... -+--- -+name: b -+alignment: 16 -+exposesReturnsTwice: false -+legalized: false -+regBankSelected: false -+selected: false -+failedISel: false -+tracksRegLiveness: true -+hasWinCFI: false -+registers: [] -+liveins: -+ - { reg: '$x3', virtual-reg: '' } -+ - { reg: '$x4', virtual-reg: '' } -+frameInfo: -+ isFrameAddressTaken: false -+ isReturnAddressTaken: false -+ hasStackMap: false -+ hasPatchPoint: false -+ stackSize: 64 -+ offsetAdjustment: 0 -+ maxAlignment: 1 -+ adjustsStack: true -+ hasCalls: true -+ stackProtector: '' -+ maxCallFrameSize: 32 -+ cvBytesOfCalleeSavedRegisters: 0 -+ hasOpaqueSPAdjustment: false -+ hasVAStart: false -+ hasMustTailInVarArgFunc: false -+ localFrameSize: 0 -+ savePoint: '' -+ restorePoint: '' -+fixedStack: -+ - { id: 0, type: spill-slot, offset: -80, size: 8, alignment: 16, stack-id: default, -+ callee-saved-register: '$x30', callee-saved-restored: true, debug-info-variable: '', -+ debug-info-expression: '', debug-info-location: '' } -+ - { id: 1, type: spill-slot, offset: -88, size: 8, alignment: 8, stack-id: default, -+ callee-saved-register: '$x29', callee-saved-restored: true, debug-info-variable: '', -+ debug-info-expression: '', debug-info-location: '' } -+stack: [] -+callSites: [] -+constants: [] -+machineFunctionInfo: {} -+body: | -+ bb.0.entry: -+ liveins: $x3, $x4, $x29, $x30 -+ -+ ; CHECK-LABEL: name: b -+ ; CHECK: liveins: $x3, $x4, $x29, $x30 -+ ; CHECK: $x0 = MFLR8 implicit $lr8 -+ ; CHECK: STD killed $x29, -24, $x1 :: (store 8 into %fixed-stack.0) -+ ; CHECK: STD killed $x30, -16, $x1 :: (store 8 into %fixed-stack.1, align 16) -+ ; CHECK: STD killed $x0, 16, $x1 -+ ; CHECK: $x1 = STDU $x1, -64, $x1 -+ ; CHECK: $x30 = OR8 killed $x4, $x4 -+ ; CHECK: dead $r4 = LI 10, implicit-def $x4 -+ ; CHECK: $x29 = OR8 $x3, $x3 -+ ; CHECK: BL8_NOP @g, csr_ppc64_r2_altivec, implicit-def dead $lr8, implicit $rm, implicit killed $x3, implicit killed $x4, implicit $x2, implicit-def $r1, implicit-def $x3 -+ ; CHECK: STW8 killed renamable $x3, 0, killed renamable $x30 :: (store 4 into %ir.b) -+ ; CHECK: $x3 = OR8 killed $x29, $x29 -+ ; CHECK: BL8_NOP @g, csr_ppc64_r2_altivec, implicit-def dead $lr8, implicit $rm, implicit killed $x3, implicit $x2, implicit-def $r1, implicit-def $x3 -+ ; CHECK: $x1 = ADDI8 $x1, 64 -+ ; CHECK: $x0 = LD 16, $x1 -+ ; CHECK: $x30 = LD -16, $x1 :: (load 8 from %fixed-stack.1, align 16) -+ ; CHECK: $x29 = LD -24, $x1 :: (load 8 from %fixed-stack.0) -+ ; CHECK: MTLR8 killed $x0, implicit-def $lr8 -+ ; CHECK: BLR8 implicit $lr8, implicit $rm, implicit killed $x3 -+ $x0 = MFLR8 implicit $lr8 -+ STD killed $x29, -24, $x1 :: (store 8 into %fixed-stack.1) -+ STD killed $x30, -16, $x1 :: (store 8 into %fixed-stack.0, align 16) -+ STD killed $x0, 16, $x1 -+ $x1 = STDU $x1, -64, $x1 -+ $x30 = OR8 killed $x4, $x4 -+ dead $r4 = LI 10, implicit-def $x4 -+ $x29 = OR8 $x3, $x3 -+ BL8_NOP @g, csr_ppc64_r2_altivec, implicit-def dead $lr8, implicit $rm, implicit killed $x3, implicit killed $x4, implicit $x2, implicit-def $r1, implicit-def $x3 -+ STW8 killed renamable $x3, 0, killed renamable $x30 :: (store 4 into %ir.b) -+ $x3 = OR8 killed $x29, $x29 -+ BL8_NOP @g, csr_ppc64_r2_altivec, implicit-def dead $lr8, implicit $rm, implicit killed $x3, implicit $x2, implicit-def $r1, implicit-def $x3 -+ $x1 = ADDI8 $x1, 64 -+ $x0 = LD 16, $x1 -+ $x30 = LD -16, $x1 :: (load 8 from %fixed-stack.0, align 16) -+ $x29 = LD -24, $x1 :: (load 8 from %fixed-stack.1) -+ MTLR8 killed $x0, implicit-def $lr8 -+ BLR8 implicit $lr8, implicit $rm, implicit killed $x3 -+ -+... --- -2.26.0 - diff --git a/deps/patches/llvm-10.0-PPC_SELECT_CC.patch b/deps/patches/llvm-10.0-PPC_SELECT_CC.patch deleted file mode 100644 index a56b20eb064f0..0000000000000 --- a/deps/patches/llvm-10.0-PPC_SELECT_CC.patch +++ /dev/null @@ -1,135 +0,0 @@ -From 4765db99fa35257a4209e2976903d81087a3f0d7 Mon Sep 17 00:00:00 2001 -From: Nemanja Ivanovic -Date: Thu, 9 Apr 2020 13:53:02 -0500 -Subject: [PATCH] [PowerPC] Don't assert on SELECT_CC with i1 type - -When we try to select a SELECT_CC on Power9, we check if it can be matched to a -SETB instruction. In that function, we assert that the output type is i32/i64. -This is unnecessary as it is perfectly reasonable to have an i1 SELECT_CC. -Change that from an assert to an early exit condition. -Fixes: https://bugs.llvm.org/show_bug.cgi?id=45448 ---- - llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 7 +- - llvm/test/CodeGen/PowerPC/pr45448.ll | 90 +++++++++++++++++++++ - 2 files changed, 92 insertions(+), 5 deletions(-) - create mode 100644 llvm/test/CodeGen/PowerPC/pr45448.ll - -diff --git llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp -index 776ec52e260..9230ce4118b 100644 ---- llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp -+++ llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp -@@ -4241,13 +4241,10 @@ static bool mayUseP9Setb(SDNode *N, const ISD::CondCode &CC, SelectionDAG *DAG, - SDValue TrueRes = N->getOperand(2); - SDValue FalseRes = N->getOperand(3); - ConstantSDNode *TrueConst = dyn_cast(TrueRes); -- if (!TrueConst) -+ if (!TrueConst || (N->getSimpleValueType(0) != MVT::i64 && -+ N->getSimpleValueType(0) != MVT::i32)) - return false; - -- assert((N->getSimpleValueType(0) == MVT::i64 || -- N->getSimpleValueType(0) == MVT::i32) && -- "Expecting either i64 or i32 here."); -- - // We are looking for any of: - // (select_cc lhs, rhs, 1, (sext (setcc [lr]hs, [lr]hs, cc2)), cc1) - // (select_cc lhs, rhs, -1, (zext (setcc [lr]hs, [lr]hs, cc2)), cc1) -diff --git llvm/test/CodeGen/PowerPC/pr45448.ll llvm/test/CodeGen/PowerPC/pr45448.ll -new file mode 100644 -index 00000000000..eb0a61cb075 ---- /dev/null -+++ llvm/test/CodeGen/PowerPC/pr45448.ll -@@ -0,0 +1,90 @@ -+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -+; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu \ -+; RUN: -mcpu=pwr9 -ppc-asm-full-reg-names -ppc-vsr-nums-as-vr < %s | \ -+; RUN: FileCheck %s -+define hidden void @julia_tryparse_internal_45896() #0 { -+; CHECK-LABEL: julia_tryparse_internal_45896: -+; CHECK: # %bb.0: # %top -+; CHECK-NEXT: ld r3, 0(r3) -+; CHECK-NEXT: cmpldi r3, 0 -+; CHECK-NEXT: beq cr0, .LBB0_3 -+; CHECK-NEXT: # %bb.1: # %top -+; CHECK-NEXT: cmpldi r3, 10 -+; CHECK-NEXT: beq cr0, .LBB0_4 -+; CHECK-NEXT: # %bb.2: # %top -+; CHECK-NEXT: .LBB0_3: # %fail194 -+; CHECK-NEXT: .LBB0_4: # %L294 -+; CHECK-NEXT: bc 12, 4*cr5+lt, .LBB0_6 -+; CHECK-NEXT: # %bb.5: # %L294 -+; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_7 -+; CHECK-NEXT: .LBB0_6: # %L1057.preheader -+; CHECK-NEXT: .LBB0_7: # %L670 -+; CHECK-NEXT: lis r5, 4095 -+; CHECK-NEXT: ori r5, r5, 65533 -+; CHECK-NEXT: sldi r5, r5, 4 -+; CHECK-NEXT: cmpdi r3, 0 -+; CHECK-NEXT: sradi r4, r3, 63 -+; CHECK-NEXT: mulhdu r3, r3, r5 -+; CHECK-NEXT: maddld r6, r4, r5, r3 -+; CHECK-NEXT: crnor 4*cr5+gt, eq, eq -+; CHECK-NEXT: cmpld r6, r3 -+; CHECK-NEXT: mulld r3, r4, r5 -+; CHECK-NEXT: cmpldi cr1, r3, 0 -+; CHECK-NEXT: crandc 4*cr5+lt, lt, 4*cr1+eq -+; CHECK-NEXT: mulhdu. r3, r4, r5 -+; CHECK-NEXT: bc 4, 4*cr5+gt, .LBB0_10 -+; CHECK-NEXT: # %bb.8: # %L670 -+; CHECK-NEXT: crorc 4*cr5+lt, 4*cr5+lt, eq -+; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_10 -+; CHECK-NEXT: # %bb.9: # %L917 -+; CHECK-NEXT: .LBB0_10: # %L994 -+top: -+ %0 = load i64, i64* undef, align 8 -+ %1 = icmp ne i64 %0, 0 -+ %2 = sext i64 %0 to i128 -+ switch i64 %0, label %pass195 [ -+ i64 10, label %L294 -+ i64 16, label %L294.fold.split -+ i64 0, label %fail194 -+ ] -+ -+L294.fold.split: ; preds = %top -+ unreachable -+ -+L294: ; preds = %top -+ %3 = add nsw i32 0, -48 -+ %4 = zext i32 %3 to i128 -+ %5 = add i128 %4, 0 -+ switch i32 undef, label %L670 [ -+ i32 -1031471104, label %L1057.preheader -+ i32 536870912, label %L1057.preheader -+ ] -+ -+L670: ; preds = %L294 -+ br label %L898 -+ -+L1057.preheader: ; preds = %L294, %L294 -+ unreachable -+ -+L898: ; preds = %L670 -+ %umul = call { i128, i1 } @llvm.umul.with.overflow.i128(i128 %2, i128 %5) -+ %umul.ov = extractvalue { i128, i1 } %umul, 1 -+ %value_phi102 = and i1 %1, %umul.ov -+ %6 = or i1 %value_phi102, false -+ br i1 %6, label %L917, label %L994 -+ -+L917: ; preds = %L898 -+ unreachable -+ -+L994: ; preds = %L898 -+ unreachable -+ -+fail194: ; preds = %top -+ unreachable -+ -+pass195: ; preds = %top -+ unreachable -+} -+ -+; Function Attrs: nounwind readnone speculatable willreturn -+declare { i128, i1 } @llvm.umul.with.overflow.i128(i128, i128) #1 --- -2.26.0 - diff --git a/deps/patches/llvm-8.0-D75072-SCEV-add-type.patch b/deps/patches/llvm-12-D75072-SCEV-add-type.patch similarity index 79% rename from deps/patches/llvm-8.0-D75072-SCEV-add-type.patch rename to deps/patches/llvm-12-D75072-SCEV-add-type.patch index 6418eca5d28b6..c74cd70b20e65 100644 --- a/deps/patches/llvm-8.0-D75072-SCEV-add-type.patch +++ b/deps/patches/llvm-12-D75072-SCEV-add-type.patch @@ -1,10 +1,8 @@ -From f11f45a45ce8b90c798dd939d2782205e4291360 Mon Sep 17 00:00:00 2001 +From 4827d22b3e297b82c7689f0fb06b38e67d92b578 Mon Sep 17 00:00:00 2001 From: Keno Fischer -Date: Fri, 6 Mar 2020 10:29:20 -0500 +Date: Wed, 21 Apr 2021 12:25:07 -0400 Subject: [PATCH] [SCEV] Record NI types in add exprs -Summary: -(Rebased to LLVM 8 from the original LLVM 9 patch) This fixes a case where loop-reduce introduces ptrtoint/inttoptr for non-integral address space pointers. Over the past several years, we have gradually improved the SCEVExpander to actually do something @@ -70,28 +68,22 @@ However, given the practical considerations above, that's a project for another time. For now, simply allowing the existing pointer-diff pattern for non-integral pointers seems to work ok. -Reviewers: sanjoy, reames, vtjnash, vchuravy - -Subscribers: hiraditya, javed.absar, llvm-commits - -Tags: #llvm, #julialang - Differential Revision: https://reviews.llvm.org/D75072 --- - llvm/include/llvm/Analysis/ScalarEvolution.h | 26 +++++-- - .../Analysis/ScalarEvolutionExpressions.h | 70 ++++++++++++++++--- - llvm/lib/Analysis/ScalarEvolution.cpp | 44 +++++++++--- - .../LoopStrengthReduce/nonintegral.ll | 35 +++++++++- - 4 files changed, 150 insertions(+), 25 deletions(-) + llvm/include/llvm/Analysis/ScalarEvolution.h | 21 ++++- + .../Analysis/ScalarEvolutionExpressions.h | 81 ++++++++++++++++--- + llvm/lib/Analysis/ScalarEvolution.cpp | 41 +++++++--- + .../LoopStrengthReduce/nonintegral.ll | 35 +++++++- + 4 files changed, 155 insertions(+), 23 deletions(-) diff --git llvm/include/llvm/Analysis/ScalarEvolution.h llvm/include/llvm/Analysis/ScalarEvolution.h -index 5286f6a220e..f27fceb70d2 100644 +index b3f199de2cfa..d98fbeb5dcf7 100644 --- llvm/include/llvm/Analysis/ScalarEvolution.h +++ llvm/include/llvm/Analysis/ScalarEvolution.h -@@ -116,6 +116,19 @@ public: +@@ -120,6 +120,19 @@ public: NoWrapMask = (1 << 3) - 1 }; - + + /// HasNonIntegralPointerFlag are bitfield indices into SubclassData. + /// + /// When constructing SCEV expressions for LLVM expressions with non-integral @@ -105,12 +97,12 @@ index 5286f6a220e..f27fceb70d2 100644 + FlagHasNIPointers = (1 << 3) + }; + - explicit SCEV(const FoldingSetNodeIDRef ID, unsigned SCEVTy) - : FastID(ID), SCEVType(SCEVTy) {} - SCEV(const SCEV &) = delete; -@@ -138,6 +138,10 @@ public: - /// Return true if the specified scev is negated, but not a constant. - bool isNonConstantNegative() const; + explicit SCEV(const FoldingSetNodeIDRef ID, SCEVTypes SCEVTy, + unsigned short ExpressionSize) + : FastID(ID), SCEVType(SCEVTy), ExpressionSize(ExpressionSize) {} +@@ -156,6 +169,10 @@ public: + return ExpressionSize; + } + bool hasNonIntegralPointers() const { + return SubclassData & FlagHasNIPointers; @@ -119,11 +111,29 @@ index 5286f6a220e..f27fceb70d2 100644 /// Print out the internal representation of this scalar to the specified /// stream. This should really only be used for debugging purposes. void print(raw_ostream &OS) const; +@@ -745,7 +762,7 @@ public: + const BasicBlock *ExitingBlock); + + /// The terms "backedge taken count" and "exit count" are used +- /// interchangeably to refer to the number of times the backedge of a loop ++ /// interchangeably to refer to the number of times the backedge of a loop + /// has executed before the loop is exited. + enum ExitCountKind { + /// An expression exactly describing the number of times the backedge has +@@ -758,7 +775,7 @@ public: + }; + + /// Return the number of times the backedge executes before the given exit +- /// would be taken; if not exactly computable, return SCEVCouldNotCompute. ++ /// would be taken; if not exactly computable, return SCEVCouldNotCompute. + /// For a single exit loop, this value is equivelent to the result of + /// getBackedgeTakenCount. The loop is guaranteed to exit (via *some* exit) + /// before the backedge is executed (ExitCount + 1) times. Note that there diff --git llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h -index 876d68438ef..b9ea23c0086 100644 +index 37e675f08afc..6e532b22f5b3 100644 --- llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h +++ llvm/include/llvm/Analysis/ScalarEvolutionExpressions.h -@@ -181,6 +184,13 @@ class Type; +@@ -228,6 +228,13 @@ class Type; return getNoWrapFlags(FlagNW) != FlagAnyWrap; } @@ -137,30 +147,35 @@ index 876d68438ef..b9ea23c0086 100644 /// Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const SCEV *S) { return S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr || -@@ -215,24 +220,54 @@ class Type; - class SCEVAddExpr : public SCEVCommutativeExpr { - friend class ScalarEvolution; +@@ -264,19 +271,16 @@ class Type; + + Type *Ty; + protected: - SCEVAddExpr(const FoldingSetNodeIDRef ID, - const SCEV *const *O, size_t N) - : SCEVCommutativeExpr(ID, scAddExpr, O, N) {} + SCEVAddExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N) + : SCEVCommutativeExpr(ID, scAddExpr, O, N) { +- auto *FirstPointerTypedOp = find_if(operands(), [](const SCEV *Op) { +- return Op->getType()->isPointerTy(); +- }); +- if (FirstPointerTypedOp != operands().end()) +- Ty = (*FirstPointerTypedOp)->getType(); +- else +- Ty = getOperand(0)->getType(); ++ + } public: -- Type *getType() const { -- // Use the type of the last operand, which is likely to be a pointer -- // type, if there is one. This doesn't usually matter, but it can help -- // reduce casts when the expressions are expanded. -- return getOperand(getNumOperands() - 1)->getType(); -+ /// Returns the type of the add expression, by looking either at the last -+ /// operand or deferring to the SCEVAddNIExpr subclass for non-integral -+ /// pointers. +- Type *getType() const { return Ty; } ++ // Returns the type of the add expression, by looking either at the last operand ++ // or deferring to the SCEVAddNIExpr subclass. + Type *getType() const; -+ -+ /// Methods for support type inquiry through isa, cast, and dyn_cast: -+ static bool classof(const SCEV *S) { return S->getSCEVType() == scAddExpr; } -+ }; -+ + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const SCEV *S) { +@@ -284,6 +288,46 @@ class Type; + } + }; + + /// This node represents an addition of some number of SCEVs, one which + /// is a non-integral pointer type, requiring us to know the type exactly for + /// correctness. @@ -172,18 +187,17 @@ index 876d68438ef..b9ea23c0086 100644 + PointerType *NIType) + : SCEVAddExpr(ID, O, N), NIType(NIType) { + SubclassData |= FlagHasNIPointers; - } - ++ } ++ + public: + Type *getType() const { return NIType; } + - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static bool classof(const SCEV *S) { -- return S->getSCEVType() == scAddExpr; ++ /// Methods for support type inquiry through isa, cast, and dyn_cast: ++ static bool classof(const SCEV *S) { + return S->getSCEVType() == scAddExpr && S->hasNonIntegralPointers(); - } - }; - ++ } ++ }; ++ + inline Type *SCEVAddExpr::getType() const { + // In general, use the type of the last operand, which is likely to be a + // pointer type, if there is one. This doesn't usually matter, but it can @@ -192,13 +206,20 @@ index 876d68438ef..b9ea23c0086 100644 + // that stores that type explicitly. + if (hasNonIntegralPointers()) + return cast(this)->getType(); -+ return getOperand(getNumOperands() - 1)->getType(); ++ ++ auto *FirstPointerTypedOp = find_if(operands(), [](const SCEV *Op) { ++ return Op->getType()->isPointerTy(); ++ }); ++ if (FirstPointerTypedOp != operands().end()) ++ return (*FirstPointerTypedOp)->getType(); ++ else ++ return getOperand(0)->getType(); + } + /// This node represents multiplication of some number of SCEVs. class SCEVMulExpr : public SCEVCommutativeExpr { friend class ScalarEvolution; -@@ -242,6 +273,18 @@ class Type; +@@ -293,6 +337,18 @@ class Type; : SCEVCommutativeExpr(ID, scMulExpr, O, N) {} public: @@ -217,16 +238,16 @@ index 876d68438ef..b9ea23c0086 100644 /// Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const SCEV *S) { return S->getSCEVType() == scMulExpr; -@@ -467,9 +690,12 @@ class Type; +@@ -531,9 +587,12 @@ class Type; /// instances owned by a ScalarEvolution. SCEVUnknown *Next; - SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V, - ScalarEvolution *se, SCEVUnknown *next) : -- SCEV(ID, scUnknown), CallbackVH(V), SE(se), Next(next) {} +- SCEV(ID, scUnknown, 1), CallbackVH(V), SE(se), Next(next) {} + SCEVUnknown(const FoldingSetNodeIDRef ID, Value *V, ScalarEvolution *se, + SCEVUnknown *next, bool ValueIsNIPtr) -+ : SCEV(ID, scUnknown), CallbackVH(V), SE(se), Next(next) { ++ : SCEV(ID, scUnknown, 1), CallbackVH(V), SE(se), Next(next) { + if (ValueIsNIPtr) + SubclassData |= FlagHasNIPointers; + } @@ -234,10 +255,10 @@ index 876d68438ef..b9ea23c0086 100644 // Implement CallbackVH. void deleted() override; diff --git llvm/lib/Analysis/ScalarEvolution.cpp llvm/lib/Analysis/ScalarEvolution.cpp -index cd74815a895..09e98345d0f 100644 +index fe9d8297d679..1fa7b8ce1451 100644 --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp -@@ -354,12 +354,13 @@ Type *SCEV::getType() const { +@@ -389,12 +389,13 @@ Type *SCEV::getType() const { case scSignExtend: return cast(this)->getType(); case scAddRecExpr: @@ -252,18 +273,7 @@ index cd74815a895..09e98345d0f 100644 case scAddExpr: return cast(this)->getType(); case scUDivExpr: -@@ -2419,8 +2420,9 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl &Ops, - } - - // Limit recursion calls depth. -- if (Depth > MaxArithDepth) -+ if (Depth > MaxArithDepth) { - return getOrCreateAddExpr(Ops, Flags); -+ } - - // Okay, check to see if the same value occurs in the operand list more than - // once. If so, merge them together into an multiply expression. Since we -@@ -2761,16 +2763,27 @@ ScalarEvolution::getOrCreateAddExpr(ArrayRef Ops, +@@ -2679,16 +2680,27 @@ ScalarEvolution::getOrCreateAddExpr(ArrayRef Ops, SCEV::NoWrapFlags Flags) { FoldingSetNodeID ID; ID.AddInteger(scAddExpr); @@ -295,7 +305,7 @@ index cd74815a895..09e98345d0f 100644 UniqueSCEVs.InsertNode(S, IP); addToLoopUseLists(S); } -@@ -2783,8 +2763,10 @@ ScalarEvolution::getOrCreateAddRecExpr(ArrayRef Ops, +@@ -2701,8 +2713,10 @@ ScalarEvolution::getOrCreateAddRecExpr(ArrayRef Ops, const Loop *L, SCEV::NoWrapFlags Flags) { FoldingSetNodeID ID; ID.AddInteger(scAddRecExpr); @@ -307,15 +317,15 @@ index cd74815a895..09e98345d0f 100644 ID.AddPointer(L); void *IP = nullptr; SCEVAddRecExpr *S = -@@ -2798,6 +2813,7 @@ ScalarEvolution::getOrCreateAddRecExpr(ArrayRef Ops, +@@ -2716,6 +2730,7 @@ ScalarEvolution::getOrCreateAddRecExpr(ArrayRef Ops, addToLoopUseLists(S); } - S->setNoWrapFlags(Flags); + setNoWrapFlags(S, Flags); + S->setHasNIPtr(Ops[0]->hasNonIntegralPointers()); return S; } -@@ -2806,8 +2822,11 @@ ScalarEvolution::getOrCreateMulExpr(ArrayRef Ops, +@@ -2724,8 +2739,11 @@ ScalarEvolution::getOrCreateMulExpr(ArrayRef Ops, SCEV::NoWrapFlags Flags) { FoldingSetNodeID ID; ID.AddInteger(scMulExpr); @@ -328,7 +338,7 @@ index cd74815a895..09e98345d0f 100644 void *IP = nullptr; SCEVMulExpr *S = static_cast(UniqueSCEVs.FindNodeOrInsertPos(ID, IP)); -@@ -2820,6 +2839,7 @@ ScalarEvolution::getOrCreateMulExpr(ArrayRef Ops, +@@ -2738,6 +2756,7 @@ ScalarEvolution::getOrCreateMulExpr(ArrayRef Ops, addToLoopUseLists(S); } S->setNoWrapFlags(Flags); @@ -336,20 +346,20 @@ index cd74815a895..09e98345d0f 100644 return S; } -@@ -3631,8 +3591,11 @@ const SCEV *ScalarEvolution::getMinMaxExpr(unsigned Kind, - if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; +@@ -3615,8 +3634,11 @@ const SCEV *ScalarEvolution::getMinMaxExpr(SCEVTypes Kind, + return ExistingSCEV; const SCEV **O = SCEVAllocator.Allocate(Ops.size()); std::uninitialized_copy(Ops.begin(), Ops.end(), O); -- SCEV *S = new (SCEVAllocator) SCEVMinMaxExpr( -+ SCEVMinMaxExpr *S = new (SCEVAllocator) SCEVMinMaxExpr( - ID.Intern(SCEVAllocator), static_cast(Kind), O, Ops.size()); +- SCEV *S = new (SCEVAllocator) ++ SCEVMinMaxExpr *S = new (SCEVAllocator) + SCEVMinMaxExpr(ID.Intern(SCEVAllocator), Kind, O, Ops.size()); + // For MinMaxExprs it's sufficient to see if the first Op has NI data, as the + // operands all need to be of the same type. + S->setHasNIPtr(Ops[0]->hasNonIntegralPointers()); + UniqueSCEVs.InsertNode(S, IP); addToLoopUseLists(S); - return S; -@@ -3708,8 +3731,9 @@ const SCEV *ScalarEvolution::getUnknown(Value *V) { +@@ -3716,8 +3738,9 @@ const SCEV *ScalarEvolution::getUnknown(Value *V) { "Stale SCEVUnknown in uniquing map!"); return S; } @@ -361,7 +371,7 @@ index cd74815a895..09e98345d0f 100644 UniqueSCEVs.InsertNode(S, IP); return S; diff --git llvm/test/Transforms/LoopStrengthReduce/nonintegral.ll llvm/test/Transforms/LoopStrengthReduce/nonintegral.ll -index 5648e3aa74a..6936521f3a6 100644 +index 5648e3aa74af..6936521f3a64 100644 --- llvm/test/Transforms/LoopStrengthReduce/nonintegral.ll +++ llvm/test/Transforms/LoopStrengthReduce/nonintegral.ll @@ -2,7 +2,7 @@ @@ -411,5 +421,5 @@ index 5648e3aa74a..6936521f3a6 100644 +!1 = distinct !{!1, !2} +!2 = !{!"llvm.loop.isvectorized", i32 1} -- -2.25.1 +2.31.1 diff --git a/deps/patches/llvm-12-D97435-AArch64-movaddrreg.patch b/deps/patches/llvm-12-D97435-AArch64-movaddrreg.patch new file mode 100644 index 0000000000000..01d49a85f1007 --- /dev/null +++ b/deps/patches/llvm-12-D97435-AArch64-movaddrreg.patch @@ -0,0 +1,164 @@ +From 3adadbab531e0d7dc17499a6570b129e87f00c77 Mon Sep 17 00:00:00 2001 +From: Keno Fischer +Date: Wed, 21 Apr 2021 12:38:40 -0400 +Subject: [PATCH] [Aarch64] Correct register class for pseudo instructions + +This constrains the Mov* and similar pseudo instruction to take +GPR64common register classes rather than GPR64. GPR64 includs XZR +which is invalid here, because this pseudo instructions expands +into an adrp/add pair sharing a destination register. XZR is invalid +on add and attempting to encode it will instead increment the stack +pointer causing crashes (downstream report at [1]). The test case +there reproduces on LLVM11, but I do not have a test case that +reaches this code path on main, since it is being masked by +improved dead code elimination introduced in D91513. Nevertheless, +this seems like a good thing to fix in case there are other cases +that dead code elimination doesn't clean up (e.g. if `optnone` is +used and the optimization is skipped). + +I think it would be worth auditing uses of GPR64 in pseudo +instructions to see if there are any similar issues, but I do not +have a high enough view of the backend or knowledge of the +Aarch64 architecture to do this quickly. + +[1] https://github.com/JuliaLang/julia/issues/39818 + +Reviewed By: t.p.northover + +Differential Revision: https://reviews.llvm.org/D97435 +--- + .../AArch64/AArch64ExpandPseudoInsts.cpp | 1 + + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 32 +++++++++---------- + .../GlobalISel/select-blockaddress.mir | 5 +-- + .../select-jump-table-brjt-constrain.mir | 2 +- + .../GlobalISel/select-jump-table-brjt.mir | 2 +- + 5 files changed, 22 insertions(+), 20 deletions(-) + +diff --git llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +index e57650ae60b1..612fbeb5f531 100644 +--- llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp ++++ llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp +@@ -886,6 +886,7 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB, + case AArch64::MOVaddrEXT: { + // Expand into ADRP + ADD. + Register DstReg = MI.getOperand(0).getReg(); ++ assert(DstReg != AArch64::XZR); + MachineInstrBuilder MIB1 = + BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::ADRP), DstReg) + .add(MI.getOperand(1)); +diff --git llvm/lib/Target/AArch64/AArch64InstrInfo.td llvm/lib/Target/AArch64/AArch64InstrInfo.td +index 171d3dbaa814..6fe0bd1ef168 100644 +--- llvm/lib/Target/AArch64/AArch64InstrInfo.td ++++ llvm/lib/Target/AArch64/AArch64InstrInfo.td +@@ -656,40 +656,40 @@ let isReMaterializable = 1, isCodeGenOnly = 1 in { + // removed, along with the AArch64Wrapper node. + + let AddedComplexity = 10 in +-def LOADgot : Pseudo<(outs GPR64:$dst), (ins i64imm:$addr), +- [(set GPR64:$dst, (AArch64LOADgot tglobaladdr:$addr))]>, ++def LOADgot : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), ++ [(set GPR64common:$dst, (AArch64LOADgot tglobaladdr:$addr))]>, + Sched<[WriteLDAdr]>; + + // The MOVaddr instruction should match only when the add is not folded + // into a load or store address. + def MOVaddr +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp tglobaladdr:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tglobaladdr:$hi), + tglobaladdr:$low))]>, + Sched<[WriteAdrAdr]>; + def MOVaddrJT +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp tjumptable:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tjumptable:$hi), + tjumptable:$low))]>, + Sched<[WriteAdrAdr]>; + def MOVaddrCP +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp tconstpool:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tconstpool:$hi), + tconstpool:$low))]>, + Sched<[WriteAdrAdr]>; + def MOVaddrBA +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp tblockaddress:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tblockaddress:$hi), + tblockaddress:$low))]>, + Sched<[WriteAdrAdr]>; + def MOVaddrTLS +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp tglobaltlsaddr:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tglobaltlsaddr:$hi), + tglobaltlsaddr:$low))]>, + Sched<[WriteAdrAdr]>; + def MOVaddrEXT +- : Pseudo<(outs GPR64:$dst), (ins i64imm:$hi, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow (AArch64adrp texternalsym:$hi), ++ : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), ++ [(set GPR64common:$dst, (AArch64addlow (AArch64adrp texternalsym:$hi), + texternalsym:$low))]>, + Sched<[WriteAdrAdr]>; + // Normally AArch64addlow either gets folded into a following ldr/str, +@@ -697,8 +697,8 @@ def MOVaddrEXT + // might appear without either of them, so allow lowering it into a plain + // add. + def ADDlowTLS +- : Pseudo<(outs GPR64:$dst), (ins GPR64:$src, i64imm:$low), +- [(set GPR64:$dst, (AArch64addlow GPR64:$src, ++ : Pseudo<(outs GPR64sp:$dst), (ins GPR64sp:$src, i64imm:$low), ++ [(set GPR64sp:$dst, (AArch64addlow GPR64sp:$src, + tglobaltlsaddr:$low))]>, + Sched<[WriteAdr]>; + +diff --git llvm/test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir llvm/test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir +index 45012f23de62..70cb802ed3a3 100644 +--- llvm/test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir ++++ llvm/test/CodeGen/AArch64/GlobalISel/select-blockaddress.mir +@@ -30,9 +30,10 @@ registers: + body: | + ; CHECK-LABEL: name: test_blockaddress + ; CHECK: bb.0 (%ir-block.0): +- ; CHECK: [[MOVaddrBA:%[0-9]+]]:gpr64 = MOVaddrBA target-flags(aarch64-page) blockaddress(@test_blockaddress, %ir-block.block), target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block) ++ ; CHECK: [[MOVaddrBA:%[0-9]+]]:gpr64common = MOVaddrBA target-flags(aarch64-page) blockaddress(@test_blockaddress, %ir-block.block), target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@test_blockaddress, %ir-block.block) + ; CHECK: [[MOVaddr:%[0-9]+]]:gpr64common = MOVaddr target-flags(aarch64-page) @addr, target-flags(aarch64-pageoff, aarch64-nc) @addr +- ; CHECK: STRXui [[MOVaddrBA]], [[MOVaddr]], 0 :: (store 8 into @addr) ++ ; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY [[MOVaddrBA]] ++ ; CHECK: STRXui [[COPY]], [[MOVaddr]], 0 :: (store 8 into @addr) + ; CHECK: BR [[MOVaddrBA]] + ; CHECK: bb.1.block (address-taken): + ; CHECK: RET_ReallyLR +diff --git llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt-constrain.mir llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt-constrain.mir +index 440a03173c83..59b8dea2d0ce 100644 +--- llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt-constrain.mir ++++ llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt-constrain.mir +@@ -30,7 +30,7 @@ body: | + ; CHECK: Bcc 8, %bb.3, implicit $nzcv + ; CHECK: bb.1: + ; CHECK: successors: %bb.2(0x40000000), %bb.3(0x40000000) +- ; CHECK: [[MOVaddrJT:%[0-9]+]]:gpr64 = MOVaddrJT target-flags(aarch64-page) %jump-table.0, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0 ++ ; CHECK: [[MOVaddrJT:%[0-9]+]]:gpr64common = MOVaddrJT target-flags(aarch64-page) %jump-table.0, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0 + ; CHECK: early-clobber %6:gpr64, early-clobber %7:gpr64sp = JumpTableDest32 [[MOVaddrJT]], [[SUBREG_TO_REG]], %jump-table.0 + ; CHECK: BR %6 + ; CHECK: bb.2: +diff --git llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt.mir llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt.mir +index 6b84c6d10843..b8c9a6c881da 100644 +--- llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt.mir ++++ llvm/test/CodeGen/AArch64/GlobalISel/select-jump-table-brjt.mir +@@ -65,7 +65,7 @@ body: | + ; CHECK: bb.1.entry: + ; CHECK: successors: %bb.3(0x2aaaaaab), %bb.4(0x2aaaaaab), %bb.2(0x2aaaaaab) + ; CHECK: [[COPY2:%[0-9]+]]:gpr32 = COPY $wzr +- ; CHECK: [[MOVaddrJT:%[0-9]+]]:gpr64 = MOVaddrJT target-flags(aarch64-page) %jump-table.0, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0 ++ ; CHECK: [[MOVaddrJT:%[0-9]+]]:gpr64common = MOVaddrJT target-flags(aarch64-page) %jump-table.0, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0 + ; CHECK: early-clobber %18:gpr64, early-clobber %19:gpr64sp = JumpTableDest32 [[MOVaddrJT]], [[SUBREG_TO_REG]], %jump-table.0 + ; CHECK: BR %18 + ; CHECK: bb.2.sw.bb: +-- +2.31.1 + diff --git a/deps/patches/llvm-8.0-D50167-scev-umin.patch b/deps/patches/llvm-8.0-D50167-scev-umin.patch deleted file mode 100644 index f11fd546bb72c..0000000000000 --- a/deps/patches/llvm-8.0-D50167-scev-umin.patch +++ /dev/null @@ -1,1870 +0,0 @@ -commit 18e563f695dd561c32393512fbdb8ce8771d7e5f -Author: Keno Fischer -Date: Thu May 2 08:35:22 2019 -0400 - - [SCEV] Add explicit representations of umin/smin - - Summary: - Currently we express umin as `~umax(~x, ~y)`. However, this becomes - a problem for operands in non-integral pointer spaces, because `~x` - is not something we can compute for `x` non-integral. However, since - comparisons are generally still allowed, we are actually able to - express `umin(x, y)` directly as long as we don't try to express is - as a umax. Support this by adding an explicit umin/smin representation - to SCEV. We do this by factoring the existing getUMax/getSMax functions - into a new function that does all four. The previous two functions were - largely identical. - - Reviewers: reames, sanjoy, mkazantsev - - Reviewed By: sanjoy - - Subscribers: tvvikram, dmgreen, vchuravy, javed.absar, llvm-commits - - Tags: #llvm - - Differential Revision: https://reviews.llvm.org/D50167 - -diff --git a/include/llvm/Analysis/ScalarEvolution.h b/include/llvm/Analysis/ScalarEvolution.h -index 8f4200b07e5..6b76a16a2b4 100644 ---- a/include/llvm/Analysis/ScalarEvolution.h -+++ b/include/llvm/Analysis/ScalarEvolution.h -@@ -582,6 +582,8 @@ public: - /// \p IndexExprs The expressions for the indices. - const SCEV *getGEPExpr(GEPOperator *GEP, - const SmallVectorImpl &IndexExprs); -+ const SCEV *getMinMaxExpr(unsigned Kind, -+ SmallVectorImpl &Operands); - const SCEV *getSMaxExpr(const SCEV *LHS, const SCEV *RHS); - const SCEV *getSMaxExpr(SmallVectorImpl &Operands); - const SCEV *getUMaxExpr(const SCEV *LHS, const SCEV *RHS); -diff --git a/include/llvm/Analysis/ScalarEvolutionExpander.h b/include/llvm/Analysis/ScalarEvolutionExpander.h -index 58d42680d6b..57d658b157d 100644 ---- a/include/llvm/Analysis/ScalarEvolutionExpander.h -+++ b/include/llvm/Analysis/ScalarEvolutionExpander.h -@@ -368,6 +368,10 @@ namespace llvm { - - Value *visitUMaxExpr(const SCEVUMaxExpr *S); - -+ Value *visitSMinExpr(const SCEVSMinExpr *S); -+ -+ Value *visitUMinExpr(const SCEVUMinExpr *S); -+ - Value *visitUnknown(const SCEVUnknown *S) { - return S->getValue(); - } -diff --git a/include/llvm/Analysis/ScalarEvolutionExpressions.h b/include/llvm/Analysis/ScalarEvolutionExpressions.h -index 42e76094eb2..99e39d484c5 100644 ---- a/include/llvm/Analysis/ScalarEvolutionExpressions.h -+++ b/include/llvm/Analysis/ScalarEvolutionExpressions.h -@@ -40,7 +40,7 @@ class Type; - // These should be ordered in terms of increasing complexity to make the - // folders simpler. - scConstant, scTruncate, scZeroExtend, scSignExtend, scAddExpr, scMulExpr, -- scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr, -+ scUDivExpr, scAddRecExpr, scUMaxExpr, scSMaxExpr, scUMinExpr, scSMinExpr, - scUnknown, scCouldNotCompute - }; - -@@ -183,10 +183,9 @@ class Type; - - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static bool classof(const SCEV *S) { -- return S->getSCEVType() == scAddExpr || -- S->getSCEVType() == scMulExpr || -- S->getSCEVType() == scSMaxExpr || -- S->getSCEVType() == scUMaxExpr || -+ return S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr || -+ S->getSCEVType() == scSMaxExpr || S->getSCEVType() == scUMaxExpr || -+ S->getSCEVType() == scSMinExpr || S->getSCEVType() == scUMinExpr || - S->getSCEVType() == scAddRecExpr; - } - }; -@@ -201,10 +200,9 @@ class Type; - public: - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static bool classof(const SCEV *S) { -- return S->getSCEVType() == scAddExpr || -- S->getSCEVType() == scMulExpr || -- S->getSCEVType() == scSMaxExpr || -- S->getSCEVType() == scUMaxExpr; -+ return S->getSCEVType() == scAddExpr || S->getSCEVType() == scMulExpr || -+ S->getSCEVType() == scSMaxExpr || S->getSCEVType() == scUMaxExpr || -+ S->getSCEVType() == scSMinExpr || S->getSCEVType() == scUMinExpr; - } - - /// Set flags for a non-recurrence without clearing previously set flags. -@@ -358,17 +356,53 @@ class Type; - } - }; - -- /// This class represents a signed maximum selection. -- class SCEVSMaxExpr : public SCEVCommutativeExpr { -+ /// This node is the base class min/max selections. -+ class SCEVMinMaxExpr : public SCEVCommutativeExpr { - friend class ScalarEvolution; - -- SCEVSMaxExpr(const FoldingSetNodeIDRef ID, -- const SCEV *const *O, size_t N) -- : SCEVCommutativeExpr(ID, scSMaxExpr, O, N) { -- // Max never overflows. -+ static bool isMinMaxType(enum SCEVTypes T) { -+ return T == scSMaxExpr || T == scUMaxExpr || T == scSMinExpr || -+ T == scUMinExpr; -+ } -+ -+ protected: -+ /// Note: Constructing subclasses via this constructor is allowed -+ SCEVMinMaxExpr(const FoldingSetNodeIDRef ID, enum SCEVTypes T, -+ const SCEV *const *O, size_t N) -+ : SCEVCommutativeExpr(ID, T, O, N) { -+ assert(isMinMaxType(T)); -+ // Min and max nenver overflow - setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW)); - } - -+ public: -+ static bool classof(const SCEV *S) { -+ return isMinMaxType(static_cast(S->getSCEVType())); -+ } -+ -+ static enum SCEVTypes negate(enum SCEVTypes T) { -+ switch (T) { -+ case scSMaxExpr: -+ return scSMinExpr; -+ case scSMinExpr: -+ return scSMaxExpr; -+ case scUMaxExpr: -+ return scUMaxExpr; -+ case scUMinExpr: -+ return scUMinExpr; -+ default: -+ llvm_unreachable("Not a min or max SCEV type!"); -+ } -+ } -+ }; -+ -+ /// This class represents a signed maximum selection. -+ class SCEVSMaxExpr : public SCEVMinMaxExpr { -+ friend class ScalarEvolution; -+ -+ SCEVSMaxExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N) -+ : SCEVMinMaxExpr(ID, scSMaxExpr, O, N) {} -+ - public: - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static bool classof(const SCEV *S) { -@@ -377,15 +411,11 @@ class Type; - }; - - /// This class represents an unsigned maximum selection. -- class SCEVUMaxExpr : public SCEVCommutativeExpr { -+ class SCEVUMaxExpr : public SCEVMinMaxExpr { - friend class ScalarEvolution; - -- SCEVUMaxExpr(const FoldingSetNodeIDRef ID, -- const SCEV *const *O, size_t N) -- : SCEVCommutativeExpr(ID, scUMaxExpr, O, N) { -- // Max never overflows. -- setNoWrapFlags((NoWrapFlags)(FlagNUW | FlagNSW)); -- } -+ SCEVUMaxExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N) -+ : SCEVMinMaxExpr(ID, scUMaxExpr, O, N) {} - - public: - /// Methods for support type inquiry through isa, cast, and dyn_cast: -@@ -394,6 +424,34 @@ class Type; - } - }; - -+ /// This class represents a signed minimum selection. -+ class SCEVSMinExpr : public SCEVMinMaxExpr { -+ friend class ScalarEvolution; -+ -+ SCEVSMinExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N) -+ : SCEVMinMaxExpr(ID, scSMinExpr, O, N) {} -+ -+ public: -+ /// Methods for support type inquiry through isa, cast, and dyn_cast: -+ static bool classof(const SCEV *S) { -+ return S->getSCEVType() == scSMinExpr; -+ } -+ }; -+ -+ /// This class represents an unsigned minimum selection. -+ class SCEVUMinExpr : public SCEVMinMaxExpr { -+ friend class ScalarEvolution; -+ -+ SCEVUMinExpr(const FoldingSetNodeIDRef ID, const SCEV *const *O, size_t N) -+ : SCEVMinMaxExpr(ID, scUMinExpr, O, N) {} -+ -+ public: -+ /// Methods for support type inquiry through isa, cast, and dyn_cast: -+ static bool classof(const SCEV *S) { -+ return S->getSCEVType() == scUMinExpr; -+ } -+ }; -+ - /// This means that we are dealing with an entirely unknown SCEV - /// value, and only represent it as its LLVM Value. This is the - /// "bottom" value for the analysis. -@@ -466,6 +524,10 @@ class Type; - return ((SC*)this)->visitSMaxExpr((const SCEVSMaxExpr*)S); - case scUMaxExpr: - return ((SC*)this)->visitUMaxExpr((const SCEVUMaxExpr*)S); -+ case scSMinExpr: -+ return ((SC *)this)->visitSMinExpr((const SCEVSMinExpr *)S); -+ case scUMinExpr: -+ return ((SC *)this)->visitUMinExpr((const SCEVUMinExpr *)S); - case scUnknown: - return ((SC*)this)->visitUnknown((const SCEVUnknown*)S); - case scCouldNotCompute: -@@ -519,6 +581,8 @@ class Type; - case scMulExpr: - case scSMaxExpr: - case scUMaxExpr: -+ case scSMinExpr: -+ case scUMinExpr: - case scAddRecExpr: - for (const auto *Op : cast(S)->operands()) - push(Op); -@@ -681,6 +745,26 @@ class Type; - return !Changed ? Expr : SE.getUMaxExpr(Operands); - } - -+ const SCEV *visitSMinExpr(const SCEVSMinExpr *Expr) { -+ SmallVector Operands; -+ bool Changed = false; -+ for (auto *Op : Expr->operands()) { -+ Operands.push_back(((SC *)this)->visit(Op)); -+ Changed |= Op != Operands.back(); -+ } -+ return !Changed ? Expr : SE.getSMinExpr(Operands); -+ } -+ -+ const SCEV *visitUMinExpr(const SCEVUMinExpr *Expr) { -+ SmallVector Operands; -+ bool Changed = false; -+ for (auto *Op : Expr->operands()) { -+ Operands.push_back(((SC *)this)->visit(Op)); -+ Changed |= Op != Operands.back(); -+ } -+ return !Changed ? Expr : SE.getUMinExpr(Operands); -+ } -+ - const SCEV *visitUnknown(const SCEVUnknown *Expr) { - return Expr; - } -diff --git a/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp -index e5134f2eeda..f2553de0af1 100644 ---- a/lib/Analysis/ScalarEvolution.cpp -+++ b/lib/Analysis/ScalarEvolution.cpp -@@ -273,7 +273,9 @@ void SCEV::print(raw_ostream &OS) const { - case scAddExpr: - case scMulExpr: - case scUMaxExpr: -- case scSMaxExpr: { -+ case scSMaxExpr: -+ case scUMinExpr: -+ case scSMinExpr: { - const SCEVNAryExpr *NAry = cast(this); - const char *OpStr = nullptr; - switch (NAry->getSCEVType()) { -@@ -281,6 +283,12 @@ void SCEV::print(raw_ostream &OS) const { - case scMulExpr: OpStr = " * "; break; - case scUMaxExpr: OpStr = " umax "; break; - case scSMaxExpr: OpStr = " smax "; break; -+ case scUMinExpr: -+ OpStr = " umin "; -+ break; -+ case scSMinExpr: -+ OpStr = " smin "; -+ break; - } - OS << "("; - for (SCEVNAryExpr::op_iterator I = NAry->op_begin(), E = NAry->op_end(); -@@ -349,6 +357,8 @@ Type *SCEV::getType() const { - case scMulExpr: - case scUMaxExpr: - case scSMaxExpr: -+ case scUMinExpr: -+ case scSMinExpr: - return cast(this)->getType(); - case scAddExpr: - return cast(this)->getType(); -@@ -713,7 +723,9 @@ static int CompareSCEVComplexity( - case scAddExpr: - case scMulExpr: - case scSMaxExpr: -- case scUMaxExpr: { -+ case scUMaxExpr: -+ case scSMinExpr: -+ case scUMinExpr: { - const SCEVNAryExpr *LC = cast(LHS); - const SCEVNAryExpr *RC = cast(RHS); - -@@ -913,6 +925,8 @@ public: - void visitUDivExpr(const SCEVUDivExpr *Numerator) {} - void visitSMaxExpr(const SCEVSMaxExpr *Numerator) {} - void visitUMaxExpr(const SCEVUMaxExpr *Numerator) {} -+ void visitSMinExpr(const SCEVSMinExpr *Numerator) {} -+ void visitUMinExpr(const SCEVUMinExpr *Numerator) {} - void visitUnknown(const SCEVUnknown *Numerator) {} - void visitCouldNotCompute(const SCEVCouldNotCompute *Numerator) {} - -@@ -3493,209 +3507,153 @@ ScalarEvolution::getGEPExpr(GEPOperator *GEP, - return getAddExpr(BaseExpr, TotalOffset, Wrap); - } - --const SCEV *ScalarEvolution::getSMaxExpr(const SCEV *LHS, -- const SCEV *RHS) { -- SmallVector Ops = {LHS, RHS}; -- return getSMaxExpr(Ops); --} -- --const SCEV * --ScalarEvolution::getSMaxExpr(SmallVectorImpl &Ops) { -- assert(!Ops.empty() && "Cannot get empty smax!"); -+const SCEV *ScalarEvolution::getMinMaxExpr(unsigned Kind, -+ SmallVectorImpl &Ops) { -+ assert(!Ops.empty() && "Cannot get empty (u|s)(min|max)!"); - if (Ops.size() == 1) return Ops[0]; - #ifndef NDEBUG - Type *ETy = getEffectiveSCEVType(Ops[0]->getType()); - for (unsigned i = 1, e = Ops.size(); i != e; ++i) - assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy && -- "SCEVSMaxExpr operand types don't match!"); -+ "Operand types don't match!"); - #endif - -+ bool IsSigned = Kind == scSMaxExpr || Kind == scSMinExpr; -+ bool IsMax = Kind == scSMaxExpr || Kind == scUMaxExpr; -+ - // Sort by complexity, this groups all similar expression types together. - GroupByComplexity(Ops, &LI, DT); - -+ -+ -+ -+ -+ - // If there are any constants, fold them together. - unsigned Idx = 0; - if (const SCEVConstant *LHSC = dyn_cast(Ops[0])) { - ++Idx; - assert(Idx < Ops.size()); -+ auto FoldOp = [&](const APInt &LHS, const APInt &RHS) { -+ if (Kind == scSMaxExpr) -+ return APIntOps::smax(LHS, RHS); -+ else if (Kind == scSMinExpr) -+ return APIntOps::smin(LHS, RHS); -+ else if (Kind == scUMaxExpr) -+ return APIntOps::umax(LHS, RHS); -+ else if (Kind == scUMinExpr) -+ return APIntOps::umin(LHS, RHS); -+ llvm_unreachable("Unknown SCEV min/max opcode"); -+ }; -+ - while (const SCEVConstant *RHSC = dyn_cast(Ops[Idx])) { - // We found two constants, fold them together! - ConstantInt *Fold = ConstantInt::get( -- getContext(), APIntOps::smax(LHSC->getAPInt(), RHSC->getAPInt())); -+ getContext(), FoldOp(LHSC->getAPInt(), RHSC->getAPInt())); - Ops[0] = getConstant(Fold); - Ops.erase(Ops.begin()+1); // Erase the folded element - if (Ops.size() == 1) return Ops[0]; - LHSC = cast(Ops[0]); - } - -- // If we are left with a constant minimum-int, strip it off. -- if (cast(Ops[0])->getValue()->isMinValue(true)) { -+ bool IsMinV = LHSC->getValue()->isMinValue(IsSigned); -+ bool IsMaxV = LHSC->getValue()->isMaxValue(IsSigned); -+ -+ if (IsMax ? IsMinV : IsMaxV) { -+ // If we are left with a constant minimum(/maximum)-int, strip it off. - Ops.erase(Ops.begin()); - --Idx; -- } else if (cast(Ops[0])->getValue()->isMaxValue(true)) { -- // If we have an smax with a constant maximum-int, it will always be -- // maximum-int. -- return Ops[0]; -+ } else if (IsMax ? IsMaxV : IsMinV) { -+ // If we have a max(/min) with a constant maximum(/minimum)-int, -+ // it will always be the extremum. -+ return LHSC; - } - - if (Ops.size() == 1) return Ops[0]; - } - -- // Find the first SMax -- while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scSMaxExpr) -+ // Find the first operation of the same kind -+ while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < Kind) - ++Idx; - -- // Check to see if one of the operands is an SMax. If so, expand its operands -- // onto our operand list, and recurse to simplify. -+ // Check to see if one of the operands is of the same kind. If so, expand its -+ // operands onto our operand list, and recurse to simplify. - if (Idx < Ops.size()) { -- bool DeletedSMax = false; -- while (const SCEVSMaxExpr *SMax = dyn_cast(Ops[Idx])) { -+ bool DeletedAny = false; -+ while (Ops[Idx]->getSCEVType() == Kind) { -+ const SCEVMinMaxExpr *SMME = cast(Ops[Idx]); - Ops.erase(Ops.begin()+Idx); -- Ops.append(SMax->op_begin(), SMax->op_end()); -- DeletedSMax = true; -+ Ops.append(SMME->op_begin(), SMME->op_end()); -+ DeletedAny = true; - } - -- if (DeletedSMax) -- return getSMaxExpr(Ops); -+ if (DeletedAny) -+ return getMinMaxExpr(Kind, Ops); - } - - // Okay, check to see if the same value occurs in the operand list twice. If - // so, delete one. Since we sorted the list, these values are required to - // be adjacent. -- for (unsigned i = 0, e = Ops.size()-1; i != e; ++i) -- // X smax Y smax Y --> X smax Y -- // X smax Y --> X, if X is always greater than Y -- if (Ops[i] == Ops[i+1] || -- isKnownPredicate(ICmpInst::ICMP_SGE, Ops[i], Ops[i+1])) { -- Ops.erase(Ops.begin()+i+1, Ops.begin()+i+2); -- --i; --e; -- } else if (isKnownPredicate(ICmpInst::ICMP_SLE, Ops[i], Ops[i+1])) { -- Ops.erase(Ops.begin()+i, Ops.begin()+i+1); -- --i; --e; -+ llvm::CmpInst::Predicate GEPred = -+ IsSigned ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_UGE; -+ llvm::CmpInst::Predicate LEPred = -+ IsSigned ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; -+ llvm::CmpInst::Predicate FirstPred = IsMax ? GEPred : LEPred; -+ llvm::CmpInst::Predicate SecondPred = IsMax ? LEPred : GEPred; -+ for (unsigned i = 0, e = Ops.size() - 1; i != e; ++i) { -+ if (Ops[i] == Ops[i + 1] || -+ isKnownViaNonRecursiveReasoning(FirstPred, Ops[i], Ops[i + 1])) { -+ // X op Y op Y --> X op Y -+ // X op Y --> X, if we know X, Y are ordered appropriately -+ Ops.erase(Ops.begin() + i + 1, Ops.begin() + i + 2); -+ --i; -+ --e; -+ } else if (isKnownViaNonRecursiveReasoning(SecondPred, Ops[i], -+ Ops[i + 1])) { -+ // X op Y --> Y, if we know X, Y are ordered appropriately -+ Ops.erase(Ops.begin() + i, Ops.begin() + i + 1); -+ --i; -+ --e; - } -+ } - - if (Ops.size() == 1) return Ops[0]; - - assert(!Ops.empty() && "Reduced smax down to nothing!"); - -- // Okay, it looks like we really DO need an smax expr. Check to see if we -+ // Okay, it looks like we really DO need an expr. Check to see if we - // already have one, otherwise create a new one. - FoldingSetNodeID ID; -- ID.AddInteger(scSMaxExpr); -+ ID.AddInteger(Kind); - for (unsigned i = 0, e = Ops.size(); i != e; ++i) - ID.AddPointer(Ops[i]); - void *IP = nullptr; - if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; - const SCEV **O = SCEVAllocator.Allocate(Ops.size()); - std::uninitialized_copy(Ops.begin(), Ops.end(), O); -- SCEV *S = new (SCEVAllocator) SCEVSMaxExpr(ID.Intern(SCEVAllocator), -- O, Ops.size()); -+ SCEV *S = new (SCEVAllocator) SCEVMinMaxExpr( -+ ID.Intern(SCEVAllocator), static_cast(Kind), O, Ops.size()); - UniqueSCEVs.InsertNode(S, IP); - addToLoopUseLists(S); - return S; - } - --const SCEV *ScalarEvolution::getUMaxExpr(const SCEV *LHS, -- const SCEV *RHS) { -+const SCEV *ScalarEvolution::getSMaxExpr(const SCEV *LHS, const SCEV *RHS) { - SmallVector Ops = {LHS, RHS}; -- return getUMaxExpr(Ops); -+ return getSMaxExpr(Ops); - } - --const SCEV * --ScalarEvolution::getUMaxExpr(SmallVectorImpl &Ops) { -- assert(!Ops.empty() && "Cannot get empty umax!"); -- if (Ops.size() == 1) return Ops[0]; --#ifndef NDEBUG -- Type *ETy = getEffectiveSCEVType(Ops[0]->getType()); -- for (unsigned i = 1, e = Ops.size(); i != e; ++i) -- assert(getEffectiveSCEVType(Ops[i]->getType()) == ETy && -- "SCEVUMaxExpr operand types don't match!"); --#endif -- -- // Sort by complexity, this groups all similar expression types together. -- GroupByComplexity(Ops, &LI, DT); -- -- // If there are any constants, fold them together. -- unsigned Idx = 0; -- if (const SCEVConstant *LHSC = dyn_cast(Ops[0])) { -- ++Idx; -- assert(Idx < Ops.size()); -- while (const SCEVConstant *RHSC = dyn_cast(Ops[Idx])) { -- // We found two constants, fold them together! -- ConstantInt *Fold = ConstantInt::get( -- getContext(), APIntOps::umax(LHSC->getAPInt(), RHSC->getAPInt())); -- Ops[0] = getConstant(Fold); -- Ops.erase(Ops.begin()+1); // Erase the folded element -- if (Ops.size() == 1) return Ops[0]; -- LHSC = cast(Ops[0]); -- } -- -- // If we are left with a constant minimum-int, strip it off. -- if (cast(Ops[0])->getValue()->isMinValue(false)) { -- Ops.erase(Ops.begin()); -- --Idx; -- } else if (cast(Ops[0])->getValue()->isMaxValue(false)) { -- // If we have an umax with a constant maximum-int, it will always be -- // maximum-int. -- return Ops[0]; -- } -- -- if (Ops.size() == 1) return Ops[0]; -- } -- -- // Find the first UMax -- while (Idx < Ops.size() && Ops[Idx]->getSCEVType() < scUMaxExpr) -- ++Idx; -- -- // Check to see if one of the operands is a UMax. If so, expand its operands -- // onto our operand list, and recurse to simplify. -- if (Idx < Ops.size()) { -- bool DeletedUMax = false; -- while (const SCEVUMaxExpr *UMax = dyn_cast(Ops[Idx])) { -- Ops.erase(Ops.begin()+Idx); -- Ops.append(UMax->op_begin(), UMax->op_end()); -- DeletedUMax = true; -- } -- -- if (DeletedUMax) -- return getUMaxExpr(Ops); -- } -- -- // Okay, check to see if the same value occurs in the operand list twice. If -- // so, delete one. Since we sorted the list, these values are required to -- // be adjacent. -- for (unsigned i = 0, e = Ops.size()-1; i != e; ++i) -- // X umax Y umax Y --> X umax Y -- // X umax Y --> X, if X is always greater than Y -- if (Ops[i] == Ops[i + 1] || isKnownViaNonRecursiveReasoning( -- ICmpInst::ICMP_UGE, Ops[i], Ops[i + 1])) { -- Ops.erase(Ops.begin() + i + 1, Ops.begin() + i + 2); -- --i; --e; -- } else if (isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_ULE, Ops[i], -- Ops[i + 1])) { -- Ops.erase(Ops.begin() + i, Ops.begin() + i + 1); -- --i; --e; -- } -- -- if (Ops.size() == 1) return Ops[0]; -+const SCEV *ScalarEvolution::getSMaxExpr(SmallVectorImpl &Ops) { -+ return getMinMaxExpr(scSMaxExpr, Ops); -+} - -- assert(!Ops.empty() && "Reduced umax down to nothing!"); -+const SCEV *ScalarEvolution::getUMaxExpr(const SCEV *LHS, const SCEV *RHS) { -+ SmallVector Ops = {LHS, RHS}; -+ return getUMaxExpr(Ops); -+} - -- // Okay, it looks like we really DO need a umax expr. Check to see if we -- // already have one, otherwise create a new one. -- FoldingSetNodeID ID; -- ID.AddInteger(scUMaxExpr); -- for (unsigned i = 0, e = Ops.size(); i != e; ++i) -- ID.AddPointer(Ops[i]); -- void *IP = nullptr; -- if (const SCEV *S = UniqueSCEVs.FindNodeOrInsertPos(ID, IP)) return S; -- const SCEV **O = SCEVAllocator.Allocate(Ops.size()); -- std::uninitialized_copy(Ops.begin(), Ops.end(), O); -- SCEV *S = new (SCEVAllocator) SCEVUMaxExpr(ID.Intern(SCEVAllocator), -- O, Ops.size()); -- UniqueSCEVs.InsertNode(S, IP); -- addToLoopUseLists(S); -- return S; -+const SCEV *ScalarEvolution::getUMaxExpr(SmallVectorImpl &Ops) { -+ return getMinMaxExpr(scUMaxExpr, Ops); - } - - const SCEV *ScalarEvolution::getSMinExpr(const SCEV *LHS, -@@ -3705,11 +3663,7 @@ const SCEV *ScalarEvolution::getSMinExpr(const SCEV *LHS, - } - - const SCEV *ScalarEvolution::getSMinExpr(SmallVectorImpl &Ops) { -- // ~smax(~x, ~y, ~z) == smin(x, y, z). -- SmallVector NotOps; -- for (auto *S : Ops) -- NotOps.push_back(getNotSCEV(S)); -- return getNotSCEV(getSMaxExpr(NotOps)); -+ return getMinMaxExpr(scSMinExpr, Ops); - } - - const SCEV *ScalarEvolution::getUMinExpr(const SCEV *LHS, -@@ -3719,16 +3673,7 @@ const SCEV *ScalarEvolution::getUMinExpr(const SCEV *LHS, - } - - const SCEV *ScalarEvolution::getUMinExpr(SmallVectorImpl &Ops) { -- assert(!Ops.empty() && "At least one operand must be!"); -- // Trivial case. -- if (Ops.size() == 1) -- return Ops[0]; -- -- // ~umax(~x, ~y, ~z) == umin(x, y, z). -- SmallVector NotOps; -- for (auto *S : Ops) -- NotOps.push_back(getNotSCEV(S)); -- return getNotSCEV(getUMaxExpr(NotOps)); -+ return getMinMaxExpr(scUMinExpr, Ops); - } - - const SCEV *ScalarEvolution::getSizeOfExpr(Type *IntTy, Type *AllocTy) { -@@ -3970,12 +3915,45 @@ const SCEV *ScalarEvolution::getNegativeSCEV(const SCEV *V, - V, getConstant(cast(Constant::getAllOnesValue(Ty))), Flags); - } - -+/// If Expr computes ~A, return A else return nullptr -+static const SCEV *MatchNotExpr(const SCEV *Expr) { -+ const SCEVAddExpr *Add = dyn_cast(Expr); -+ if (!Add || Add->getNumOperands() != 2 || -+ !Add->getOperand(0)->isAllOnesValue()) -+ return nullptr; -+ -+ const SCEVMulExpr *AddRHS = dyn_cast(Add->getOperand(1)); -+ if (!AddRHS || AddRHS->getNumOperands() != 2 || -+ !AddRHS->getOperand(0)->isAllOnesValue()) -+ return nullptr; -+ -+ return AddRHS->getOperand(1); -+} -+ - /// Return a SCEV corresponding to ~V = -1-V - const SCEV *ScalarEvolution::getNotSCEV(const SCEV *V) { - if (const SCEVConstant *VC = dyn_cast(V)) - return getConstant( - cast(ConstantExpr::getNot(VC->getValue()))); - -+ // Fold ~(u|s)(min|max)(~x, ~y) to (u|s)(max|min)(x, y) -+ if (const SCEVMinMaxExpr *MME = dyn_cast(V)) { -+ auto MatchMinMaxNegation = [&](const SCEVMinMaxExpr *MME) { -+ SmallVector MatchedOperands; -+ for (const SCEV *Operand : MME->operands()) { -+ const SCEV *Matched = MatchNotExpr(Operand); -+ if (!Matched) -+ return (const SCEV *)nullptr; -+ MatchedOperands.push_back(Matched); -+ } -+ return getMinMaxExpr( -+ SCEVMinMaxExpr::negate(static_cast(MME->getSCEVType())), -+ MatchedOperands); -+ }; -+ if (const SCEV *Replaced = MatchMinMaxNegation(MME)) -+ return Replaced; -+ } -+ - Type *Ty = V->getType(); - Ty = getEffectiveSCEVType(Ty); - const SCEV *AllOnes = -@@ -5196,6 +5174,8 @@ static bool IsAvailableOnEntry(const Loop *L, DominatorTree &DT, const SCEV *S, - switch (S->getSCEVType()) { - case scConstant: case scTruncate: case scZeroExtend: case scSignExtend: - case scAddExpr: case scMulExpr: case scUMaxExpr: case scSMaxExpr: -+ case scUMinExpr: -+ case scSMinExpr: - // These expressions are available if their operand(s) is/are. - return true; - -@@ -8075,7 +8055,9 @@ static Constant *BuildConstantFromSCEV(const SCEV *V) { - } - case scSMaxExpr: - case scUMaxExpr: -- break; // TODO: smax, umax. -+ case scSMinExpr: -+ case scUMinExpr: -+ break; // TODO: smax, umax, smin, umax. - } - return nullptr; - } -@@ -8201,10 +8183,8 @@ const SCEV *ScalarEvolution::computeSCEVAtScope(const SCEV *V, const Loop *L) { - return getAddExpr(NewOps); - if (isa(Comm)) - return getMulExpr(NewOps); -- if (isa(Comm)) -- return getSMaxExpr(NewOps); -- if (isa(Comm)) -- return getUMaxExpr(NewOps); -+ if (isa(Comm)) -+ return getMinMaxExpr(Comm->getSCEVType(), NewOps); - llvm_unreachable("Unknown commutative SCEV type!"); - } - } -@@ -10045,41 +10025,15 @@ bool ScalarEvolution::isImpliedCondOperands(ICmpInst::Predicate Pred, - getNotSCEV(FoundLHS)); - } - --/// If Expr computes ~A, return A else return nullptr --static const SCEV *MatchNotExpr(const SCEV *Expr) { -- const SCEVAddExpr *Add = dyn_cast(Expr); -- if (!Add || Add->getNumOperands() != 2 || -- !Add->getOperand(0)->isAllOnesValue()) -- return nullptr; -- -- const SCEVMulExpr *AddRHS = dyn_cast(Add->getOperand(1)); -- if (!AddRHS || AddRHS->getNumOperands() != 2 || -- !AddRHS->getOperand(0)->isAllOnesValue()) -- return nullptr; -- -- return AddRHS->getOperand(1); --} -- --/// Is MaybeMaxExpr an SMax or UMax of Candidate and some other values? --template --static bool IsMaxConsistingOf(const SCEV *MaybeMaxExpr, -- const SCEV *Candidate) { -- const MaxExprType *MaxExpr = dyn_cast(MaybeMaxExpr); -- if (!MaxExpr) return false; -- -- return find(MaxExpr->operands(), Candidate) != MaxExpr->op_end(); --} -- --/// Is MaybeMinExpr an SMin or UMin of Candidate and some other values? --template --static bool IsMinConsistingOf(ScalarEvolution &SE, -- const SCEV *MaybeMinExpr, -- const SCEV *Candidate) { -- const SCEV *MaybeMaxExpr = MatchNotExpr(MaybeMinExpr); -- if (!MaybeMaxExpr) -+/// Is MaybeMinMaxExpr an (U|S)(Min|Max) of Candidate and some other values? -+template -+static bool IsMinMaxConsistingOf(const SCEV *MaybeMinMaxExpr, -+ const SCEV *Candidate) { -+ const MinMaxExprType *MinMaxExpr = dyn_cast(MaybeMinMaxExpr); -+ if (!MinMaxExpr) - return false; - -- return IsMaxConsistingOf(MaybeMaxExpr, SE.getNotSCEV(Candidate)); -+ return find(MinMaxExpr->operands(), Candidate) != MinMaxExpr->op_end(); - } - - static bool IsKnownPredicateViaAddRecStart(ScalarEvolution &SE, -@@ -10128,20 +10082,20 @@ static bool IsKnownPredicateViaMinOrMax(ScalarEvolution &SE, - LLVM_FALLTHROUGH; - case ICmpInst::ICMP_SLE: - return -- // min(A, ...) <= A -- IsMinConsistingOf(SE, LHS, RHS) || -- // A <= max(A, ...) -- IsMaxConsistingOf(RHS, LHS); -+ // min(A, ...) <= A -+ IsMinMaxConsistingOf(LHS, RHS) || -+ // A <= max(A, ...) -+ IsMinMaxConsistingOf(RHS, LHS); - - case ICmpInst::ICMP_UGE: - std::swap(LHS, RHS); - LLVM_FALLTHROUGH; - case ICmpInst::ICMP_ULE: - return -- // min(A, ...) <= A -- IsMinConsistingOf(SE, LHS, RHS) || -- // A <= max(A, ...) -- IsMaxConsistingOf(RHS, LHS); -+ // min(A, ...) <= A -+ IsMinMaxConsistingOf(LHS, RHS) || -+ // A <= max(A, ...) -+ IsMinMaxConsistingOf(RHS, LHS); - } - - llvm_unreachable("covered switch fell through?!"); -@@ -11611,7 +11565,9 @@ ScalarEvolution::computeLoopDisposition(const SCEV *S, const Loop *L) { - case scAddExpr: - case scMulExpr: - case scUMaxExpr: -- case scSMaxExpr: { -+ case scSMaxExpr: -+ case scUMinExpr: -+ case scSMinExpr: { - bool HasVarying = false; - for (auto *Op : cast(S)->operands()) { - LoopDisposition D = getLoopDisposition(Op, L); -@@ -11698,7 +11654,9 @@ ScalarEvolution::computeBlockDisposition(const SCEV *S, const BasicBlock *BB) { - case scAddExpr: - case scMulExpr: - case scUMaxExpr: -- case scSMaxExpr: { -+ case scSMaxExpr: -+ case scUMinExpr: -+ case scSMinExpr: { - const SCEVNAryExpr *NAry = cast(S); - bool Proper = true; - for (const SCEV *NAryOp : NAry->operands()) { -diff --git a/lib/Analysis/ScalarEvolutionExpander.cpp b/lib/Analysis/ScalarEvolutionExpander.cpp -index ca5cf1663b8..b56ec40ab75 100644 ---- a/lib/Analysis/ScalarEvolutionExpander.cpp -+++ b/lib/Analysis/ScalarEvolutionExpander.cpp -@@ -1634,7 +1634,8 @@ Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { - for (int i = S->getNumOperands()-2; i >= 0; --i) { - // In the case of mixed integer and pointer types, do the - // rest of the comparisons as integer. -- if (S->getOperand(i)->getType() != Ty) { -+ Type *OpTy = S->getOperand(i)->getType(); -+ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { - Ty = SE.getEffectiveSCEVType(Ty); - LHS = InsertNoopCastOfTo(LHS, Ty); - } -@@ -1658,7 +1659,8 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { - for (int i = S->getNumOperands()-2; i >= 0; --i) { - // In the case of mixed integer and pointer types, do the - // rest of the comparisons as integer. -- if (S->getOperand(i)->getType() != Ty) { -+ Type *OpTy = S->getOperand(i)->getType(); -+ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { - Ty = SE.getEffectiveSCEVType(Ty); - LHS = InsertNoopCastOfTo(LHS, Ty); - } -@@ -1676,6 +1678,56 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { - return LHS; - } - -+Value *SCEVExpander::visitSMinExpr(const SCEVSMinExpr *S) { -+ Value *LHS = expand(S->getOperand(S->getNumOperands() - 1)); -+ Type *Ty = LHS->getType(); -+ for (int i = S->getNumOperands() - 2; i >= 0; --i) { -+ // In the case of mixed integer and pointer types, do the -+ // rest of the comparisons as integer. -+ Type *OpTy = S->getOperand(i)->getType(); -+ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { -+ Ty = SE.getEffectiveSCEVType(Ty); -+ LHS = InsertNoopCastOfTo(LHS, Ty); -+ } -+ Value *RHS = expandCodeFor(S->getOperand(i), Ty); -+ Value *ICmp = Builder.CreateICmpSLT(LHS, RHS); -+ rememberInstruction(ICmp); -+ Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "smin"); -+ rememberInstruction(Sel); -+ LHS = Sel; -+ } -+ // In the case of mixed integer and pointer types, cast the -+ // final result back to the pointer type. -+ if (LHS->getType() != S->getType()) -+ LHS = InsertNoopCastOfTo(LHS, S->getType()); -+ return LHS; -+} -+ -+Value *SCEVExpander::visitUMinExpr(const SCEVUMinExpr *S) { -+ Value *LHS = expand(S->getOperand(S->getNumOperands() - 1)); -+ Type *Ty = LHS->getType(); -+ for (int i = S->getNumOperands() - 2; i >= 0; --i) { -+ // In the case of mixed integer and pointer types, do the -+ // rest of the comparisons as integer. -+ Type *OpTy = S->getOperand(i)->getType(); -+ if (OpTy->isIntegerTy() != Ty->isIntegerTy()) { -+ Ty = SE.getEffectiveSCEVType(Ty); -+ LHS = InsertNoopCastOfTo(LHS, Ty); -+ } -+ Value *RHS = expandCodeFor(S->getOperand(i), Ty); -+ Value *ICmp = Builder.CreateICmpULT(LHS, RHS); -+ rememberInstruction(ICmp); -+ Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "umin"); -+ rememberInstruction(Sel); -+ LHS = Sel; -+ } -+ // In the case of mixed integer and pointer types, cast the -+ // final result back to the pointer type. -+ if (LHS->getType() != S->getType()) -+ LHS = InsertNoopCastOfTo(LHS, S->getType()); -+ return LHS; -+} -+ - Value *SCEVExpander::expandCodeFor(const SCEV *SH, Type *Ty, - Instruction *IP) { - setInsertPoint(IP); -@@ -2102,7 +2154,7 @@ bool SCEVExpander::isHighCostExpansionHelper( - - // HowManyLessThans uses a Max expression whenever the loop is not guarded by - // the exit condition. -- if (isa(S) || isa(S)) -+ if (isa(S)) - return true; - - // Recurse past nary expressions, which commonly occur in the -diff --git a/test/Analysis/LoopAccessAnalysis/memcheck-ni.ll b/test/Analysis/LoopAccessAnalysis/memcheck-ni.ll -new file mode 100644 -index 00000000000..a08632f38d1 ---- /dev/null -+++ b/test/Analysis/LoopAccessAnalysis/memcheck-ni.ll -@@ -0,0 +1,50 @@ -+; RUN: opt -loop-versioning -S < %s | FileCheck %s -+ -+; NB: addrspaces 10-13 are non-integral -+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:10:11:12:13" -+ -+%jl_value_t = type opaque -+%jl_array_t = type { i8 addrspace(13)*, i64, i16, i16, i32 } -+ -+define void @"japi1_permutedims!_33509"(%jl_value_t addrspace(10)**) { -+; CHECK: [[CMP:%[^ ]*]] = icmp ult double addrspace(13)* [[A:%[^ ]*]], [[B:%[^ ]*]] -+; CHECK: [[SELECT:%[^ ]*]] = select i1 %18, double addrspace(13)* [[A]], double addrspace(13)* [[B]] -+top: -+ %1 = alloca [3 x i64], align 8 -+ %2 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %0, align 8 -+ %3 = getelementptr inbounds %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %0, i64 1 -+ %4 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %3, align 8 -+ %5 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 0 -+ store i64 1, i64* %5, align 8 -+ %6 = getelementptr inbounds [3 x i64], [3 x i64]* %1, i64 0, i64 1 -+ %7 = load i64, i64* inttoptr (i64 24 to i64*), align 8 -+ %8 = addrspacecast %jl_value_t addrspace(10)* %4 to %jl_value_t addrspace(11)* -+ %9 = bitcast %jl_value_t addrspace(11)* %8 to double addrspace(13)* addrspace(11)* -+ %10 = load double addrspace(13)*, double addrspace(13)* addrspace(11)* %9, align 8 -+ %11 = addrspacecast %jl_value_t addrspace(10)* %2 to %jl_value_t addrspace(11)* -+ %12 = bitcast %jl_value_t addrspace(11)* %11 to double addrspace(13)* addrspace(11)* -+ %13 = load double addrspace(13)*, double addrspace(13)* addrspace(11)* %12, align 8 -+ %14 = load i64, i64* %6, align 8 -+ br label %L74 -+ -+L74: -+ %value_phi20 = phi i64 [ 1, %top ], [ %22, %L74 ] -+ %value_phi21 = phi i64 [ 1, %top ], [ %23, %L74 ] -+ %value_phi22 = phi i64 [ 1, %top ], [ %25, %L74 ] -+ %15 = add i64 %value_phi21, -1 -+ %16 = getelementptr inbounds double, double addrspace(13)* %10, i64 %15 -+ %17 = bitcast double addrspace(13)* %16 to i64 addrspace(13)* -+ %18 = load i64, i64 addrspace(13)* %17, align 8 -+ %19 = add i64 %value_phi20, -1 -+ %20 = getelementptr inbounds double, double addrspace(13)* %13, i64 %19 -+ %21 = bitcast double addrspace(13)* %20 to i64 addrspace(13)* -+ store i64 %18, i64 addrspace(13)* %21, align 8 -+ %22 = add i64 %value_phi20, 1 -+ %23 = add i64 %14, %value_phi21 -+ %24 = icmp eq i64 %value_phi22, %7 -+ %25 = add i64 %value_phi22, 1 -+ br i1 %24, label %L94, label %L74 -+ -+L94: -+ ret void -+} -diff --git a/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll b/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll -index 405a47554e4..4285ef0f117 100644 ---- a/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll -+++ b/test/Analysis/LoopAccessAnalysis/reverse-memcheck-bounds.ll -@@ -58,7 +58,7 @@ for.end: ; preds = %for.body - - ; Here it is not obvious what the limits are, since 'step' could be negative. - --; CHECK: Low: (-1 + (-1 * ((-60001 + (-1 * %a)) umax (-60001 + (40000 * %step) + (-1 * %a))))) -+; CHECK: Low: ((60000 + %a) umin (60000 + (-40000 * %step) + %a)) - ; CHECK: High: (4 + ((60000 + %a) umax (60000 + (-40000 * %step) + %a))) - - define void @g(i64 %step) { -diff --git a/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll b/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll -index 3542ad2a41e..d930706d7d2 100644 ---- a/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll -+++ b/test/Analysis/ScalarEvolution/2008-07-29-SMinExpr.ll -@@ -22,5 +22,5 @@ afterfor: ; preds = %forinc, %entry - ret i32 %j.0.lcssa - } - --; CHECK: backedge-taken count is (-2147483632 + ((-1 + (-1 * %{{[xy]}})) smax (-1 + (-1 * %{{[xy]}})))) -+; CHECK: backedge-taken count is (-2147483633 + (-1 * (%{{[xy]}} smin %{{[xy]}}))) - -diff --git a/test/Analysis/ScalarEvolution/min-max-exprs.ll b/test/Analysis/ScalarEvolution/min-max-exprs.ll -index e8c1e33e095..51f72c643cc 100644 ---- a/test/Analysis/ScalarEvolution/min-max-exprs.ll -+++ b/test/Analysis/ScalarEvolution/min-max-exprs.ll -@@ -33,7 +33,7 @@ bb2: ; preds = %bb1 - %tmp9 = select i1 %tmp4, i64 %tmp5, i64 %tmp6 - ; min(N, i+3) - ; CHECK: select i1 %tmp4, i64 %tmp5, i64 %tmp6 --; CHECK-NEXT: --> (-1 + (-1 * ((-1 + (-1 * (sext i32 {3,+,1}<%bb1> to i64))) smax (-1 + (-1 * (sext i32 %N to i64)))))) -+; CHECK-NEXT: --> ((sext i32 {3,+,1}<%bb1> to i64) smin (sext i32 %N to i64)) - %tmp11 = getelementptr inbounds i32, i32* %A, i64 %tmp9 - %tmp12 = load i32, i32* %tmp11, align 4 - %tmp13 = shl nsw i32 %tmp12, 1 -diff --git a/test/Analysis/ScalarEvolution/predicated-trip-count.ll b/test/Analysis/ScalarEvolution/predicated-trip-count.ll -index a0afcf457d2..b07662ed95f 100644 ---- a/test/Analysis/ScalarEvolution/predicated-trip-count.ll -+++ b/test/Analysis/ScalarEvolution/predicated-trip-count.ll -@@ -80,7 +80,7 @@ return: ; preds = %bb5 - ; CHECK-NEXT: --> (sext i16 {%Start,+,-1}<%bb3> to i32) - ; CHECK: Loop %bb3: Unpredictable backedge-taken count. - ; CHECK-NEXT: Loop %bb3: Unpredictable max backedge-taken count. --; CHECK-NEXT: Loop %bb3: Predicated backedge-taken count is (2 + (sext i16 %Start to i32) + ((-2 + (-1 * (sext i16 %Start to i32))) smax (-1 + (-1 * %M)))) -+; CHECK-NEXT: Loop %bb3: Predicated backedge-taken count is (1 + (sext i16 %Start to i32) + (-1 * ((1 + (sext i16 %Start to i32)) smin %M))) - ; CHECK-NEXT: Predicates: - ; CHECK-NEXT: {%Start,+,-1}<%bb3> Added Flags: - -diff --git a/test/Analysis/ScalarEvolution/trip-count14.ll b/test/Analysis/ScalarEvolution/trip-count14.ll -index 5e6cfe85101..15080613881 100644 ---- a/test/Analysis/ScalarEvolution/trip-count14.ll -+++ b/test/Analysis/ScalarEvolution/trip-count14.ll -@@ -81,7 +81,7 @@ if.end: - br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times - - ; CHECK-LABEL: Determining loop execution counts for: @s32_max2_unpredictable_exit --; CHECK-NEXT: Loop %do.body: backedge-taken count is (-1 + (-1 * ((-1 + (-1 * ((2 + %n) smax %n)) + %n) umax (-1 + (-1 * %x) + %n)))) -+; CHECK-NEXT: Loop %do.body: backedge-taken count is (((-1 * %n) + ((2 + %n) smax %n)) umin ((-1 * %n) + %x)) - ; CHECK-NEXT: Loop %do.body: max backedge-taken count is 2{{$}} - - do.end: -@@ -169,7 +169,7 @@ if.end: - br i1 %cmp1, label %do.body, label %do.end ; taken either 0 or 2 times - - ; CHECK-LABEL: Determining loop execution counts for: @u32_max2_unpredictable_exit --; CHECK-NEXT: Loop %do.body: backedge-taken count is (-1 + (-1 * ((-1 + (-1 * ((2 + %n) umax %n)) + %n) umax (-1 + (-1 * %x) + %n)))) -+; CHECK-NEXT: Loop %do.body: backedge-taken count is (((-1 * %n) + ((2 + %n) umax %n)) umin ((-1 * %n) + %x)) - ; CHECK-NEXT: Loop %do.body: max backedge-taken count is 2{{$}} - - do.end: -diff --git a/test/Analysis/ScalarEvolution/trip-count3.ll b/test/Analysis/ScalarEvolution/trip-count3.ll -index df6637a4ced..e10012c0c32 100644 ---- a/test/Analysis/ScalarEvolution/trip-count3.ll -+++ b/test/Analysis/ScalarEvolution/trip-count3.ll -@@ -4,7 +4,7 @@ - ; dividing by the stride will have a remainder. This could theoretically - ; be teaching it how to use a more elaborate trip count computation. - --; CHECK: Loop %bb3.i: backedge-taken count is ((64 + (-64 smax (-1 + (-1 * %0))) + %0) /u 64) -+; CHECK: Loop %bb3.i: backedge-taken count is ((63 + (-1 * (63 smin %0)) + %0) /u 64) - ; CHECK: Loop %bb3.i: max backedge-taken count is 33554431 - - %struct.FILE = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.FILE*, i32, i32, i64, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i64, i32, [20 x i8] } -diff --git a/test/Transforms/IRCE/conjunctive-checks.ll b/test/Transforms/IRCE/conjunctive-checks.ll -index 60a0af83174..8711c1b00e8 100644 ---- a/test/Transforms/IRCE/conjunctive-checks.ll -+++ b/test/Transforms/IRCE/conjunctive-checks.ll -@@ -5,17 +5,15 @@ define void @f_0(i32 *%arr, i32 *%a_len_ptr, i32 %n, i1* %cond_buf) { - ; CHECK-LABEL: @f_0( - - ; CHECK: loop.preheader: --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_safe_range_end:[^ ]+]] = sub i32 3, %len --; CHECK: [[not_exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_n]], [[not_safe_range_end]] --; CHECK: [[not_exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[not_exit_main_loop_at_hiclamp_cmp]], i32 [[not_n]], i32 [[not_safe_range_end]] --; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = sub i32 -1, [[not_exit_main_loop_at_hiclamp]] -+; CHECK: [[len_sub:[^ ]+]] = add i32 %len, -4 -+; CHECK: [[exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp slt i32 %n, [[len_sub]] -+; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[exit_main_loop_at_hiclamp_cmp]], i32 %n, i32 [[len_sub]] - ; CHECK: [[exit_main_loop_at_loclamp_cmp:[^ ]+]] = icmp sgt i32 [[exit_main_loop_at_hiclamp]], 0 - ; CHECK: [[exit_main_loop_at_loclamp:[^ ]+]] = select i1 [[exit_main_loop_at_loclamp_cmp]], i32 [[exit_main_loop_at_hiclamp]], i32 0 - ; CHECK: [[enter_main_loop:[^ ]+]] = icmp slt i32 0, [[exit_main_loop_at_loclamp]] --; CHECK: br i1 [[enter_main_loop]], label %loop.preheader2, label %main.pseudo.exit -+; CHECK: br i1 [[enter_main_loop]], label %[[loop_preheader2:[^ ,]+]], label %main.pseudo.exit - --; CHECK: loop.preheader2: -+; CHECK: [[loop_preheader2]]: - ; CHECK: br label %loop - - entry: -@@ -35,9 +33,9 @@ define void @f_0(i32 *%arr, i32 *%a_len_ptr, i32 %n, i1* %cond_buf) { - ; CHECK: loop: - ; CHECK: %cond = load volatile i1, i1* %cond_buf - ; CHECK: %abc = and i1 %cond, true --; CHECK: br i1 %abc, label %in.bounds, label %out.of.bounds.loopexit3, !prof !1 -+; CHECK: br i1 %abc, label %in.bounds, label %[[loop_exit:[^ ,]+]], !prof !1 - --; CHECK: out.of.bounds.loopexit: -+; CHECK: [[loop_exit]]: - ; CHECK: br label %out.of.bounds - - in.bounds: -@@ -58,14 +56,10 @@ define void @f_1( - ; CHECK-LABEL: @f_1( - - ; CHECK: loop.preheader: --; CHECK: [[not_len_b:[^ ]+]] = sub i32 -1, %len.b --; CHECK: [[not_len_a:[^ ]+]] = sub i32 -1, %len.a --; CHECK: [[smax_not_len_cond:[^ ]+]] = icmp sgt i32 [[not_len_b]], [[not_len_a]] --; CHECK: [[smax_not_len:[^ ]+]] = select i1 [[smax_not_len_cond]], i32 [[not_len_b]], i32 [[not_len_a]] --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_upper_limit_cond_loclamp:[^ ]+]] = icmp sgt i32 [[smax_not_len]], [[not_n]] --; CHECK: [[not_upper_limit_loclamp:[^ ]+]] = select i1 [[not_upper_limit_cond_loclamp]], i32 [[smax_not_len]], i32 [[not_n]] --; CHECK: [[upper_limit_loclamp:[^ ]+]] = sub i32 -1, [[not_upper_limit_loclamp]] -+; CHECK: [[smax_len_cond:[^ ]+]] = icmp slt i32 %len.b, %len.a -+; CHECK: [[smax_len:[^ ]+]] = select i1 [[smax_len_cond]], i32 %len.b, i32 %len.a -+; CHECK: [[upper_limit_cond_loclamp:[^ ]+]] = icmp slt i32 [[smax_len]], %n -+; CHECK: [[upper_limit_loclamp:[^ ]+]] = select i1 [[upper_limit_cond_loclamp]], i32 [[smax_len]], i32 %n - ; CHECK: [[upper_limit_cmp:[^ ]+]] = icmp sgt i32 [[upper_limit_loclamp]], 0 - ; CHECK: [[upper_limit:[^ ]+]] = select i1 [[upper_limit_cmp]], i32 [[upper_limit_loclamp]], i32 0 - -@@ -85,9 +79,9 @@ define void @f_1( - - ; CHECK: loop: - ; CHECK: %abc = and i1 true, true --; CHECK: br i1 %abc, label %in.bounds, label %out.of.bounds.loopexit4, !prof !1 -+; CHECK: br i1 %abc, label %in.bounds, label %[[oob_loopexit:[^ ,]+]], !prof !1 - --; CHECK: out.of.bounds.loopexit: -+; CHECK: [[oob_loopexit]]: - ; CHECK-NEXT: br label %out.of.bounds - - -diff --git a/test/Transforms/IRCE/decrementing-loop.ll b/test/Transforms/IRCE/decrementing-loop.ll -index 4c82cd3e341..2994a432a71 100644 ---- a/test/Transforms/IRCE/decrementing-loop.ll -+++ b/test/Transforms/IRCE/decrementing-loop.ll -@@ -29,11 +29,8 @@ define void @decrementing_loop(i32 *%arr, i32 *%a_len_ptr, i32 %n) { - ret void - - ; CHECK: loop.preheader: --; CHECK: [[not_len:[^ ]+]] = sub i32 -1, %len --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_len_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_len]], [[not_n]] --; CHECK: [[not_len_hiclamp:[^ ]+]] = select i1 [[not_len_hiclamp_cmp]], i32 [[not_len]], i32 [[not_n]] --; CHECK: [[len_hiclamp:[^ ]+]] = sub i32 -1, [[not_len_hiclamp]] -+; CHECK: [[len_hiclamp_cmp:[^ ]+]] = icmp slt i32 %len, %n -+; CHECK: [[len_hiclamp:[^ ]+]] = select i1 [[len_hiclamp_cmp]], i32 %len, i32 %n - ; CHECK: [[not_exit_preloop_at_cmp:[^ ]+]] = icmp sgt i32 [[len_hiclamp]], 0 - ; CHECK: [[not_exit_preloop_at:[^ ]+]] = select i1 [[not_exit_preloop_at_cmp]], i32 [[len_hiclamp]], i32 0 - ; CHECK: %exit.preloop.at = add i32 [[not_exit_preloop_at]], -1 -diff --git a/test/Transforms/IRCE/multiple-access-no-preloop.ll b/test/Transforms/IRCE/multiple-access-no-preloop.ll -index 000d1ab36f2..3bde9bd8668 100644 ---- a/test/Transforms/IRCE/multiple-access-no-preloop.ll -+++ b/test/Transforms/IRCE/multiple-access-no-preloop.ll -@@ -38,14 +38,10 @@ define void @multiple_access_no_preloop( - ; CHECK-LABEL: @multiple_access_no_preloop( - - ; CHECK: loop.preheader: --; CHECK: [[not_len_b:[^ ]+]] = sub i32 -1, %len.b --; CHECK: [[not_len_a:[^ ]+]] = sub i32 -1, %len.a --; CHECK: [[smax_not_len_cond:[^ ]+]] = icmp sgt i32 [[not_len_b]], [[not_len_a]] --; CHECK: [[smax_not_len:[^ ]+]] = select i1 [[smax_not_len_cond]], i32 [[not_len_b]], i32 [[not_len_a]] --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_upper_limit_cond_loclamp:[^ ]+]] = icmp sgt i32 [[smax_not_len]], [[not_n]] --; CHECK: [[not_upper_limit_loclamp:[^ ]+]] = select i1 [[not_upper_limit_cond_loclamp]], i32 [[smax_not_len]], i32 [[not_n]] --; CHECK: [[upper_limit_loclamp:[^ ]+]] = sub i32 -1, [[not_upper_limit_loclamp]] -+; CHECK: [[smax_len_cond:[^ ]+]] = icmp slt i32 %len.b, %len.a -+; CHECK: [[smax_len:[^ ]+]] = select i1 [[smax_len_cond]], i32 %len.b, i32 %len.a -+; CHECK: [[upper_limit_cond_loclamp:[^ ]+]] = icmp slt i32 [[smax_len]], %n -+; CHECK: [[upper_limit_loclamp:[^ ]+]] = select i1 [[upper_limit_cond_loclamp]], i32 [[smax_len]], i32 %n - ; CHECK: [[upper_limit_cmp:[^ ]+]] = icmp sgt i32 [[upper_limit_loclamp]], 0 - ; CHECK: [[upper_limit:[^ ]+]] = select i1 [[upper_limit_cmp]], i32 [[upper_limit_loclamp]], i32 0 - -diff --git a/test/Transforms/IRCE/ranges_of_different_types.ll b/test/Transforms/IRCE/ranges_of_different_types.ll -index 5c8161369f2..46bd94ce687 100644 ---- a/test/Transforms/IRCE/ranges_of_different_types.ll -+++ b/test/Transforms/IRCE/ranges_of_different_types.ll -@@ -23,12 +23,11 @@ define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NOT: preloop - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 12, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102 --; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX]] --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0 --; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB2]], i32 0 -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = add i32 %len, -13 -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp slt i32 [[SUB1]], 101 -+; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 101 -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SMAX]], 0 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SMAX]], i32 0 - ; CHECK-NEXT: [[GOTO_LOOP:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at - ; CHECK-NEXT: br i1 [[GOTO_LOOP]], label %loop.preheader, label %main.pseudo.exit - ; CHECK: loop -@@ -83,13 +82,11 @@ define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NEXT: [[LEN_MINUS_SMAX:%[^ ]+]] = add i32 %len, -2147483647 - ; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[LEN_MINUS_SMAX]], -13 - ; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[LEN_MINUS_SMAX]], i32 -13 --; CHECK-NEXT: [[ADD1:%[^ ]+]] = add i32 [[SMAX1]], -1 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 [[ADD1]], %len --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102 --; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX2]] --; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0 --; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SUB2]], i32 0 -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 %len, [[SMAX1]] -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp slt i32 [[SUB1]], 101 -+; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 101 -+; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SMAX2]], 0 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SMAX2]], i32 0 - ; CHECK-NEXT: br i1 true, label %loop.preloop.preheader - ; CHECK: loop.preloop: - ; CHECK-NEXT: %idx.preloop = phi i32 [ %idx.next.preloop, %in.bounds.preloop ], [ 0, %loop.preloop.preheader ] -@@ -151,14 +148,11 @@ define void @test_03(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NOT: preloop - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -2, %len --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB2]], -14 --; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB2]], i32 -14 --; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 [[SUB1]], [[SMAX1]] --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ugt i32 [[SUB3]], -102 --; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB3]], i32 -102 --; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]] -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp slt i32 %len, 13 -+; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 %len, i32 13 -+; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 %len, [[SMAX1]] -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ult i32 [[SUB3]], 101 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB3]], i32 101 - ; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at - ; CHECK-NEXT: br i1 [[CMP3]], label %loop.preheader, label %main.pseudo.exit - ; CHECK: postloop: -@@ -208,10 +202,9 @@ define void @test_04(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-LABEL: test_04( - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -14, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ugt i32 [[SUB1]], -102 --; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]] -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = add i32 %len, 13 -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ult i32 [[SUB1]], 101 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP1]], i32 [[SUB1]], i32 101 - ; CHECK-NEXT: br i1 true, label %loop.preloop.preheader - ; CHECK: in.bounds.preloop: - ; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop -@@ -252,12 +245,11 @@ define void @test_05(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NOT: preloop - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 12, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102 --; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX]] --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0 --; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB2]], i32 0 -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = add i32 %len, -13 -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp slt i32 [[SUB1]], 101 -+; CHECK-NEXT: [[SMAX:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 101 -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SMAX]], 0 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SMAX]], i32 0 - ; CHECK-NEXT: [[GOTO_LOOP:%[^ ]+]] = icmp slt i32 0, %exit.mainloop.at - ; CHECK-NEXT: br i1 [[GOTO_LOOP]], label %loop.preheader, label %main.pseudo.exit - ; CHECK: loop -@@ -297,13 +289,11 @@ define void @test_06(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NEXT: [[LEN_MINUS_SMAX:%[^ ]+]] = add i32 %len, -2147483647 - ; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[LEN_MINUS_SMAX]], -13 - ; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[LEN_MINUS_SMAX]], i32 -13 --; CHECK-NEXT: [[ADD1:%[^ ]+]] = add i32 [[SMAX1]], -1 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 [[ADD1]], %len --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp sgt i32 [[SUB1]], -102 --; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, [[SMAX2]] --; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SUB2]], 0 --; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SUB2]], i32 0 -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 %len, [[SMAX1]] -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp slt i32 [[SUB1]], 101 -+; CHECK-NEXT: [[SMAX2:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB1]], i32 101 -+; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp sgt i32 [[SMAX2]], 0 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP3]], i32 [[SMAX2]], i32 0 - ; CHECK-NEXT: br i1 true, label %loop.preloop.preheader - ; CHECK: in.bounds.preloop: - ; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop -@@ -344,14 +334,11 @@ define void @test_07(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-NOT: preloop - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -2, %len --; CHECK-NEXT: [[SUB2:%[^ ]+]] = sub i32 -1, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp sgt i32 [[SUB2]], -14 --; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB2]], i32 -14 --; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 [[SUB1]], [[SMAX1]] --; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ugt i32 [[SUB3]], -102 --; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP2]], i32 [[SUB3]], i32 -102 --; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]] -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp slt i32 %len, 13 -+; CHECK-NEXT: [[SMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 %len, i32 13 -+; CHECK-NEXT: [[SUB3:%[^ ]+]] = sub i32 %len, [[SMAX1]] -+; CHECK-NEXT: [[CMP2:%[^ ]+]] = icmp ult i32 [[SUB3]], 101 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP2]], i32 [[SUB3]], i32 101 - ; CHECK-NEXT: [[CMP3:%[^ ]+]] = icmp ult i32 0, %exit.mainloop.at - ; CHECK-NEXT: br i1 [[CMP3]], label %loop.preheader, label %main.pseudo.exit - ; CHECK: loop -@@ -388,10 +375,9 @@ define void @test_08(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK-LABEL: test_08( - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 --; CHECK-NEXT: [[SUB1:%[^ ]+]] = sub i32 -14, %len --; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ugt i32 [[SUB1]], -102 --; CHECK-NEXT: [[UMAX1:%[^ ]+]] = select i1 [[CMP1]], i32 [[SUB1]], i32 -102 --; CHECK-NEXT: %exit.mainloop.at = sub i32 -1, [[UMAX1]] -+; CHECK-NEXT: [[SUB1:%[^ ]+]] = add i32 %len, 13 -+; CHECK-NEXT: [[CMP1:%[^ ]+]] = icmp ult i32 [[SUB1]], 101 -+; CHECK-NEXT: %exit.mainloop.at = select i1 [[CMP1]], i32 [[SUB1]], i32 101 - ; CHECK-NEXT: br i1 true, label %loop.preloop.preheader - ; CHECK: in.bounds.preloop: - ; CHECK-NEXT: %addr.preloop = getelementptr i32, i32* %arr, i32 %idx.preloop -diff --git a/test/Transforms/IRCE/rc-negative-bound.ll b/test/Transforms/IRCE/rc-negative-bound.ll -index bfc0cd14778..d226bffeaae 100644 ---- a/test/Transforms/IRCE/rc-negative-bound.ll -+++ b/test/Transforms/IRCE/rc-negative-bound.ll -@@ -114,49 +114,44 @@ define void @test_03(i32 *%arr, i32 %n, i32 %bound) { - ; CHECK: loop.preheader: - ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[BOUND:%.*]], -2147483647 - ; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[TMP0]], 0 --; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 0 --; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BOUND]], [[SMAX]] --; CHECK-NEXT: [[TMP3:%.*]] = sub i32 -1, [[BOUND]] --; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], -1 --; CHECK-NEXT: [[SMAX1:%.*]] = select i1 [[TMP4]], i32 [[TMP3]], i32 -1 --; CHECK-NEXT: [[TMP5:%.*]] = sub i32 -1, [[SMAX1]] --; CHECK-NEXT: [[TMP6:%.*]] = icmp sgt i32 [[TMP5]], -1 --; CHECK-NEXT: [[SMAX2:%.*]] = select i1 [[TMP6]], i32 [[TMP5]], i32 -1 --; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[SMAX2]], 1 --; CHECK-NEXT: [[TMP8:%.*]] = mul i32 [[TMP2]], [[TMP7]] --; CHECK-NEXT: [[TMP9:%.*]] = sub i32 -1, [[TMP8]] --; CHECK-NEXT: [[TMP10:%.*]] = sub i32 -1, [[N]] --; CHECK-NEXT: [[TMP11:%.*]] = icmp sgt i32 [[TMP9]], [[TMP10]] --; CHECK-NEXT: [[SMAX3:%.*]] = select i1 [[TMP11]], i32 [[TMP9]], i32 [[TMP10]] --; CHECK-NEXT: [[TMP12:%.*]] = sub i32 -1, [[SMAX3]] --; CHECK-NEXT: [[TMP13:%.*]] = icmp sgt i32 [[TMP12]], 0 --; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP13]], i32 [[TMP12]], i32 0 --; CHECK-NEXT: [[TMP14:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP14]], label [[LOOP_PREHEADER5:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] --; CHECK: loop.preheader5: -+; CHECK-NEXT: [[SMIN:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 0 -+; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BOUND]], [[SMIN]] -+; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[BOUND]], 0 -+; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP3]], i32 [[BOUND]], i32 0 -+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[SMAX]], -1 -+; CHECK-NEXT: [[SMIN1:%.*]] = select i1 [[TMP4]], i32 [[SMAX]], i32 -1 -+; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[SMIN1]], 1 -+; CHECK-NEXT: [[TMP6:%.*]] = mul i32 [[TMP2]], [[TMP5]] -+; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[N]], [[TMP6]] -+; CHECK-NEXT: [[SMAX2:%.*]] = select i1 [[TMP7]], i32 [[N]], i32 [[TMP6]] -+; CHECK-NEXT: [[TMP8:%.*]] = icmp sgt i32 [[SMAX2]], 0 -+; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP8]], i32 [[SMAX2]], i32 0 -+; CHECK-NEXT: [[TMP9:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP9]], label [[LOOP_PREHEADER4:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] -+; CHECK: loop.preheader4: - ; CHECK-NEXT: br label [[LOOP:%.*]] - ; CHECK: loop: --; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER5]] ] -+; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER4]] ] - ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], 1 - ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[BOUND]] --; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT6:%.*]], !prof !0 -+; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]], !prof !0 - ; CHECK: in.bounds: - ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i32 [[IDX]] - ; CHECK-NEXT: store i32 0, i32* [[ADDR]] - ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], [[N]] --; CHECK-NEXT: [[TMP15:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP15]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] -+; CHECK-NEXT: [[TMP10:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP10]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] - ; CHECK: main.exit.selector: - ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] --; CHECK-NEXT: [[TMP16:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], [[N]] --; CHECK-NEXT: br i1 [[TMP16]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] -+; CHECK-NEXT: [[TMP11:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], [[N]] -+; CHECK-NEXT: br i1 [[TMP11]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] - ; CHECK: main.pseudo.exit: - ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: br label [[POSTLOOP:%.*]] - ; CHECK: out.of.bounds.loopexit: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] --; CHECK: out.of.bounds.loopexit6: -+; CHECK: out.of.bounds.loopexit5: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] - ; CHECK: out.of.bounds: - ; CHECK-NEXT: ret void -@@ -211,47 +206,41 @@ define void @test_04(i32 *%arr, i32 %n, i32 %bound) { - ; CHECK-NEXT: [[FIRST_ITR_CHECK:%.*]] = icmp sgt i32 [[N:%.*]], 0 - ; CHECK-NEXT: br i1 [[FIRST_ITR_CHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]] - ; CHECK: loop.preheader: --; CHECK-NEXT: [[TMP0:%.*]] = sub i32 -1, [[BOUND:%.*]] --; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[TMP0]], -1 --; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 -1 --; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[BOUND]], [[SMAX]] --; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1 --; CHECK-NEXT: [[TMP4:%.*]] = sub i32 -1, [[SMAX]] --; CHECK-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], -1 --; CHECK-NEXT: [[SMAX1:%.*]] = select i1 [[TMP5]], i32 [[TMP4]], i32 -1 --; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[SMAX1]], 1 --; CHECK-NEXT: [[TMP7:%.*]] = mul i32 [[TMP3]], [[TMP6]] --; CHECK-NEXT: [[TMP8:%.*]] = sub i32 -1, [[TMP7]] --; CHECK-NEXT: [[TMP9:%.*]] = sub i32 -1, [[N]] --; CHECK-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP8]], [[TMP9]] --; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP10]], i32 [[TMP8]], i32 [[TMP9]] --; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = sub i32 -1, [[UMAX]] --; CHECK-NEXT: [[TMP11:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP11]], label [[LOOP_PREHEADER2:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] --; CHECK: loop.preheader2: -+; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[BOUND:%.*]], 0 -+; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[BOUND]], i32 0 -+; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[BOUND]], [[SMAX]] -+; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[SMAX]], -1 -+; CHECK-NEXT: [[SMIN:%.*]] = select i1 [[TMP2]], i32 [[SMAX]], i32 -1 -+; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[SMIN]], 1 -+; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[TMP1]], [[TMP3]] -+; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[N]], [[TMP4]] -+; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP5]], i32 [[N]], i32 [[TMP4]] -+; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER1:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] -+; CHECK: loop.preheader1: - ; CHECK-NEXT: br label [[LOOP:%.*]] - ; CHECK: loop: --; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER2]] ] -+; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER1]] ] - ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], 1 - ; CHECK-NEXT: [[ABC:%.*]] = icmp slt i32 [[IDX]], [[BOUND]] --; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT3:%.*]], !prof !0 -+; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT2:%.*]], !prof !0 - ; CHECK: in.bounds: - ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i32 [[IDX]] - ; CHECK-NEXT: store i32 0, i32* [[ADDR]] - ; CHECK-NEXT: [[NEXT:%.*]] = icmp ult i32 [[IDX_NEXT]], [[N]] --; CHECK-NEXT: [[TMP12:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP12]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] -+; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP7]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] - ; CHECK: main.exit.selector: - ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] --; CHECK-NEXT: [[TMP13:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], [[N]] --; CHECK-NEXT: br i1 [[TMP13]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] -+; CHECK-NEXT: [[TMP8:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], [[N]] -+; CHECK-NEXT: br i1 [[TMP8]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] - ; CHECK: main.pseudo.exit: - ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: br label [[POSTLOOP:%.*]] - ; CHECK: out.of.bounds.loopexit: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] --; CHECK: out.of.bounds.loopexit3: -+; CHECK: out.of.bounds.loopexit2: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] - ; CHECK: out.of.bounds: - ; CHECK-NEXT: ret void -@@ -413,49 +402,44 @@ define void @test_07(i32 *%arr, i32 %n, i32 %bound) { - ; CHECK: loop.preheader: - ; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[BOUND:%.*]], -2147483647 - ; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[TMP0]], 0 --; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 0 --; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BOUND]], [[SMAX]] --; CHECK-NEXT: [[TMP3:%.*]] = sub i32 -1, [[BOUND]] --; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[TMP3]], -1 --; CHECK-NEXT: [[SMAX1:%.*]] = select i1 [[TMP4]], i32 [[TMP3]], i32 -1 --; CHECK-NEXT: [[TMP5:%.*]] = sub i32 -1, [[SMAX1]] --; CHECK-NEXT: [[TMP6:%.*]] = icmp sgt i32 [[TMP5]], -1 --; CHECK-NEXT: [[SMAX2:%.*]] = select i1 [[TMP6]], i32 [[TMP5]], i32 -1 --; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[SMAX2]], 1 --; CHECK-NEXT: [[TMP8:%.*]] = mul i32 [[TMP2]], [[TMP7]] --; CHECK-NEXT: [[TMP9:%.*]] = sub i32 -1, [[TMP8]] --; CHECK-NEXT: [[TMP10:%.*]] = sub i32 -1, [[N]] --; CHECK-NEXT: [[TMP11:%.*]] = icmp sgt i32 [[TMP9]], [[TMP10]] --; CHECK-NEXT: [[SMAX3:%.*]] = select i1 [[TMP11]], i32 [[TMP9]], i32 [[TMP10]] --; CHECK-NEXT: [[TMP12:%.*]] = sub i32 -1, [[SMAX3]] --; CHECK-NEXT: [[TMP13:%.*]] = icmp sgt i32 [[TMP12]], 0 --; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP13]], i32 [[TMP12]], i32 0 --; CHECK-NEXT: [[TMP14:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP14]], label [[LOOP_PREHEADER5:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] --; CHECK: loop.preheader5: -+; CHECK-NEXT: [[SMIN:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 0 -+; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[BOUND]], [[SMIN]] -+; CHECK-NEXT: [[TMP3:%.*]] = icmp slt i32 [[BOUND]], 0 -+; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP3]], i32 [[BOUND]], i32 0 -+; CHECK-NEXT: [[TMP4:%.*]] = icmp sgt i32 [[SMAX]], -1 -+; CHECK-NEXT: [[SMIN1:%.*]] = select i1 [[TMP4]], i32 [[SMAX]], i32 -1 -+; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[SMIN1]], 1 -+; CHECK-NEXT: [[TMP6:%.*]] = mul i32 [[TMP2]], [[TMP5]] -+; CHECK-NEXT: [[TMP7:%.*]] = icmp slt i32 [[N]], [[TMP6]] -+; CHECK-NEXT: [[SMAX2:%.*]] = select i1 [[TMP7]], i32 [[N]], i32 [[TMP6]] -+; CHECK-NEXT: [[TMP8:%.*]] = icmp sgt i32 [[SMAX2]], 0 -+; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP8]], i32 [[SMAX2]], i32 0 -+; CHECK-NEXT: [[TMP9:%.*]] = icmp slt i32 0, [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP9]], label [[LOOP_PREHEADER4:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] -+; CHECK: loop.preheader4: - ; CHECK-NEXT: br label [[LOOP:%.*]] - ; CHECK: loop: --; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER5]] ] -+; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER4]] ] - ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], 1 - ; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[BOUND]] --; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT6:%.*]], !prof !0 -+; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT5:%.*]], !prof !0 - ; CHECK: in.bounds: - ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i32 [[IDX]] - ; CHECK-NEXT: store i32 0, i32* [[ADDR]] - ; CHECK-NEXT: [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], [[N]] --; CHECK-NEXT: [[TMP15:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP15]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] -+; CHECK-NEXT: [[TMP10:%.*]] = icmp slt i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP10]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] - ; CHECK: main.exit.selector: - ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] --; CHECK-NEXT: [[TMP16:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], [[N]] --; CHECK-NEXT: br i1 [[TMP16]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] -+; CHECK-NEXT: [[TMP11:%.*]] = icmp slt i32 [[IDX_NEXT_LCSSA]], [[N]] -+; CHECK-NEXT: br i1 [[TMP11]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] - ; CHECK: main.pseudo.exit: - ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: br label [[POSTLOOP:%.*]] - ; CHECK: out.of.bounds.loopexit: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] --; CHECK: out.of.bounds.loopexit6: -+; CHECK: out.of.bounds.loopexit5: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] - ; CHECK: out.of.bounds: - ; CHECK-NEXT: ret void -@@ -512,47 +496,41 @@ define void @test_08(i32 *%arr, i32 %n, i32 %bound) { - ; CHECK-NEXT: [[FIRST_ITR_CHECK:%.*]] = icmp sgt i32 [[N:%.*]], 0 - ; CHECK-NEXT: br i1 [[FIRST_ITR_CHECK]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]] - ; CHECK: loop.preheader: --; CHECK-NEXT: [[TMP0:%.*]] = sub i32 -1, [[BOUND:%.*]] --; CHECK-NEXT: [[TMP1:%.*]] = icmp sgt i32 [[TMP0]], -1 --; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP1]], i32 [[TMP0]], i32 -1 --; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[BOUND]], [[SMAX]] --; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], 1 --; CHECK-NEXT: [[TMP4:%.*]] = sub i32 -1, [[SMAX]] --; CHECK-NEXT: [[TMP5:%.*]] = icmp sgt i32 [[TMP4]], -1 --; CHECK-NEXT: [[SMAX1:%.*]] = select i1 [[TMP5]], i32 [[TMP4]], i32 -1 --; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[SMAX1]], 1 --; CHECK-NEXT: [[TMP7:%.*]] = mul i32 [[TMP3]], [[TMP6]] --; CHECK-NEXT: [[TMP8:%.*]] = sub i32 -1, [[TMP7]] --; CHECK-NEXT: [[TMP9:%.*]] = sub i32 -1, [[N]] --; CHECK-NEXT: [[TMP10:%.*]] = icmp ugt i32 [[TMP8]], [[TMP9]] --; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP10]], i32 [[TMP8]], i32 [[TMP9]] --; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = sub i32 -1, [[UMAX]] --; CHECK-NEXT: [[TMP11:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP11]], label [[LOOP_PREHEADER2:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] --; CHECK: loop.preheader2: -+; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i32 [[BOUND:%.*]], 0 -+; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[BOUND]], i32 0 -+; CHECK-NEXT: [[TMP1:%.*]] = sub i32 [[BOUND]], [[SMAX]] -+; CHECK-NEXT: [[TMP2:%.*]] = icmp sgt i32 [[SMAX]], -1 -+; CHECK-NEXT: [[SMIN:%.*]] = select i1 [[TMP2]], i32 [[SMAX]], i32 -1 -+; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[SMIN]], 1 -+; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[TMP1]], [[TMP3]] -+; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i32 [[N]], [[TMP4]] -+; CHECK-NEXT: [[EXIT_MAINLOOP_AT:%.*]] = select i1 [[TMP5]], i32 [[N]], i32 [[TMP4]] -+; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i32 0, [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP6]], label [[LOOP_PREHEADER1:%.*]], label [[MAIN_PSEUDO_EXIT:%.*]] -+; CHECK: loop.preheader1: - ; CHECK-NEXT: br label [[LOOP:%.*]] - ; CHECK: loop: --; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER2]] ] -+; CHECK-NEXT: [[IDX:%.*]] = phi i32 [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ], [ 0, [[LOOP_PREHEADER1]] ] - ; CHECK-NEXT: [[IDX_NEXT]] = add i32 [[IDX]], 1 - ; CHECK-NEXT: [[ABC:%.*]] = icmp ult i32 [[IDX]], [[BOUND]] --; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT3:%.*]], !prof !0 -+; CHECK-NEXT: br i1 true, label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS_LOOPEXIT2:%.*]], !prof !0 - ; CHECK: in.bounds: - ; CHECK-NEXT: [[ADDR:%.*]] = getelementptr i32, i32* [[ARR:%.*]], i32 [[IDX]] - ; CHECK-NEXT: store i32 0, i32* [[ADDR]] - ; CHECK-NEXT: [[NEXT:%.*]] = icmp ult i32 [[IDX_NEXT]], [[N]] --; CHECK-NEXT: [[TMP12:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] --; CHECK-NEXT: br i1 [[TMP12]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] -+; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[IDX_NEXT]], [[EXIT_MAINLOOP_AT]] -+; CHECK-NEXT: br i1 [[TMP7]], label [[LOOP]], label [[MAIN_EXIT_SELECTOR:%.*]] - ; CHECK: main.exit.selector: - ; CHECK-NEXT: [[IDX_NEXT_LCSSA:%.*]] = phi i32 [ [[IDX_NEXT]], [[IN_BOUNDS]] ] --; CHECK-NEXT: [[TMP13:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], [[N]] --; CHECK-NEXT: br i1 [[TMP13]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] -+; CHECK-NEXT: [[TMP8:%.*]] = icmp ult i32 [[IDX_NEXT_LCSSA]], [[N]] -+; CHECK-NEXT: br i1 [[TMP8]], label [[MAIN_PSEUDO_EXIT]], label [[EXIT_LOOPEXIT:%.*]] - ; CHECK: main.pseudo.exit: - ; CHECK-NEXT: [[IDX_COPY:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: [[INDVAR_END:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ], [ [[IDX_NEXT_LCSSA]], [[MAIN_EXIT_SELECTOR]] ] - ; CHECK-NEXT: br label [[POSTLOOP:%.*]] - ; CHECK: out.of.bounds.loopexit: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS:%.*]] --; CHECK: out.of.bounds.loopexit3: -+; CHECK: out.of.bounds.loopexit2: - ; CHECK-NEXT: br label [[OUT_OF_BOUNDS]] - ; CHECK: out.of.bounds: - ; CHECK-NEXT: ret void -diff --git a/test/Transforms/IRCE/single-access-no-preloop.ll b/test/Transforms/IRCE/single-access-no-preloop.ll -index fb643139c6d..7bf36f7c254 100644 ---- a/test/Transforms/IRCE/single-access-no-preloop.ll -+++ b/test/Transforms/IRCE/single-access-no-preloop.ll -@@ -86,15 +86,13 @@ define void @single_access_no_preloop_with_offset(i32 *%arr, i32 *%a_len_ptr, i3 - ; CHECK-LABEL: @single_access_no_preloop_with_offset( - - ; CHECK: loop.preheader: --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_safe_range_end:[^ ]+]] = sub i32 3, %len --; CHECK: [[not_exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp sgt i32 [[not_n]], [[not_safe_range_end]] --; CHECK: [[not_exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[not_exit_main_loop_at_hiclamp_cmp]], i32 [[not_n]], i32 [[not_safe_range_end]] --; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = sub i32 -1, [[not_exit_main_loop_at_hiclamp]] -+; CHECK: [[safe_range_end:[^ ]+]] = add i32 %len, -4 -+; CHECK: [[exit_main_loop_at_hiclamp_cmp:[^ ]+]] = icmp slt i32 %n, [[safe_range_end]] -+; CHECK: [[exit_main_loop_at_hiclamp:[^ ]+]] = select i1 [[exit_main_loop_at_hiclamp_cmp]], i32 %n, i32 [[safe_range_end]] - ; CHECK: [[exit_main_loop_at_loclamp_cmp:[^ ]+]] = icmp sgt i32 [[exit_main_loop_at_hiclamp]], 0 - ; CHECK: [[exit_main_loop_at_loclamp:[^ ]+]] = select i1 [[exit_main_loop_at_loclamp_cmp]], i32 [[exit_main_loop_at_hiclamp]], i32 0 - ; CHECK: [[enter_main_loop:[^ ]+]] = icmp slt i32 0, [[exit_main_loop_at_loclamp]] --; CHECK: br i1 [[enter_main_loop]], label %loop.preheader2, label %main.pseudo.exit -+; CHECK: br i1 [[enter_main_loop]], label %[[loop_preheader:[^ ,]+]], label %main.pseudo.exit - - ; CHECK: loop: - ; CHECK: br i1 true, label %in.bounds, label %out.of.bounds -diff --git a/test/Transforms/IRCE/single-access-with-preloop.ll b/test/Transforms/IRCE/single-access-with-preloop.ll -index 6f3b0324e39..bd235aa4a73 100644 ---- a/test/Transforms/IRCE/single-access-with-preloop.ll -+++ b/test/Transforms/IRCE/single-access-with-preloop.ll -@@ -34,11 +34,9 @@ define void @single_access_with_preloop(i32 *%arr, i32 *%a_len_ptr, i32 %n, i32 - ; CHECK: [[check_min_sint_offset:[^ ]+]] = icmp sgt i32 %offset, -2147483647 - ; CHECK: [[safe_offset_preloop:[^ ]+]] = select i1 [[check_min_sint_offset]], i32 %offset, i32 -2147483647 - ; If Offset was a SINT_MIN, we could have an overflow here. That is why we calculated its safe version. --; CHECK: [[not_safe_start:[^ ]+]] = add i32 [[safe_offset_preloop]], -1 --; CHECK: [[not_n:[^ ]+]] = sub i32 -1, %n --; CHECK: [[not_exit_preloop_at_cond_loclamp:[^ ]+]] = icmp sgt i32 [[not_safe_start]], [[not_n]] --; CHECK: [[not_exit_preloop_at_loclamp:[^ ]+]] = select i1 [[not_exit_preloop_at_cond_loclamp]], i32 [[not_safe_start]], i32 [[not_n]] --; CHECK: [[exit_preloop_at_loclamp:[^ ]+]] = sub i32 -1, [[not_exit_preloop_at_loclamp]] -+; CHECK: [[safe_start:[^ ]+]] = sub i32 0, [[safe_offset_preloop]] -+; CHECK: [[exit_preloop_at_cond_loclamp:[^ ]+]] = icmp slt i32 %n, [[safe_start]] -+; CHECK: [[exit_preloop_at_loclamp:[^ ]+]] = select i1 [[exit_preloop_at_cond_loclamp]], i32 %n, i32 [[safe_start]] - ; CHECK: [[exit_preloop_at_cond:[^ ]+]] = icmp sgt i32 [[exit_preloop_at_loclamp]], 0 - ; CHECK: [[exit_preloop_at:[^ ]+]] = select i1 [[exit_preloop_at_cond]], i32 [[exit_preloop_at_loclamp]], i32 0 - -@@ -46,17 +44,15 @@ define void @single_access_with_preloop(i32 *%arr, i32 *%a_len_ptr, i32 %n, i32 - ; CHECK: [[len_minus_sint_max:[^ ]+]] = add i32 %len, -2147483647 - ; CHECK: [[check_len_min_sint_offset:[^ ]+]] = icmp sgt i32 %offset, [[len_minus_sint_max]] - ; CHECK: [[safe_offset_mainloop:[^ ]+]] = select i1 [[check_len_min_sint_offset]], i32 %offset, i32 [[len_minus_sint_max]] --; CHECK: [[not_safe_start_2:[^ ]+]] = add i32 [[safe_offset_mainloop]], -1 - ; If Offset was a SINT_MIN, we could have an overflow here. That is why we calculated its safe version. --; CHECK: [[not_safe_upper_end:[^ ]+]] = sub i32 [[not_safe_start_2]], %len --; CHECK: [[not_exit_mainloop_at_cond_loclamp:[^ ]+]] = icmp sgt i32 [[not_safe_upper_end]], [[not_n]] --; CHECK: [[not_exit_mainloop_at_loclamp:[^ ]+]] = select i1 [[not_exit_mainloop_at_cond_loclamp]], i32 [[not_safe_upper_end]], i32 [[not_n]] -+; CHECK: [[safe_upper_end:[^ ]+]] = sub i32 %len, [[safe_offset_mainloop]] -+; CHECK: [[exit_mainloop_at_cond_loclamp:[^ ]+]] = icmp slt i32 %n, [[safe_upper_end]] -+; CHECK: [[exit_mainloop_at_loclamp:[^ ]+]] = select i1 [[exit_mainloop_at_cond_loclamp]], i32 %n, i32 [[safe_upper_end]] - ; CHECK: [[check_offset_mainloop_2:[^ ]+]] = icmp sgt i32 %offset, 0 - ; CHECK: [[safe_offset_mainloop_2:[^ ]+]] = select i1 [[check_offset_mainloop_2]], i32 %offset, i32 0 --; CHECK: [[not_safe_lower_end:[^ ]+]] = add i32 [[safe_offset_mainloop_2]], -2147483648 --; CHECK: [[not_exit_mainloop_at_cond_hiclamp:[^ ]+]] = icmp sgt i32 [[not_exit_mainloop_at_loclamp]], [[not_safe_lower_end]] --; CHECK: [[not_exit_mainloop_at_hiclamp:[^ ]+]] = select i1 [[not_exit_mainloop_at_cond_hiclamp]], i32 [[not_exit_mainloop_at_loclamp]], i32 [[not_safe_lower_end]] --; CHECK: [[exit_mainloop_at_hiclamp:[^ ]+]] = sub i32 -1, [[not_exit_mainloop_at_hiclamp]] -+; CHECK: [[safe_lower_end:[^ ]+]] = sub i32 2147483647, [[safe_offset_mainloop_2]] -+; CHECK: [[exit_mainloop_at_cond_hiclamp:[^ ]+]] = icmp slt i32 [[exit_mainloop_at_loclamp]], [[safe_lower_end]] -+; CHECK: [[exit_mainloop_at_hiclamp:[^ ]+]] = select i1 [[exit_mainloop_at_cond_hiclamp]], i32 [[exit_mainloop_at_loclamp]], i32 [[safe_lower_end]] - ; CHECK: [[exit_mainloop_at_cmp:[^ ]+]] = icmp sgt i32 [[exit_mainloop_at_hiclamp]], 0 - ; CHECK: [[exit_mainloop_at:[^ ]+]] = select i1 [[exit_mainloop_at_cmp]], i32 [[exit_mainloop_at_hiclamp]], i32 0 - -@@ -67,7 +63,7 @@ define void @single_access_with_preloop(i32 *%arr, i32 *%a_len_ptr, i32 %n, i32 - ; CHECK: %abc.high = icmp slt i32 %array.idx, %len - ; CHECK: %abc.low = icmp sge i32 %array.idx, 0 - ; CHECK: %abc = and i1 true, true --; CHECK: br i1 %abc, label %in.bounds, label %out.of.bounds.loopexit11 -+; CHECK: br i1 %abc, label %in.bounds, label %[[loopexit:[^ ,]+]] - - ; CHECK: in.bounds: - ; CHECK: [[continue_mainloop_cond:[^ ]+]] = icmp slt i32 %idx.next, [[exit_mainloop_at]] -diff --git a/test/Transforms/IRCE/unsigned_comparisons_ugt.ll b/test/Transforms/IRCE/unsigned_comparisons_ugt.ll -index 8f00c733569..3451d65c7bb 100644 ---- a/test/Transforms/IRCE/unsigned_comparisons_ugt.ll -+++ b/test/Transforms/IRCE/unsigned_comparisons_ugt.ll -@@ -58,8 +58,8 @@ define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 - ; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 --; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 --; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 -+; CHECK-NEXT: [[UMIN:%[^ ]+]] = select i1 [[COND1]], i32 %len, i32 1 -+; CHECK-NEXT: %exit.preloop.at = add i32 [[UMIN]], -1 - ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 100, %exit.preloop.at - ; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit - ; CHECK: mainloop: -@@ -149,8 +149,8 @@ define void @test_04(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 - ; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 --; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 --; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 -+; CHECK-NEXT: [[UMIN:%[^ ]+]] = select i1 [[COND1]], i32 %len, i32 1 -+; CHECK-NEXT: %exit.preloop.at = add i32 [[UMIN]], -1 - ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 -2147483648, %exit.preloop.at - ; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit - ; CHECK: mainloop: -diff --git a/test/Transforms/IRCE/unsigned_comparisons_ult.ll b/test/Transforms/IRCE/unsigned_comparisons_ult.ll -index dc59c11df1b..aca3c3d192e 100644 ---- a/test/Transforms/IRCE/unsigned_comparisons_ult.ll -+++ b/test/Transforms/IRCE/unsigned_comparisons_ult.ll -@@ -61,8 +61,8 @@ define void @test_02(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 - ; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 --; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 --; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 -+; CHECK-NEXT: [[UMIN:%[^ ]+]] = select i1 [[COND1]], i32 %len, i32 1 -+; CHECK-NEXT: %exit.preloop.at = add i32 [[UMIN]], -1 - ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 100, %exit.preloop.at - ; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit - ; CHECK: mainloop: -@@ -194,8 +194,8 @@ define void @test_05(i32* %arr, i32* %a_len_ptr) #0 { - ; CHECK: entry: - ; CHECK-NEXT: %len = load i32, i32* %a_len_ptr, !range !0 - ; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ugt i32 %len, 1 --; CHECK-NEXT: %umax = select i1 [[COND1]], i32 %len, i32 1 --; CHECK-NEXT: %exit.preloop.at = add i32 %umax, -1 -+; CHECK-NEXT: [[UMIN:%[^ ]+]] = select i1 [[COND1]], i32 %len, i32 1 -+; CHECK-NEXT: %exit.preloop.at = add i32 [[UMIN]], -1 - ; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ugt i32 -2147483648, %exit.preloop.at - ; CHECK-NEXT: br i1 [[COND2]], label %loop.preloop.preheader, label %preloop.pseudo.exit - ; CHECK: mainloop: -diff --git a/test/Transforms/LoopStrengthReduce/2013-01-14-ReuseCast.ll b/test/Transforms/LoopStrengthReduce/2013-01-14-ReuseCast.ll -index ea3f6077231..d5232e1874c 100644 ---- a/test/Transforms/LoopStrengthReduce/2013-01-14-ReuseCast.ll -+++ b/test/Transforms/LoopStrengthReduce/2013-01-14-ReuseCast.ll -@@ -14,8 +14,6 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3 - ; current LSR cost model. - ; CHECK-NOT: = ptrtoint i8* undef to i64 - ; CHECK: .lr.ph --; CHECK: [[TMP:%[^ ]+]] = add i64 %tmp{{[0-9]+}}, -1 --; CHECK: sub i64 [[TMP]], %tmp{{[0-9]+}} - ; CHECK: ret void - define void @VerifyDiagnosticConsumerTest() unnamed_addr nounwind uwtable align 2 { - bb: -diff --git a/test/Transforms/LoopVectorize/X86/pr35432.ll b/test/Transforms/LoopVectorize/X86/pr35432.ll -index 1f2a2061586..6aaa13c183a 100644 ---- a/test/Transforms/LoopVectorize/X86/pr35432.ll -+++ b/test/Transforms/LoopVectorize/X86/pr35432.ll -@@ -27,7 +27,6 @@ define i32 @main() local_unnamed_addr #0 { - ; CHECK-NEXT: [[CMP8:%.*]] = icmp eq i32 [[CONV17]], 0 - ; CHECK-NEXT: br i1 [[CMP8]], label [[FOR_BODY_LR_PH:%.*]], label [[FOR_END12:%.*]] - ; CHECK: for.body.lr.ph: --; CHECK-NEXT: [[TMP3:%.*]] = sub i32 -1, [[TMP2]] - ; CHECK-NEXT: br label [[FOR_BODY:%.*]] - ; CHECK: for.body: - ; CHECK-NEXT: [[STOREMERGE_IN9:%.*]] = phi i32 [ [[TMP2]], [[FOR_BODY_LR_PH]] ], [ [[ADD:%.*]], [[FOR_INC9:%.*]] ] -@@ -37,77 +36,74 @@ define i32 @main() local_unnamed_addr #0 { - ; CHECK: for.body8.lr.ph: - ; CHECK-NEXT: [[CONV3:%.*]] = trunc i32 [[STOREMERGE_IN9]] to i8 - ; CHECK-NEXT: [[DOTPROMOTED:%.*]] = load i32, i32* getelementptr inbounds ([192 x [192 x i32]], [192 x [192 x i32]]* @a, i64 0, i64 0, i64 0), align 16 --; CHECK-NEXT: [[TMP4:%.*]] = add i8 [[CONV3]], -1 --; CHECK-NEXT: [[TMP5:%.*]] = zext i8 [[TMP4]] to i32 --; CHECK-NEXT: [[TMP6:%.*]] = sub i32 -1, [[TMP5]] --; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i32 [[TMP3]], [[TMP6]] --; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP7]], i32 [[TMP3]], i32 [[TMP6]] --; CHECK-NEXT: [[TMP8:%.*]] = add i32 [[UMAX]], 2 --; CHECK-NEXT: [[TMP9:%.*]] = add i32 [[TMP8]], [[TMP5]] --; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[TMP9]], 8 -+; CHECK-NEXT: [[TMP3:%.*]] = add i8 [[CONV3]], -1 -+; CHECK-NEXT: [[TMP4:%.*]] = zext i8 [[TMP3]] to i32 -+; CHECK-NEXT: [[TMP5:%.*]] = add i32 [[TMP4]], 1 -+; CHECK-NEXT: [[TMP6:%.*]] = icmp ult i32 [[TMP2]], [[TMP4]] -+; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP6]], i32 [[TMP2]], i32 [[TMP4]] -+; CHECK-NEXT: [[TMP7:%.*]] = sub i32 [[TMP5]], [[UMAX]] -+; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[TMP7]], 8 - ; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_SCEVCHECK:%.*]] - ; CHECK: vector.scevcheck: --; CHECK-NEXT: [[TMP10:%.*]] = add i8 [[CONV3]], -1 --; CHECK-NEXT: [[TMP11:%.*]] = zext i8 [[TMP10]] to i32 --; CHECK-NEXT: [[TMP12:%.*]] = sub i32 -1, [[TMP11]] --; CHECK-NEXT: [[TMP13:%.*]] = icmp ugt i32 [[TMP3]], [[TMP12]] --; CHECK-NEXT: [[UMAX1:%.*]] = select i1 [[TMP13]], i32 [[TMP3]], i32 [[TMP12]] --; CHECK-NEXT: [[TMP14:%.*]] = add i32 [[UMAX1]], 1 --; CHECK-NEXT: [[TMP15:%.*]] = add i32 [[TMP14]], [[TMP11]] --; CHECK-NEXT: [[TMP16:%.*]] = trunc i32 [[TMP15]] to i8 --; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 1, i8 [[TMP16]]) -+; CHECK-NEXT: [[TMP8:%.*]] = add i8 [[CONV3]], -1 -+; CHECK-NEXT: [[TMP9:%.*]] = zext i8 [[TMP8]] to i32 -+; CHECK-NEXT: [[TMP10:%.*]] = icmp ult i32 [[TMP2]], [[TMP9]] -+; CHECK-NEXT: [[UMAX1:%.*]] = select i1 [[TMP10]], i32 [[TMP2]], i32 [[TMP9]] -+; CHECK-NEXT: [[TMP11:%.*]] = sub i32 [[TMP9]], [[UMAX1]] -+; CHECK-NEXT: [[TMP12:%.*]] = trunc i32 [[TMP11]] to i8 -+; CHECK-NEXT: [[MUL:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 1, i8 [[TMP12]]) - ; CHECK-NEXT: [[MUL_RESULT:%.*]] = extractvalue { i8, i1 } [[MUL]], 0 - ; CHECK-NEXT: [[MUL_OVERFLOW:%.*]] = extractvalue { i8, i1 } [[MUL]], 1 --; CHECK-NEXT: [[TMP17:%.*]] = add i8 [[TMP10]], [[MUL_RESULT]] --; CHECK-NEXT: [[TMP18:%.*]] = sub i8 [[TMP10]], [[MUL_RESULT]] --; CHECK-NEXT: [[TMP19:%.*]] = icmp ugt i8 [[TMP18]], [[TMP10]] --; CHECK-NEXT: [[TMP20:%.*]] = icmp ult i8 [[TMP17]], [[TMP10]] --; CHECK-NEXT: [[TMP21:%.*]] = select i1 true, i1 [[TMP19]], i1 [[TMP20]] --; CHECK-NEXT: [[TMP22:%.*]] = icmp ugt i32 [[TMP15]], 255 --; CHECK-NEXT: [[TMP23:%.*]] = or i1 [[TMP21]], [[TMP22]] --; CHECK-NEXT: [[TMP24:%.*]] = or i1 [[TMP23]], [[MUL_OVERFLOW]] --; CHECK-NEXT: [[TMP25:%.*]] = or i1 false, [[TMP24]] --; CHECK-NEXT: br i1 [[TMP25]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]] -+; CHECK-NEXT: [[TMP13:%.*]] = add i8 [[TMP8]], [[MUL_RESULT]] -+; CHECK-NEXT: [[TMP14:%.*]] = sub i8 [[TMP8]], [[MUL_RESULT]] -+; CHECK-NEXT: [[TMP15:%.*]] = icmp ugt i8 [[TMP14]], [[TMP8]] -+; CHECK-NEXT: [[TMP16:%.*]] = icmp ult i8 [[TMP13]], [[TMP8]] -+; CHECK-NEXT: [[TMP17:%.*]] = select i1 true, i1 [[TMP15]], i1 [[TMP16]] -+; CHECK-NEXT: [[TMP18:%.*]] = icmp ugt i32 [[TMP11]], 255 -+; CHECK-NEXT: [[TMP19:%.*]] = or i1 [[TMP17]], [[TMP18]] -+; CHECK-NEXT: [[TMP20:%.*]] = or i1 [[TMP19]], [[MUL_OVERFLOW]] -+; CHECK-NEXT: [[TMP21:%.*]] = or i1 false, [[TMP20]] -+; CHECK-NEXT: br i1 [[TMP21]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]] - ; CHECK: vector.ph: --; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[TMP9]], 8 --; CHECK-NEXT: [[N_VEC:%.*]] = sub i32 [[TMP9]], [[N_MOD_VF]] -+; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i32 [[TMP7]], 8 -+; CHECK-NEXT: [[N_VEC:%.*]] = sub i32 [[TMP7]], [[N_MOD_VF]] - ; CHECK-NEXT: [[CAST_CRD:%.*]] = trunc i32 [[N_VEC]] to i8 - ; CHECK-NEXT: [[IND_END:%.*]] = sub i8 [[CONV3]], [[CAST_CRD]] --; CHECK-NEXT: [[TMP26:%.*]] = insertelement <4 x i32> zeroinitializer, i32 [[DOTPROMOTED]], i32 0 -+; CHECK-NEXT: [[TMP22:%.*]] = insertelement <4 x i32> zeroinitializer, i32 [[DOTPROMOTED]], i32 0 - ; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] - ; CHECK: vector.body: - ; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] --; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ [[TMP26]], [[VECTOR_PH]] ], [ [[TMP30:%.*]], [[VECTOR_BODY]] ] --; CHECK-NEXT: [[VEC_PHI2:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP31:%.*]], [[VECTOR_BODY]] ] --; CHECK-NEXT: [[TMP27:%.*]] = trunc i32 [[INDEX]] to i8 --; CHECK-NEXT: [[OFFSET_IDX:%.*]] = sub i8 [[CONV3]], [[TMP27]] -+; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ [[TMP22]], [[VECTOR_PH]] ], [ [[TMP26:%.*]], [[VECTOR_BODY]] ] -+; CHECK-NEXT: [[VEC_PHI2:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP27:%.*]], [[VECTOR_BODY]] ] -+; CHECK-NEXT: [[TMP23:%.*]] = trunc i32 [[INDEX]] to i8 -+; CHECK-NEXT: [[OFFSET_IDX:%.*]] = sub i8 [[CONV3]], [[TMP23]] - ; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i8> undef, i8 [[OFFSET_IDX]], i32 0 - ; CHECK-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i8> [[BROADCAST_SPLATINSERT]], <4 x i8> undef, <4 x i32> zeroinitializer - ; CHECK-NEXT: [[INDUCTION:%.*]] = add <4 x i8> [[BROADCAST_SPLAT]], - ; CHECK-NEXT: [[INDUCTION3:%.*]] = add <4 x i8> [[BROADCAST_SPLAT]], --; CHECK-NEXT: [[TMP28:%.*]] = add i8 [[OFFSET_IDX]], 0 --; CHECK-NEXT: [[TMP29:%.*]] = add i8 [[OFFSET_IDX]], -4 --; CHECK-NEXT: [[TMP30]] = add <4 x i32> [[VEC_PHI]], --; CHECK-NEXT: [[TMP31]] = add <4 x i32> [[VEC_PHI2]], --; CHECK-NEXT: [[TMP32:%.*]] = add i8 [[TMP28]], -1 --; CHECK-NEXT: [[TMP33:%.*]] = add i8 [[TMP29]], -1 --; CHECK-NEXT: [[TMP34:%.*]] = zext i8 [[TMP32]] to i32 --; CHECK-NEXT: [[TMP35:%.*]] = zext i8 [[TMP33]] to i32 -+; CHECK-NEXT: [[TMP24:%.*]] = add i8 [[OFFSET_IDX]], 0 -+; CHECK-NEXT: [[TMP25:%.*]] = add i8 [[OFFSET_IDX]], -4 -+; CHECK-NEXT: [[TMP26]] = add <4 x i32> [[VEC_PHI]], -+; CHECK-NEXT: [[TMP27]] = add <4 x i32> [[VEC_PHI2]], -+; CHECK-NEXT: [[TMP28:%.*]] = add i8 [[TMP24]], -1 -+; CHECK-NEXT: [[TMP29:%.*]] = add i8 [[TMP25]], -1 -+; CHECK-NEXT: [[TMP30:%.*]] = zext i8 [[TMP28]] to i32 -+; CHECK-NEXT: [[TMP31:%.*]] = zext i8 [[TMP29]] to i32 - ; CHECK-NEXT: [[INDEX_NEXT]] = add i32 [[INDEX]], 8 --; CHECK-NEXT: [[TMP36:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]] --; CHECK-NEXT: br i1 [[TMP36]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop !0 -+; CHECK-NEXT: [[TMP32:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]] -+; CHECK-NEXT: br i1 [[TMP32]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop !0 - ; CHECK: middle.block: --; CHECK-NEXT: [[BIN_RDX:%.*]] = add <4 x i32> [[TMP31]], [[TMP30]] -+; CHECK-NEXT: [[BIN_RDX:%.*]] = add <4 x i32> [[TMP27]], [[TMP26]] - ; CHECK-NEXT: [[RDX_SHUF:%.*]] = shufflevector <4 x i32> [[BIN_RDX]], <4 x i32> undef, <4 x i32> - ; CHECK-NEXT: [[BIN_RDX4:%.*]] = add <4 x i32> [[BIN_RDX]], [[RDX_SHUF]] - ; CHECK-NEXT: [[RDX_SHUF5:%.*]] = shufflevector <4 x i32> [[BIN_RDX4]], <4 x i32> undef, <4 x i32> - ; CHECK-NEXT: [[BIN_RDX6:%.*]] = add <4 x i32> [[BIN_RDX4]], [[RDX_SHUF5]] --; CHECK-NEXT: [[TMP37:%.*]] = extractelement <4 x i32> [[BIN_RDX6]], i32 0 --; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP9]], [[N_VEC]] -+; CHECK-NEXT: [[TMP33:%.*]] = extractelement <4 x i32> [[BIN_RDX6]], i32 0 -+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP7]], [[N_VEC]] - ; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_COND4_FOR_INC9_CRIT_EDGE:%.*]], label [[SCALAR_PH]] - ; CHECK: scalar.ph: - ; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i8 [ [[IND_END]], [[MIDDLE_BLOCK]] ], [ [[CONV3]], [[FOR_BODY8_LR_PH]] ], [ [[CONV3]], [[VECTOR_SCEVCHECK]] ] --; CHECK-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[DOTPROMOTED]], [[FOR_BODY8_LR_PH]] ], [ [[DOTPROMOTED]], [[VECTOR_SCEVCHECK]] ], [ [[TMP37]], [[MIDDLE_BLOCK]] ] -+; CHECK-NEXT: [[BC_MERGE_RDX:%.*]] = phi i32 [ [[DOTPROMOTED]], [[FOR_BODY8_LR_PH]] ], [ [[DOTPROMOTED]], [[VECTOR_SCEVCHECK]] ], [ [[TMP33]], [[MIDDLE_BLOCK]] ] - ; CHECK-NEXT: br label [[FOR_BODY8:%.*]] - ; CHECK: for.body8: - ; CHECK-NEXT: [[INC5:%.*]] = phi i32 [ [[BC_MERGE_RDX]], [[SCALAR_PH]] ], [ [[INC:%.*]], [[FOR_BODY8]] ] -@@ -118,7 +114,7 @@ define i32 @main() local_unnamed_addr #0 { - ; CHECK-NEXT: [[CMP6:%.*]] = icmp ult i32 [[TMP2]], [[CONV5]] - ; CHECK-NEXT: br i1 [[CMP6]], label [[FOR_BODY8]], label [[FOR_COND4_FOR_INC9_CRIT_EDGE]], !llvm.loop !2 - ; CHECK: for.cond4.for.inc9_crit_edge: --; CHECK-NEXT: [[INC_LCSSA:%.*]] = phi i32 [ [[INC]], [[FOR_BODY8]] ], [ [[TMP37]], [[MIDDLE_BLOCK]] ] -+; CHECK-NEXT: [[INC_LCSSA:%.*]] = phi i32 [ [[INC]], [[FOR_BODY8]] ], [ [[TMP33]], [[MIDDLE_BLOCK]] ] - ; CHECK-NEXT: store i32 [[INC_LCSSA]], i32* getelementptr inbounds ([192 x [192 x i32]], [192 x [192 x i32]]* @a, i64 0, i64 0, i64 0), align 16 - ; CHECK-NEXT: br label [[FOR_INC9]] - ; CHECK: for.inc9: diff --git a/deps/patches/llvm-8.0-D55758-tablegen-cond.patch b/deps/patches/llvm-8.0-D55758-tablegen-cond.patch deleted file mode 100644 index ae9e610883d7c..0000000000000 --- a/deps/patches/llvm-8.0-D55758-tablegen-cond.patch +++ /dev/null @@ -1,794 +0,0 @@ -From 95135c5a18ee14ca091d3513cc7801521d4eb204 Mon Sep 17 00:00:00 2001 -From: Javed Absar -Date: Fri, 25 Jan 2019 10:25:25 +0000 -Subject: [PATCH] [TblGen] Extend !if semantics through new feature !cond - -This patch extends TableGen language with !cond operator. -Instead of embedding !if inside !if which can get cumbersome, -one can now use !cond. -Below is an example to convert an integer 'x' into a string: - - !cond(!lt(x,0) : "Negative", - !eq(x,0) : "Zero", - !eq(x,1) : "One, - 1 : "MoreThanOne") - -Reviewed By: hfinkel, simon_tatham, greened -Differential Revision: https://reviews.llvm.org/D55758 - -llvm-svn: 352185 ---- - docs/TableGen/LangIntro.rst | 14 +++ - docs/TableGen/LangRef.rst | 10 +- - include/llvm/TableGen/Record.h | 78 ++++++++++++++++ - lib/TableGen/Record.cpp | 131 +++++++++++++++++++++++++++ - lib/TableGen/TGLexer.cpp | 1 + - lib/TableGen/TGLexer.h | 2 +- - lib/TableGen/TGParser.cpp | 90 ++++++++++++++++++ - lib/TableGen/TGParser.h | 1 + - test/TableGen/cond-bitlist.td | 27 ++++++ - test/TableGen/cond-default.td | 11 +++ - test/TableGen/cond-empty-list-arg.td | 8 ++ - test/TableGen/cond-inheritance.td | 22 +++++ - test/TableGen/cond-let.td | 36 ++++++++ - test/TableGen/cond-list.td | 38 ++++++++ - test/TableGen/cond-subclass.td | 27 ++++++ - test/TableGen/cond-type.td | 11 +++ - test/TableGen/cond-usage.td | 29 ++++++ - test/TableGen/condsbit.td | 15 +++ - 18 files changed, 549 insertions(+), 2 deletions(-) - create mode 100644 llvm/test/TableGen/cond-bitlist.td - create mode 100644 llvm/test/TableGen/cond-default.td - create mode 100644 llvm/test/TableGen/cond-empty-list-arg.td - create mode 100644 llvm/test/TableGen/cond-inheritance.td - create mode 100644 llvm/test/TableGen/cond-let.td - create mode 100644 llvm/test/TableGen/cond-list.td - create mode 100644 llvm/test/TableGen/cond-subclass.td - create mode 100644 llvm/test/TableGen/cond-type.td - create mode 100644 llvm/test/TableGen/cond-usage.td - create mode 100644 llvm/test/TableGen/condsbit.td - -diff --git a/docs/TableGen/LangIntro.rst b/docs/TableGen/LangIntro.rst -index ea46550ffc0..390f941f0ca 100644 ---- a/docs/TableGen/LangIntro.rst -+++ b/docs/TableGen/LangIntro.rst -@@ -258,6 +258,20 @@ supported include: - ``!if(a,b,c)`` - 'b' if the result of 'int' or 'bit' operator 'a' is nonzero, 'c' otherwise. - -+``!cond(condition_1 : val1, condition_2 : val2, ..., condition_n : valn)`` -+ Instead of embedding !if inside !if which can get cumbersome, -+ one can use !cond. !cond returns 'val1' if the result of 'int' or 'bit' -+ operator 'condition1' is nonzero. Otherwise, it checks 'condition2'. -+ If 'condition2' is nonzero, returns 'val2', and so on. -+ If all conditions are zero, it reports an error. -+ -+ Below is an example to convert an integer 'x' into a string: -+ -+ !cond(!lt(x,0) : "Negative", -+ !eq(x,0) : "Zero", -+ !eq(x,1) : "One, -+ 1 : "MoreThanOne") -+ - ``!eq(a,b)`` - 'bit 1' if string a is equal to string b, 0 otherwise. This only operates - on string, int and bit objects. Use !cast to compare other types of -diff --git a/docs/TableGen/LangRef.rst b/docs/TableGen/LangRef.rst -index 2efee12ec9d..a3dbf363151 100644 ---- a/docs/TableGen/LangRef.rst -+++ b/docs/TableGen/LangRef.rst -@@ -102,6 +102,12 @@ wide variety of meanings: - :!isa !dag !le !lt !ge - :!gt !ne - -+TableGen also has !cond operator that needs a slightly different -+syntax compared to other "bang operators": -+ -+.. productionlist:: -+ CondOperator: !cond -+ - - Syntax - ====== -@@ -140,7 +146,7 @@ considered to define the class if any of the following is true: - #. The :token:`Body` in the :token:`ObjectBody` is present and is not empty. - #. The :token:`BaseClassList` in the :token:`ObjectBody` is present. - --You can declare an empty class by giving and empty :token:`TemplateArgList` -+You can declare an empty class by giving an empty :token:`TemplateArgList` - and an empty :token:`ObjectBody`. This can serve as a restricted form of - forward declaration: note that records deriving from the forward-declared - class will inherit no fields from it since the record expansion is done -@@ -315,6 +321,8 @@ The initial :token:`DagArg` is called the "operator" of the dag. - - .. productionlist:: - SimpleValue: `BangOperator` ["<" `Type` ">"] "(" `ValueListNE` ")" -+ :| `CondOperator` "(" `CondVal` ("," `CondVal`)* ")" -+ CondVal: `Value` ":" `Value` - - Bodies - ------ -diff --git a/include/llvm/TableGen/Record.h b/include/llvm/TableGen/Record.h -index e022bc82b4e..3ca67ec72bd 100644 ---- a/include/llvm/TableGen/Record.h -+++ b/include/llvm/TableGen/Record.h -@@ -316,6 +316,7 @@ protected: - IK_TernOpInit, - IK_UnOpInit, - IK_LastOpInit, -+ IK_CondOpInit, - IK_FoldOpInit, - IK_IsAOpInit, - IK_StringInit, -@@ -912,6 +913,83 @@ public: - std::string getAsString() const override; - }; - -+/// !cond(condition_1: value1, ... , condition_n: value) -+/// Selects the first value for which condition is true. -+/// Otherwise reports an error. -+class CondOpInit final : public TypedInit, public FoldingSetNode, -+ public TrailingObjects { -+ unsigned NumConds; -+ RecTy *ValType; -+ -+ CondOpInit(unsigned NC, RecTy *Type) -+ : TypedInit(IK_CondOpInit, Type), -+ NumConds(NC), ValType(Type) {} -+ -+ size_t numTrailingObjects(OverloadToken) const { -+ return 2*NumConds; -+ } -+ -+public: -+ CondOpInit(const CondOpInit &) = delete; -+ CondOpInit &operator=(const CondOpInit &) = delete; -+ -+ static bool classof(const Init *I) { -+ return I->getKind() == IK_CondOpInit; -+ } -+ -+ static CondOpInit *get(ArrayRef C, ArrayRef V, -+ RecTy *Type); -+ -+ void Profile(FoldingSetNodeID &ID) const; -+ -+ RecTy *getValType() const { return ValType; } -+ -+ unsigned getNumConds() const { return NumConds; } -+ -+ Init *getCond(unsigned Num) const { -+ assert(Num < NumConds && "Condition number out of range!"); -+ return getTrailingObjects()[Num]; -+ } -+ -+ Init *getVal(unsigned Num) const { -+ assert(Num < NumConds && "Val number out of range!"); -+ return getTrailingObjects()[Num+NumConds]; -+ } -+ -+ ArrayRef getConds() const { -+ return makeArrayRef(getTrailingObjects(), NumConds); -+ } -+ -+ ArrayRef getVals() const { -+ return makeArrayRef(getTrailingObjects()+NumConds, NumConds); -+ } -+ -+ Init *Fold(Record *CurRec) const; -+ -+ Init *resolveReferences(Resolver &R) const override; -+ -+ bool isConcrete() const override; -+ bool isComplete() const override; -+ std::string getAsString() const override; -+ -+ using const_case_iterator = SmallVectorImpl::const_iterator; -+ using const_val_iterator = SmallVectorImpl::const_iterator; -+ -+ inline const_case_iterator arg_begin() const { return getConds().begin(); } -+ inline const_case_iterator arg_end () const { return getConds().end(); } -+ -+ inline size_t case_size () const { return NumConds; } -+ inline bool case_empty() const { return NumConds == 0; } -+ -+ inline const_val_iterator name_begin() const { return getVals().begin();} -+ inline const_val_iterator name_end () const { return getVals().end(); } -+ -+ inline size_t val_size () const { return NumConds; } -+ inline bool val_empty() const { return NumConds == 0; } -+ -+ Init *getBit(unsigned Bit) const override; -+}; -+ - /// !foldl (a, b, expr, start, lst) - Fold over a list. - class FoldOpInit : public TypedInit, public FoldingSetNode { - private: -diff --git a/lib/TableGen/Record.cpp b/lib/TableGen/Record.cpp -index cf1685a2e8c..26ffe761b66 100644 ---- a/lib/TableGen/Record.cpp -+++ b/lib/TableGen/Record.cpp -@@ -1694,6 +1694,137 @@ Init *FieldInit::Fold(Record *CurRec) const { - return const_cast(this); - } - -+static void ProfileCondOpInit(FoldingSetNodeID &ID, -+ ArrayRef CondRange, -+ ArrayRef ValRange, -+ const RecTy *ValType) { -+ assert(CondRange.size() == ValRange.size() && -+ "Number of conditions and values must match!"); -+ ID.AddPointer(ValType); -+ ArrayRef::iterator Case = CondRange.begin(); -+ ArrayRef::iterator Val = ValRange.begin(); -+ -+ while (Case != CondRange.end()) { -+ ID.AddPointer(*Case++); -+ ID.AddPointer(*Val++); -+ } -+} -+ -+void CondOpInit::Profile(FoldingSetNodeID &ID) const { -+ ProfileCondOpInit(ID, -+ makeArrayRef(getTrailingObjects(), NumConds), -+ makeArrayRef(getTrailingObjects() + NumConds, NumConds), -+ ValType); -+} -+ -+CondOpInit * -+CondOpInit::get(ArrayRef CondRange, -+ ArrayRef ValRange, RecTy *Ty) { -+ assert(CondRange.size() == ValRange.size() && -+ "Number of conditions and values must match!"); -+ -+ static FoldingSet ThePool; -+ FoldingSetNodeID ID; -+ ProfileCondOpInit(ID, CondRange, ValRange, Ty); -+ -+ void *IP = nullptr; -+ if (CondOpInit *I = ThePool.FindNodeOrInsertPos(ID, IP)) -+ return I; -+ -+ void *Mem = Allocator.Allocate(totalSizeToAlloc(2*CondRange.size()), -+ alignof(BitsInit)); -+ CondOpInit *I = new(Mem) CondOpInit(CondRange.size(), Ty); -+ -+ std::uninitialized_copy(CondRange.begin(), CondRange.end(), -+ I->getTrailingObjects()); -+ std::uninitialized_copy(ValRange.begin(), ValRange.end(), -+ I->getTrailingObjects()+CondRange.size()); -+ ThePool.InsertNode(I, IP); -+ return I; -+} -+ -+Init *CondOpInit::resolveReferences(Resolver &R) const { -+ SmallVector NewConds; -+ bool Changed = false; -+ for (const Init *Case : getConds()) { -+ Init *NewCase = Case->resolveReferences(R); -+ NewConds.push_back(NewCase); -+ Changed |= NewCase != Case; -+ } -+ -+ SmallVector NewVals; -+ for (const Init *Val : getVals()) { -+ Init *NewVal = Val->resolveReferences(R); -+ NewVals.push_back(NewVal); -+ Changed |= NewVal != Val; -+ } -+ -+ if (Changed) -+ return (CondOpInit::get(NewConds, NewVals, -+ getValType()))->Fold(R.getCurrentRecord()); -+ -+ return const_cast(this); -+} -+ -+Init *CondOpInit::Fold(Record *CurRec) const { -+ for ( unsigned i = 0; i < NumConds; ++i) { -+ Init *Cond = getCond(i); -+ Init *Val = getVal(i); -+ -+ if (IntInit *CondI = dyn_cast_or_null( -+ Cond->convertInitializerTo(IntRecTy::get()))) { -+ if (CondI->getValue()) -+ return Val->convertInitializerTo(getValType()); -+ } else -+ return const_cast(this); -+ } -+ -+ PrintFatalError(CurRec->getLoc(), -+ CurRec->getName() + -+ " does not have any true condition in:" + -+ this->getAsString()); -+ return nullptr; -+} -+ -+bool CondOpInit::isConcrete() const { -+ for (const Init *Case : getConds()) -+ if (!Case->isConcrete()) -+ return false; -+ -+ for (const Init *Val : getVals()) -+ if (!Val->isConcrete()) -+ return false; -+ -+ return true; -+} -+ -+bool CondOpInit::isComplete() const { -+ for (const Init *Case : getConds()) -+ if (!Case->isComplete()) -+ return false; -+ -+ for (const Init *Val : getVals()) -+ if (!Val->isConcrete()) -+ return false; -+ -+ return true; -+} -+ -+std::string CondOpInit::getAsString() const { -+ std::string Result = "!cond("; -+ for (unsigned i = 0; i < getNumConds(); i++) { -+ Result += getCond(i)->getAsString() + ": "; -+ Result += getVal(i)->getAsString(); -+ if (i != getNumConds()-1) -+ Result += ", "; -+ } -+ return Result + ")"; -+} -+ -+Init *CondOpInit::getBit(unsigned Bit) const { -+ return VarBitInit::get(const_cast(this), Bit); -+} -+ - static void ProfileDagInit(FoldingSetNodeID &ID, Init *V, StringInit *VN, - ArrayRef ArgRange, - ArrayRef NameRange) { -diff --git a/lib/TableGen/TGLexer.cpp b/lib/TableGen/TGLexer.cpp -index 16aeee56107..f733cc3c134 100644 ---- a/lib/TableGen/TGLexer.cpp -+++ b/lib/TableGen/TGLexer.cpp -@@ -545,6 +545,7 @@ tgtok::TokKind TGLexer::LexExclaim() { - .Case("ge", tgtok::XGe) - .Case("gt", tgtok::XGt) - .Case("if", tgtok::XIf) -+ .Case("cond", tgtok::XCond) - .Case("isa", tgtok::XIsA) - .Case("head", tgtok::XHead) - .Case("tail", tgtok::XTail) -diff --git a/lib/TableGen/TGLexer.h b/lib/TableGen/TGLexer.h -index e9980b36b97..9bdb01cf3dd 100644 ---- a/lib/TableGen/TGLexer.h -+++ b/lib/TableGen/TGLexer.h -@@ -51,7 +51,7 @@ namespace tgtok { - - // !keywords. - XConcat, XADD, XAND, XOR, XSRA, XSRL, XSHL, XListConcat, XStrConcat, XCast, -- XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XEq, XIsA, XDag, -+ XSubst, XForEach, XFoldl, XHead, XTail, XSize, XEmpty, XIf, XCond, XEq, XIsA, XDag, - XNe, XLe, XLt, XGe, XGt, - - // Integer value. -diff --git a/lib/TableGen/TGParser.cpp b/lib/TableGen/TGParser.cpp -index 1d1f3603c83..200190acd59 100644 ---- a/lib/TableGen/TGParser.cpp -+++ b/lib/TableGen/TGParser.cpp -@@ -1445,6 +1445,9 @@ Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) { - return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec); - } - -+ case tgtok::XCond: -+ return ParseOperationCond(CurRec, ItemType); -+ - case tgtok::XFoldl: { - // Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')' - Lex.Lex(); // eat the operation -@@ -1603,6 +1606,91 @@ RecTy *TGParser::ParseOperatorType() { - return Type; - } - -+Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) { -+ Lex.Lex(); // eat the operation 'cond' -+ -+ if (Lex.getCode() != tgtok::l_paren) { -+ TokError("expected '(' after !cond operator"); -+ return nullptr; -+ } -+ Lex.Lex(); // eat the '(' -+ -+ // Parse through '[Case: Val,]+' -+ SmallVector Case; -+ SmallVector Val; -+ while (true) { -+ if (Lex.getCode() == tgtok::r_paren) { -+ Lex.Lex(); // eat the ')' -+ break; -+ } -+ -+ Init *V = ParseValue(CurRec); -+ if (!V) -+ return nullptr; -+ Case.push_back(V); -+ -+ if (Lex.getCode() != tgtok::colon) { -+ TokError("expected ':' following a condition in !cond operator"); -+ return nullptr; -+ } -+ Lex.Lex(); // eat the ':' -+ -+ V = ParseValue(CurRec, ItemType); -+ if (!V) -+ return nullptr; -+ Val.push_back(V); -+ -+ if (Lex.getCode() == tgtok::r_paren) { -+ Lex.Lex(); // eat the ')' -+ break; -+ } -+ -+ if (Lex.getCode() != tgtok::comma) { -+ TokError("expected ',' or ')' following a value in !cond operator"); -+ return nullptr; -+ } -+ Lex.Lex(); // eat the ',' -+ } -+ -+ if (Case.size() < 1) { -+ TokError("there should be at least 1 'condition : value' in the !cond operator"); -+ return nullptr; -+ } -+ -+ // resolve type -+ RecTy *Type = nullptr; -+ for (Init *V : Val) { -+ RecTy *VTy = nullptr; -+ if (TypedInit *Vt = dyn_cast(V)) -+ VTy = Vt->getType(); -+ if (BitsInit *Vbits = dyn_cast(V)) -+ VTy = BitsRecTy::get(Vbits->getNumBits()); -+ if (isa(V)) -+ VTy = BitRecTy::get(); -+ -+ if (Type == nullptr) { -+ if (!isa(V)) -+ Type = VTy; -+ } else { -+ if (!isa(V)) { -+ RecTy *RType = resolveTypes(Type, VTy); -+ if (!RType) { -+ TokError(Twine("inconsistent types '") + Type->getAsString() + -+ "' and '" + VTy->getAsString() + "' for !cond"); -+ return nullptr; -+ } -+ Type = RType; -+ } -+ } -+ } -+ -+ if (!Type) { -+ TokError("could not determine type for !cond from its arguments"); -+ return nullptr; -+ } -+ return CondOpInit::get(Case, Val, Type)->Fold(CurRec); -+} -+ - /// ParseSimpleValue - Parse a tblgen value. This returns null on error. - /// - /// SimpleValue ::= IDValue -@@ -1621,6 +1709,7 @@ RecTy *TGParser::ParseOperatorType() { - /// SimpleValue ::= SRLTOK '(' Value ',' Value ')' - /// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')' - /// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')' -+/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')' - /// - Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, - IDParseMode Mode) { -@@ -1933,6 +2022,7 @@ Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType, - case tgtok::XListConcat: - case tgtok::XStrConcat: // Value ::= !binop '(' Value ',' Value ')' - case tgtok::XIf: -+ case tgtok::XCond: - case tgtok::XFoldl: - case tgtok::XForEach: - case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')' -diff --git a/lib/TableGen/TGParser.h b/lib/TableGen/TGParser.h -index e3849043513..215b9dad770 100644 ---- a/lib/TableGen/TGParser.h -+++ b/lib/TableGen/TGParser.h -@@ -194,6 +194,7 @@ private: // Parser methods. - bool ParseRangePiece(SmallVectorImpl &Ranges); - RecTy *ParseType(); - Init *ParseOperation(Record *CurRec, RecTy *ItemType); -+ Init *ParseOperationCond(Record *CurRec, RecTy *ItemType); - RecTy *ParseOperatorType(); - Init *ParseObjectName(MultiClass *CurMultiClass); - Record *ParseClassID(); -diff --git a/test/TableGen/cond-bitlist.td b/test/TableGen/cond-bitlist.td -new file mode 100644 -index 00000000000..bce615838df ---- /dev/null -+++ b/test/TableGen/cond-bitlist.td -@@ -0,0 +1,27 @@ -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+class S { -+ bits<2> val = !cond(!eq(s, 8): {0, 0}, -+ !eq(s, 16): 0b01, -+ !eq(s, 32): 2, -+ !eq(s, 64): {1, 1}, -+ 1 : ?); -+} -+ -+def D8 : S<8>; -+def D16 : S<16>; -+def D32 : S<32>; -+def D64 : S<64>; -+def D128: S<128>; -+// CHECK: def D128 -+// CHECK-NEXT: bits<2> val = { ?, ? }; -+// CHECK: def D16 -+// CHECK-NEXT: bits<2> val = { 0, 1 }; -+// CHECK: def D32 -+// CHECK-NEXT: bits<2> val = { 1, 0 }; -+// CHECK: def D64 -+// CHECK-NEXT: bits<2> val = { 1, 1 }; -+// CHECK: def D8 -+// CHECK-NEXT: bits<2> val = { 0, 0 }; -+ -diff --git a/test/TableGen/cond-default.td b/test/TableGen/cond-default.td -new file mode 100644 -index 00000000000..816bf10676f ---- /dev/null -+++ b/test/TableGen/cond-default.td -@@ -0,0 +1,11 @@ -+// Check that not specifying a valid condition results in error -+ -+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s -+// XFAIL: vg_leak -+ -+class C { -+ string s = !cond(!lt(x,0) : "negative", !gt(x,0) : "positive"); -+} -+ -+def Zero : C<0>; -+//CHECK: error: Zero does not have any true condition in:!cond(0: "negative", 0: "positive") -diff --git a/test/TableGen/cond-empty-list-arg.td b/test/TableGen/cond-empty-list-arg.td -new file mode 100644 -index 00000000000..5f4ccade169 ---- /dev/null -+++ b/test/TableGen/cond-empty-list-arg.td -@@ -0,0 +1,8 @@ -+// RUN: llvm-tblgen %s -+// XFAIL: vg_leak -+ -+class C { -+ bit true = 1; -+ list X = !cond(cond: [1, 2, 3], true : []); -+ list Y = !cond(cond: [], true : [4, 5, 6]); -+} -diff --git a/test/TableGen/cond-inheritance.td b/test/TableGen/cond-inheritance.td -new file mode 100644 -index 00000000000..4b4abdf72f3 ---- /dev/null -+++ b/test/TableGen/cond-inheritance.td -@@ -0,0 +1,22 @@ -+// Make sure !cond gets propagated across multiple layers of inheritance. -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+class getInt { -+ int ret = !cond(c: 0, 1 : 1); -+} -+ -+class I1 { -+ int i = getInt.ret; -+} -+ -+class I2 : I1; -+ -+def DI1: I1<1>; -+// CHECK: def DI1 { // I1 -+// CHECK-NEXT: int i = 0; -+ -+// CHECK: def DI2 { // I1 I2 -+// CHECK-NEXT: int i = 0; -+def DI2: I2<1>; -+ -diff --git a/test/TableGen/cond-let.td b/test/TableGen/cond-let.td -new file mode 100644 -index 00000000000..044878f2ab8 ---- /dev/null -+++ b/test/TableGen/cond-let.td -@@ -0,0 +1,36 @@ -+// Check support for `!cond' operator as part of a `let' statement. -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+ -+class C x, bits<4> y, bit z> { -+ bits<16> n; -+ -+ let n{11} = !cond(y{3}: 1, -+ y{2}: x{0}, -+ y{1}: x{1}, -+ y{0}: x{2}, -+ {1} :?); -+ let n{10-9}= !cond(x{2}: y{3-2}, -+ x{1}: y{2-1}, -+ x{1}: y{1-0}, -+ {1} : ?); -+ let n{8-6} = !cond(x{2}: 0b010, 1 : 0b110); -+ let n{5-4} = !cond(x{1}: y{3-2}, 1 : {0, 1}); -+ let n{3-0} = !cond(x{0}: y{3-0}, 1 : {z, y{2}, y{1}, y{0}}); -+} -+ -+ -+def C1 : C<{1, 0, 1}, {0, 1, 0, 1}, 0>; -+def C2 : C<{0, 1, 0}, {1, 0, 1, 0}, 1>; -+def C3 : C<{0, 0, 0}, {1, 0, 1, 0}, 0>; -+def C4 : C<{0, 0, 0}, {0, 0, 0, 0}, 0>; -+ -+// CHECK: def C1 -+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1 }; -+// CHECK: def C2 -+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0 }; -+// CHECK: def C3 -+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, 1, ?, ?, 1, 1, 0, 0, 1, 0, 0, 1, 0 }; -+// CHECK: def C4 -+// CHECK-NEXT: bits<16> n = { ?, ?, ?, ?, ?, ?, ?, 1, 1, 0, 0, 1, 0, 0, 0, 0 }; -diff --git a/test/TableGen/cond-list.td b/test/TableGen/cond-list.td -new file mode 100644 -index 00000000000..aa013cea4e1 ---- /dev/null -+++ b/test/TableGen/cond-list.td -@@ -0,0 +1,38 @@ -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+ -+class A> vals> { -+ list first = vals[0]; -+ list rest = !cond(!empty(!tail(vals)): vals[0], -+ 1 : vals[1]); -+} -+ -+def A_OneEl : A<[[1,2,3]]>; -+// CHECK: def A_OneEl { // A -+// CHECK-NEXT: list first = [1, 2, 3]; -+// CHECK-NEXT: list rest = [1, 2, 3]; -+// CHECK-NEXT: } -+ -+def A_TwoEl : A<[[1,2,3], [4,5,6]]>; -+// CHECK: def A_TwoEl { // A -+// CHECK-NEXT: list first = [1, 2, 3]; -+// CHECK-NEXT: list rest = [4, 5, 6]; -+// CHECK-NEXT: } -+ -+ -+class B v> { -+ list vals = v; -+} -+class BB> vals> : B; -+class BBB> vals> : BB; -+ -+def B_OneEl : BBB<[[1,2,3]]>; -+// CHECK: def B_OneEl { // B BB BBB -+// CHECK-NEXT: list vals = [1, 2, 3]; -+// CHECK-NEXT: } -+ -+def B_TwoEl : BBB<[[1,2,3],[4,5,6]]>; -+// CHECK: def B_TwoEl { // B BB BBB -+// CHECK-NEXT: list vals = [4, 5, 6]; -+// CHECK-NEXT: } -diff --git a/test/TableGen/cond-subclass.td b/test/TableGen/cond-subclass.td -new file mode 100644 -index 00000000000..9f6f6e2cb8c ---- /dev/null -+++ b/test/TableGen/cond-subclass.td -@@ -0,0 +1,27 @@ -+// Check that !cond with operands of different subtypes can -+// initialize a supertype variable. -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+class E {} -+class E1 : E {} -+class E2 : E {} -+ -+class EX { -+ E x = !cond(cc: b, 1 : c); -+} -+ -+def E1d : E1<0>; -+def E2d : E2<0>; -+ -+def EXd1 : EX<1, E1d, E2d>; -+def EXd2 : EX<0, E1d, E2d>; -+ -+// CHECK: def EXd1 { -+// CHECK: E x = E1d; -+// CHECK: } -+// -+// CHECK: def EXd2 { -+// CHECK: E x = E2d; -+// CHECK: } -+ -diff --git a/test/TableGen/cond-type.td b/test/TableGen/cond-type.td -new file mode 100644 -index 00000000000..fd2a3cc52b7 ---- /dev/null -+++ b/test/TableGen/cond-type.td -@@ -0,0 +1,11 @@ -+// RUN: not llvm-tblgen %s 2>&1 | FileCheck %s -+// XFAIL: vg_leak -+ -+class A {} -+class B : A {} -+class C : A {} -+ -+// CHECK: Value 'x' of type 'C' is incompatible with initializer '{{.*}}' of type 'A' -+class X { -+ C x = !cond(cc: b, 1 : c); -+} -diff --git a/test/TableGen/cond-usage.td b/test/TableGen/cond-usage.td -new file mode 100644 -index 00000000000..055fd6d7c69 ---- /dev/null -+++ b/test/TableGen/cond-usage.td -@@ -0,0 +1,29 @@ -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+ -+// Check that !cond picks the first true value -+// CHECK: class A -+// CHECK-NEXT: string S = !cond(!eq(A:x, 10): "ten", !eq(A:x, 11): "eleven", !eq(A:x, 10): "TEN", !gt(A:x, 9): "MoreThanNine", 1: "unknown"); -+// CHECK: B1 -+// CHECK-NEXT: string S = "unknown" -+// CHECK: B10 -+// CHECK-NEXT: string S = "ten"; -+// CHECK: def B11 -+// CHECK-NEXT: string S = "eleven"; -+// CHECK: def B12 -+// CHECK-NEXT: string S = "MoreThanNine"; -+// CHECK: def B9 -+// CHECK-NEXT: string S = "unknown" -+ -+class A { -+ string S = !cond(!eq(x,10) : "ten", -+ !eq(x,11) : "eleven", -+ !eq(x,10) : "TEN", -+ !gt(x,9) : "MoreThanNine", -+ !eq(1,1) : "unknown"); -+} -+def B1 : A<1>; -+def B9 : A<9>; -+def B10 : A<10>; -+def B11 : A<11>; -+def B12 : A<12>; -diff --git a/test/TableGen/condsbit.td b/test/TableGen/condsbit.td -new file mode 100644 -index 00000000000..e08ac97f68b ---- /dev/null -+++ b/test/TableGen/condsbit.td -@@ -0,0 +1,15 @@ -+// check that !cond works well with bit conditional values -+// RUN: llvm-tblgen %s | FileCheck %s -+// XFAIL: vg_leak -+// CHECK: a = 6 -+// CHECK: a = 5 -+ -+class A { -+ bit true = 1; -+ int a = !cond(b: 5, true : 6); -+ bit c = !cond(b: 0, true : 1); -+ bits<1> d = !cond(b: 0, true : 1); -+} -+ -+def X : A<0>; -+def Y : A; --- -2.17.1 - diff --git a/deps/patches/llvm-8.0-D59389-refactor-wmma.patch b/deps/patches/llvm-8.0-D59389-refactor-wmma.patch deleted file mode 100644 index 31af5246715a1..0000000000000 --- a/deps/patches/llvm-8.0-D59389-refactor-wmma.patch +++ /dev/null @@ -1,899 +0,0 @@ -From e9737bf498597707d084398b9485676dc7421644 Mon Sep 17 00:00:00 2001 -From: Artem Belevich -Date: Thu, 25 Apr 2019 22:27:35 +0000 -Subject: [PATCH] [NVPTX] Refactor generation of MMA intrinsics and - instructions. NFC. - -Generalized constructions of 'fragments' of MMA operations to provide -common primitives for construction of the ops. This will make it easier -to add new variants of the instructions that operate on integer types. - -Use nested foreach loops which makes it possible to better control -naming of the intrinsics. - -This patch does not affect LLVM's output, so there are no test changes. - -Differential Revision: https://reviews.llvm.org/D59389 - -llvm-svn: 359245 ---- - include/llvm/IR/IntrinsicsNVVM.td | 258 ++++++-------- - lib/Target/NVPTX/NVPTXIntrinsics.td | 512 ++++++++++------------------ - 2 files changed, 295 insertions(+), 475 deletions(-) - -diff --git a/include/llvm/IR/IntrinsicsNVVM.td b/include/llvm/IR/IntrinsicsNVVM.td -index 7f694f68969..e30a27613a6 100644 ---- a/include/llvm/IR/IntrinsicsNVVM.td -+++ b/include/llvm/IR/IntrinsicsNVVM.td -@@ -38,6 +38,69 @@ def llvm_anyi64ptr_ty : LLVMAnyPointerType; // (space)i64* - // MISC - // - -+// Helper class for construction of n-element list [t,t,...,t] -+class RepLLVMType { -+ list ret = !if(N, !listconcat(RepLLVMType.ret, [T]), []); -+} -+ -+// Helper class that represents a 'fragment' of an NVPTX *MMA instruction. -+// Geom: mnk. E.g. m8n32k16 -+// Frag: [abcd] -+// PtxEltType: PTX type for the element. -+class WMMA_REGS { -+ string geom = Geom; -+ string frag = Frag; -+ string ptx_elt_type = PtxEltType; -+ string ft = frag#":"#ptx_elt_type; -+ list regs = !cond( -+ // fp16 -> fp16/fp32 @ m16n16k16/m8n32k16/m32n8k16 -+ // All currently supported geometries use the same fragment format, -+ // so we only need to consider {fragment, type}. -+ !eq(ft,"a:f16") : RepLLVMType<8, llvm_v2f16_ty>.ret, -+ !eq(ft,"b:f16") : RepLLVMType<8, llvm_v2f16_ty>.ret, -+ !eq(ft,"c:f16") : RepLLVMType<4, llvm_v2f16_ty>.ret, -+ !eq(ft,"d:f16") : RepLLVMType<4, llvm_v2f16_ty>.ret, -+ !eq(ft,"c:f32") : RepLLVMType<8, llvm_float_ty>.ret, -+ !eq(ft,"d:f32") : RepLLVMType<8, llvm_float_ty>.ret); -+} -+ -+class WMMA_NAME_LDST { -+ string intr = "llvm.nvvm.wmma." -+ # Frag.geom -+ # "." # Op -+ # "." # Frag.frag -+ # "." # Layout -+ # !if(WithStride, ".stride", "") -+ # "." # Frag.ptx_elt_type -+ ; -+ // TODO(tra): record name should ideally use the same field order as the intrinsic. -+ // E.g. string record = !subst("llvm", "int", -+ // !subst(".", "_", llvm)); -+ string record = "int_nvvm_wmma_" -+ # Frag.geom -+ # "_" # Op -+ # "_" # Frag.frag -+ # "_" # Frag.ptx_elt_type -+ # "_" # Layout -+ # !if(WithStride, "_stride", ""); -+} -+ -+class WMMA_NAME_MMA { -+ string llvm = "llvm.nvvm.wmma." -+ # C.geom -+ # ".mma" -+ # "." # ALayout -+ # "." # BLayout -+ # "." # D.ptx_elt_type // Intrinsic encodes 'd' first. -+ # "." # C.ptx_elt_type -+ # !if(Satfinite, ".satfinite", ""); -+ -+ string record = !subst(".", "_", -+ !subst("llvm.", "int_", llvm)); -+} -+ - let TargetPrefix = "nvvm" in { - def int_nvvm_prmt : GCCBuiltin<"__nvvm_prmt">, - Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], -@@ -3882,166 +3945,69 @@ def int_nvvm_match_all_sync_i64p : - // - // WMMA instructions - // -- - // WMMA.LOAD --class NVVM_WMMA_LD_GALSTS -- : Intrinsic -+ : Intrinsic, NoCapture<0>], -- "llvm.nvvm.wmma." -- # Geometry -- # ".load" -- # "." # Abc -- # "." # Layout -- # !if(WithStride, ".stride", "") -- # "." # Type>; -- --multiclass NVVM_WMMA_LD_GALT { -- def _stride: NVVM_WMMA_LD_GALSTS; -- def NAME : NVVM_WMMA_LD_GALSTS; --} -- --multiclass NVVM_WMMA_LD_GAT { -- defm _row: NVVM_WMMA_LD_GALT; -- defm _col: NVVM_WMMA_LD_GALT; --} -- --multiclass NVVM_WMMA_LD_G { -- defm _a_f16: NVVM_WMMA_LD_GAT; -- defm _b_f16: NVVM_WMMA_LD_GAT; -- defm _c_f16: NVVM_WMMA_LD_GAT; -- defm _c_f32: NVVM_WMMA_LD_GAT; --} -- --multiclass NVVM_WMMA_LD { -- defm _m32n8k16_load: NVVM_WMMA_LD_G<"m32n8k16">; -- defm _m16n16k16_load: NVVM_WMMA_LD_G<"m16n16k16">; -- defm _m8n32k16_load: NVVM_WMMA_LD_G<"m8n32k16">; --} -- --defm int_nvvm_wmma: NVVM_WMMA_LD; -+ WMMA_NAME_LDST<"load", Frag, Layout, WithStride>.intr>; - - // WMMA.STORE.D --class NVVM_WMMA_STD_GLSTSEmpty=[]> -+class NVVM_WMMA_ST - : Intrinsic<[], - !listconcat( - [llvm_anyptr_ty], -- !if(!eq(Type,"f16"), -- [regty, regty, regty, regty], -- [regty, regty, regty, regty, -- regty, regty, regty, regty]), -- !if(WithStride, [llvm_i32_ty], Empty)), -+ Frag.regs, -+ !if(WithStride, [llvm_i32_ty], [])), - [IntrWriteMem, IntrArgMemOnly, WriteOnly<0>, NoCapture<0>], -- "llvm.nvvm.wmma." -- # Geometry -- # ".store.d" -- # "." # Layout -- # !if(WithStride, ".stride", "") -- # "." # Type>; -- --multiclass NVVM_WMMA_STD_GLT { -- def _stride: NVVM_WMMA_STD_GLSTS; -- def NAME: NVVM_WMMA_STD_GLSTS; --} -- --multiclass NVVM_WMMA_STD_GT { -- defm _row: NVVM_WMMA_STD_GLT; -- defm _col: NVVM_WMMA_STD_GLT; --} --multiclass NVVM_WMMA_STD_G { -- defm _d_f16: NVVM_WMMA_STD_GT; -- defm _d_f32: NVVM_WMMA_STD_GT; --} -- --multiclass NVVM_WMMA_STD { -- defm _m32n8k16_store: NVVM_WMMA_STD_G<"m32n8k16">; -- defm _m16n16k16_store: NVVM_WMMA_STD_G<"m16n16k16">; -- defm _m8n32k16_store: NVVM_WMMA_STD_G<"m8n32k16">; -+ WMMA_NAME_LDST<"store", Frag, Layout, WithStride>.intr>; -+ -+// Create all load/store variants -+foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout = ["row", "col"] in { -+ foreach stride = [0, 1] in { -+ foreach frag = [WMMA_REGS, -+ WMMA_REGS, -+ WMMA_REGS, -+ WMMA_REGS] in { -+ def WMMA_NAME_LDST<"load", frag, layout, stride>.record -+ : NVVM_WMMA_LD; -+ } -+ foreach frag = [WMMA_REGS, -+ WMMA_REGS] in { -+ def WMMA_NAME_LDST<"store", frag, layout, stride>.record -+ : NVVM_WMMA_ST; -+ } -+ } -+ } - } - --defm int_nvvm_wmma: NVVM_WMMA_STD; -- - // WMMA.MMA --class NVVM_WMMA_MMA_GABDCS -- : Intrinsic -+ : Intrinsic.regs, -+ WMMA_REGS.regs, -+ C.regs), - [IntrNoMem], -- "llvm.nvvm.wmma." -- # Geometry -- # ".mma" -- # "." # ALayout -- # "." # BLayout -- # "." # DType -- # "." # CType -- # Satfinite> { --} -- --multiclass NVVM_WMMA_MMA_GABDC { -- def NAME : NVVM_WMMA_MMA_GABDCS; -- def _satfinite: NVVM_WMMA_MMA_GABDCS; --} -- --multiclass NVVM_WMMA_MMA_GABD { -- defm _f16: NVVM_WMMA_MMA_GABDC; -- defm _f32: NVVM_WMMA_MMA_GABDC; --} -- --multiclass NVVM_WMMA_MMA_GAB { -- defm _f16: NVVM_WMMA_MMA_GABD; -- defm _f32: NVVM_WMMA_MMA_GABD; --} -- --multiclass NVVM_WMMA_MMA_GA { -- defm _col: NVVM_WMMA_MMA_GAB; -- defm _row: NVVM_WMMA_MMA_GAB; --} -- --multiclass NVVM_WMMA_MMA_G { -- defm _col: NVVM_WMMA_MMA_GA; -- defm _row: NVVM_WMMA_MMA_GA; --} -- --multiclass NVVM_WMMA_MMA { -- defm _m32n8k16_mma : NVVM_WMMA_MMA_G<"m32n8k16">; -- defm _m16n16k16_mma : NVVM_WMMA_MMA_G<"m16n16k16">; -- defm _m8n32k16_mma : NVVM_WMMA_MMA_G<"m8n32k16">; -+ WMMA_NAME_MMA.llvm>; -+ -+foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout_a = ["row", "col"] in { -+ foreach layout_b = ["row", "col"] in { -+ foreach frag_c = [WMMA_REGS, -+ WMMA_REGS] in { -+ foreach frag_d = [WMMA_REGS, -+ WMMA_REGS] in { -+ foreach satf = [0, 1] in { -+ def WMMA_NAME_MMA.record -+ : NVVM_WMMA_MMA; -+ } -+ } -+ } -+ } -+ } - } - --defm int_nvvm_wmma : NVVM_WMMA_MMA; -- - } // let TargetPrefix = "nvvm" -diff --git a/lib/Target/NVPTX/NVPTXIntrinsics.td b/lib/Target/NVPTX/NVPTXIntrinsics.td -index 47dcdcf6e0b..b9a67ba5ed3 100644 ---- a/lib/Target/NVPTX/NVPTXIntrinsics.td -+++ b/lib/Target/NVPTX/NVPTXIntrinsics.td -@@ -27,7 +27,17 @@ def immDouble1 : PatLeaf<(fpimm), [{ - return (d==1.0); - }]>; - -- -+def AS_match { -+ code generic = [{ -+ return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GENERIC); -+ }]; -+ code shared = [{ -+ return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_SHARED); -+ }]; -+ code global = [{ -+ return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GLOBAL); -+ }]; -+} - - //----------------------------------- - // Synchronization and shuffle functions -@@ -1007,17 +1017,11 @@ def INT_FNS_iii : INT_FNS_MBO<(ins i32imm:$mask, i32imm:$base, i32imm:$ - //----------------------------------- - - class ATOMIC_GLOBAL_CHK -- : PatFrag; -+ : PatFrag; - class ATOMIC_SHARED_CHK -- : PatFrag; -+ : PatFrag; - class ATOMIC_GENERIC_CHK -- : PatFrag; -+ : PatFrag; - - multiclass F_ATOMIC_2_imp; - --// --// wmma.load.[a|b|c].sync.[row|col].m16n16k16[|.global|.shared].[f16|f32] --// -- - class EmptyNVPTXInst : NVPTXInst<(outs), (ins), "?", []>; -+// Generates list of n sequential register names. -+class RegSeq { -+ list ret = !if(n, !listconcat(RegSeq.ret, -+ [prefix # !add(n, -1)]), -+ []); -+} - --class WMMA_LOAD_GALSTOS -- : EmptyNVPTXInst, -- Requires<[!if(!eq(Geometry, "m16n16k16"), -- hasPTX60, -- hasPTX61), -- hasSM70]> { -- // Pattern (created by WMMA_LOAD_INTR_HELPER below) that matches the intrinsic -- // for this function. -- PatFrag IntrMatcher = !cast("INT_WMMA_" -- # Geometry # "_load_" -- # !subst("c", "c_" # Type, Abc) -- # "_" # Layout -- # !subst(".", "_", Space) -- # !if(WithStride,"_stride", "") -- # "_Intr"); -- dag OutsR03 = (outs regclass:$r0, regclass:$r1, regclass:$r2, regclass:$r3); -- dag OutsR47 = (outs regclass:$r4, regclass:$r5, regclass:$r6, regclass:$r7); -- dag Outs = !if(!eq(Abc#Type,"cf16"), OutsR03, !con(OutsR03, OutsR47)); -- -- dag StrideArg = !if(WithStride, (ins Int32Regs:$ldm), (ins)); -- dag Ins = !con((ins SrcOp:$src), StrideArg); -+// Helper class that represents a 'fragment' of an NVPTX *MMA instruction. -+// In addition to target-independent fields provided by WMMA_REGS, it adds -+// the fields commonly used to implement specific PTX instruction -- register -+// types and names, constraints, parts of assembly, etc. -+class WMMA_REGINFO -+ : WMMA_REGS { -+ // NVPTX register types used to carry fragment data. -+ NVPTXRegClass regclass = !cond( -+ !eq(PtxEltType, "f16") : Float16x2Regs, -+ !eq(PtxEltType, "f32") : Float32Regs); -+ -+ // Instruction input/output arguments for the fragment. -+ list ptx_regs = !foreach(tmp, regs, regclass); -+ -+ // List of register names for the fragment -- ["ra0", "ra1",...] -+ list reg_names = RegSeq.ret; -+ // Generates "{{$r0, $r1,.... $rN-1}}" for use in asm string construction. -+ string regstring = "{{$" # !head(reg_names) -+ # !foldl("", !tail(reg_names), a, b, -+ !strconcat(a, ", $", b)) -+ # "}}"; -+ -+ // Predicates for particular fragment variant. Technically those are -+ // per-instruction predicates, but currently all fragments that can be used in -+ // a given instruction are subject to the same constraints, so an instruction -+ // can use predicates from any of its fragments. If/when this is no -+ // longer the case, we can concat all per-fragment predicates to enforce that -+ // all fragments of the instruction are viable. -+ list Predicates = !cond( -+ // fp16 -> fp16/fp32 @ m16n16k16 -+ !and(!eq(Geom, "m16n16k16"), -+ !or(!eq(PtxEltType, "f16"), -+ !eq(PtxEltType, "f32"))) : [hasSM70, hasPTX60], -+ -+ // fp16 -> fp16/fp32 @ m8n32k16/m32n8k16 -+ !and(!or(!eq(Geom, "m8n32k16"), -+ !eq(Geom, "m32n8k16")), -+ !or(!eq(PtxEltType, "f16"), -+ !eq(PtxEltType, "f32"))) : [hasSM70, hasPTX61]); -+ -+ // template DAGs for instruction inputs/output. -+ dag Outs = !dag(outs, ptx_regs, reg_names); -+ dag Ins = !dag(ins, ptx_regs, reg_names); -+} - -+class BuildPattern { - // Build a dag pattern that matches the intrinsic call. - // We want a dag that looks like this: - // (set , (intrinsic )) where input and -@@ -7431,277 +7459,127 @@ class WMMA_LOAD_GALSTOS -+// -+// wmma.load.[a|b|c].sync.[row|col].m16n16k16[|.global|.shared].[f16|f32] -+// -+ -+class WMMA_LOAD_INTR_HELPER - : PatFrag <(ops),(ops)> { - // Intrinsic that matches this instruction. -- Intrinsic Intr = !cast("int_nvvm_wmma" -- # "_" # Geometry # "_load_" -- # Abc # "_" # Type # "_" # Layout -- # !if(WithStride,"_stride", "")); -- code match_generic = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GENERIC); -- }]; -- code match_shared = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_SHARED); -- }]; -- code match_global = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GLOBAL); -- }]; -- -+ Intrinsic Intr = !cast(WMMA_NAME_LDST<"load", Frag, Layout, -+ WithStride>.record); - let Operands = !if(WithStride, (ops node:$src, node:$ldm), (ops node:$src)); - let Fragments = [!foreach(tmp, Operands, !subst(ops, Intr, tmp))]; -- let PredicateCode = !if(!eq(Space, ".shared"), match_shared, -- !if(!eq(Space, ".global"), match_global, match_generic)); --} -- --multiclass WMMA_LOAD_GALSTS { -- def _avar: WMMA_LOAD_GALSTOS; -- def _areg: WMMA_LOAD_GALSTOS; -- def _areg64: WMMA_LOAD_GALSTOS; -- def _ari: WMMA_LOAD_GALSTOS; -- def _ari64: WMMA_LOAD_GALSTOS; -+ let PredicateCode = !cond(!eq(Space, ".shared"): AS_match.shared, -+ !eq(Space, ".global"): AS_match.global, -+ 1: AS_match.generic); - } - --multiclass WMMA_LOAD_GALSTSh { -- // Define a PatFrag that matches appropriate intrinsic that loads from the -- // given address space. -- def _Intr: WMMA_LOAD_INTR_HELPER; -- defm NAME: WMMA_LOAD_GALSTS; --} -- --multiclass WMMA_LOAD_GALST { -- defm _stride: WMMA_LOAD_GALSTSh; -- defm NAME: WMMA_LOAD_GALSTSh; --} -- --multiclass WMMA_LOAD_GALT { -- defm _global: WMMA_LOAD_GALST; -- defm _shared: WMMA_LOAD_GALST; -- defm NAME: WMMA_LOAD_GALST; --} -- --multiclass WMMA_LOAD_GAT { -- defm _row: WMMA_LOAD_GALT; -- defm _col: WMMA_LOAD_GALT; --} -+class WMMA_LOAD -+ : EmptyNVPTXInst, -+ Requires { -+ // Pattern that matches the intrinsic for this instruction variant. -+ PatFrag IntrMatcher = WMMA_LOAD_INTR_HELPER; -+ dag Ins = !con((ins SrcOp:$src), !if(WithStride, (ins Int32Regs:$ldm), (ins))); - --multiclass WMMA_LOAD_G { -- defm _load_a: WMMA_LOAD_GAT; -- defm _load_b: WMMA_LOAD_GAT; -- defm _load_c_f16: WMMA_LOAD_GAT; -- defm _load_c_f32: WMMA_LOAD_GAT; -+ let Pattern = [BuildPattern.ret]; -+ let OutOperandList = Frag.Outs; -+ let InOperandList = Ins; -+ let AsmString = "wmma.load." -+ # Frag.frag -+ # ".sync" -+ # "." # Layout -+ # "." # Frag.geom -+ # Space -+ # "." # Frag.ptx_elt_type # " \t" -+ # Frag.regstring -+ # ", [$src]" -+ # !if(WithStride, ", $ldm", "") -+ # ";"; - } - --defm INT_WMMA_m32n8k16: WMMA_LOAD_G<"m32n8k16">; --defm INT_WMMA_m16n16k16: WMMA_LOAD_G<"m16n16k16">; --defm INT_WMMA_m8n32k16: WMMA_LOAD_G<"m8n32k16">; -- - // - // wmma.store.d.sync.[row|col].m16n16k16[|.global|.shared].[f16|f32] - // --class WMMA_STORE_D_GLSTSO -+class WMMA_STORE_INTR_HELPER -+ : PatFrag <(ops),(ops)> { -+ // Intrinsic that matches this instruction. -+ Intrinsic Intr = !cast(WMMA_NAME_LDST<"store", Frag, Layout, -+ WithStride>.record); -+ let Operands = !con((ops node:$dst), -+ !dag(ops, !foreach(tmp, Frag.regs, node), Frag.reg_names), -+ !if(WithStride, (ops node:$ldm), (ops))); -+ let Fragments = [!foreach(tmp, Operands, !subst(ops, Intr, tmp))]; -+ let PredicateCode = !cond(!eq(Space, ".shared"): AS_match.shared, -+ !eq(Space, ".global"): AS_match.global, -+ 1: AS_match.generic); -+} -+ -+class WMMA_STORE - : EmptyNVPTXInst, -- Requires<[!if(!eq(Geometry, "m16n16k16"), -- hasPTX60, -- hasPTX61), -- hasSM70]> { -- PatFrag IntrMatcher = !cast("INT_WMMA" -- # "_" # Geometry # "_store_d" -- # "_" # Type -- # "_" # Layout -- # !subst(".", "_", Space) -- # !if(WithStride,"_stride", "") -- # "_Intr"); -- dag InsR03 = (ins DstOp:$src, regclass:$r0, regclass:$r1, -- regclass:$r2, regclass:$r3); -- dag InsR47 = (ins regclass:$r4, regclass:$r5, -- regclass:$r6, regclass:$r7); -- dag InsR = !if(!eq(Type,"f16"), InsR03, !con(InsR03, InsR47)); -- dag StrideArg = !if(WithStride, (ins Int32Regs:$ldm), (ins)); -- dag Ins = !con(InsR, StrideArg); -- -- // Construct the pattern to match corresponding intrinsic call. See the -- // details in the comments in WMMA_LOAD_ALSTOS. -- dag PatArgs = !foreach(tmp, Ins, -- !subst(imem, ADDRvar, -- !subst(MEMri64, ADDRri64, -- !subst(MEMri, ADDRri, -- !subst(ins, IntrMatcher, tmp))))); -- let Pattern = [PatArgs]; -+ Requires { -+ PatFrag IntrMatcher = WMMA_STORE_INTR_HELPER; -+ dag Ins = !con((ins DstOp:$src), -+ Frag.Ins, -+ !if(WithStride, (ins Int32Regs:$ldm), (ins))); -+ let Pattern = [BuildPattern<(set), IntrMatcher, Ins>.ret]; - let OutOperandList = (outs); - let InOperandList = Ins; - let AsmString = "wmma.store.d.sync." - # Layout -- # "." # Geometry -+ # "." # Frag.geom - # Space -- # "." # Type -+ # "." # Frag.ptx_elt_type - # " \t[$src]," -- # !if(!eq(Type,"f16"), -- "{{$r0, $r1, $r2, $r3}}", -- "{{$r0, $r1, $r2, $r3, $r4, $r5, $r6, $r7}}") -+ # Frag.regstring - # !if(WithStride, ", $ldm", "") - # ";"; -- - } - --class WMMA_STORE_INTR_HELPER -- : PatFrag <(ops),(ops)> { -- // Intrinsic that matches this instruction. -- Intrinsic Intr = !cast("int_nvvm_wmma_" -- # Geometry -- # "_store_d" -- # "_" # Type -- # "_" # Layout -- # !if(WithStride, "_stride", "")); -- code match_generic = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GENERIC); -- }]; -- code match_shared = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_SHARED); -- }]; -- code match_global = [{ -- return ChkMemSDNodeAddressSpace(N, llvm::ADDRESS_SPACE_GLOBAL); -- }]; -- -- dag Args = !if(!eq(Type,"f16"), -- (ops node:$dst, node:$r0, node:$r1, node:$r2, node:$r3), -- (ops node:$dst, node:$r0, node:$r1, node:$r2, node:$r3, -- node:$r4, node:$r5, node:$r6, node:$r7)); -- dag StrideArg = !if(WithStride, (ops node:$ldm), (ops)); -- let Operands = !con(Args, StrideArg); -- let Fragments = [!foreach(tmp, Operands, !subst(ops, Intr, tmp))]; -- let PredicateCode = !if(!eq(Space, ".shared"), match_shared, -- !if(!eq(Space, ".global"), match_global, match_generic)); --} -- --multiclass WMMA_STORE_D_GLSTS { -- def _avar: WMMA_STORE_D_GLSTSO; -- def _areg: WMMA_STORE_D_GLSTSO; -- def _areg64: WMMA_STORE_D_GLSTSO; -- def _ari: WMMA_STORE_D_GLSTSO; -- def _ari64: WMMA_STORE_D_GLSTSO; --} -- --multiclass WMMA_STORE_D_GLSTSh { -- // Define a PatFrag that matches appropriate intrinsic that loads from the -- // given address space. -- def _Intr: WMMA_STORE_INTR_HELPER; -- defm NAME: WMMA_STORE_D_GLSTS; --} -- --multiclass WMMA_STORE_D_GLST { -- defm _stride: WMMA_STORE_D_GLSTSh; -- defm NAME: WMMA_STORE_D_GLSTSh; --} -- --multiclass WMMA_STORE_D_GLT { -- defm _global: WMMA_STORE_D_GLST; -- defm _shared: WMMA_STORE_D_GLST; -- defm NAME: WMMA_STORE_D_GLST; --} -- --multiclass WMMA_STORE_D_GT { -- defm _row: WMMA_STORE_D_GLT; -- defm _col: WMMA_STORE_D_GLT; --} -- --multiclass WMMA_STORE_D_G { -- defm _store_d_f16: WMMA_STORE_D_GT; -- defm _store_d_f32: WMMA_STORE_D_GT; --} -- --defm INT_WMMA_m32n8k16: WMMA_STORE_D_G<"m32n8k16">; --defm INT_WMMA_m16n16k16: WMMA_STORE_D_G<"m16n16k16">; --defm INT_WMMA_m8n32k16: WMMA_STORE_D_G<"m8n32k16">; -+// Create all load/store variants -+foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout = ["row", "col"] in { -+ foreach stride = [0, 1] in { -+ foreach space = [".global", ".shared", ""] in { -+ foreach addr = [imem, Int32Regs, Int64Regs, MEMri, MEMri64] in { -+ foreach frag = [WMMA_REGINFO, -+ WMMA_REGINFO, -+ WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ def : WMMA_LOAD; -+ } -+ foreach frag = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ def : WMMA_STORE; -+ } -+ } // addr -+ } // space -+ } // stride -+ } // layout -+} // geom - - // WMMA.MMA --class WMMA_MMA_GABDCS -+class WMMA_MMA - : EmptyNVPTXInst, -- Requires<[!if(!eq(Geometry, "m16n16k16"), -- hasPTX60, -- hasPTX61), -- hasSM70]> { -- Intrinsic Intr = !cast("int_nvvm_wmma_" -- # Geometry -- # "_mma" -- # "_" # ALayout -- # "_" # BLayout -- # "_" # DType -- # "_" # CType -- # !subst(".", "_", Satfinite)); -- dag Outs = !if(!eq(DType,"f16"), -- (outs d_reg:$d0, d_reg:$d1, d_reg:$d2, d_reg:$d3), -- (outs d_reg:$d0, d_reg:$d1, d_reg:$d2, d_reg:$d3, -- d_reg:$d4, d_reg:$d5, d_reg:$d6, d_reg:$d7)); -- dag InsExtraCArgs = !if(!eq(CType,"f16"), -- (ins), -- (ins c_reg:$c4, c_reg:$c5, c_reg:$c6, c_reg:$c7)); -- dag Ins = !con((ins ab_reg:$a0, ab_reg:$a1, ab_reg:$a2, ab_reg:$a3, -- ab_reg:$a4, ab_reg:$a5, ab_reg:$a6, ab_reg:$a7, -- ab_reg:$b0, ab_reg:$b1, ab_reg:$b2, ab_reg:$b3, -- ab_reg:$b4, ab_reg:$b5, ab_reg:$b6, ab_reg:$b7, -- c_reg:$c0, c_reg:$c1, c_reg:$c2, c_reg:$c3), -- InsExtraCArgs); -- -- // Construct the pattern to match corresponding intrinsic call. See the -- // details in the comments in WMMA_LOAD_ALSTOS. -+ Requires { -+ //Intrinsic Intr = int_nvvm_suld_1d_v4i32_zero; -+ Intrinsic Intr = !cast(WMMA_NAME_MMA.record); -+ dag Outs = FragD.Outs; -+ dag Ins = !con(FragA.Ins, -+ FragB.Ins, -+ FragC.Ins); -+ -+ // Construct the pattern to match corresponding intrinsic call. -+ // mma does not load/store anything, so we don't need complex operand matching here. - dag PatOuts = !foreach(tmp, Outs, !subst(outs, set, tmp)); - dag PatArgs = !foreach(tmp, Ins, !subst(ins, Intr, tmp)); - let Pattern = [!con(PatOuts, (set PatArgs))]; -@@ -7710,54 +7588,30 @@ class WMMA_MMA_GABDCS { -- def _satfinite: WMMA_MMA_GABDCS; -- def NAME: WMMA_MMA_GABDCS; --} -- --multiclass WMMA_MMA_GABD { -- defm _f16: WMMA_MMA_GABDC; -- defm _f32: WMMA_MMA_GABDC; --} -- --multiclass WMMA_MMA_GAB { -- defm _f16: WMMA_MMA_GABD; -- defm _f32: WMMA_MMA_GABD; --} -- --multiclass WMMA_MMA_GA { -- defm _col: WMMA_MMA_GAB; -- defm _row: WMMA_MMA_GAB; --} -- --multiclass WMMA_MMA_G { -- defm _col: WMMA_MMA_GA; -- defm _row: WMMA_MMA_GA; -+ # "." # FragA.geom -+ # "." # FragD.ptx_elt_type -+ # "." # FragC.ptx_elt_type -+ # !if(Satfinite, ".satfinite", "") # "\n\t\t" -+ # FragD.regstring # ",\n\t\t" -+ # FragA.regstring # ",\n\t\t" -+ # FragB.regstring # ",\n\t\t" -+ # FragC.regstring # ";"; - } - --defm INT_WMMA_MMA_m32n8k16 : WMMA_MMA_G<"m32n8k16">; --defm INT_WMMA_MMA_m16n16k16 : WMMA_MMA_G<"m16n16k16">; --defm INT_WMMA_MMA_m8n32k16 : WMMA_MMA_G<"m8n32k16">; -+foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout_a = ["row", "col"] in { -+ foreach layout_b = ["row", "col"] in { -+ foreach frag_c = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ foreach frag_d = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ foreach satf = [0, 1] in { -+ def : WMMA_MMA, -+ WMMA_REGINFO, -+ frag_c, frag_d, layout_a, layout_b, satf>; -+ } // satf -+ } // frag_d -+ } // frag_c -+ } // layout_b -+ } // layout_a -+} // geom --- -2.17.1 - diff --git a/deps/patches/llvm-8.0-D59393-mma-ptx63-fix.patch b/deps/patches/llvm-8.0-D59393-mma-ptx63-fix.patch deleted file mode 100644 index 10e6cd7b6f98d..0000000000000 --- a/deps/patches/llvm-8.0-D59393-mma-ptx63-fix.patch +++ /dev/null @@ -1,510 +0,0 @@ -From be924be7f9e699775fe7690d4b421bebfed73aa9 Mon Sep 17 00:00:00 2001 -From: Artem Belevich -Date: Thu, 25 Apr 2019 22:27:46 +0000 -Subject: [PATCH] [NVPTX] generate correct MMA instruction mnemonics with - PTX63+. - -PTX 6.3 requires using ".aligned" in the MMA instruction names. -In order to generate correct name, now we pass current -PTX version to each instruction as an extra constant operand -and InstPrinter adjusts its output accordingly. - -Differential Revision: https://reviews.llvm.org/D59393 - -llvm-svn: 359246 ---- - .../NVPTX/InstPrinter/NVPTXInstPrinter.cpp | 14 + - .../NVPTX/InstPrinter/NVPTXInstPrinter.h | 2 + - lib/Target/NVPTX/NVPTXInstrInfo.td | 4 + - lib/Target/NVPTX/NVPTXIntrinsics.td | 279 ++++++++++-------- - test/CodeGen/NVPTX/wmma.py | 17 +- - 5 files changed, 184 insertions(+), 132 deletions(-) - -diff --git a/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.cpp b/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.cpp -index b774fe169d7..6fb577d5499 100644 ---- a/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.cpp -+++ b/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.cpp -@@ -270,6 +270,20 @@ void NVPTXInstPrinter::printLdStCode(const MCInst *MI, int OpNum, - llvm_unreachable("Empty Modifier"); - } - -+void NVPTXInstPrinter::printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O, -+ const char *Modifier) { -+ const MCOperand &MO = MI->getOperand(OpNum); -+ int Imm = (int)MO.getImm(); -+ if (Modifier == nullptr || strcmp(Modifier, "version") == 0) { -+ O << Imm; // Just print out PTX version -+ } else if (strcmp(Modifier, "aligned") == 0) { -+ // PTX63 requires '.aligned' in the name of the instruction. -+ if (Imm >= 63) -+ O << ".aligned"; -+ } else -+ llvm_unreachable("Unknown Modifier"); -+} -+ - void NVPTXInstPrinter::printMemOperand(const MCInst *MI, int OpNum, - raw_ostream &O, const char *Modifier) { - printOperand(MI, OpNum, O); -diff --git a/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.h b/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.h -index f0f223aa057..588439137f9 100644 ---- a/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.h -+++ b/lib/Target/NVPTX/InstPrinter/NVPTXInstPrinter.h -@@ -41,6 +41,8 @@ public: - const char *Modifier = nullptr); - void printLdStCode(const MCInst *MI, int OpNum, - raw_ostream &O, const char *Modifier = nullptr); -+ void printMmaCode(const MCInst *MI, int OpNum, raw_ostream &O, -+ const char *Modifier = nullptr); - void printMemOperand(const MCInst *MI, int OpNum, - raw_ostream &O, const char *Modifier = nullptr); - void printProtoIdent(const MCInst *MI, int OpNum, -diff --git a/lib/Target/NVPTX/NVPTXInstrInfo.td b/lib/Target/NVPTX/NVPTXInstrInfo.td -index 02a40b9f526..603d3212395 100644 ---- a/lib/Target/NVPTX/NVPTXInstrInfo.td -+++ b/lib/Target/NVPTX/NVPTXInstrInfo.td -@@ -1549,6 +1549,10 @@ def LdStCode : Operand { - let PrintMethod = "printLdStCode"; - } - -+def MmaCode : Operand { -+ let PrintMethod = "printMmaCode"; -+} -+ - def SDTWrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; - def Wrapper : SDNode<"NVPTXISD::Wrapper", SDTWrapper>; - -diff --git a/lib/Target/NVPTX/NVPTXIntrinsics.td b/lib/Target/NVPTX/NVPTXIntrinsics.td -index b9a67ba5ed3..5cd534914f7 100644 ---- a/lib/Target/NVPTX/NVPTXIntrinsics.td -+++ b/lib/Target/NVPTX/NVPTXIntrinsics.td -@@ -39,6 +39,24 @@ def AS_match { - }]; - } - -+// A node that will be replaced with the current PTX version. -+class PTX { -+ SDNodeXForm PTXVerXform = SDNodeXFormgetPTXVersion(), SDLoc(N)); -+ }]>; -+ // (i32 0) will be XForm'ed to the currently used PTX version. -+ dag version = (PTXVerXform (i32 0)); -+} -+def ptx : PTX; -+ -+// Generates list of n sequential register names. -+// E.g. RegNames<3,"r">.ret -> ["r0", "r1", "r2" ] -+class RegSeq { -+ list ret = !if(n, !listconcat(RegSeq.ret, -+ [prefix # !add(n, -1)]), -+ []); -+} -+ - //----------------------------------- - // Synchronization and shuffle functions - //----------------------------------- -@@ -7385,14 +7403,6 @@ def INT_PTX_SREG_WARPSIZE : - NVPTXInst<(outs Int32Regs:$dst), (ins), "mov.u32 \t$dst, WARP_SZ;", - [(set Int32Regs:$dst, (int_nvvm_read_ptx_sreg_warpsize))]>; - --class EmptyNVPTXInst : NVPTXInst<(outs), (ins), "?", []>; --// Generates list of n sequential register names. --class RegSeq { -- list ret = !if(n, !listconcat(RegSeq.ret, -- [prefix # !add(n, -1)]), -- []); --} -- - // Helper class that represents a 'fragment' of an NVPTX *MMA instruction. - // In addition to target-independent fields provided by WMMA_REGS, it adds - // the fields commonly used to implement specific PTX instruction -- register -@@ -7409,6 +7419,7 @@ class WMMA_REGINFO - - // List of register names for the fragment -- ["ra0", "ra1",...] - list reg_names = RegSeq.ret; -+ - // Generates "{{$r0, $r1,.... $rN-1}}" for use in asm string construction. - string regstring = "{{$" # !head(reg_names) - # !foldl("", !tail(reg_names), a, b, -@@ -7438,61 +7449,65 @@ class WMMA_REGINFO - dag Ins = !dag(ins, ptx_regs, reg_names); - } - --class BuildPattern { -+// Convert dag of arguments into a dag to match given intrinsic. -+class BuildPatternI { -+ // Build a dag pattern that matches the intrinsic call. -+ dag ret = !foreach(tmp, Ins, -+ !subst(imem, ADDRvar, -+ !subst(MEMri64, ADDRri64, -+ !subst(MEMri, ADDRri, -+ !subst(ins, Intr, tmp))))); -+} -+ -+// Same as above, but uses PatFrag instead of an Intrinsic. -+class BuildPatternPF { - // Build a dag pattern that matches the intrinsic call. -- // We want a dag that looks like this: -- // (set , (intrinsic )) where input and -- // output arguments are named patterns that would match corresponding -- // input/output arguments of the instruction. -- // -- // First we construct (set ) from instruction's outs dag by -- // replacing dag operator 'outs' with 'set'. -- dag PatOuts = !foreach(tmp, Outs, !subst(outs, set, tmp)); -- // Similarly, construct (intrinsic ) sub-dag from -- // instruction's input arguments, only now we also need to replace operands -- // with patterns that would match them and the operator 'ins' with the -- // intrinsic. -- dag PatArgs = !foreach(tmp, Ins, -- !subst(imem, ADDRvar, -- !subst(MEMri64, ADDRri64, -- !subst(MEMri, ADDRri, -- !subst(ins, IntrMatcher, tmp))))); -- // Finally, consatenate both parts together. !con() requires both dags to have -- // the same operator, so we wrap PatArgs in a (set ...) dag. -- dag ret = !con(PatOuts, (set PatArgs)); -+ dag ret = !foreach(tmp, Ins, -+ !subst(imem, ADDRvar, -+ !subst(MEMri64, ADDRri64, -+ !subst(MEMri, ADDRri, -+ !subst(ins, Intr, tmp))))); -+} -+ -+// Common WMMA-related fields used for building patterns for all MMA instructions. -+class WMMA_INSTR _Args> -+ : NVPTXInst<(outs), (ins), "?", []> { -+ Intrinsic Intr = !cast(_Intr); -+ // Concatenate all arguments into a single dag. -+ dag Args = !foldl((ins), _Args, a, b, !con(a,b)); -+ // Pre-build the pattern to match (intrinsic arg0, arg1, ...). -+ dag IntrinsicPattern = BuildPatternI(Intr), Args>.ret; - } - - // - // wmma.load.[a|b|c].sync.[row|col].m16n16k16[|.global|.shared].[f16|f32] - // - --class WMMA_LOAD_INTR_HELPER -- : PatFrag <(ops),(ops)> { -- // Intrinsic that matches this instruction. -- Intrinsic Intr = !cast(WMMA_NAME_LDST<"load", Frag, Layout, -- WithStride>.record); -- let Operands = !if(WithStride, (ops node:$src, node:$ldm), (ops node:$src)); -- let Fragments = [!foreach(tmp, Operands, !subst(ops, Intr, tmp))]; -- let PredicateCode = !cond(!eq(Space, ".shared"): AS_match.shared, -- !eq(Space, ".global"): AS_match.global, -- 1: AS_match.generic); --} -- - class WMMA_LOAD -- : EmptyNVPTXInst, -+ : WMMA_INSTR.record, -+ [!con((ins SrcOp:$src), -+ !if(WithStride, (ins Int32Regs:$ldm), (ins)))]>, - Requires { -- // Pattern that matches the intrinsic for this instruction variant. -- PatFrag IntrMatcher = WMMA_LOAD_INTR_HELPER; -- dag Ins = !con((ins SrcOp:$src), !if(WithStride, (ins Int32Regs:$ldm), (ins))); -+ // Load/store intrinsics are overloaded on pointer's address space. -+ // To match the right intrinsic, we need to build AS-constrained PatFrag. -+ // Operands is a dag equivalent in shape to Args, but using (ops node:$name, .....). -+ dag PFOperands = !if(WithStride, (ops node:$src, node:$ldm), (ops node:$src)); -+ // Build PatFrag that only matches particular address space. -+ PatFrag IntrFrag = PatFrag; -+ // Build AS-constrained pattern. -+ let IntrinsicPattern = BuildPatternPF.ret; - -- let Pattern = [BuildPattern.ret]; - let OutOperandList = Frag.Outs; -- let InOperandList = Ins; -+ let InOperandList = !con(Args, (ins MmaCode:$ptx)); - let AsmString = "wmma.load." - # Frag.frag - # ".sync" -+ # "${ptx:aligned}" - # "." # Layout - # "." # Frag.geom - # Space -@@ -7506,87 +7521,79 @@ class WMMA_LOAD -- : PatFrag <(ops),(ops)> { -- // Intrinsic that matches this instruction. -- Intrinsic Intr = !cast(WMMA_NAME_LDST<"store", Frag, Layout, -- WithStride>.record); -- let Operands = !con((ops node:$dst), -- !dag(ops, !foreach(tmp, Frag.regs, node), Frag.reg_names), -- !if(WithStride, (ops node:$ldm), (ops))); -- let Fragments = [!foreach(tmp, Operands, !subst(ops, Intr, tmp))]; -- let PredicateCode = !cond(!eq(Space, ".shared"): AS_match.shared, -- !eq(Space, ".global"): AS_match.global, -- 1: AS_match.generic); --} -- --class WMMA_STORE -- : EmptyNVPTXInst, -+class WMMA_STORE_D -+ : WMMA_INSTR.record, -+ [!con((ins DstOp:$dst), -+ Frag.Ins, -+ !if(WithStride, (ins Int32Regs:$ldm), (ins)))]>, - Requires { -- PatFrag IntrMatcher = WMMA_STORE_INTR_HELPER; -- dag Ins = !con((ins DstOp:$src), -- Frag.Ins, -- !if(WithStride, (ins Int32Regs:$ldm), (ins))); -- let Pattern = [BuildPattern<(set), IntrMatcher, Ins>.ret]; -+ -+ // Load/store intrinsics are overloaded on pointer's address space. -+ // To match the right intrinsic, we need to build AS-constrained PatFrag. -+ // Operands is a dag equivalent in shape to Args, but using (ops node:$name, .....). -+ dag PFOperands = !con((ops node:$dst), -+ !dag(ops, !foreach(tmp, Frag.regs, node), Frag.reg_names), -+ !if(WithStride, (ops node:$ldm), (ops))); -+ // Build PatFrag that only matches particular address space. -+ PatFrag IntrFrag = PatFrag; -+ // Build AS-constrained pattern. -+ let IntrinsicPattern = BuildPatternPF.ret; -+ -+ let InOperandList = !con(Args, (ins MmaCode:$ptx)); - let OutOperandList = (outs); -- let InOperandList = Ins; -- let AsmString = "wmma.store.d.sync." -- # Layout -+ let AsmString = "wmma.store.d.sync" -+ # "${ptx:aligned}" -+ # "." # Layout - # "." # Frag.geom - # Space - # "." # Frag.ptx_elt_type -- # " \t[$src]," -+ # " \t[$dst]," - # Frag.regstring - # !if(WithStride, ", $ldm", "") - # ";"; - } - - // Create all load/store variants --foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -- foreach layout = ["row", "col"] in { -- foreach stride = [0, 1] in { -- foreach space = [".global", ".shared", ""] in { -- foreach addr = [imem, Int32Regs, Int64Regs, MEMri, MEMri64] in { -- foreach frag = [WMMA_REGINFO, -- WMMA_REGINFO, -- WMMA_REGINFO, -- WMMA_REGINFO] in { -- def : WMMA_LOAD; -- } -- foreach frag = [WMMA_REGINFO, -- WMMA_REGINFO] in { -- def : WMMA_STORE; -- } -- } // addr -- } // space -- } // stride -- } // layout --} // geom -+defset list MMA_LDSTs = { -+ foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout = ["row", "col"] in { -+ foreach stride = [0, 1] in { -+ foreach space = [".global", ".shared", ""] in { -+ foreach addr = [imem, Int32Regs, Int64Regs, MEMri, MEMri64] in { -+ foreach frag = [WMMA_REGINFO, -+ WMMA_REGINFO, -+ WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ def : WMMA_LOAD; -+ } -+ foreach frag = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ def : WMMA_STORE_D; -+ } -+ } // addr -+ } // space -+ } // stride -+ } // layout -+ } // geom -+} // defset - - // WMMA.MMA - class WMMA_MMA -- : EmptyNVPTXInst, -+ : WMMA_INSTR.record, -+ [FragA.Ins, FragB.Ins, FragC.Ins]>, - Requires { -- //Intrinsic Intr = int_nvvm_suld_1d_v4i32_zero; -- Intrinsic Intr = !cast(WMMA_NAME_MMA.record); -- dag Outs = FragD.Outs; -- dag Ins = !con(FragA.Ins, -- FragB.Ins, -- FragC.Ins); -- -- // Construct the pattern to match corresponding intrinsic call. -- // mma does not load/store anything, so we don't need complex operand matching here. -- dag PatOuts = !foreach(tmp, Outs, !subst(outs, set, tmp)); -- dag PatArgs = !foreach(tmp, Ins, !subst(ins, Intr, tmp)); -- let Pattern = [!con(PatOuts, (set PatArgs))]; -- let OutOperandList = Outs; -- let InOperandList = Ins; -- let AsmString = "wmma.mma.sync." -- # ALayout -+ let OutOperandList = FragD.Outs; -+ let InOperandList = !con(Args, (ins MmaCode:$ptx)); -+ let AsmString = "wmma.mma.sync" -+ # "${ptx:aligned}" -+ # "." # ALayout - # "." # BLayout - # "." # FragA.geom - # "." # FragD.ptx_elt_type -@@ -7598,20 +7605,34 @@ class WMMA_MMA, -- WMMA_REGINFO] in { -- foreach frag_d = [WMMA_REGINFO, -- WMMA_REGINFO] in { -- foreach satf = [0, 1] in { -- def : WMMA_MMA, -- WMMA_REGINFO, -- frag_c, frag_d, layout_a, layout_b, satf>; -- } // satf -- } // frag_d -- } // frag_c -- } // layout_b -- } // layout_a --} // geom -+defset list MMAs = { -+ foreach geom = ["m16n16k16", "m32n8k16", "m8n32k16" ] in { -+ foreach layout_a = ["row", "col"] in { -+ foreach layout_b = ["row", "col"] in { -+ foreach frag_c = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ foreach frag_d = [WMMA_REGINFO, -+ WMMA_REGINFO] in { -+ foreach satf = [0, 1] in { -+ def : WMMA_MMA, -+ WMMA_REGINFO, -+ frag_c, frag_d, layout_a, layout_b, satf>; -+ } // satf -+ } // frag_d -+ } // frag_c -+ } // layout_b -+ } // layout_a -+ } // geom -+} // defset -+ -+// Constructing non-flat DAGs is still a pain. I can't !subst a dag node with a -+// dag, so the ptx.version must be appended *after* foreach replaces 'ins' with -+// the instruction record. -+class WMMA_PAT -+ : Pat; -+ -+// Build intrinsic->instruction patterns for all MMA instructions. -+foreach mma = !listconcat(MMAs, MMA_LDSTs) in -+ def : WMMA_PAT; -diff --git a/test/CodeGen/NVPTX/wmma.py b/test/CodeGen/NVPTX/wmma.py -index 14bbfd7df09..72d189ca050 100644 ---- a/test/CodeGen/NVPTX/wmma.py -+++ b/test/CodeGen/NVPTX/wmma.py -@@ -3,9 +3,12 @@ - - # RUN: python %s > %t.ll - # RUN: llc < %t.ll -march=nvptx64 -mcpu=sm_70 -mattr=+ptx61 | FileCheck %t.ll -+# RUN: python %s --ptx=63 > %t-ptx63.ll -+# RUN: llc < %t-ptx63.ll -march=nvptx64 -mcpu=sm_70 -mattr=+ptx63 | FileCheck %t-ptx63.ll - - from __future__ import print_function - -+import argparse - from itertools import product - from string import Template - -@@ -64,7 +67,7 @@ define ${ret_ty} @test_${function}_o(i8 ${as}* %src ${extra_args}) { - } - """ - intrinsic_template = "llvm.nvvm.wmma.${geom}.load.${abc}.${layout}${stride}.${itype}.${pspace}" -- instruction_template = "wmma.load.${abc}.sync.${layout}.${geom}${space}.${itype}" -+ instruction_template = "wmma.load.${abc}.sync${aligned}.${layout}.${geom}${space}.${itype}" - - for geom, abc, layout, space, stride, itype in product( - known_geoms, -@@ -76,6 +79,7 @@ define ${ret_ty} @test_${function}_o(i8 ${as}* %src ${extra_args}) { - - params = { - "abc" : abc, -+ "aligned" : ".aligned" if ptx_version >= 63 else "", - "layout" : layout, - "space" : space, - "stride" : stride, -@@ -135,7 +139,7 @@ define void @test_${function}_o(i8 ${as}* %src, ${args}${extra_args}) { - } - """ - intrinsic_template = "llvm.nvvm.wmma.${geom}.store.${abc}.${layout}${stride}.${itype}.${pspace}" -- instruction_template = "wmma.store.${abc}.sync.${layout}.${geom}${space}.${itype}" -+ instruction_template = "wmma.store.${abc}.sync${aligned}.${layout}.${geom}${space}.${itype}" - - for geom, abc, layout, space, stride, itype in product( - known_geoms, -@@ -147,6 +151,7 @@ define void @test_${function}_o(i8 ${as}* %src, ${args}${extra_args}) { - - params = { - "abc" : abc, -+ "aligned" : ".aligned" if ptx_version >= 63 else "", - "layout" : layout, - "space" : space, - "stride" : stride, -@@ -191,7 +196,7 @@ define ${ret_ty} @test_${function}( - } - """ - intrinsic_template = "llvm.nvvm.wmma.${geom}.mma.${alayout}.${blayout}.${dtype}.${ctype}${satf}" -- instruction_template = "wmma.mma.sync.${alayout}.${blayout}.${geom}.${dtype}.${ctype}${satf}" -+ instruction_template = "wmma.mma.sync${aligned}.${alayout}.${blayout}.${geom}.${dtype}.${ctype}${satf}" - - for geom, alayout, blayout, ctype, dtype, satf in product( - known_geoms, -@@ -202,6 +207,7 @@ define ${ret_ty} @test_${function}( - [".satfinite", ""]): - - params = { -+ "aligned" : ".aligned" if ptx_version >= 63 else "", - "alayout" : alayout, - "blayout" : blayout, - "ctype" : ctype, -@@ -230,4 +236,9 @@ def main(): - gen_wmma_store_tests() - gen_wmma_mma_tests() - -+parser = argparse.ArgumentParser() -+parser.add_argument('--ptx', type=int, default=60) -+args = parser.parse_args() -+ptx_version = args.ptx -+ - main() --- -2.17.1 - diff --git a/deps/patches/llvm-8.0-D63688-wasm-isLocal.patch b/deps/patches/llvm-8.0-D63688-wasm-isLocal.patch deleted file mode 100644 index 820363d305424..0000000000000 --- a/deps/patches/llvm-8.0-D63688-wasm-isLocal.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 83d5085a7fcbb4596d964dbe037c5ebf4de02b69 Mon Sep 17 00:00:00 2001 -From: Keno Fischer -Date: Sun, 23 Jun 2019 00:29:59 +0000 -Subject: [PATCH] [Support] Fix build under Emscripten - -Summary: -Emscripten's libc doesn't define MNT_LOCAL, thus causing a build -failure in the fallback path. However, to the best of my knowledge, -it also doesn't support remote file system mounts, so we may simply -return `true` here (as we do for e.g. Fuchsia). With this fix, the -core LLVM libraries build correctly under emscripten (though some -of the tools and utils do not). - -Reviewers: kripken -Differential Revision: https://reviews.llvm.org/D63688 - -llvm-svn: 364143 -(cherry picked from commit 5f4ae7c45718618c4c571495e7d910d5722f70ad) ---- - llvm/lib/Support/Unix/Path.inc | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc -index d7cc0d627d0..eb38a71fffb 100644 ---- a/lib/Support/Unix/Path.inc -+++ b/lib/Support/Unix/Path.inc -@@ -398,6 +398,9 @@ static bool is_local_impl(struct STATVFS &Vfs) { - #elif defined(__Fuchsia__) - // Fuchsia doesn't yet support remote filesystem mounts. - return true; -+#elif defined(__EMSCRIPTEN__) -+ // Emscripten doesn't currently support remote filesystem mounts. -+ return true; - #elif defined(__HAIKU__) - // Haiku doesn't expose this information. - return false; --- -2.24.0 - diff --git a/deps/patches/llvm-8.0-D65174-limit-merge-stores.patch b/deps/patches/llvm-8.0-D65174-limit-merge-stores.patch deleted file mode 100644 index 646c44f454641..0000000000000 --- a/deps/patches/llvm-8.0-D65174-limit-merge-stores.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 19992a8c7f2df2000ea7fd4a284ec7b407400fb0 Mon Sep 17 00:00:00 2001 -From: Wei Mi -Date: Sun, 29 Mar 2020 17:14:12 -0400 -Subject: [PATCH] [DAGCombine] Limit the number of times for the same store and - root nodes to bail out in store merging dependence check. - -We run into a case where dependence check in store merging bail out many times -for the same store and root nodes in a huge basicblock. That increases compile -time by almost 100x. The patch add a map to track how many times the bailing -out happen for the same store and root, and if it is over a limit, stop -considering the store with the same root as a merging candidate. - -Differential Revision: https://reviews.llvm.org/D65174 ---- - llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 45 +++++++++++++++++-- - 1 file changed, 42 insertions(+), 3 deletions(-) - -diff --git llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -index 6af01423ca1..9c7e37d6945 100644 ---- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -+++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -@@ -112,6 +112,11 @@ static cl::opt - MaySplitLoadIndex("combiner-split-load-index", cl::Hidden, cl::init(true), - cl::desc("DAG combiner may split indexing from loads")); - -+static cl::opt StoreMergeDependenceLimit( -+ "combiner-store-merge-dependence-limit", cl::Hidden, cl::init(10), -+ cl::desc("Limit the number of times for the same StoreNode and RootNode " -+ "to bail out in store merging dependence check")); -+ - namespace { - - class DAGCombiner { -@@ -145,6 +150,14 @@ namespace { - /// which have not yet been combined to the worklist. - SmallPtrSet CombinedNodes; - -+ /// Map from candidate StoreNode to the pair of RootNode and count. -+ /// The count is used to track how many times we have seen the StoreNode -+ /// with the same RootNode bail out in dependence check. If we have seen -+ /// the bail out for the same pair many times over a limit, we won't -+ /// consider the StoreNode with the same RootNode as store merging -+ /// candidate again. -+ DenseMap> StoreRootCountMap; -+ - // AA - Used for DAG load/store alias analysis. - AliasAnalysis *AA; - -@@ -190,6 +203,7 @@ namespace { - /// Remove all instances of N from the worklist. - void removeFromWorklist(SDNode *N) { - CombinedNodes.erase(N); -+ StoreRootCountMap.erase(N); - - auto It = WorklistMap.find(N); - if (It == WorklistMap.end()) -@@ -14423,6 +14437,18 @@ void DAGCombiner::getStoreMergeCandidates( - return (BasePtr.equalBaseIndex(Ptr, DAG, Offset)); - }; - -+ // Check if the pair of StoreNode and the RootNode already bail out many -+ // times which is over the limit in dependence check. -+ auto OverLimitInDependenceCheck = [&](SDNode *StoreNode, -+ SDNode *RootNode) -> bool { -+ auto RootCount = StoreRootCountMap.find(StoreNode); -+ if (RootCount != StoreRootCountMap.end() && -+ RootCount->second.first == RootNode && -+ RootCount->second.second > StoreMergeDependenceLimit) -+ return true; -+ return false; -+ }; -+ - // We looking for a root node which is an ancestor to all mergable - // stores. We search up through a load, to our root and then down - // through all children. For instance we will find Store{1,2,3} if -@@ -14450,7 +14476,8 @@ void DAGCombiner::getStoreMergeCandidates( - if (StoreSDNode *OtherST = dyn_cast(*I2)) { - BaseIndexOffset Ptr; - int64_t PtrDiff; -- if (CandidateMatch(OtherST, Ptr, PtrDiff)) -+ if (CandidateMatch(OtherST, Ptr, PtrDiff) && -+ !OverLimitInDependenceCheck(OtherST, RootNode)) - StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); - } - } else -@@ -14459,7 +14486,8 @@ void DAGCombiner::getStoreMergeCandidates( - if (StoreSDNode *OtherST = dyn_cast(*I)) { - BaseIndexOffset Ptr; - int64_t PtrDiff; -- if (CandidateMatch(OtherST, Ptr, PtrDiff)) -+ if (CandidateMatch(OtherST, Ptr, PtrDiff) && -+ !OverLimitInDependenceCheck(OtherST, RootNode)) - StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); - } - } -@@ -14517,8 +14545,19 @@ bool DAGCombiner::checkMergeStoreCandidatesForDependencies( - // Search through DAG. We can stop early if we find a store node. - for (unsigned i = 0; i < NumStores; ++i) - if (SDNode::hasPredecessorHelper(StoreNodes[i].MemNode, Visited, Worklist, -- Max)) -+ Max)) { -+ // If the searching bail out, record the StoreNode and RootNode in the -+ // StoreRootCountMap. If we have seen the pair many times over a limit, -+ // we won't add the StoreNode into StoreNodes set again. -+ if (Visited.size() >= Max) { -+ auto &RootCount = StoreRootCountMap[StoreNodes[i].MemNode]; -+ if (RootCount.first == RootNode) -+ RootCount.second++; -+ else -+ RootCount = {RootNode, 1}; -+ } - return false; -+ } - return true; - } - --- -2.25.2 - diff --git a/deps/patches/llvm-8.0-D66401-mingw-reloc.patch b/deps/patches/llvm-8.0-D66401-mingw-reloc.patch deleted file mode 100644 index 384399f2162f2..0000000000000 --- a/deps/patches/llvm-8.0-D66401-mingw-reloc.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git a/test/CodeGen/X86/mingw-refptr.ll b/test/CodeGen/X86/mingw-refptr.ll ---- a/test/CodeGen/X86/mingw-refptr.ll -+++ b/test/CodeGen/X86/mingw-refptr.ll -@@ -1,5 +1,6 @@ - ; RUN: llc < %s -mtriple=x86_64-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X64 - ; RUN: llc < %s -mtriple=i686-w64-mingw32 | FileCheck %s -check-prefix=CHECK-X86 -+; RUN: llc < %s -mtriple=i686-w64-mingw32-none-elf | FileCheck %s -check-prefix=CHECK-X86-ELF - - @var = external local_unnamed_addr global i32, align 4 - @dsolocalvar = external dso_local local_unnamed_addr global i32, align 4 -@@ -16,6 +17,9 @@ - ; CHECK-X86: movl .refptr._var, %eax - ; CHECK-X86: movl (%eax), %eax - ; CHECK-X86: retl -+; CHECK-X86-ELF-LABEL: getVar: -+; CHECK-X86-ELF: movl var, %eax -+; CHECK-X86-ELF: retl - entry: - %0 = load i32, i32* @var, align 4 - ret i32 %0 -@@ -66,6 +70,9 @@ - ; CHECK-X86: movl __imp__extvar, %eax - ; CHECK-X86: movl (%eax), %eax - ; CHECK-X86: retl -+; CHECK-X86-ELF-LABEL: getExtVar: -+; CHECK-X86-ELF: movl extvar, %eax -+; CHECK-X86-ELF: retl - entry: - %0 = load i32, i32* @extvar, align 4 - ret i32 %0 -diff --git a/lib/Target/X86/X86Subtarget.cpp b/lib/Target/X86/X86Subtarget.cpp ---- a/lib/Target/X86/X86Subtarget.cpp -+++ b/lib/Target/X86/X86Subtarget.cpp -@@ -146,6 +146,9 @@ - return X86II::MO_DLLIMPORT; - return X86II::MO_COFFSTUB; - } -+ // Some JIT users use *-win32-elf triples; these shouldn't use GOT tables. -+ if (isOSWindows()) -+ return X86II::MO_NO_FLAG; - - if (is64Bit()) { - // ELF supports a large, truly PIC code model with non-PC relative GOT -diff --git a/lib/Target/TargetMachine.cpp b/lib/Target/TargetMachine.cpp ---- a/lib/Target/TargetMachine.cpp -+++ b/lib/Target/TargetMachine.cpp -@@ -128,8 +128,8 @@ - // don't assume the variables to be DSO local unless we actually know - // that for sure. This only has to be done for variables; for functions - // the linker can insert thunks for calling functions from another DLL. -- if (TT.isWindowsGNUEnvironment() && GV && GV->isDeclarationForLinker() && -- isa(GV)) -+ if (TT.isWindowsGNUEnvironment() && TT.isOSBinFormatCOFF() && GV && -+ GV->isDeclarationForLinker() && isa(GV)) - return false; - - // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols -@@ -142,7 +142,9 @@ - // Make an exception for windows OS in the triple: Some firmware builds use - // *-win32-macho triples. This (accidentally?) produced windows relocations - // without GOT tables in older clang versions; Keep this behaviour. -- if (TT.isOSBinFormatCOFF() || (TT.isOSWindows() && TT.isOSBinFormatMachO())) -+ // Some JIT users use *-win32-elf triples; these shouldn't use GOT tables -+ // either. -+ if (TT.isOSBinFormatCOFF() || TT.isOSWindows()) - return true; - - // Most PIC code sequences that assume that a symbol is local cannot - diff --git a/deps/patches/llvm-8.0-D66657-codegen-degenerate.patch b/deps/patches/llvm-8.0-D66657-codegen-degenerate.patch deleted file mode 100644 index ddcf4dc7ddaa6..0000000000000 --- a/deps/patches/llvm-8.0-D66657-codegen-degenerate.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 4c7e1defbddafcfcfe1211b041d43a36114a8f48 Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Sat, 14 Dec 2019 10:33:30 -0500 -Subject: [PATCH 2/2] [CodegenPrepare] Guard against degenerate branches - -Summary: -Guard against a potential crash observed in https://github.com/JuliaLang/julia/issues/32994#issuecomment-524249628 -If two branches are collapsed we can encounter a degenerate conditional branch `TBB==FBB`. -The subsequent code assumes that they differ, so we exit out early. - -Reviewers: ributzka, spatel - -Subscribers: loladiro, dexonsmith, hiraditya, llvm-commits - -Tags: #llvm - -Differential Revision: https://reviews.llvm.org/D66657 ---- - llvm/lib/CodeGen/CodeGenPrepare.cpp | 4 ++++ - .../CodeGen/X86/codegen-prepare-collapse.ll | 18 ++++++++++++++++++ - 2 files changed, 22 insertions(+) - create mode 100644 llvm/test/CodeGen/X86/codegen-prepare-collapse.ll - -diff --git a/lib/CodeGen/CodeGenPrepare.cpp b/lib/CodeGen/CodeGenPrepare.cpp -index c35f8666fa3..3647641c594 100644 ---- a/lib/CodeGen/CodeGenPrepare.cpp -+++ b/lib/CodeGen/CodeGenPrepare.cpp -@@ -6929,6 +6929,10 @@ bool CodeGenPrepare::splitBranchCondition(Function &F) { - if (Br1->getMetadata(LLVMContext::MD_unpredictable)) - continue; - -+ // The merging of mostly empty BB can cause a degenerate branch. -+ if (TBB == FBB) -+ continue; -+ - unsigned Opc; - Value *Cond1, *Cond2; - if (match(LogicOp, m_And(m_OneUse(m_Value(Cond1)), -diff --git a/test/CodeGen/X86/codegen-prepare-collapse.ll b/test/CodeGen/X86/codegen-prepare-collapse.ll -new file mode 100644 -index 00000000000..18e3ef7afbd ---- /dev/null -+++ b/test/CodeGen/X86/codegen-prepare-collapse.ll -@@ -0,0 +1,18 @@ -+; RUN: llc -fast-isel=true -O1 -mtriple=x86_64-unkown-linux-gnu -start-before=codegenprepare -stop-after=codegenprepare -o - < %s | FileCheck %s -+ -+; CHECK-LABEL: @foo -+define void @foo() { -+top: -+; CHECK: br label %L34 -+ br label %L34 -+ -+L34: ; preds = %L34, %L34, %top -+ %.sroa.075.0 = phi i64 [ undef, %top ], [ undef, %L34 ], [ undef, %L34 ] -+ %0 = icmp sgt i8 undef, -1 -+ %cond5896 = icmp eq i8 0, 2 -+ %cond58 = and i1 %cond5896, %0 -+; During codegenprepare such degenerate branches can occur and should not -+; lead to crashes. -+; CHECK: br label %L34 -+ br i1 %cond58, label %L34, label %L34 -+} --- -2.24.1 - diff --git a/deps/patches/llvm-8.0-D71495-vectorize-freduce.patch b/deps/patches/llvm-8.0-D71495-vectorize-freduce.patch deleted file mode 100644 index fb461920c176f..0000000000000 --- a/deps/patches/llvm-8.0-D71495-vectorize-freduce.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 7c30e23f115ae285b497ef11af0153703111dff2 Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Sun, 22 Dec 2019 14:25:50 -0500 -Subject: [PATCH 1/2] [SelectionDAG] Copy FP flags when visiting a binary - instruction. - -Summary: -We noticed in Julia that the sequence below no longer turned into -a sequence of FMA instructions in LLVM 7+, but it did in LLVM 6. - -``` - %29 = fmul contract <4 x double> %wide.load, %wide.load16 - %30 = fmul contract <4 x double> %wide.load13, %wide.load17 - %31 = fmul contract <4 x double> %wide.load14, %wide.load18 - %32 = fmul contract <4 x double> %wide.load15, %wide.load19 - %33 = fadd fast <4 x double> %vec.phi, %29 - %34 = fadd fast <4 x double> %vec.phi10, %30 - %35 = fadd fast <4 x double> %vec.phi11, %31 - %36 = fadd fast <4 x double> %vec.phi12, %32 -``` - -Unlike Clang, Julia doesn't set the `unsafe-fp-math=true` function -attribute, but rather emits more local instruction flags. - -This partially undoes https://reviews.llvm.org/D46854 and if required I can try to minimize the test further. - -Reviewers: spatel, mcberg2017 - -Reviewed By: spatel - -Subscribers: chriselrod, merge_guards_bot, hiraditya, llvm-commits - -Tags: #llvm - -Differential Revision: https://reviews.llvm.org/D71495 ---- - .../SelectionDAG/SelectionDAGBuilder.cpp | 7 +++++ - llvm/test/CodeGen/X86/fmf-reduction.ll | 26 +++++++++++++++++++ - 2 files changed, 33 insertions(+) - create mode 100644 llvm/test/CodeGen/X86/fmf-reduction.ll - -diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp -index bfeb3d1bc2b..e6362c19691 100644 ---- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp -+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp -@@ -2833,6 +2833,13 @@ void SelectionDAGBuilder::visitBinary(const User &I, unsigned Opcode) { - if (isVectorReductionOp(&I)) { - Flags.setVectorReduction(true); - LLVM_DEBUG(dbgs() << "Detected a reduction operation:" << I << "\n"); -+ -+ // If no flags are set we will propagate the incoming flags, if any flags -+ // are set, we will intersect them with the incoming flag and so we need to -+ // copy the FMF flags here. -+ if (auto *FPOp = dyn_cast(&I)) { -+ Flags.copyFMF(*FPOp); -+ } - } - - SDValue Op1 = getValue(I.getOperand(0)); -diff --git a/test/CodeGen/X86/fmf-reduction.ll b/test/CodeGen/X86/fmf-reduction.ll -new file mode 100644 -index 00000000000..1d669d2a924 ---- /dev/null -+++ b/test/CodeGen/X86/fmf-reduction.ll -@@ -0,0 +1,26 @@ -+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -+; RUN: llc < %s -mtriple=x86_64-- -mattr=fma | FileCheck %s -+ -+; Propagation of IR FMF should not drop flags when adding the DAG reduction flag. -+; This should include an FMA instruction, not separate FMUL/FADD. -+ -+define double @julia_dotf(<4 x double> %x, <4 x double> %y, <4 x double> %z, i1 %t3) { -+; CHECK-LABEL: julia_dotf: -+; CHECK: # %bb.0: -+; CHECK-NEXT: vfmadd213pd {{.*#+}} ymm0 = (ymm1 * ymm0) + ymm2 -+; CHECK-NEXT: vextractf128 $1, %ymm0, %xmm1 -+; CHECK-NEXT: vaddpd %xmm1, %xmm0, %xmm0 -+; CHECK-NEXT: vpermilpd {{.*#+}} xmm1 = xmm0[1,0] -+; CHECK-NEXT: vaddsd %xmm1, %xmm0, %xmm0 -+; CHECK-NEXT: vzeroupper -+; CHECK-NEXT: retq -+ %t1 = fmul contract <4 x double> %x, %y -+ %t2 = fadd fast <4 x double> %z, %t1 -+ %rdx.shuf = shufflevector <4 x double> %t2, <4 x double> undef, <4 x i32> -+ %bin.rdx22 = fadd fast <4 x double> %t2, %rdx.shuf -+ %rdx.shuf23 = shufflevector <4 x double> %bin.rdx22, <4 x double> undef, <4 x i32> -+ %bin.rdx24 = fadd fast <4 x double> %bin.rdx22, %rdx.shuf23 -+ %t4 = extractelement <4 x double> %bin.rdx24, i32 0 -+ ret double %t4 -+} -+ --- -2.24.1 - diff --git a/deps/patches/llvm-9.0-D65174-limit-merge-stores.patch b/deps/patches/llvm-9.0-D65174-limit-merge-stores.patch deleted file mode 100644 index 6d6cfb4acd800..0000000000000 --- a/deps/patches/llvm-9.0-D65174-limit-merge-stores.patch +++ /dev/null @@ -1,116 +0,0 @@ -commit f49c107f06c6a98d11a09d758f08554c78b9b933 -Author: Wei Mi -Date: Wed Jul 31 19:59:24 2019 +0000 - - [DAGCombine] Limit the number of times for the same store and root nodes - to bail out in store merging dependence check. - - We run into a case where dependence check in store merging bail out many times - for the same store and root nodes in a huge basicblock. That increases compile - time by almost 100x. The patch add a map to track how many times the bailing - out happen for the same store and root, and if it is over a limit, stop - considering the store with the same root as a merging candidate. - - Differential Revision: https://reviews.llvm.org/D65174 - - llvm-svn: 367472 - -diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -index bf62aa86509..2e5ba82af22 100644 ---- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -+++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp -@@ -120,6 +120,11 @@ static cl::opt TokenFactorInlineLimit( - "combiner-tokenfactor-inline-limit", cl::Hidden, cl::init(2048), - cl::desc("Limit the number of operands to inline for Token Factors")); - -+static cl::opt StoreMergeDependenceLimit( -+ "combiner-store-merge-dependence-limit", cl::Hidden, cl::init(10), -+ cl::desc("Limit the number of times for the same StoreNode and RootNode " -+ "to bail out in store merging dependence check")); -+ - namespace { - - class DAGCombiner { -@@ -157,6 +162,14 @@ namespace { - /// which have not yet been combined to the worklist. - SmallPtrSet CombinedNodes; - -+ /// Map from candidate StoreNode to the pair of RootNode and count. -+ /// The count is used to track how many times we have seen the StoreNode -+ /// with the same RootNode bail out in dependence check. If we have seen -+ /// the bail out for the same pair many times over a limit, we won't -+ /// consider the StoreNode with the same RootNode as store merging -+ /// candidate again. -+ DenseMap> StoreRootCountMap; -+ - // AA - Used for DAG load/store alias analysis. - AliasAnalysis *AA; - -@@ -241,6 +254,7 @@ namespace { - void removeFromWorklist(SDNode *N) { - CombinedNodes.erase(N); - PruningList.remove(N); -+ StoreRootCountMap.erase(N); - - auto It = WorklistMap.find(N); - if (It == WorklistMap.end()) -@@ -15423,6 +15437,18 @@ void DAGCombiner::getStoreMergeCandidates( - return (BasePtr.equalBaseIndex(Ptr, DAG, Offset)); - }; - -+ // Check if the pair of StoreNode and the RootNode already bail out many -+ // times which is over the limit in dependence check. -+ auto OverLimitInDependenceCheck = [&](SDNode *StoreNode, -+ SDNode *RootNode) -> bool { -+ auto RootCount = StoreRootCountMap.find(StoreNode); -+ if (RootCount != StoreRootCountMap.end() && -+ RootCount->second.first == RootNode && -+ RootCount->second.second > StoreMergeDependenceLimit) -+ return true; -+ return false; -+ }; -+ - // We looking for a root node which is an ancestor to all mergable - // stores. We search up through a load, to our root and then down - // through all children. For instance we will find Store{1,2,3} if -@@ -15452,7 +15478,8 @@ void DAGCombiner::getStoreMergeCandidates( - if (StoreSDNode *OtherST = dyn_cast(*I2)) { - BaseIndexOffset Ptr; - int64_t PtrDiff; -- if (CandidateMatch(OtherST, Ptr, PtrDiff)) -+ if (CandidateMatch(OtherST, Ptr, PtrDiff) && -+ !OverLimitInDependenceCheck(OtherST, RootNode)) - StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); - } - } else -@@ -15462,7 +15489,8 @@ void DAGCombiner::getStoreMergeCandidates( - if (StoreSDNode *OtherST = dyn_cast(*I)) { - BaseIndexOffset Ptr; - int64_t PtrDiff; -- if (CandidateMatch(OtherST, Ptr, PtrDiff)) -+ if (CandidateMatch(OtherST, Ptr, PtrDiff) && -+ !OverLimitInDependenceCheck(OtherST, RootNode)) - StoreNodes.push_back(MemOpLink(OtherST, PtrDiff)); - } - } -@@ -15520,8 +15548,19 @@ bool DAGCombiner::checkMergeStoreCandidatesForDependencies( - // Search through DAG. We can stop early if we find a store node. - for (unsigned i = 0; i < NumStores; ++i) - if (SDNode::hasPredecessorHelper(StoreNodes[i].MemNode, Visited, Worklist, -- Max)) -+ Max)) { -+ // If the searching bail out, record the StoreNode and RootNode in the -+ // StoreRootCountMap. If we have seen the pair many times over a limit, -+ // we won't add the StoreNode into StoreNodes set again. -+ if (Visited.size() >= Max) { -+ auto &RootCount = StoreRootCountMap[StoreNodes[i].MemNode]; -+ if (RootCount.first == RootNode) -+ RootCount.second++; -+ else -+ RootCount = {RootNode, 1}; -+ } - return false; -+ } - return true; - } - diff --git a/deps/patches/llvm-9.0-D78196.patch b/deps/patches/llvm-9.0-D78196.patch deleted file mode 100644 index 6ae23fd7d8600..0000000000000 --- a/deps/patches/llvm-9.0-D78196.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp ---- a/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp -+++ b/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp -@@ -210,6 +210,10 @@ - for (auto *Sym : UpdateOther) - if (Sym->isVariable()) - copyLocalEntry(Sym, Sym->getVariableValue()); -+ -+ // Clear the set of symbols that needs to be updated so the streamer can -+ // be reused without issues. -+ UpdateOther.clear(); - } - - private: - diff --git a/deps/patches/llvm-9.0-D85499.patch b/deps/patches/llvm-9.0-D85499.patch deleted file mode 100644 index 1be91fc4717f5..0000000000000 --- a/deps/patches/llvm-9.0-D85499.patch +++ /dev/null @@ -1,425 +0,0 @@ -commit ac8729e23232d0fd3933b76093a40b7c65332aff -Author: Keno Fischer -Date: Fri Aug 7 00:31:43 2020 -0400 - - [X86] Canonicalize andnp for bitmask arithmetic - - We have a DAG combine that tries to fold (vselect cond, 0000..., X) -> (andnp cond, x). - However, it does so by attempting to create an i64 vector with the number - of elements obtained by truncating division by 64 from the bitwidth. This is - bad for mask vectors like v8i1, since that division is just zero. Besides, - we don't want i64 vectors anyway. The easy change is just to avoid changing - the VT, but this is slightly problematic because the canonical pattern for - `kandn` is `(and (vnot a) b)` rather than `(x86andnp a b)`, so this fails - to select. Rather than playing games here with having the mask vectors - use a different canonical representation, the bulk of this commit switches - the canonical ISD representation for `kandn` to `(x86andnp a b)` such - that all vector types may be handled equally here. To avoid regressing - other tests, we need to extend a few other folds to handle `x86andnp` in - addition to plain `and`. However, that should be generally a good - improvement, since x86andnp is already canonical for non-i1 vectors - prior to this commit, and said folds were just missing. - - When all is said and done, fixes the issue reported in - https://github.com/JuliaLang/julia/issues/36955. - - Differential Revision: https://reviews.llvm.org/D85499 - -diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp -index 34ad589d205..eb21b0de89d 100644 ---- a/lib/Target/X86/X86ISelDAGToDAG.cpp -+++ b/lib/Target/X86/X86ISelDAGToDAG.cpp -@@ -503,7 +503,7 @@ namespace { - bool isMaskZeroExtended(SDNode *N) const; - bool tryShiftAmountMod(SDNode *N); - bool tryShrinkShlLogicImm(SDNode *N); -- bool tryVPTESTM(SDNode *Root, SDValue Setcc, SDValue Mask); -+ bool tryVPTESTM(SDNode *Root, SDValue Setcc, SDValue Mask, bool Invert); - - MachineSDNode *emitPCMPISTR(unsigned ROpc, unsigned MOpc, bool MayFoldLoad, - const SDLoc &dl, MVT VT, SDNode *Node); -@@ -2998,7 +2998,7 @@ bool X86DAGToDAGISel::foldLoadStoreIntoMemOperand(SDNode *Node) { - bool IsNegOne = isAllOnesConstant(StoredVal.getOperand(1)); - // ADD/SUB with 1/-1 and carry flag isn't used can use inc/dec. - if ((IsOne || IsNegOne) && hasNoCarryFlagUses(StoredVal.getValue(1))) { -- unsigned NewOpc = -+ unsigned NewOpc = - ((Opc == X86ISD::ADD) == IsOne) - ? SelectOpcode(X86::INC64m, X86::INC32m, X86::INC16m, X86::INC8m) - : SelectOpcode(X86::DEC64m, X86::DEC32m, X86::DEC16m, X86::DEC8m); -@@ -3999,8 +3999,8 @@ static unsigned getVPTESTMOpc(MVT TestVT, bool IsTestN, bool FoldedLoad, - - // Try to create VPTESTM instruction. If InMask is not null, it will be used - // to form a masked operation. --bool X86DAGToDAGISel::tryVPTESTM(SDNode *Root, SDValue Setcc, -- SDValue InMask) { -+bool X86DAGToDAGISel::tryVPTESTM(SDNode *Root, SDValue Setcc, SDValue InMask, -+ bool Invert) { - assert(Subtarget->hasAVX512() && "Expected AVX512!"); - assert(Setcc.getSimpleValueType().getVectorElementType() == MVT::i1 && - "Unexpected VT!"); -@@ -4140,6 +4140,9 @@ bool X86DAGToDAGISel::tryVPTESTM(SDNode *Root, SDValue Setcc, - } - - bool IsTestN = CC == ISD::SETEQ; -+ if (Invert) -+ IsTestN = !IsTestN; -+ - unsigned Opc = getVPTESTMOpc(CmpVT, IsTestN, FoldedLoad, FoldedBCast, - IsMasked); - -@@ -4309,16 +4312,27 @@ void X86DAGToDAGISel::Select(SDNode *Node) { - return; - break; - -+ case X86ISD::ANDNP: -+ if (NVT.isVector() && NVT.getVectorElementType() == MVT::i1) { -+ SDValue N0 = Node->getOperand(0); -+ SDValue N1 = Node->getOperand(1); -+ // Try to form a masked VPTESTM -+ if (N0.getOpcode() == ISD::SETCC && N0.hasOneUse() && -+ tryVPTESTM(Node, N0, N1, true)) -+ return; -+ } -+ break; -+ - case ISD::AND: - if (NVT.isVector() && NVT.getVectorElementType() == MVT::i1) { - // Try to form a masked VPTESTM. Operands can be in either order. - SDValue N0 = Node->getOperand(0); - SDValue N1 = Node->getOperand(1); - if (N0.getOpcode() == ISD::SETCC && N0.hasOneUse() && -- tryVPTESTM(Node, N0, N1)) -+ tryVPTESTM(Node, N0, N1, false)) - return; - if (N1.getOpcode() == ISD::SETCC && N1.hasOneUse() && -- tryVPTESTM(Node, N1, N0)) -+ tryVPTESTM(Node, N1, N0, false)) - return; - } - -@@ -5000,7 +5014,7 @@ void X86DAGToDAGISel::Select(SDNode *Node) { - } - - case ISD::SETCC: { -- if (NVT.isVector() && tryVPTESTM(Node, SDValue(Node, 0), SDValue())) -+ if (NVT.isVector() && tryVPTESTM(Node, SDValue(Node, 0), SDValue(), false)) - return; - - break; -diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp -index 920cdd7e625..6b9738074c7 100644 ---- a/lib/Target/X86/X86ISelLowering.cpp -+++ b/lib/Target/X86/X86ISelLowering.cpp -@@ -196,7 +196,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM, - // Integer absolute. - if (Subtarget.hasCMov()) { - setOperationAction(ISD::ABS , MVT::i16 , Custom); -- setOperationAction(ISD::ABS , MVT::i32 , Custom); -+ setOperationAction(ISD::ABS , MVT::i32 , Custom); - } - setOperationAction(ISD::ABS , MVT::i64 , Custom); - -@@ -26053,7 +26053,7 @@ X86TargetLowering::lowerIdempotentRMWIntoFencedLoad(AtomicRMWInst *AI) const { - - // If this is a canonical idempotent atomicrmw w/no uses, we have a better - // lowering available in lowerAtomicArith. -- // TODO: push more cases through this path. -+ // TODO: push more cases through this path. - if (auto *C = dyn_cast(AI->getValOperand())) - if (AI->getOperation() == AtomicRMWInst::Or && C->isZero() && - AI->use_empty()) -@@ -26111,7 +26111,7 @@ X86TargetLowering::lowerIdempotentRMWIntoFencedLoad(AtomicRMWInst *AI) const { - /// Emit a locked operation on a stack location which does not change any - /// memory location, but does involve a lock prefix. Location is chosen to be - /// a) very likely accessed only by a single thread to minimize cache traffic, --/// and b) definitely dereferenceable. Returns the new Chain result. -+/// and b) definitely dereferenceable. Returns the new Chain result. - static SDValue emitLockedStackOp(SelectionDAG &DAG, - const X86Subtarget &Subtarget, - SDValue Chain, SDLoc DL) { -@@ -26120,22 +26120,22 @@ static SDValue emitLockedStackOp(SelectionDAG &DAG, - // operations issued by the current processor. As such, the location - // referenced is not relevant for the ordering properties of the instruction. - // See: Intel® 64 and IA-32 ArchitecturesSoftware Developer’s Manual, -- // 8.2.3.9 Loads and Stores Are Not Reordered with Locked Instructions -+ // 8.2.3.9 Loads and Stores Are Not Reordered with Locked Instructions - // 2) Using an immediate operand appears to be the best encoding choice - // here since it doesn't require an extra register. - // 3) OR appears to be very slightly faster than ADD. (Though, the difference - // is small enough it might just be measurement noise.) - // 4) When choosing offsets, there are several contributing factors: - // a) If there's no redzone, we default to TOS. (We could allocate a cache -- // line aligned stack object to improve this case.) -+ // line aligned stack object to improve this case.) - // b) To minimize our chances of introducing a false dependence, we prefer -- // to offset the stack usage from TOS slightly. -+ // to offset the stack usage from TOS slightly. - // c) To minimize concerns about cross thread stack usage - in particular, - // the idiomatic MyThreadPool.run([&StackVars]() {...}) pattern which - // captures state in the TOS frame and accesses it from many threads - - // we want to use an offset such that the offset is in a distinct cache - // line from the TOS frame. -- // -+ // - // For a general discussion of the tradeoffs and benchmark results, see: - // https://shipilev.net/blog/2014/on-the-fence-with-dependencies/ - -@@ -26188,7 +26188,7 @@ static SDValue LowerATOMIC_FENCE(SDValue Op, const X86Subtarget &Subtarget, - if (Subtarget.hasMFence()) - return DAG.getNode(X86ISD::MFENCE, dl, MVT::Other, Op.getOperand(0)); - -- SDValue Chain = Op.getOperand(0); -+ SDValue Chain = Op.getOperand(0); - return emitLockedStackOp(DAG, Subtarget, Chain, dl); - } - -@@ -26677,12 +26677,12 @@ static SDValue lowerAtomicArith(SDValue N, SelectionDAG &DAG, - // seq_cst which isn't SingleThread, everything just needs to be preserved - // during codegen and then dropped. Note that we expect (but don't assume), - // that orderings other than seq_cst and acq_rel have been canonicalized to -- // a store or load. -+ // a store or load. - if (AN->getOrdering() == AtomicOrdering::SequentiallyConsistent && - AN->getSyncScopeID() == SyncScope::System) { - // Prefer a locked operation against a stack location to minimize cache - // traffic. This assumes that stack locations are very likely to be -- // accessed only by the owning thread. -+ // accessed only by the owning thread. - SDValue NewChain = emitLockedStackOp(DAG, Subtarget, Chain, DL); - assert(!N->hasAnyUseOfValue(0)); - // NOTE: The getUNDEF is needed to give something for the unused result 0. -@@ -35620,7 +35620,7 @@ static SDValue scalarizeExtEltFP(SDNode *ExtElt, SelectionDAG &DAG) { - } - - // TODO: This switch could include FNEG and the x86-specific FP logic ops -- // (FAND, FANDN, FOR, FXOR). But that may require enhancements to avoid -+ // (FAND, FANDN, FOR, FXOR). But that may require enhancements to avoid - // missed load folding and fma+fneg combining. - switch (Vec.getOpcode()) { - case ISD::FMA: // Begin 3 operands -@@ -35935,10 +35935,8 @@ combineVSelectWithAllOnesOrZeros(SDNode *N, SelectionDAG &DAG, - - // vselect Cond, 000..., X -> andn Cond, X - if (TValIsAllZeros) { -- MVT AndNVT = MVT::getVectorVT(MVT::i64, CondVT.getSizeInBits() / 64); -- SDValue CastCond = DAG.getBitcast(AndNVT, Cond); -- SDValue CastRHS = DAG.getBitcast(AndNVT, RHS); -- SDValue AndN = DAG.getNode(X86ISD::ANDNP, DL, AndNVT, CastCond, CastRHS); -+ SDValue CastRHS = DAG.getBitcast(CondVT, RHS); -+ SDValue AndN = DAG.getNode(X86ISD::ANDNP, DL, CondVT, Cond, CastRHS); - return DAG.getBitcast(VT, AndN); - } - -@@ -38147,12 +38145,17 @@ static SDValue IsNOT(SDValue V, SelectionDAG &DAG) { - return SDValue(); - } - --/// Try to fold: (and (xor X, -1), Y) -> (andnp X, Y). --static SDValue combineANDXORWithAllOnesIntoANDNP(SDNode *N, SelectionDAG &DAG) { -+ -+/// Try to fold: -+/// (and (not X), Y) -> (andnp X, Y) -+/// (and (xor X, -1), Y) -> (andnp X, Y). -+static SDValue combineANDXORWithAllOnesIntoANDNP(SDNode *N, SelectionDAG &DAG, -+ const X86Subtarget &Subtarget) { - assert(N->getOpcode() == ISD::AND); - - MVT VT = N->getSimpleValueType(0); -- if (!VT.is128BitVector() && !VT.is256BitVector() && !VT.is512BitVector()) -+ if (!VT.is128BitVector() && !VT.is256BitVector() && !VT.is512BitVector() && -+ !(VT.isVector() && VT.getVectorElementType() == MVT::i1 && Subtarget.hasAVX512())) - return SDValue(); - - SDValue X, Y; -@@ -38558,7 +38561,7 @@ static SDValue combineAnd(SDNode *N, SelectionDAG &DAG, - if (SDValue FPLogic = convertIntLogicToFPLogic(N, DAG, Subtarget)) - return FPLogic; - -- if (SDValue R = combineANDXORWithAllOnesIntoANDNP(N, DAG)) -+ if (SDValue R = combineANDXORWithAllOnesIntoANDNP(N, DAG, Subtarget)) - return R; - - if (SDValue ShiftRight = combineAndMaskToShift(N, DAG, Subtarget)) -diff --git a/lib/Target/X86/X86InstrAVX512.td b/lib/Target/X86/X86InstrAVX512.td -index 54eddeacaa1..91027fa903f 100644 ---- a/lib/Target/X86/X86InstrAVX512.td -+++ b/lib/Target/X86/X86InstrAVX512.td -@@ -2978,7 +2978,6 @@ multiclass avx512_mask_binop_all opc, string OpcodeStr, - def andn : PatFrag<(ops node:$i0, node:$i1), (and (not node:$i0), node:$i1)>; - def xnor : PatFrag<(ops node:$i0, node:$i1), (not (xor node:$i0, node:$i1))>; - // These nodes use 'vnot' instead of 'not' to support vectors. --def vandn : PatFrag<(ops node:$i0, node:$i1), (and (vnot node:$i0), node:$i1)>; - def vxnor : PatFrag<(ops node:$i0, node:$i1), (vnot (xor node:$i0, node:$i1))>; - - // TODO - do we need a X86SchedWriteWidths::KMASK type? -@@ -2986,7 +2985,7 @@ defm KAND : avx512_mask_binop_all<0x41, "kand", and, SchedWriteVecLogic.XM - defm KOR : avx512_mask_binop_all<0x45, "kor", or, SchedWriteVecLogic.XMM, 1>; - defm KXNOR : avx512_mask_binop_all<0x46, "kxnor", vxnor, SchedWriteVecLogic.XMM, 1>; - defm KXOR : avx512_mask_binop_all<0x47, "kxor", xor, SchedWriteVecLogic.XMM, 1>; --defm KANDN : avx512_mask_binop_all<0x42, "kandn", vandn, SchedWriteVecLogic.XMM, 0>; -+defm KANDN : avx512_mask_binop_all<0x42, "kandn", X86andnp, SchedWriteVecLogic.XMM, 0>; - defm KADD : avx512_mask_binop_all<0x4A, "kadd", X86kadd, SchedWriteVecLogic.XMM, 1, HasDQI>; - - multiclass avx512_binop_pat; --defm : avx512_binop_pat; -+defm : avx512_binop_pat; - defm : avx512_binop_pat; - defm : avx512_binop_pat; - defm : avx512_binop_pat; -@@ -11570,7 +11569,7 @@ multiclass avx512_fixupimm_scalar opc, string OpcodeStr, - } - - multiclass avx512_fixupimm_packed_all { - let Predicates = [HasAVX512] in - defm Z : avx512_fixupimm_packed_sae<0x54, "vfixupimm", sched.ZMM, -@@ -11687,7 +11686,7 @@ multiclass AVX512_scalar_math_fp_patterns("V"#OpcPrefix#Zrr_Intkz) -+ (!cast("V"#OpcPrefix#Zrr_Intkz) - VK1WM:$mask, _.VT:$src1, - (_.VT (COPY_TO_REGCLASS _.FRC:$src2, VR128X)))>; - def : Pat<(MoveNode (_.VT VR128X:$src1), -diff --git a/test/CodeGen/X86/avx512-select.ll b/test/CodeGen/X86/avx512-select.ll -index 1ed7b408baf..64320d63eac 100644 ---- a/test/CodeGen/X86/avx512-select.ll -+++ b/test/CodeGen/X86/avx512-select.ll -@@ -595,3 +595,74 @@ define <16 x i64> @narrowExtractedVectorSelect_crash(<16 x i64> %arg, <16 x i16> - %tmp3 = zext <16 x i16> %tmp2 to <16 x i64> - ret <16 x i64> %tmp3 - } -+ -+; Regression test from https://github.com/JuliaLang/julia/issues/36955 -+define i8 @julia_issue36955(<8 x i1> %mask, <8 x double> %a) { -+; X86-AVX512F-LABEL: julia_issue36955: -+; X86-AVX512F: # %bb.0: -+; X86-AVX512F-NEXT: vpmovsxwq %xmm0, %zmm0 -+; X86-AVX512F-NEXT: vpsllq $63, %zmm0, %zmm0 -+; X86-AVX512F-NEXT: vptestmq %zmm0, %zmm0, %k0 -+; X86-AVX512F-NEXT: vpxor %xmm0, %xmm0, %xmm0 -+; X86-AVX512F-NEXT: vcmpnlepd %zmm0, %zmm1, %k1 -+; X86-AVX512F-NEXT: kandnw %k0, %k1, %k0 -+; X86-AVX512F-NEXT: kandw %k1, %k0, %k0 -+; X86-AVX512F-NEXT: knotw %k1, %k1 -+; X86-AVX512F-NEXT: korw %k1, %k0, %k0 -+; X86-AVX512F-NEXT: kmovw %k0, %eax -+; X86-AVX512F-NEXT: # kill: def $al killed $al killed $eax -+; X86-AVX512F-NEXT: vzeroupper -+; X86-AVX512F-NEXT: retl -+; -+; X64-AVX512F-LABEL: julia_issue36955: -+; X64-AVX512F: # %bb.0: -+; X64-AVX512F-NEXT: vpmovsxwq %xmm0, %zmm0 -+; X64-AVX512F-NEXT: vpsllq $63, %zmm0, %zmm0 -+; X64-AVX512F-NEXT: vptestmq %zmm0, %zmm0, %k0 -+; X64-AVX512F-NEXT: vpxor %xmm0, %xmm0, %xmm0 -+; X64-AVX512F-NEXT: vcmpnlepd %zmm0, %zmm1, %k1 -+; X64-AVX512F-NEXT: kandnw %k0, %k1, %k0 -+; X64-AVX512F-NEXT: kandw %k1, %k0, %k0 -+; X64-AVX512F-NEXT: knotw %k1, %k1 -+; X64-AVX512F-NEXT: korw %k1, %k0, %k0 -+; X64-AVX512F-NEXT: kmovw %k0, %eax -+; X64-AVX512F-NEXT: # kill: def $al killed $al killed $eax -+; X64-AVX512F-NEXT: vzeroupper -+; X64-AVX512F-NEXT: retq -+; -+; X86-AVX512BW-LABEL: julia_issue36955: -+; X86-AVX512BW: # %bb.0: -+; X86-AVX512BW-NEXT: vpsllw $15, %xmm0, %xmm0 -+; X86-AVX512BW-NEXT: vpmovw2m %zmm0, %k0 -+; X86-AVX512BW-NEXT: vpxor %xmm0, %xmm0, %xmm0 -+; X86-AVX512BW-NEXT: vcmpnlepd %zmm0, %zmm1, %k1 -+; X86-AVX512BW-NEXT: kandnw %k0, %k1, %k0 -+; X86-AVX512BW-NEXT: kandw %k1, %k0, %k0 -+; X86-AVX512BW-NEXT: knotw %k1, %k1 -+; X86-AVX512BW-NEXT: korw %k1, %k0, %k0 -+; X86-AVX512BW-NEXT: kmovd %k0, %eax -+; X86-AVX512BW-NEXT: # kill: def $al killed $al killed $eax -+; X86-AVX512BW-NEXT: vzeroupper -+; X86-AVX512BW-NEXT: retl -+; -+; X64-AVX512BW-LABEL: julia_issue36955: -+; X64-AVX512BW: # %bb.0: -+; X64-AVX512BW-NEXT: vpsllw $15, %xmm0, %xmm0 -+; X64-AVX512BW-NEXT: vpmovw2m %zmm0, %k0 -+; X64-AVX512BW-NEXT: vpxor %xmm0, %xmm0, %xmm0 -+; X64-AVX512BW-NEXT: vcmpnlepd %zmm0, %zmm1, %k1 -+; X64-AVX512BW-NEXT: kandnw %k0, %k1, %k0 -+; X64-AVX512BW-NEXT: kandw %k1, %k0, %k0 -+; X64-AVX512BW-NEXT: knotw %k1, %k1 -+; X64-AVX512BW-NEXT: korw %k1, %k0, %k0 -+; X64-AVX512BW-NEXT: kmovd %k0, %eax -+; X64-AVX512BW-NEXT: # kill: def $al killed $al killed $eax -+; X64-AVX512BW-NEXT: vzeroupper -+; X64-AVX512BW-NEXT: retq -+ %fcmp = fcmp ugt <8 x double> %a, zeroinitializer -+ %xor = xor <8 x i1> %fcmp, -+ %select1 = select <8 x i1> %fcmp, <8 x i1> zeroinitializer, <8 x i1> %mask -+ %select2 = select <8 x i1> %xor, <8 x i1> , <8 x i1> %select1 -+ %ret = bitcast <8 x i1> %select2 to i8 -+ ret i8 %ret -+} -diff --git a/test/CodeGen/X86/combine-bitselect.ll b/test/CodeGen/X86/combine-bitselect.ll -index 8cb6a4dca09..3c08a871c86 100644 ---- a/test/CodeGen/X86/combine-bitselect.ll -+++ b/test/CodeGen/X86/combine-bitselect.ll -@@ -616,13 +616,13 @@ define <4 x i1> @bitselect_v4i1_loop(<4 x i32> %a0, <4 x i32> %a1) { - ; AVX512F: # %bb.0: # %bb - ; AVX512F-NEXT: # kill: def $xmm1 killed $xmm1 def $zmm1 - ; AVX512F-NEXT: # kill: def $xmm0 killed $xmm0 def $zmm0 --; AVX512F-NEXT: vpbroadcastd {{.*#+}} xmm2 = [12,12,12,12] --; AVX512F-NEXT: vpcmpeqd %zmm2, %zmm1, %k1 -+; AVX512F-NEXT: vptestmd %zmm0, %zmm0, %k1 -+; AVX512F-NEXT: vpbroadcastd {{.*#+}} xmm0 = [12,12,12,12] - ; AVX512F-NEXT: vpbroadcastd {{.*#+}} xmm2 = [15,15,15,15] --; AVX512F-NEXT: vpcmpeqd %zmm2, %zmm1, %k2 --; AVX512F-NEXT: vptestnmd %zmm0, %zmm0, %k0 {%k2} --; AVX512F-NEXT: vptestmd %zmm0, %zmm0, %k1 {%k1} --; AVX512F-NEXT: korw %k0, %k1, %k1 -+; AVX512F-NEXT: vpcmpeqd %zmm2, %zmm1, %k0 -+; AVX512F-NEXT: vpcmpeqd %zmm0, %zmm1, %k2 {%k1} -+; AVX512F-NEXT: kandnw %k0, %k1, %k0 -+; AVX512F-NEXT: korw %k0, %k2, %k1 - ; AVX512F-NEXT: vpternlogd $255, %zmm0, %zmm0, %zmm0 {%k1} {z} - ; AVX512F-NEXT: # kill: def $xmm0 killed $xmm0 killed $zmm0 - ; AVX512F-NEXT: vzeroupper -diff --git a/test/CodeGen/X86/vec_ssubo.ll b/test/CodeGen/X86/vec_ssubo.ll -index 515dc5c5aa2..dfb1e7c4dee 100644 ---- a/test/CodeGen/X86/vec_ssubo.ll -+++ b/test/CodeGen/X86/vec_ssubo.ll -@@ -1640,7 +1640,7 @@ define <4 x i32> @ssubo_v4i1(<4 x i1> %a0, <4 x i1> %a1, <4 x i1>* %p2) nounwind - ; AVX512-NEXT: vptestmd %xmm1, %xmm1, %k0 - ; AVX512-NEXT: vpslld $31, %xmm0, %xmm0 - ; AVX512-NEXT: vptestmd %xmm0, %xmm0, %k1 --; AVX512-NEXT: vptestnmd %xmm1, %xmm1, %k2 {%k1} -+; AVX512-NEXT: kandnw %k1, %k0, %k2 - ; AVX512-NEXT: kxorw %k0, %k1, %k0 - ; AVX512-NEXT: kxorw %k2, %k0, %k1 - ; AVX512-NEXT: vpcmpeqd %xmm0, %xmm0, %xmm0 -diff --git a/test/CodeGen/X86/vec_usubo.ll b/test/CodeGen/X86/vec_usubo.ll -index c5a7b19cf14..367c491d25a 100644 ---- a/test/CodeGen/X86/vec_usubo.ll -+++ b/test/CodeGen/X86/vec_usubo.ll -@@ -1244,10 +1244,10 @@ define <4 x i32> @usubo_v4i1(<4 x i1> %a0, <4 x i1> %a1, <4 x i1>* %p2) nounwind - ; AVX512: # %bb.0: - ; AVX512-NEXT: vpslld $31, %xmm0, %xmm0 - ; AVX512-NEXT: vptestmd %xmm0, %xmm0, %k0 --; AVX512-NEXT: vpslld $31, %xmm1, %xmm1 --; AVX512-NEXT: vptestmd %xmm1, %xmm1, %k1 -+; AVX512-NEXT: vpslld $31, %xmm1, %xmm0 -+; AVX512-NEXT: vptestmd %xmm0, %xmm0, %k1 - ; AVX512-NEXT: kxorw %k1, %k0, %k1 --; AVX512-NEXT: vptestnmd %xmm0, %xmm0, %k2 {%k1} -+; AVX512-NEXT: kandnw %k1, %k0, %k2 - ; AVX512-NEXT: vpcmpeqd %xmm0, %xmm0, %xmm0 - ; AVX512-NEXT: vmovdqa32 %xmm0, %xmm0 {%k2} {z} - ; AVX512-NEXT: kmovd %k1, %eax diff --git a/deps/patches/llvm-D57118-powerpc.patch b/deps/patches/llvm-D57118-powerpc.patch deleted file mode 100644 index 328fe205d1280..0000000000000 --- a/deps/patches/llvm-D57118-powerpc.patch +++ /dev/null @@ -1,30 +0,0 @@ -commit 812db527538f30ac77a19d755e24109a6db7e569 -Author: Keno Fischer -Date: Wed Jan 23 16:46:59 2019 -0500 - - [CMake][PowerPC] Recognize LLVM_NATIVE_TARGET="ppc64le" as PowerPC - - Summary: - This value is derived from the host triple, which on the machine - I'm currently using is `ppc64le-linux-redhat`. This change makes - LLVM compile. - - Reviewers: hfinkel - - Subscribers: nemanjai, mgorny, jsji, llvm-commits - - Differential Revision: https://reviews.llvm.org/D57118 - -diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake -index 900c35ee4f0..b9c9757a4f6 100644 ---- a/cmake/config-ix.cmake -+++ b/cmake/config-ix.cmake -@@ -386,6 +386,8 @@ elseif (LLVM_NATIVE_ARCH MATCHES "sparc") - set(LLVM_NATIVE_ARCH Sparc) - elseif (LLVM_NATIVE_ARCH MATCHES "powerpc") - set(LLVM_NATIVE_ARCH PowerPC) -+elseif (LLVM_NATIVE_ARCH MATCHES "ppc64le") -+ set(LLVM_NATIVE_ARCH PowerPC) - elseif (LLVM_NATIVE_ARCH MATCHES "aarch64") - set(LLVM_NATIVE_ARCH AArch64) - elseif (LLVM_NATIVE_ARCH MATCHES "arm64") diff --git a/deps/patches/llvm-exegesis-mingw.patch b/deps/patches/llvm-exegesis-mingw.patch deleted file mode 100644 index ff11f4da8231e..0000000000000 --- a/deps/patches/llvm-exegesis-mingw.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9ba86352649a39b03adce98670714c4c8eb5341d Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Wed, 24 Jul 2019 21:19:20 -0400 -Subject: [PATCH] Fix build of llvm-exegis on mingw32 - ---- - llvm/tools/llvm-exegesis/CMakeLists.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/llvm-exegesis/CMakeLists.txt b/tools/llvm-exegesis/CMakeLists.txt -index a59e1b74024..7a30e0ea98f 100644 ---- a/tools/llvm-exegesis/CMakeLists.txt -+++ b/tools/llvm-exegesis/CMakeLists.txt -@@ -4,7 +4,7 @@ set(LLVM_LINK_COMPONENTS - native - ) - --add_llvm_tool(llvm-exegesis -+add_llvm_tool(llvm-exegesis DISABLE_LLVM_LINK_LLVM_DYLIB - llvm-exegesis.cpp - ) - --- -2.22.0 diff --git a/deps/patches/llvm-symver-jlprefix.patch b/deps/patches/llvm-symver-jlprefix.patch deleted file mode 100644 index 59872380ad073..0000000000000 --- a/deps/patches/llvm-symver-jlprefix.patch +++ /dev/null @@ -1,18 +0,0 @@ -From f23277bb91a4925ba8763337137a3123a7600557 Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Tue, 16 Jan 2018 17:29:05 -0500 -Subject: [PATCH] add JL prefix to all LLVM version suffixes - ---- - tools/llvm-shlib/simple_version_script.map.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/tools/llvm-shlib/simple_version_script.map.in b/tools/llvm-shlib/simple_version_script.map.in -index e9515fe7862..af082581627 100644 ---- a/tools/llvm-shlib/simple_version_script.map.in -+++ b/tools/llvm-shlib/simple_version_script.map.in -@@ -1 +1 @@ --LLVM_@LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ { global: *; }; -+JL_LLVM_@LLVM_VERSION_MAJOR@.@LLVM_VERSION_MINOR@ { global: *; }; --- -2.15.1 diff --git a/deps/patches/llvm-test-plugin-mingw.patch b/deps/patches/llvm-test-plugin-mingw.patch deleted file mode 100644 index 14cf07166d861..0000000000000 --- a/deps/patches/llvm-test-plugin-mingw.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9bd3774db73533c8df475639805ff1516aea274c Mon Sep 17 00:00:00 2001 -From: Valentin Churavy -Date: Wed, 24 Jul 2019 21:45:33 -0400 -Subject: [PATCH] add missing components to TestPlugin - ---- - llvm/unittests/Passes/CMakeLists.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/unittests/Passes/CMakeLists.txt b/unittests/Passes/CMakeLists.txt -index 3e83b527958..4b09f47c234 100644 ---- a/unittests/Passes/CMakeLists.txt -+++ b/unittests/Passes/CMakeLists.txt -@@ -14,7 +14,7 @@ add_llvm_unittest(PluginsTests - export_executable_symbols(PluginsTests) - target_link_libraries(PluginsTests PRIVATE LLVMTestingSupport) - --set(LLVM_LINK_COMPONENTS) -+set(LLVM_LINK_COMPONENTS Support Passes Core) - add_llvm_library(TestPlugin MODULE BUILDTREE_ONLY - TestPlugin.cpp - ) --- -2.22.0 diff --git a/deps/patches/llvm7-D50010-VNCoercion-ni.patch b/deps/patches/llvm7-D50010-VNCoercion-ni.patch deleted file mode 100644 index 729c4185128c9..0000000000000 --- a/deps/patches/llvm7-D50010-VNCoercion-ni.patch +++ /dev/null @@ -1,67 +0,0 @@ -diff --git a/lib/Transforms/Utils/VNCoercion.cpp b/lib/Transforms/Utils/VNCoercion.cpp -index 948d9bd5baa..fbd5b9bb3be 100644 ---- a/lib/Transforms/Utils/VNCoercion.cpp -+++ b/lib/Transforms/Utils/VNCoercion.cpp -@@ -20,7 +20,8 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, - StoredVal->getType()->isStructTy() || StoredVal->getType()->isArrayTy()) - return false; - -- uint64_t StoreSize = DL.getTypeSizeInBits(StoredVal->getType()); -+ Type *StoredValTy = StoredVal->getType(); -+ uint64_t StoreSize = DL.getTypeSizeInBits(StoredValTy); - - // The store size must be byte-aligned to support future type casts. - if (llvm::alignTo(StoreSize, 8) != StoreSize) -@@ -30,10 +31,15 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, - if (StoreSize < DL.getTypeSizeInBits(LoadTy)) - return false; - -- // Don't coerce non-integral pointers to integers or vice versa. -- if (DL.isNonIntegralPointerType(StoredVal->getType()) != -- DL.isNonIntegralPointerType(LoadTy)) -+ bool StoredNI = DL.isNonIntegralPointerType(StoredValTy); -+ bool LoadNI = DL.isNonIntegralPointerType(LoadTy); -+ if (StoredNI != LoadNI) { -+ return false; -+ } else if (StoredNI && LoadNI && -+ cast(StoredValTy)->getAddressSpace() != -+ cast(LoadTy)->getAddressSpace()) { - return false; -+ } - - return true; - } -diff --git a/test/Transforms/GVN/non-integral-pointers.ll b/test/Transforms/GVN/non-integral-pointers.ll -index 9ae4132231d..5217fc1a06a 100644 ---- a/test/Transforms/GVN/non-integral-pointers.ll -+++ b/test/Transforms/GVN/non-integral-pointers.ll -@@ -1,6 +1,6 @@ - ; RUN: opt -gvn -S < %s | FileCheck %s - --target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4" -+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128-ni:4:5" - target triple = "x86_64-unknown-linux-gnu" - - define void @f0(i1 %alwaysFalse, i64 %val, i64* %loc) { -@@ -37,3 +37,21 @@ define i64 @f1(i1 %alwaysFalse, i8 addrspace(4)* %val, i8 addrspace(4)** %loc) { - alwaysTaken: - ret i64 42 - } -+ -+ define i8 addrspace(5)* @multini(i1 %alwaysFalse, i8 addrspace(4)* %val, i8 addrspace(4)** %loc) { -+ ; CHECK-LABEL: @multini( -+ ; CHECK-NOT: inttoptr -+ ; CHECK-NOT: ptrtoint -+ ; CHECK-NOT: addrspacecast -+ entry: -+ store i8 addrspace(4)* %val, i8 addrspace(4)** %loc -+ br i1 %alwaysFalse, label %neverTaken, label %alwaysTaken -+ -+ neverTaken: -+ %loc.bc = bitcast i8 addrspace(4)** %loc to i8 addrspace(5)** -+ %differentas = load i8 addrspace(5)*, i8 addrspace(5)** %loc.bc -+ ret i8 addrspace(5)* %differentas -+ -+ alwaysTaken: -+ ret i8 addrspace(5)* null -+ } diff --git a/deps/patches/llvm7-windows-race.patch b/deps/patches/llvm7-windows-race.patch deleted file mode 100644 index b6ae6bae43ba4..0000000000000 --- a/deps/patches/llvm7-windows-race.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt -index f59402ac4b0..5de4c6febe7 100644 ---- a/tools/llvm-config/CMakeLists.txt -+++ b/tools/llvm-config/CMakeLists.txt -@@ -77,5 +77,10 @@ if(CMAKE_CROSSCOMPILING AND NOT LLVM_CONFIG_PATH) - add_custom_target(NativeLLVMConfig DEPENDS ${LLVM_CONFIG_PATH}) - add_dependencies(NativeLLVMConfig CONFIGURE_LLVM_NATIVE) - -+ # Add a dependency on the host tblgen, which uses the same working -+ # directory and with which we're otherwise racing to build some -+ # of the utility libraries. -+ add_dependencies(NativeLLVMConfig LLVM-tablegen-host) -+ - add_dependencies(llvm-config NativeLLVMConfig) - endif() diff --git a/deps/patches/llvm9-D71443-PPC-MC-redef-symbol.patch b/deps/patches/llvm9-D71443-PPC-MC-redef-symbol.patch deleted file mode 100644 index 904514a60f83f..0000000000000 --- a/deps/patches/llvm9-D71443-PPC-MC-redef-symbol.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 5cd52dbfa9c60cfd12676924bed97701ee9bc4ef Mon Sep 17 00:00:00 2001 -From: Fangrui Song -Date: Thu, 12 Dec 2019 16:18:57 -0800 -Subject: [PATCH] [MC][PowerPC] Fix a crash when redefining a symbol after .set - -Fix PR44284. This is probably not valid assembly but we should not crash. - -Reviewed By: luporl, #powerpc, steven.zhang - -Differential Revision: https://reviews.llvm.org/D71443 - -(cherry picked from commit f99eedeb72644671cd584f48e4c136d47f6b0020) ---- - llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp | 3 ++- - llvm/test/MC/PowerPC/ppc64-localentry-symbols.s | 5 +++++ - 2 files changed, 7 insertions(+), 1 deletion(-) - -diff --git llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp -index 90c3c8d20ed..71f926c265e 100644 ---- llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp -+++ llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp -@@ -196,7 +196,8 @@ public: - - void finish() override { - for (auto *Sym : UpdateOther) -- copyLocalEntry(Sym, Sym->getVariableValue()); -+ if (Sym->isVariable()) -+ copyLocalEntry(Sym, Sym->getVariableValue()); - } - - private: -diff --git llvm/test/MC/PowerPC/ppc64-localentry-symbols.s llvm/test/MC/PowerPC/ppc64-localentry-symbols.s -index f1d5c5d0ab1..a663af57ad4 100644 ---- llvm/test/MC/PowerPC/ppc64-localentry-symbols.s -+++ llvm/test/MC/PowerPC/ppc64-localentry-symbols.s -@@ -32,3 +32,8 @@ func: - nop - nop - .localentry func, 8 -+ -+## PR44284 Don't crash if err is redefined after .set -+.set err, _err -+.globl err -+err: --- -2.26.0 - diff --git a/deps/pcre.mk b/deps/pcre.mk index 2120f3c95bc3a..67185a7213c85 100644 --- a/deps/pcre.mk +++ b/deps/pcre.mk @@ -14,7 +14,7 @@ $(SRCCACHE)/pcre2-$(PCRE_VER)/source-extracted: $(SRCCACHE)/pcre2-$(PCRE_VER).ta cp $(SRCDIR)/patches/config.sub $(SRCCACHE)/pcre2-$(PCRE_VER)/config.sub echo 1 > $@ -checksum-pcre2: $(SRCCACHE)/pcre2-$(PCRE_VER).tar.bz2 +checksum-pcre: $(SRCCACHE)/pcre2-$(PCRE_VER).tar.bz2 $(JLCHECKSUM) $< $(SRCCACHE)/pcre2-$(PCRE_VER)/pcre2-sljit-apple-silicon-support.patch-applied: $(SRCCACHE)/pcre2-$(PCRE_VER)/source-extracted diff --git a/deps/suitesparse.mk b/deps/suitesparse.mk deleted file mode 100644 index 5be8589875dc4..0000000000000 --- a/deps/suitesparse.mk +++ /dev/null @@ -1,152 +0,0 @@ -## SUITESPARSE ## - -ifeq ($(USE_BLAS64), 1) -UMFPACK_CONFIG := -DLONGBLAS='long long' -CHOLMOD_CONFIG := -DLONGBLAS='long long' -SPQR_CONFIG := -DLONGBLAS='long long' -UMFPACK_CONFIG += -DSUN64 -CHOLMOD_CONFIG += -DSUN64 -SPQR_CONFIG += -DSUN64 -endif - -# Disable linking to libmetis -CHOLMOD_CONFIG += -DNPARTITION - -ifneq ($(USE_BINARYBUILDER_SUITESPARSE), 1) - -SUITESPARSE_PROJECTS := AMD BTF CAMD CCOLAMD COLAMD CHOLMOD LDL KLU UMFPACK RBio SPQR -SUITESPARSE_LIBS := $(addsuffix .*$(SHLIB_EXT)*,suitesparseconfig amd btf camd ccolamd colamd cholmod klu ldl umfpack rbio spqr) - -SUITE_SPARSE_LIB := $(LDFLAGS) -L"$(abspath $(BUILDDIR))/SuiteSparse-$(SUITESPARSE_VER)/lib" -ifeq ($(OS), Darwin) -SUITE_SPARSE_LIB += $(RPATH_ESCAPED_ORIGIN) -endif -SUITESPARSE_MFLAGS := CC="$(CC)" CXX="$(CXX)" F77="$(FC)" AR="$(AR)" RANLIB="$(RANLIB)" BLAS="-L$(build_shlibdir) -lblastrampoline" LAPACK="-L$(build_shlibdir) -lblastrampoline" \ - LDFLAGS="$(SUITE_SPARSE_LIB)" CFOPENMP="" CUDA=no CUDA_PATH="" \ - UMFPACK_CONFIG="$(UMFPACK_CONFIG)" CHOLMOD_CONFIG="$(CHOLMOD_CONFIG)" SPQR_CONFIG="$(SPQR_CONFIG)" -ifeq ($(OS),WINNT) -SUITESPARSE_MFLAGS += UNAME=Windows -else -SUITESPARSE_MFLAGS += UNAME=$(OS) -endif - -$(SRCCACHE)/SuiteSparse-$(SUITESPARSE_VER).tar.gz: | $(SRCCACHE) - $(JLDOWNLOAD) $@ https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v$(SUITESPARSE_VER).tar.gz - -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/source-extracted: $(SRCCACHE)/SuiteSparse-$(SUITESPARSE_VER).tar.gz - $(JLCHECKSUM) $< - mkdir -p $(dir $@) - $(TAR) -C $(dir $@) --strip-components 1 -zxf $< - echo 1 > $@ - -checksum-suitesparse: $(SRCCACHE)/SuiteSparse-$(SUITESPARSE_VER).tar.gz - $(JLCHECKSUM) $< - -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SuiteSparse-winclang.patch-applied: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/source-extracted - cd $(dir $@) && patch -p0 < $(SRCDIR)/patches/SuiteSparse-winclang.patch - echo 1 > $@ -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SuiteSparse-shlib.patch-applied: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/source-extracted - cd $(dir $@) && patch -p1 < $(SRCDIR)/patches/SuiteSparse-shlib.patch - echo 1 > $@ -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SuiteSparse-winclang.patch-applied -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SuiteSparse-shlib.patch-applied - -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled: | $(build_prefix)/manifest/blastrampoline - -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/source-extracted - $(MAKE) -C $(dir $<)SuiteSparse_config library config $(SUITESPARSE_MFLAGS) - $(INSTALL_NAME_CMD)libsuitesparseconfig.$(SHLIB_EXT) $(dir $<)lib/libsuitesparseconfig.$(SHLIB_EXT) - for PROJ in $(SUITESPARSE_PROJECTS); do \ - $(MAKE) -C $(dir $<)$${PROJ} library $(SUITESPARSE_MFLAGS) || exit 1; \ - $(INSTALL_NAME_CMD)lib`echo $${PROJ} | tr A-Z a-z`.$(SHLIB_EXT) $(dir $<)lib/lib`echo $${PROJ} | tr A-Z a-z`.$(SHLIB_EXT) || exit 1; \ - done - echo 1 > $@ - -ifeq ($(OS),WINNT) -SUITESPARSE_SHLIB_ENV:=PATH="$(abspath $(dir $<))lib:$(build_bindir):$(PATH)" -else -SUITESPARSE_SHLIB_ENV:=LD_LIBRARY_PATH="$(build_shlibdir)" -endif -$(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-checked: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled - for PROJ in $(SUITESPARSE_PROJECTS); do \ - $(SUITESPARSE_SHLIB_ENV) $(MAKE) -C $(dir $<)$${PROJ} default $(SUITESPARSE_MFLAGS) || exit 1; \ - done - echo 1 > $@ - -$(build_prefix)/manifest/suitesparse: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled | $(build_prefix)/manifest $(build_shlibdir) - for lib in $(SUITESPARSE_LIBS); do \ - cp -a $(dir $<)lib/lib$${lib} $(build_shlibdir) || exit 1; \ - done - #cp -a $(dir $<)lib/* $(build_shlibdir) - #cp -a $(dir $<)include/* $(build_includedir) - echo $(SUITESPARSE_VER) > $@ - -uninstall-suitesparse: - -rm $(build_prefix)/manifest/suitesparse - -rm $(addprefix $(build_shlibdir)/lib, $(SUITESPARSE_LIBS)) - -clean-suitesparse: clean-suitesparse-wrapper uninstall-suitesparse - -rm $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled - -rm -fr $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/lib - -rm -fr $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/include - -$(MAKE) -C $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER) clean - -distclean-suitesparse: clean-suitesparse-wrapper - -rm -rf $(SRCCACHE)/SuiteSparse-$(SUITESPARSE_VER).tar.gz \ - $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER) - -get-suitesparse: $(SRCCACHE)/SuiteSparse-$(SUITESPARSE_VER).tar.gz -extract-suitesparse: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/source-extracted -configure-suitesparse: extract-suitesparse -compile-suitesparse: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-compiled -fastcheck-suitesparse: #none -check-suitesparse: $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/build-checked -install-suitesparse: $(build_prefix)/manifest/suitesparse install-suitesparse-wrapper - -# SUITESPARSE WRAPPER - -ifeq ($(USE_SYSTEM_SUITESPARSE), 1) -SUITESPARSE_INC := -I $(LOCALBASE)/include/suitesparse -SUITESPARSE_LIB := -lumfpack -lcholmod -lamd -lcamd -lcolamd -lspqr -else -SUITESPARSE_INC := -I $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/CHOLMOD/Include -I $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SuiteSparse_config -I $(BUILDDIR)/SuiteSparse-$(SUITESPARSE_VER)/SPQR/Include -SUITESPARSE_LIB := -L$(build_shlibdir) -lcholmod -lumfpack -lspqr $(RPATH_ORIGIN) -$(build_shlibdir)/libsuitesparse_wrapper.$(SHLIB_EXT): $(build_prefix)/manifest/suitesparse -endif - -$(build_shlibdir)/libsuitesparse_wrapper.$(SHLIB_EXT): $(SRCDIR)/SuiteSparse_wrapper.c - mkdir -p $(build_shlibdir) - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -O2 -shared $(fPIC) $(SUITESPARSE_INC) $< -o $@ $(SUITESPARSE_LIB) - $(INSTALL_NAME_CMD)libsuitesparse_wrapper.$(SHLIB_EXT) $@ - touch -c $@ - -clean-suitesparse-wrapper: - -rm -f $(build_shlibdir)/libsuitesparse_wrapper.$(SHLIB_EXT) - -distclean-suitesparse-wrapper: clean-suitesparse-wrapper - -get-suitesparse-wrapper: -extract-suitesparse-wrapper: -configure-suitesparse-wrapper: -compile-suitesparse-wrapper: -fastcheck-suitesparse-wrapper: #none -check-suitesparse-wrapper: -install-suitesparse-wrapper: $(build_shlibdir)/libsuitesparse_wrapper.$(SHLIB_EXT) - -else # USE_BINARYBUILDER_SUITESPARSE - -$(eval $(call bb-install,suitesparse,SUITESPARSE,false)) - -get-suitesparse-wrapper: get-suitesparse -extract-suitesparse-wrapper: extract-suitesparse -configure-suitesparse-wrapper: configure-suitesparse -compile-suitesparse-wrapper: compile-suitesparse -fastcheck-suitesparse-wrapper: fastcheck-suitesparse -check-suitesparse-wrapper: check-suitesparse -clean-suitesparse-wrapper: clean-suitesparse -distclean-suitesparse-wrapper: distclean-suitesparse -install-suitesparse-wrapper: install-suitesparse - -# suitesparse depends on blastrampoline -compile-suitesparse: | $(build_prefix)/manifest/blastrampoline -endif diff --git a/deps/tools/common.mk b/deps/tools/common.mk index 2fbceff51fdf8..aacae86139ee6 100644 --- a/deps/tools/common.mk +++ b/deps/tools/common.mk @@ -235,6 +235,6 @@ endif ## phony targets ## -.PHONY: default get extract configure compile fastcheck check install uninstall reinstall cleanall distcleanall \ +.PHONY: default get extract configure compile fastcheck check install uninstall reinstall cleanall distcleanall version-check \ get-* extract-* configure-* compile-* fastcheck-* check-* install-* uninstall-* reinstall-* clean-* distclean-* \ update-llvm diff --git a/deps/tools/uninstallers.mk b/deps/tools/uninstallers.mk index e6e37292ab1c4..48387914643db 100644 --- a/deps/tools/uninstallers.mk +++ b/deps/tools/uninstallers.mk @@ -2,10 +2,6 @@ # defines uninstallers and version-checks # based on the contents of the UNINSTALL_* variables and the manifest files -install: version-check -version-check: $(addprefix version-check-, $(DEP_LIBS_STAGED)) -uninstall: $(addprefix uninstall-, $(DEP_LIBS_STAGED)) - ## read 'uninstall-*' definition from either the manifest or the current session define define-uninstaller MANIFEST_$1 := $$(shell [ -e $$(build_prefix)/manifest/$1 ] && cat $$(build_prefix)/manifest/$1) @@ -17,12 +13,15 @@ ifneq ($$(UNINST_HOW_$1),) UNINST_WHO_$1 := $$(firstword $$(MANIFEST_$1)) UNINST_WHERE_$1 := $$(wordlist 3,99,$$(MANIFEST_$1)) $$(eval $$(call $$(UNINST_HOW_$1),$1,$$(UNINST_WHO_$1),$$(UNINST_WHERE_$1))) +else +uninstall-$1: + @echo "skipping uninstall: $1 not installed" endif endef -$(foreach dep,$(DEP_LIBS_STAGED),$(eval $(call define-uninstaller,$(dep)))) +$(foreach dep,$(DEP_LIBS_STAGED_ALL),$(eval $(call define-uninstaller,$(dep)))) # for each subproject with a manifest, keep the user aware if something is not the expected version -$(addprefix version-check-,$(DEP_LIBS_STAGED)) : version-check-% : install-% +$(addprefix version-check-,$(DEP_LIBS_STAGED_ALL)) : version-check-% : install-% @if [ ! -e $(build_prefix)/manifest/$* ] || ( \ [ "1" != "`wc -w $(build_prefix)/manifest/$* | cut -f 1 -d ' '`" ] && \ [ "$(UNINSTALL_$*)" != "`cat $(build_prefix)/manifest/$*`" ]) ; then \ diff --git a/doc/man/julia.1 b/doc/man/julia.1 index 49ee30e0af90e..8e2ed9f94c76a 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -145,6 +145,10 @@ Run time-intensive code optimizations -O , --optimize= Set the optimization level to +.TP +--min-optlevel= +Set the minimum optimization level to , overriding per-module settings + .TP -g Enable generation of full debug info diff --git a/doc/src/base/arrays.md b/doc/src/base/arrays.md index ec8678361da60..1dc2d8ed926af 100644 --- a/doc/src/base/arrays.md +++ b/doc/src/base/arrays.md @@ -40,6 +40,7 @@ Base.trues Base.falses Base.fill Base.fill! +Base.empty Base.similar ``` @@ -51,6 +52,7 @@ Base.size Base.axes(::Any) Base.axes(::AbstractArray, ::Any) Base.length(::AbstractArray) +Base.keys(::AbstractArray) Base.eachindex Base.IndexStyle Base.IndexLinear @@ -91,6 +93,7 @@ Base.Broadcast.result_style Base.getindex(::AbstractArray, ::Any...) Base.setindex!(::AbstractArray, ::Any, ::Any...) Base.copyto!(::AbstractArray, ::CartesianIndices, ::AbstractArray, ::CartesianIndices) +Base.copy! Base.isassigned Base.Colon Base.CartesianIndex @@ -138,6 +141,7 @@ Base.cat Base.vcat Base.hcat Base.hvcat +Base.hvncat Base.vect Base.circshift Base.circshift! diff --git a/doc/src/base/base.md b/doc/src/base/base.md index fe3e7e4ff498a..1e419460bef53 100644 --- a/doc/src/base/base.md +++ b/doc/src/base/base.md @@ -15,6 +15,11 @@ Some general notes: * By convention, function names ending with an exclamation point (`!`) modify their arguments. Some functions have both modifying (e.g., `sort!`) and non-modifying (`sort`) versions. +The behaviors of `Base` and standard libraries are stable as defined in +[SemVer](https://semver.org/) only if they are documented; i.e., included in the +[Julia documentation](https://docs.julialang.org/) and not marked as unstable. +See [API FAQ](@ref man-api) for more information. + ## Getting Around ```@docs @@ -158,6 +163,7 @@ Base.typejoin Base.typeintersect Base.promote_type Base.promote_rule +Base.promote_typejoin Base.isdispatchtuple ``` @@ -213,14 +219,17 @@ Core.Union Union{} Core.UnionAll Core.Tuple +Core.NTuple Core.NamedTuple Base.@NamedTuple Base.Val Core.Vararg Core.Nothing Base.isnothing +Base.notnothing Base.Some Base.something +Base.@something Base.Enums.Enum Base.Enums.@enum Core.Expr @@ -235,6 +244,7 @@ Core.Module Core.Function Base.hasmethod Core.applicable +Base.isambiguous Core.invoke Base.@invoke Base.invokelatest @@ -243,6 +253,9 @@ new Base.:(|>) Base.:(∘) Base.ComposedFunction +Base.splat +Base.Fix1 +Base.Fix2 ``` ## Syntax @@ -277,6 +290,7 @@ Base.@deprecate Base.Missing Base.missing Base.coalesce +Base.@coalesce Base.ismissing Base.skipmissing Base.nonmissingtype @@ -297,6 +311,7 @@ Base.ignorestatus Base.detach Base.Cmd Base.setenv +Base.addenv Base.withenv Base.pipeline(::Any, ::Any, ::Any, ::Any...) Base.pipeline(::Base.AbstractCmd) @@ -341,7 +356,7 @@ Core.throw Base.rethrow Base.backtrace Base.catch_backtrace -Base.catch_stack +Base.current_exceptions Base.@assert Base.Experimental.register_error_hint Base.Experimental.show_error_hints @@ -406,6 +421,7 @@ Base.isconst Base.nameof(::Function) Base.functionloc(::Any, ::Any) Base.functionloc(::Method) +Base.@locals ``` ## Internals diff --git a/doc/src/base/collections.md b/doc/src/base/collections.md index 347d2d33724d4..f8ef12071171a 100644 --- a/doc/src/base/collections.md +++ b/doc/src/base/collections.md @@ -200,10 +200,8 @@ Base.IdDict Base.WeakKeyDict Base.ImmutableDict Base.haskey -Base.get(::Any, ::Any, ::Any) Base.get -Base.get!(::Any, ::Any, ::Any) -Base.get!(::Function, ::Any, ::Any) +Base.get! Base.getkey Base.delete! Base.pop!(::Any, ::Any, ::Any) @@ -275,6 +273,7 @@ Base.pushfirst! Base.popfirst! Base.insert! Base.deleteat! +Base.keepat! Base.splice! Base.resize! Base.append! diff --git a/doc/src/base/io-network.md b/doc/src/base/io-network.md index b798a708f22b2..2d6a462400813 100644 --- a/doc/src/base/io-network.md +++ b/doc/src/base/io-network.md @@ -36,6 +36,7 @@ Base.iswritable Base.isreadable Base.isopen Base.fd +Base.redirect_stdio Base.redirect_stdout Base.redirect_stdout(::Function, ::Any) Base.redirect_stderr diff --git a/doc/src/base/math.md b/doc/src/base/math.md index e0f094572a398..177324abccfaa 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -49,6 +49,8 @@ Base.:(~) Base.:(&) Base.:(|) Base.xor +Base.nand +Base.nor Base.:(!) && || @@ -65,6 +67,7 @@ Base.tan(::Number) Base.Math.sind Base.Math.cosd Base.Math.tand +Base.Math.sincosd Base.Math.sinpi Base.Math.cospi Base.Math.sincospi @@ -175,6 +178,7 @@ Base.nextprod Base.invmod Base.powermod Base.ndigits +Base.add_sum Base.widemul Base.Math.evalpoly Base.Math.@evalpoly diff --git a/doc/src/base/parallel.md b/doc/src/base/parallel.md index ce8e25107ab51..a508603a2d220 100644 --- a/doc/src/base/parallel.md +++ b/doc/src/base/parallel.md @@ -27,6 +27,7 @@ Base.schedule ## [Synchronization](@id lib-task-sync) ```@docs +Base.errormonitor Base.@sync Base.wait Base.fetch(t::Task) diff --git a/doc/src/base/punctuation.md b/doc/src/base/punctuation.md index 3a92d021f2f10..6b2f6501f17ae 100644 --- a/doc/src/base/punctuation.md +++ b/doc/src/base/punctuation.md @@ -2,17 +2,17 @@ Extended documentation for mathematical symbols & functions is [here](@ref math-ops). -| symbol | meaning | -|:----------- |:----------------------------------------------------------------------------------------------------------------------------------------------- | -| `@m` | the at-symbol invokes [macro](@ref man-macros) `m`; followed by space-separated expressions or a function-call-like argument list | +| symbol | meaning | +|:----------- |:--------------------------------------------------------------------------------------------| +| `@` | the at-sign marks a [macro](@ref man-macros) invocation; optionally followed by an argument list | | [`!`](@ref) | an exclamation mark is a prefix operator for logical negation ("not") | | `a!` | function names that end with an exclamation mark modify one or more of their arguments by convention | | `#` | the number sign (or hash or pound) character begins single line comments | -| `#=` | when followed by an equals sign, it begins a multi-line comment (these are nestable) | +| `#=` | when followed by an equals sign, it begins a multi-line comment (these are nestable) | | `=#` | end a multi-line comment by immediately preceding the number sign with an equals sign | | `$` | the dollar sign is used for [string](@ref string-interpolation) and [expression](@ref man-expression-interpolation) interpolation | | [`%`](@ref rem) | the percent symbol is the remainder operator | -| [`^`](@ref) | the caret is the exponentiation operator | +| [`^`](@ref) | the caret is the exponentiation operator | | [`&`](@ref) | single ampersand is bitwise and | | [`&&`](@ref)| double ampersands is short-circuiting boolean and | | [`\|`](@ref)| single pipe character is bitwise or | @@ -31,7 +31,7 @@ Extended documentation for mathematical symbols & functions is [here](@ref math- | `[,]` | [vector literal constructor](@ref man-array-literals) (calling [`vect`](@ref Base.vect)) | | `[;]` | [vertical concatenation](@ref man-array-concatenation) (calling [`vcat`](@ref) or [`hvcat`](@ref)) | | `[   ]` | with space-separated expressions, [horizontal concatenation](@ref man-concatenation) (calling [`hcat`](@ref) or [`hvcat`](@ref)) | -| `T{ }` | curly braces following a type list that type's [parameters](@ref Parametric-Types) | +| `T{ }` | curly braces following a type list that type's [parameters](@ref Parametric-Types) | | `{}` | curly braces can also be used to group multiple [`where`](@ref) expressions in function declarations | | `;` | semicolons separate statements, begin a list of keyword arguments in function declarations or calls, or are used to separate array literals for vertical concatenation | | `,` | commas separate function arguments or tuple or array components | @@ -55,6 +55,6 @@ Extended documentation for mathematical symbols & functions is [here](@ref math- | [`==`](@ref)| double equals sign is value equality comparison | | [`===`](@ref) | triple equals sign is programmatically identical equality comparison | | [`=>`](@ref Pair) | right arrow using an equals sign defines a [`Pair`](@ref) typically used to populate [dictionaries](@ref Dictionaries) | -| `->` | right arrow using a hyphen defines an [anonymous function](@ref man-anonymous-functions) on a single line | -| `|>` | pipe operator passes output from the left argument to input of the right argument, usually a [function](@ref Function-composition-and-piping) | -| `∘` | function composition operator (typed with \circ{tab}) combines two functions as though they are a single larger [function](@ref Function-composition-and-piping) | +| `->` | right arrow using a hyphen defines an [anonymous function](@ref man-anonymous-functions) on a single line | +| `|>` | pipe operator passes output from the left argument to input of the right argument, usually a [function](@ref Function-composition-and-piping) | +| `∘` | function composition operator (typed with \circ{tab}) combines two functions as though they are a single larger [function](@ref Function-composition-and-piping) | diff --git a/doc/src/base/strings.md b/doc/src/base/strings.md index 185a915705f2c..a7e9a8ee4eeee 100644 --- a/doc/src/base/strings.md +++ b/doc/src/base/strings.md @@ -33,6 +33,8 @@ Base.isvalid(::Any, ::Any) Base.isvalid(::AbstractString, ::Integer) Base.match Base.eachmatch +Base.RegexMatch +Base.keys(::RegexMatch) Base.isless(::AbstractString, ::AbstractString) Base.:(==)(::AbstractString, ::AbstractString) Base.cmp(::AbstractString, ::AbstractString) diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index af89290618fec..d02606840c431 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -63,23 +63,25 @@ call. Finally, chains of comparisons have their own special expression structure ### Bracketed forms -| Input | AST | -|:------------------------ |:------------------------------------ | -| `a[i]` | `(ref a i)` | -| `t[i;j]` | `(typed_vcat t i j)` | -| `t[i j]` | `(typed_hcat t i j)` | -| `t[a b; c d]` | `(typed_vcat t (row a b) (row c d))` | -| `a{b}` | `(curly a b)` | -| `a{b;c}` | `(curly a (parameters c) b)` | -| `[x]` | `(vect x)` | -| `[x,y]` | `(vect x y)` | -| `[x;y]` | `(vcat x y)` | -| `[x y]` | `(hcat x y)` | -| `[x y; z t]` | `(vcat (row x y) (row z t))` | -| `[x for y in z, a in b]` | `(comprehension x (= y z) (= a b))` | -| `T[x for y in z]` | `(typed_comprehension T x (= y z))` | -| `(a, b, c)` | `(tuple a b c)` | -| `(a; b; c)` | `(block a (block b c))` | +| Input | AST | +|:------------------------ |:------------------------------------------------- | +| `a[i]` | `(ref a i)` | +| `t[i;j]` | `(typed_vcat t i j)` | +| `t[i j]` | `(typed_hcat t i j)` | +| `t[a b; c d]` | `(typed_vcat t (row a b) (row c d))` | +| `t[a b;;; c d]` | `(typed_ncat t 3 (row a b) (row c d))` | +| `a{b}` | `(curly a b)` | +| `a{b;c}` | `(curly a (parameters c) b)` | +| `[x]` | `(vect x)` | +| `[x,y]` | `(vect x y)` | +| `[x;y]` | `(vcat x y)` | +| `[x y]` | `(hcat x y)` | +| `[x y; z t]` | `(vcat (row x y) (row z t))` | +| `[x;y;; z;t;;;]` | `(ncat 3 (nrow 2 (nrow 1 x y) (nrow 1 z t)))` | +| `[x for y in z, a in b]` | `(comprehension x (= y z) (= a b))` | +| `T[x for y in z]` | `(typed_comprehension T x (= y z))` | +| `(a, b, c)` | `(tuple a b c)` | +| `(a; b; c)` | `(block a (block b c))` | ### Macros diff --git a/doc/src/devdocs/boundscheck.md b/doc/src/devdocs/boundscheck.md index fbd4fa6a6bb59..300d7f8b72993 100644 --- a/doc/src/devdocs/boundscheck.md +++ b/doc/src/devdocs/boundscheck.md @@ -18,7 +18,7 @@ For example, you might write the method `sum` as: ```julia function sum(A::AbstractArray) r = zero(eltype(A)) - for i = 1:length(A) + for i in eachindex(A) @inbounds r += A[i] end return r diff --git a/doc/src/devdocs/inference.md b/doc/src/devdocs/inference.md index c8fea74995595..a9c4ec5c726ed 100644 --- a/doc/src/devdocs/inference.md +++ b/doc/src/devdocs/inference.md @@ -6,8 +6,8 @@ to the process of deducing the types of later values from the types of input values. Julia's approach to inference has been described in blog posts -([1](https://juliacomputing.com/blog/2016/04/04/inference-convergence.html), -[2](https://juliacomputing.com/blog/2017/05/15/inference-converage2.html)). +([1](https://juliacomputing.com/blog/2016/04/inference-convergence/), +[2](https://juliacomputing.com/blog/2017/05/inference-converage2/)). ## Debugging compiler.jl @@ -37,9 +37,8 @@ m = first(mths) interp = Core.Compiler.NativeInterpreter() sparams = Core.svec() # this particular method doesn't have type-parameters optimize = true # run all inference optimizations -cached = false # force inference to happen (do not use cached results) types = Tuple{typeof(convert), atypes.parameters...} # Tuple{typeof(convert), Type{Int}, UInt} -Core.Compiler.typeinf_code(interp, types, sparams, optimize, cached) +Core.Compiler.typeinf_code(interp, m, types, sparams, optimize) ``` If your debugging adventures require a `MethodInstance`, you can look it up by diff --git a/doc/src/devdocs/llvm.md b/doc/src/devdocs/llvm.md index 454cb0333443c..cda30e3403b32 100644 --- a/doc/src/devdocs/llvm.md +++ b/doc/src/devdocs/llvm.md @@ -42,7 +42,7 @@ The default version of LLVM is specified in `deps/Versions.make`. You can overri a file called `Make.user` in the top-level directory and adding a line to it such as: ``` -LLVM_VER = 6.0.1 +LLVM_VER = 12.0.0 ``` Besides the LLVM release numerals, you can also use `LLVM_VER = svn` to build against the latest diff --git a/doc/src/devdocs/reflection.md b/doc/src/devdocs/reflection.md index fbf0fd58d86a4..1a99f040a4493 100644 --- a/doc/src/devdocs/reflection.md +++ b/doc/src/devdocs/reflection.md @@ -96,7 +96,7 @@ as assignments, branches, and calls: ```jldoctest julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] )) :($(Expr(:thunk, CodeInfo( - @ none within `top-level scope' + @ none within `top-level scope` 1 ─ %1 = 1 + 2 │ %2 = sin(0.5) │ %3 = Base.vect(%1, %2) diff --git a/doc/src/manual/arrays.md b/doc/src/manual/arrays.md index 2afc264556713..c3c014ccb64fe 100644 --- a/doc/src/manual/arrays.md +++ b/doc/src/manual/arrays.md @@ -5,8 +5,8 @@ technical computing languages pay a lot of attention to their array implementati of other containers. Julia does not treat arrays in any special way. The array library is implemented almost completely in Julia itself, and derives its performance from the compiler, just like any other code written in Julia. As such, it's also possible to define custom array types by inheriting -from [`AbstractArray`](@ref). See the [manual section on the AbstractArray interface](@ref man-interface-array) for more details -on implementing a custom array type. +from [`AbstractArray`](@ref). See the [manual section on the AbstractArray interface](@ref man-interface-array) +for more details on implementing a custom array type. An array is a collection of objects stored in a multi-dimensional grid. In the most general case, an array may contain objects of type [`Any`](@ref). For most computational purposes, arrays should contain @@ -126,7 +126,7 @@ Any[] ### [Concatenation](@id man-array-concatenation) -If the arguments inside the square brackets are separated by semicolons (`;`) or newlines +If the arguments inside the square brackets are separated by single semicolons (`;`) or newlines instead of commas, then their contents are _vertically concatenated_ together instead of the arguments being used as elements themselves. @@ -154,7 +154,7 @@ julia> [1:2 6 ``` -Similarly, if the arguments are separated by tabs or spaces, then their contents are +Similarly, if the arguments are separated by tabs or spaces or double semicolons, then their contents are _horizontally concatenated_ together. ```jldoctest @@ -171,9 +171,13 @@ julia> [[1,2] [4,5] [7,8]] julia> [1 2 3] # Numbers can also be horizontally concatenated 1×3 Matrix{Int64}: 1 2 3 + +julia> [1;; 2;; 3;; 4] +1×4 Matrix{Int64}: + 1 2 3 4 ``` -Using semicolons (or newlines) and spaces (or tabs) can be combined to concatenate +Single semicolons (or newlines) and spaces (or tabs) can be combined to concatenate both horizontally and vertically at the same time. ```jldoctest @@ -189,17 +193,135 @@ julia> [zeros(Int, 2, 2) [1; 2] 0 0 1 0 0 2 3 4 5 + +julia> [[1 1]; 2 3; [4 4]] +3×2 Matrix{Int64}: + 1 1 + 2 3 + 4 4 +``` + +Spaces (and tabs) have a higher precedence than semicolons, performing any horizontal +concatenations first and then concatenating the result. Using double semicolons for the +horizontal concatenation, on the other hand, performs any vertical concatenations before +horizontally concatenating the result. + +```jldoctest +julia> [zeros(Int, 2, 2) ; [3 4] ;; [1; 2] ; 5] +3×3 Matrix{Int64}: + 0 0 1 + 0 0 2 + 3 4 5 + +julia> [1:2; 4;; 1; 3:4] +3×2 Matrix{Int64}: + 1 1 + 2 3 + 4 4 +``` + +Just as `;` and `;;` concatenate in the first and second dimension, using more semicolons +extends this same general scheme. The number of semicolons in the separator specifies the +particular dimension, so `;;;` concetenates in the third dimension, `;;;;` in the 4th, and +so on. Fewer semicolons take precedence, so the lower dimensions are generally concatenated +first. + +```jldoctest +julia> [1; 2;; 3; 4;; 5; 6;;; + 7; 8;; 9; 10;; 11; 12] +2×3×2 Array{Int64, 3}: +[:, :, 1] = + 1 3 5 + 2 4 6 + +[:, :, 2] = + 7 9 11 + 8 10 12 +``` + +Like before, spaces (and tabs) for horizontal concatenation have a higher precedence than +any number of semicolons. Thus, higher dimensional arrays can also be written by specifying +their rows first, with their elements textually arranged in a manner similar to their layout: + +```jldoctest +julia> [1 3 5 + 2 4 6;;; + 7 9 11 + 8 10 12] +2×3×2 Array{Int64, 3}: +[:, :, 1] = + 1 3 5 + 2 4 6 + +[:, :, 2] = + 7 9 11 + 8 10 12 + +julia> [1 2;;; 3 4;;;; 5 6;;; 7 8] +1×2×2×2 Array{Int64, 4}: +[:, :, 1, 1] = + 1 2 + +[:, :, 2, 1] = + 3 4 + +[:, :, 1, 2] = + 5 6 + +[:, :, 2, 2] = + 7 8 + +julia> [[1 2;;; 3 4];;;; [5 6];;; [7 8]] +1×2×2×2 Array{Int64, 4}: +[:, :, 1, 1] = + 1 2 + +[:, :, 2, 1] = + 3 4 + +[:, :, 1, 2] = + 5 6 + +[:, :, 2, 2] = + 7 8 +``` + +Although they both mean concatenation in the second dimension, spaces (or tabs) and `;;` +cannot appear in the same array expression unless the double semicolon is simply serving as +a "line continuation" character. This allows a single horizontal concatenation to span +multiple lines (without the line break being interpreted as a vertical concatenation). + +```jldoctest +julia> [1 2 ;; + 3 4] +1×4 Matrix{Int64}: + 1 2 3 4 +``` + +Terminating semicolons may also be used to add trailing length 1 dimensions. + +```jldoctest +julia> [1;;] +1×1 Matrix{Int64}: + 1 + +julia> [2; 3;;;] +2×1×1 Array{Int64, 3}: +[:, :, 1] = + 2 + 3 ``` More generally, concatenation can be accomplished through the [`cat`](@ref) function. These syntaxes are shorthands for function calls that themselves are convenience functions: -| Syntax | Function | Description | -|:----------------- |:--------------- |:-------------------------------------------------- | -| | [`cat`](@ref) | concatenate input arrays along dimension(s) `k` | -| `[A; B; C; ...]` | [`vcat`](@ref) | shorthand for `cat(A...; dims=1) | -| `[A B C ...]` | [`hcat`](@ref) | shorthand for `cat(A...; dims=2) | -| `[A B; C D; ...]` | [`hvcat`](@ref) | simultaneous vertical and horizontal concatenation | +| Syntax | Function | Description | +|:---------------------- |:---------------- |:---------------------------------------------------------------------------------------------------------- | +| | [`cat`](@ref) | concatenate input arrays along dimension(s) `k` | +| `[A; B; C; ...]` | [`vcat`](@ref) | shorthand for `cat(A...; dims=1) | +| `[A B C ...]` | [`hcat`](@ref) | shorthand for `cat(A...; dims=2) | +| `[A B; C D; ...]` | [`hvcat`](@ref) | simultaneous vertical and horizontal concatenation | +| `[A; C;; B; D;;; ...]` | [`hvncat`](@ref) | simultaneous n-dimensional concatenation, where number of semicolons indicate the dimension to concatenate | ### Typed array literals diff --git a/doc/src/manual/asynchronous-programming.md b/doc/src/manual/asynchronous-programming.md index 1791d4b0e40f7..c0181e775bd05 100644 --- a/doc/src/manual/asynchronous-programming.md +++ b/doc/src/manual/asynchronous-programming.md @@ -186,7 +186,7 @@ A channel can be visualized as a pipe, i.e., it has a write end and a read end : # we can schedule `n` instances of `foo` to be active concurrently. for _ in 1:n - @async foo() + errormonitor(@async foo()) end ``` * Channels are created via the `Channel{T}(sz)` constructor. The channel will only hold objects @@ -263,10 +263,10 @@ julia> function make_jobs(n) julia> n = 12; -julia> @async make_jobs(n); # feed the jobs channel with "n" jobs +julia> errormonitor(@async make_jobs(n)); # feed the jobs channel with "n" jobs julia> for i in 1:4 # start 4 tasks to process requests in parallel - @async do_work() + errormonitor(@async do_work()) end julia> @elapsed while n > 0 # print out results @@ -289,6 +289,10 @@ julia> @elapsed while n > 0 # print out results 0.029772311 ``` +Instead of `errormonitor(t)`, a more robust solution may be use use `bind(results, t)`, as that will +not only log any unexpected failures, but also force the associated resources to close and propagate +the exception everywhere. + ## More task operations Task operations are built on a low-level primitive called [`yieldto`](@ref). diff --git a/doc/src/manual/calling-c-and-fortran-code.md b/doc/src/manual/calling-c-and-fortran-code.md index 2bd99ea836686..89d535fd54344 100644 --- a/doc/src/manual/calling-c-and-fortran-code.md +++ b/doc/src/manual/calling-c-and-fortran-code.md @@ -157,7 +157,7 @@ This is why we don't use the `Cstring` type here: as the array is uninitialized, NUL bytes. Converting to a `Cstring` as part of the [`ccall`](@ref) checks for contained NUL bytes and could therefore throw a conversion error. -Deferencing `pointer(hostname)` with `unsafe_string` is an unsafe operation as it requires access to +Dereferencing `pointer(hostname)` with `unsafe_string` is an unsafe operation as it requires access to the memory allocated for `hostname` that may have been in the meanwhile garbage collected. The macro [`GC.@preserve`](@ref) prevents this from happening and therefore accessing an invalid memory location. @@ -657,7 +657,7 @@ For translating a C argument list to Julia: * `Ref{Any}` * argument list must be a valid Julia object (or `C_NULL`) * cannot be used for an output parameter, unless the user is able to - manage to separate arrange for the object to be GC-preserved + separately arrange for the object to be GC-preserved * `T*` * `Ref{T}`, where `T` is the Julia type corresponding to `T` @@ -928,7 +928,7 @@ macro dlsym(func, lib) let zlocal = $z[] if zlocal == C_NULL zlocal = dlsym($(esc(lib))::Ptr{Cvoid}, $(esc(func)))::Ptr{Cvoid} - $z[] = $zlocal + $z[] = zlocal end zlocal end diff --git a/doc/src/manual/command-line-options.md b/doc/src/manual/command-line-options.md index b6dd1b6b02722..47d581af430e5 100644 --- a/doc/src/manual/command-line-options.md +++ b/doc/src/manual/command-line-options.md @@ -28,6 +28,7 @@ The following is a complete list of command-line switches available when launchi |`--warn-overwrite={yes\|no}` |Enable or disable method overwrite warnings| |`-C`, `--cpu-target ` |Limit usage of CPU features up to ``; set to `help` to see the available options| |`-O`, `--optimize={0,1,2,3}` |Set the optimization level (default level is 2 if unspecified or 3 if used without a level)| +|`--min-optlevel={0,1,2,3}` |Set the lower bound on per-module optimization (default is 0)| |`-g`, `-g ` |Enable / Set the level of debug info generation (default level is 1 if unspecified or 2 if used without a level)| |`--inline={yes\|no}` |Control whether inlining is permitted, including overriding `@inline` declarations| |`--check-bounds={yes\|no}` |Emit bounds checks always or never (ignoring declarations)| diff --git a/doc/src/manual/complex-and-rational-numbers.md b/doc/src/manual/complex-and-rational-numbers.md index 99e4a677e2724..ac48e5b420f5e 100644 --- a/doc/src/manual/complex-and-rational-numbers.md +++ b/doc/src/manual/complex-and-rational-numbers.md @@ -8,7 +8,7 @@ behave as expected. ## Complex Numbers The global constant [`im`](@ref) is bound to the complex number *i*, representing the principal -square root of -1. (Using mathematicians' `i` or engineers' `j` for this global constant were rejected since they are such popular index variable names.) Since Julia allows numeric literals to be [juxtaposed with identifiers as coefficients](@ref man-numeric-literal-coefficients), +square root of -1. (Using mathematicians' `i` or engineers' `j` for this global constant was rejected since they are such popular index variable names.) Since Julia allows numeric literals to be [juxtaposed with identifiers as coefficients](@ref man-numeric-literal-coefficients), this binding suffices to provide convenient syntax for complex numbers, similar to the traditional mathematical notation: diff --git a/doc/src/manual/control-flow.md b/doc/src/manual/control-flow.md index 1b785070c0e1a..63832cc4c90c9 100644 --- a/doc/src/manual/control-flow.md +++ b/doc/src/manual/control-flow.md @@ -817,7 +817,7 @@ The power of the `try/catch` construct lies in the ability to unwind a deeply ne immediately to a much higher level in the stack of calling functions. There are situations where no error has occurred, but the ability to unwind the stack and pass a value to a higher level is desirable. Julia provides the [`rethrow`](@ref), [`backtrace`](@ref), [`catch_backtrace`](@ref) -and [`Base.catch_stack`](@ref) functions for more advanced error handling. +and [`current_exceptions`](@ref) functions for more advanced error handling. ### `finally` Clauses diff --git a/doc/src/manual/distributed-computing.md b/doc/src/manual/distributed-computing.md index e5b6e78cae981..bfcfb883e8228 100644 --- a/doc/src/manual/distributed-computing.md +++ b/doc/src/manual/distributed-computing.md @@ -80,10 +80,18 @@ you read from a remote object to obtain data needed by the next local operation. but is more efficient. ```julia-repl -julia> remotecall_fetch(getindex, 2, r, 1, 1) +julia> remotecall_fetch(r-> fetch(r)[1, 1], 2, r) 0.18526337335308085 ``` +This fetches the array on worker 2 and returns the first value. Note, that `fetch` doesn't move any data in +this case, since it's executed on the worker that owns the array. One can also write: + +```julia-repl +julia> remotecall_fetch(getindex, 2, r, 1, 1) +0.10824216411304866 +``` + Remember that [`getindex(r,1,1)`](@ref) is [equivalent](@ref man-array-indexing) to `r[1,1]`, so this call fetches the first element of the future `r`. @@ -580,7 +588,7 @@ julia> function make_jobs(n) julia> n = 12; -julia> @async make_jobs(n); # feed the jobs channel with "n" jobs +julia> errormonitor(@async make_jobs(n)); # feed the jobs channel with "n" jobs julia> for p in workers() # start tasks on the workers to process requests in parallel remote_do(do_work, p, jobs, results) @@ -648,7 +656,7 @@ Once finalized, a reference becomes invalid and cannot be used in any further ca ## Local invocations Data is necessarily copied over to the remote node for execution. This is the case for both -remotecalls and when data is stored to a[`RemoteChannel`](@ref) / [`Future`](@ref Distributed.Future) on +remotecalls and when data is stored to a [`RemoteChannel`](@ref) / [`Future`](@ref Distributed.Future) on a different node. As expected, this results in a copy of the serialized objects on the remote node. However, when the destination node is the local node, i.e. the calling process id is the same as the remote node id, it is executed diff --git a/doc/src/manual/documentation.md b/doc/src/manual/documentation.md index 8a3d41ffc8171..8c68e409b7b5b 100644 --- a/doc/src/manual/documentation.md +++ b/doc/src/manual/documentation.md @@ -91,10 +91,10 @@ As in the example above, we recommend following some simple conventions when wri 5. Provide hints to related functions. Sometimes there are functions of related functionality. To increase discoverability please provide - a short list of these in a `See also:` paragraph. + a short list of these in a `See also` paragraph. ``` - See also: [`bar!`](@ref), [`baz`](@ref), [`baaz`](@ref) + See also [`bar!`](@ref), [`baz`](@ref), [`baaz`](@ref). ``` 6. Include any code examples in an `# Examples` section. @@ -343,17 +343,17 @@ for your custom type that returns the documentation on a per-instance basis. For ```julia struct MyType - value::String + value::Int end Docs.getdoc(t::MyType) = "Documentation for MyType with value $(t.value)" -x = MyType("x") -y = MyType("y") +x = MyType(1) +y = MyType(2) ``` -`?x` will display "Documentation for MyType with value x" while `?y` will display -"Documentation for MyType with value y". +`?x` will display "Documentation for MyType with value 1" while `?y` will display +"Documentation for MyType with value 2". ## Syntax Guide diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 1cd8ec849434b..6b065bb58db7e 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -18,6 +18,33 @@ For similar reasons, automated translation to Julia would also typically generat On the other hand, language *interoperability* is extremely useful: we want to exploit existing high-quality code in other languages from Julia (and vice versa)! The best way to enable this is not a transpiler, but rather via easy inter-language calling facilities. We have worked hard on this, from the built-in `ccall` intrinsic (to call C and Fortran libraries) to [JuliaInterop](https://github.com/JuliaInterop) packages that connect Julia to Python, Matlab, C++, and more. +## [Public API](@id man-api) + +### How does Julia define its public API? + +The only interfaces that are stable with respect to [SemVer](https://semver.org/) of `julia` +version are the Julia `Base` and standard libraries interfaces described in +[the documentation](https://docs.julialang.org/) and not marked as unstable (e.g., +experimental and internal). Functions, types, and constants are not part of the public +API if they are not included in the documentation, _even if they have docstrings_. + +### There is a useful undocumented function/type/constant. Can I use it? + +Updating Julia may break your code if you use non-public API. If the code is +self-contained, it may be a good idea to copy it into your project. If you want to rely on +a complex non-public API, especially when using it from a stable package, it is a good idea +to open an [issue](https://github.com/JuliaLang/julia/issues) or +[pull request](https://github.com/JuliaLang/julia/pulls) to start a discussion for turning it +into a public API. However, we do not discourage the attempt to create packages that expose +stable public interfaces while relying on non-public implementation details of `julia` and +buffering the differences across different `julia` versions. + +### The documentation is not accurate enough. Can I rely on the existing behavior? + +Please open an [issue](https://github.com/JuliaLang/julia/issues) or +[pull request](https://github.com/JuliaLang/julia/pulls) to start a discussion for turning the +existing behavior into a public API. + ## Sessions and the REPL ### How do I delete an object in memory? @@ -293,23 +320,23 @@ julia> threefloat() and similarly: ```jldoctest -julia> function threetup() - x, y = [3, 3] +julia> function twothreetup() + x, y = [2, 3] # assigns 2 to x and 3 to y x, y # returns a tuple end -threetup (generic function with 1 method) +twothreetup (generic function with 1 method) -julia> function threearr() - x, y = [3, 3] # returns an array +julia> function twothreearr() + x, y = [2, 3] # returns an array end -threearr (generic function with 1 method) +twothreearr (generic function with 1 method) -julia> threetup() -(3, 3) +julia> twothreetup() +(2, 3) -julia> threearr() +julia> twothreearr() 2-element Vector{Int64}: - 3 + 2 3 ``` @@ -714,6 +741,32 @@ julia> remotecall_fetch(anon_bar, 2) 1 ``` +## Troubleshooting "method not matched": parametric type invariance and `MethodError`s + +### Why doesn't it work to declare `foo(bar::Vector{Real}) = 42` and then call `foo([1])`? + +As you'll see if you try this, the result is a `MethodError`: + +```jldoctest +julia> foo(x::Vector{Real}) = 42 +foo (generic function with 1 method) + +julia> foo([1]) +ERROR: MethodError: no method matching foo(::Vector{Int64}) +Closest candidates are: + foo(!Matched::Vector{Real}) at none:1 +``` + +This is because `Vector{Real}` is not a supertype of `Vector{Int}`! You can solve this problem with something +like `foo(bar::Vector{T}) where {T<:Real}` (or the short form `foo(bar::Vector{<:Real})` if the static parameter `T` +is not needed in the body of the function). The `T` is a wild card: you first specify that it must be a +subtype of Real, then specify the function takes a Vector of with elements of that type. + +This same issue goes for any composite type `Comp`, not just `Vector`. If `Comp` has a parameter declared of +type `Y`, then another type `Comp2` with a parameter of type `X<:Y` is not a subtype of `Comp`. This is +type-invariance (by contrast, Tuple is type-covariant in its parameters). See [Parametric Composite +Types](@ref man-parametric-composite-types) for more explanation of these. + ### Why does Julia use `*` for string concatenation? Why not `+` or something else? The [main argument](@ref man-concatenation) against `+` is that string concatenation is not diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index 5d1d649b75062..bfc02cbf5cba4 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -352,12 +352,26 @@ Named tuples are very similar to tuples, except that fields can additionally be using dot syntax (`x.a`) in addition to the regular indexing syntax (`x[1]`). -## Multiple Return Values +## [Destructuring Assignment and Multiple Return Values](@id destructuring-assignment) -In Julia, one returns a tuple of values to simulate returning multiple values. However, tuples -can be created and destructured without needing parentheses, thereby providing an illusion that -multiple values are being returned, rather than a single tuple value. For example, the following -function returns a pair of values: +A comma-separated list of variables (optionally wrapped in parentheses) can appear on the +left side of an assignment: the value on the right side is _destructured_ by iterating +over and assigning to each variable in turn: + +```jldoctest +julia> (a,b,c) = 1:3 +1:3 + +julia> b +2 +``` + +The value on the right should be an iterator (see [Iteration interface](@ref man-interface-iteration)) +at least as long as the number of variables on the left (any excess elements of the +iterator are ignored). + +This can be used to return multiple values from functions by returning a tuple or +other iterable value. For example, the following function returns two values: ```jldoctest foofunc julia> function foo(a,b) @@ -374,8 +388,7 @@ julia> foo(2,3) (5, 6) ``` -A typical usage of such a pair of return values, however, extracts each value into a variable. -Julia supports simple tuple "destructuring" that facilitates this: +Destructuring assignment extracts each value into a variable: ```jldoctest foofunc julia> x, y = foo(2,3) @@ -388,15 +401,79 @@ julia> y 6 ``` -You can also return multiple values using the `return` keyword: +Another common use is for swapping variables: +```jldoctest foofunc +julia> y, x = x, y +(5, 6) -```julia -function foo(a,b) - return a+b, a*b -end +julia> x +6 + +julia> y +5 +``` + +If only a subset of the elements of the iterator are required, a common convention is to assign ignored elements to a variable +consisting of only underscores `_` (which is an otherwise invalid variable name, see +[Allowed Variable Names](@ref man-allowed-variable-names)): + +```jldoctest +julia> _, _, _, d = 1:10 +1:10 + +julia> d +4 +``` + +Other valid left-hand side expressions can be used as elements of the assignment list, which will call [`setindex!`](@ref) or [`setproperty!`](@ref), or recursively destructure individual elements of the iterator: + +```jldoctest +julia> X = zeros(3); + +julia> X[1], (a,b) = (1, (2, 3)) +(1, (2, 3)) + +julia> X +3-element Vector{Float64}: + 1.0 + 0.0 + 0.0 + +julia> a +2 + +julia> b +3 +``` + +!!! compat "Julia 1.6" + `...` with assignment requires Julia 1.6 + +If the last symbol in the assignment list is suffixed by `...` (known as _slurping_), then +it will be assigned a collection or lazy iterator of the remaining elements of the +right-hand side iterator: + +```jldoctest +julia> a, b... = "hello" +"hello" + +julia> a +'h': ASCII/Unicode U+0068 (category Ll: Letter, lowercase) + +julia> b +"ello" + +julia> a, b... = Iterators.map(abs2, 1:4) +Base.Generator{UnitRange{Int64}, typeof(abs2)}(abs2, 1:4) + +julia> a +1 + +julia> b +Base.Iterators.Rest{Base.Generator{UnitRange{Int64}, typeof(abs2)}, Int64}(Base.Generator{UnitRange{Int64}, typeof(abs2)}(abs2, 1:4), 1) ``` -This has the exact same effect as the previous definition of `foo`. +See [`Base.rest`](@ref) for details on the precise handling and customization for specific iterators. ## Argument destructuring diff --git a/doc/src/manual/getting-started.md b/doc/src/manual/getting-started.md index 9caa52792be93..da8f3f985335f 100644 --- a/doc/src/manual/getting-started.md +++ b/doc/src/manual/getting-started.md @@ -61,7 +61,7 @@ bar The `--` delimiter can be used to separate command-line arguments intended for the script file from arguments intended for Julia: ``` -$ julia --color=yes -O -- foo.jl arg1 arg2.. +$ julia --color=yes -O -- script.jl arg1 arg2.. ``` See also [Scripting](@ref man-scripting) for more information on writing Julia scripts. @@ -103,3 +103,5 @@ command-line-options). ## Resources A curated list of useful learning resources to help new users get started can be found on the [learning](https://julialang.org/learning/) page of the main Julia web site. + +If you already know Julia a bit, you might want to peek ahead at [Performance Tips](@ref man-performance-tips) and [Workflow Tips](@ref man-workflow-tips). diff --git a/doc/src/manual/integers-and-floating-point-numbers.md b/doc/src/manual/integers-and-floating-point-numbers.md index 9b5b24637e5ae..8ba962da27184 100644 --- a/doc/src/manual/integers-and-floating-point-numbers.md +++ b/doc/src/manual/integers-and-floating-point-numbers.md @@ -369,6 +369,7 @@ the real number line: | `-Inf16` | `-Inf32` | `-Inf` | negative infinity | a value less than all finite floating-point values | | `NaN16` | `NaN32` | `NaN` | not a number | a value not `==` to any floating-point value (including itself) | + For further discussion of how these non-finite floating-point values are ordered with respect to each other and other floats, see [Numeric Comparisons](@ref). By the [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754-2008), these floating-point values are the results of certain arithmetic operations: @@ -409,6 +410,18 @@ NaN julia> 0 * Inf NaN + +julia> NaN == NaN +false + +julia> NaN != NaN +true + +julia> NaN < NaN +false + +julia> NaN > NaN +false ``` The [`typemin`](@ref) and [`typemax`](@ref) functions also apply to floating-point types: diff --git a/doc/src/manual/interfaces.md b/doc/src/manual/interfaces.md index a6539c457c6fc..7333434b87afb 100644 --- a/doc/src/manual/interfaces.md +++ b/doc/src/manual/interfaces.md @@ -371,7 +371,7 @@ julia> A[1:2,:] 2.0 5.0 8.0 ``` -In this example it is accomplished by defining `Base.similar{T}(A::SparseArray, ::Type{T}, dims::Dims)` +In this example it is accomplished by defining `Base.similar(A::SparseArray, ::Type{T}, dims::Dims) where T` to create the appropriate wrapped array. (Note that while `similar` supports 1- and 2-argument forms, in most case you only need to specialize the 3-argument form.) For this to work it's important that `SparseArray` is mutable (supports `setindex!`). Defining `similar`, `getindex` and @@ -479,7 +479,7 @@ they are iterable collections of their characters (see [Strings](@ref) for more) The next two steps (selecting the output array and implementation) are dependent upon determining a single answer for a given set of arguments. Broadcast must take all the varied types of its arguments and collapse them down to just one output array and one -implementation. Broadcast calls this single answer a "style." Every broadcastable object +implementation. Broadcast calls this single answer a "style". Every broadcastable object each has its own preferred style, and a promotion-like system is used to combine these styles into a single answer — the "destination style". @@ -549,7 +549,7 @@ Base.showarg(io::IO, A::ArrayAndChar, toplevel) = print(io, typeof(A), " with ch ``` -You might want broadcasting to preserve the `char` "metadata." First we define +You might want broadcasting to preserve the `char` "metadata". First we define ```jldoctest ArrayAndChar; output = false Base.BroadcastStyle(::Type{<:ArrayAndChar}) = Broadcast.ArrayStyle{ArrayAndChar}() diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 850c1f15bbd17..4d1ebc726fa6d 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -9,18 +9,18 @@ collection of standard mathematical functions. The following [arithmetic operators](https://en.wikipedia.org/wiki/Arithmetic#Arithmetic_operations) are supported on all primitive numeric types: -| Expression | Name | Description | -|:---------- |:-------------- |:-------------------------------------- | -| `+x` | unary plus | the identity operation | -| `-x` | unary minus | maps values to their additive inverses | -| `x + y` | binary plus | performs addition | -| `x - y` | binary minus | performs subtraction | -| `x * y` | times | performs multiplication | -| `x / y` | divide | performs division | -| `x ÷ y` | integer divide | x / y, truncated to an integer | -| `x \ y` | inverse divide | equivalent to `y / x` | -| `x ^ y` | power | raises `x` to the `y`th power | -| `x % y` | remainder | equivalent to `rem(x,y)` | +| Expression | Name | Description | +|:---------- |:-------------- |:----------------------------------------| +| `+x` | unary plus | the identity operation | +| `-x` | unary minus | maps values to their additive inverses | +| `x + y` | binary plus | performs addition | +| `x - y` | binary minus | performs subtraction | +| `x * y` | times | performs multiplication | +| `x / y` | divide | performs division | +| `x ÷ y` | integer divide | x / y, truncated to an integer | +| `x \ y` | inverse divide | equivalent to `y / x` | +| `x ^ y` | power | raises `x` to the `y`th power | +| `x % y` | remainder | equivalent to `rem(x,y)` | A numeric literal placed directly before an identifier or parentheses, e.g. `2x` or `2(x+y)`, is treated as a multiplication, except with higher precedence than other binary operations. See [Numeric Literal Coefficients](@ref man-numeric-literal-coefficients) for details. @@ -28,6 +28,8 @@ Julia's promotion system makes arithmetic operations on mixtures of argument typ naturally and automatically. See [Conversion and Promotion](@ref conversion-and-promotion) for details of the promotion system. +The ÷ sign can be conveniently typed by writing `\div` to the REPL or Julia IDE. See the [manual section on Unicode input](@ref Unicode-Input) for more information. + Here are some simple examples using arithmetic operators: ```jldoctest @@ -82,6 +84,8 @@ are supported on all primitive integer types: | `x & y` | bitwise and | | `x \| y` | bitwise or | | `x ⊻ y` | bitwise xor (exclusive or) | +| `x ⊼ y` | bitwise nand (not and) | +| `x ⊽ y` | bitwise nor (not or) | | `x >>> y` | [logical shift](https://en.wikipedia.org/wiki/Logical_shift) right | | `x >> y` | [arithmetic shift](https://en.wikipedia.org/wiki/Arithmetic_shift) right | | `x << y` | logical/arithmetic shift left | @@ -104,6 +108,18 @@ julia> 123 ⊻ 234 julia> xor(123, 234) 145 +julia> nand(123, 123) +-124 + +julia> 123 ⊼ 123 +-124 + +julia> nor(123, 124) +-128 + +julia> 123 ⊽ 124 +-128 + julia> ~UInt32(123) 0xffffff84 diff --git a/doc/src/manual/metaprogramming.md b/doc/src/manual/metaprogramming.md index 9880bf4417867..a374b9c879e6a 100644 --- a/doc/src/manual/metaprogramming.md +++ b/doc/src/manual/metaprogramming.md @@ -466,7 +466,7 @@ julia> eval(ex) ## [Macros](@id man-macros) -Macros provide a method to include generated code in the final body of a program. A macro maps +Macros provide a mechanism to include generated code in the final body of a program. A macro maps a tuple of arguments to a returned *expression*, and the resulting expression is compiled directly rather than requiring a runtime [`eval`](@ref) call. Macro arguments may include expressions, literal values, and symbols. @@ -981,13 +981,13 @@ block: end ``` -## Non-Standard String Literals +## [Non-Standard String Literals](@id meta-non-standard-string-literals) Recall from [Strings](@ref non-standard-string-literals) that string literals prefixed by an identifier are called non-standard string literals, and can have different semantics than un-prefixed string literals. For example: - * `r"^\s*(?:#|$)"` produces a regular expression object rather than a string - * `b"DATA\xff\u2200"` is a byte array literal for `[68,65,84,65,255,226,136,128]`. + * `r"^\s*(?:#|$)"` produces a [regular expression object](@ref man-regex-literals) rather than a string + * `b"DATA\xff\u2200"` is a [byte array literal](@ref man-byte-array-literals) for `[68,65,84,65,255,226,136,128]`. Perhaps surprisingly, these behaviors are not hard-coded into the Julia parser or compiler. Instead, they are custom behaviors provided by a general mechanism that anyone can use: prefixed string @@ -1051,20 +1051,9 @@ constructed on each iteration. In the vast majority of use cases, however, regul are not constructed based on run-time data. In this majority of cases, the ability to write regular expressions as compile-time values is invaluable. -Like non-standard string literals, non-standard command literals exist using a prefixed variant -of the command literal syntax. The command literal ```custom`literal` ``` is parsed as `@custom_cmd "literal"`. -Julia itself does not contain any non-standard command literals, but packages can make use of -this syntax. Aside from the different syntax and the `_cmd` suffix instead of the `_str` suffix, -non-standard command literals behave exactly like non-standard string literals. - -In the event that two modules provide non-standard string or command literals with the same name, -it is possible to qualify the string or command literal with a module name. For instance, if both -`Foo` and `Bar` provide non-standard string literal `@x_str`, then one can write `Foo.x"literal"` -or `Bar.x"literal"` to disambiguate between the two. - The mechanism for user-defined string literals is deeply, profoundly powerful. Not only are Julia's -non-standard literals implemented using it, but also the command literal syntax (``` `echo "Hello, $person"` ```) -is implemented with the following innocuous-looking macro: +non-standard literals implemented using it, but the command literal syntax (``` `echo "Hello, $person"` ```) +is also implemented using the following innocuous-looking macro: ```julia macro cmd(str) @@ -1077,6 +1066,20 @@ but they are just functions, written entirely in Julia. You can read their sourc what they do -- and all they do is construct expression objects to be inserted into your program's syntax tree. +Like string literals, command literals can also be prefixed by an identifier +to form what are called non-standard command literals. These command literals are parsed +as calls to specially-named macros. For example, the syntax ```custom`literal` ``` is parsed +as `@custom_cmd "literal"`. +Julia itself does not contain any non-standard command literals, but packages can make use of +this syntax. Aside from the different syntax and the `_cmd` suffix instead of the `_str` suffix, +non-standard command literals behave exactly like non-standard string literals. + +In the event that two modules provide non-standard string or command literals with the same name, +it is possible to qualify the string or command literal with a module name. For instance, if both +`Foo` and `Bar` provide non-standard string literal `@x_str`, then one can write `Foo.x"literal"` +or `Bar.x"literal"` to disambiguate between the two. + + Another way to define a macro would be like this: ```julia diff --git a/doc/src/manual/methods.md b/doc/src/manual/methods.md index 73d41294173be..a94d674501e04 100644 --- a/doc/src/manual/methods.md +++ b/doc/src/manual/methods.md @@ -546,38 +546,19 @@ Here are a few common design patterns that come up sometimes when using dispatch ### Extracting the type parameter from a super-type -Here is the correct code template for returning the element-type `T` -of any arbitrary subtype of `AbstractArray`: +Here is a correct code template for returning the element-type `T` +of any arbitrary subtype of `AbstractArray` that has well-defined +element type: ```julia abstract type AbstractArray{T, N} end eltype(::Type{<:AbstractArray{T}}) where {T} = T ``` -using so-called triangular dispatch. Note that if `T` is a `UnionAll` -type, as e.g. `eltype(Array{T} where T <: Integer)`, then `Any` is -returned (as does the version of `eltype` in `Base`). -Another way, which used to be the only correct way before the advent of -triangular dispatch in Julia v0.6, is: - -```julia -abstract type AbstractArray{T, N} end -eltype(::Type{AbstractArray}) = Any -eltype(::Type{AbstractArray{T}}) where {T} = T -eltype(::Type{AbstractArray{T, N}}) where {T, N} = T -eltype(::Type{A}) where {A<:AbstractArray} = eltype(supertype(A)) -``` - -Another possibility is the following, which could be useful to adapt -to cases where the parameter `T` would need to be matched more -narrowly: -```julia -eltype(::Type{AbstractArray{T, N} where {T<:S, N<:M}}) where {M, S} = Any -eltype(::Type{AbstractArray{T, N} where {T<:S}}) where {N, S} = Any -eltype(::Type{AbstractArray{T, N} where {N<:M}}) where {M, T} = T -eltype(::Type{AbstractArray{T, N}}) where {T, N} = T -eltype(::Type{A}) where {A <: AbstractArray} = eltype(supertype(A)) -``` +using so-called triangular dispatch. Note that `UnionAll` types, for +example `eltype(AbstractArray{T} where T <: Integer)`, do not match the +above method. The implementation of `eltype` in `Base` adds a fallback +method to `Any` for such cases. One common mistake is to try and get the element-type by using introspection: @@ -596,6 +577,25 @@ Here we have created a type `BitVector` which has no parameters, but where the element-type is still fully specified, with `T` equal to `Bool`! +Another mistake is to try to walk up the type hierarchy using +`supertype`: +```julia +eltype_wrong(::Type{AbstractArray{T}}) where {T} = T +eltype_wrong(::Type{AbstractArray{T, N}}) where {T, N} = T +eltype_wrong(::Type{A}) where {A<:AbstractArray} = eltype_wrong(supertype(A)) +``` + +While this works for declared types, it fails for types without +supertypes: + +```julia-repl +julia> eltype_wrong(Union{AbstractArray{Int}, AbstractArray{Float64}}) +ERROR: MethodError: no method matching supertype(::Type{Union{AbstractArray{Float64,N} where N, AbstractArray{Int64,N} where N}}) +Closest candidates are: + supertype(::DataType) at operators.jl:43 + supertype(::UnionAll) at operators.jl:48 +``` + ### Building a similar type with a different type parameter When building generic code, there is often a need for constructing a similar diff --git a/doc/src/manual/networking-and-streams.md b/doc/src/manual/networking-and-streams.md index 163716c583804..0bdef1b338925 100644 --- a/doc/src/manual/networking-and-streams.md +++ b/doc/src/manual/networking-and-streams.md @@ -193,13 +193,13 @@ Let's first create a simple server: ```julia-repl julia> using Sockets -julia> @async begin +julia> errormonitor(@async begin server = listen(2000) while true sock = accept(server) println("Hello World\n") end - end + end) Task (runnable) @0x00007fd31dc11ae0 ``` @@ -265,7 +265,7 @@ printed the message and waited for the next client. Reading and writing works in To see this, consider the following simple echo server: ```julia-repl -julia> @async begin +julia> errormonitor(@async begin server = listen(2001) while true sock = accept(server) @@ -273,15 +273,15 @@ julia> @async begin write(sock, readline(sock, keep=true)) end end - end + end) Task (runnable) @0x00007fd31dc12e60 julia> clientside = connect(2001) TCPSocket(RawFD(28) open, 0 bytes waiting) -julia> @async while isopen(clientside) +julia> errormonitor(@async while isopen(clientside) write(stdout, readline(clientside, keep=true)) - end + end) Task (runnable) @0x00007fd31dc11870 julia> println(clientside,"Hello World from the Echo Server") diff --git a/doc/src/manual/noteworthy-differences.md b/doc/src/manual/noteworthy-differences.md index e3279819ce204..270489ed7a9ee 100644 --- a/doc/src/manual/noteworthy-differences.md +++ b/doc/src/manual/noteworthy-differences.md @@ -240,7 +240,7 @@ For users coming to Julia from R, these are some noteworthy differences: * In Julia, the standard operators over a matrix type are matrix operations, whereas, in Python, the standard operators are element-wise operations. When both `A` and `B` are matrices, `A * B` in Julia performs matrix multiplication, not element-wise multiplication as in Python. `A * B` in Julia is equivalent with `A @ B` in Python, whereas `A * B` in Python is equivalent with `A .* B` in Julia. * The adjoint operator `'` in Julia returns an adjoint of a vector (a lazy representation of row vector), whereas the transpose operator `.T` over a vector in Python returns the original vector (non-op). * In Julia, a function may contain multiple concrete implementations (called *methods*), which are selected via multiple dispatch based on the types of all arguments to the call, as compared to functions in Python, which have a single implementation and no polymorphism (as opposed to Python method calls which use a different syntax and allows dispatch on the receiver of the method). - * There are no classes in Julia. Instead they are structures (mutable or immutable), containing data but no methods. + * There are no classes in Julia. Instead there are structures (mutable or immutable), containing data but no methods. * Calling a method of a class instance in Python (`x = MyClass(*args); x.f(y)`) corresponds to a function call in Julia, e.g. `x = MyType(args...); f(x, y)`. In general, multiple dispatch is more flexible and powerful than the Python class system. * Julia structures may have exactly one abstract supertype, whereas Python classes can inherit from one or more (abstract or concrete) superclasses. * The logical Julia program structure (Packages and Modules) is independent of the file structure (`include` for additional files), whereas the Python code structure is defined by directories (Packages) and files (Modules). @@ -310,7 +310,7 @@ For users coming to Julia from R, these are some noteworthy differences: parenthesis may be required. * Julia's [`^`](@ref) is exponentiation (pow), not bitwise XOR as in C/C++ (use [`⊻`](@ref xor), or [`xor`](@ref), in Julia) - * Julia has two right-shift operators, `>>` and `>>>`. `>>>` performs an arithmetic shift, `>>` + * Julia has two right-shift operators, `>>` and `>>>`. `>>` performs an arithmetic shift, `>>>` always performs a logical shift, unlike C/C++, where the meaning of `>>` depends on the type of the value being shifted. * Julia's `->` creates an anonymous function, it does not access a member via a pointer. @@ -353,7 +353,13 @@ For users coming to Julia from R, these are some noteworthy differences: - The typical Julia workflow for prototyping also uses continuous manipulation of the image, implemented with the [Revise.jl](https://github.com/timholy/Revise.jl) package. -- Bignums are supported, but conversion is not automatic; ordinary integers [overflow](@ref faq-integer-arithmetic). +- For performance, Julia prefers that operations have [type stability](@ref man-type-stability). Where Common Lisp abstracts away from the underlying machine operations, Julia cleaves closer to them. For example: + - Integer division using `/` always returns a floating-point result, even if the computation is exact. + - `//` always returns a rational result + - `÷` always returns a (truncated) integer result + - Bignums are supported, but conversion is not automatic; ordinary integers [overflow](@ref faq-integer-arithmetic). + - Complex numbers are supported, but to get complex results, [you need complex inputs](@ref faq-domain-errors). + - There are multiple Complex and Rational types, with different component types. - Modules (namespaces) can be hierarchical. [`import`](@ref) and [`using`](@ref) have a dual role: they load the code and make it available in the namespace. `import` for only the module name is possible (roughly equivalent to `ASDF:LOAD-OP`). Slot names don't need to be exported separately. Global variables can't be assigned to from outside the module (except with `eval(mod, :(var = val))` as an escape hatch). diff --git a/doc/src/manual/performance-tips.md b/doc/src/manual/performance-tips.md index 9f0a0b9ff4f4c..86005171e8f74 100644 --- a/doc/src/manual/performance-tips.md +++ b/doc/src/manual/performance-tips.md @@ -1514,7 +1514,7 @@ The following examples may help you interpret expressions marked as containing n element accesses * `Base.getfield(%%x, :(:data))::ARRAY{FLOAT64,N} WHERE N` - * Interpretation: getting a field that is of non-leaf type. In this case, `ArrayContainer` had a + * Interpretation: getting a field that is of non-leaf type. In this case, the type of `x`, say `ArrayContainer`, had a field `data::Array{T}`. But `Array` needs the dimension `N`, too, to be a concrete type. * Suggestion: use concrete types like `Array{T,3}` or `Array{T,N}`, where `N` is now a parameter of `ArrayContainer` @@ -1600,11 +1600,3 @@ will not require this degree of programmer annotation to attain performance. In the mean time, some user-contributed packages like [FastClosures](https://github.com/c42f/FastClosures.jl) automate the insertion of `let` statements as in `abmult3`. - -## Checking for equality with a singleton - -When checking if a value is equal to some singleton it can be -better for performance to check for identicality (`===`) instead of -equality (`==`). The same advice applies to using `!==` over `!=`. -These type of checks frequently occur e.g. when implementing the iteration -protocol and checking if `nothing` is returned from [`iterate`](@ref). diff --git a/doc/src/manual/profile.md b/doc/src/manual/profile.md index 8afadf959dbf1..b736c46f90282 100644 --- a/doc/src/manual/profile.md +++ b/doc/src/manual/profile.md @@ -341,7 +341,7 @@ For example with `OProfile` you can try a simple recording : Or similary with `perf` : ``` -$ ENABLE_JITPROFILING=1 perf record -o /tmp/perf.data --call-graph dwarf ./julia /test/fastmath.jl +$ ENABLE_JITPROFILING=1 perf record -o /tmp/perf.data --call-graph dwarf -k 1 ./julia /test/fastmath.jl $ perf inject --jit --input /tmp/perf.data --output /tmp/perf-jit.data $ perf report --call-graph -G -i /tmp/perf-jit.data ``` diff --git a/doc/src/manual/running-external-programs.md b/doc/src/manual/running-external-programs.md index a00050ffb5149..16dc779318d51 100644 --- a/doc/src/manual/running-external-programs.md +++ b/doc/src/manual/running-external-programs.md @@ -40,9 +40,8 @@ julia> run(mycommand); hello ``` -The `hello` is the output of the `echo` command, sent to [`stdout`](@ref). The run method itself -returns `nothing`, and throws an [`ErrorException`](@ref) if the external command fails to run -successfully. +The `hello` is the output of the `echo` command, sent to [`stdout`](@ref). If the external command fails to run +successfully, the run method throws an [`ErrorException`](@ref). If you want to read the output of the external command, [`read`](@ref) or [`readchomp`](@ref) can be used instead: @@ -327,6 +326,8 @@ wait(writer) fetch(reader) ``` +(commonly also, reader is not a separate task, since we immediately `fetch` it anyways). + ### Complex Example The combination of a high-level programming language, a first-class command abstraction, and automatic @@ -375,11 +376,36 @@ saturated throughput. We strongly encourage you to try all these examples to see how they work. ## `Cmd` Objects -The syntax introduced above creates objects of type [`Cmd`](@ref). Such object may also be constructed directly: +The backtick syntax create an object of type [`Cmd`](@ref). Such object may also be constructed directly from +an existing `Cmd` or list of arguments: ```julia run(Cmd(`pwd`, dir="..")) +run(Cmd(["pwd"], detach=true, ignorestatus=true)) ``` -This way, they may be customized with the `dir` keyword to set the working directory, -`detach` keyword to run the command in a new process group, and `env` keyword to set environment variables. +This allows you to specify several aspects of the `Cmd`'s execution environment via keyword arguments. For +example, the `dir` keyword provides control over the `Cmd`'s working directory: + +```jldoctest +julia> run(Cmd(`pwd`, dir="/")); +/ +``` + +And the `env` keyword allows you to set execution environment variables: + +```jldoctest +julia> run(Cmd(`sh -c "echo foo \$HOWLONG"`, env=("HOWLONG" => "ever!",))); +foo ever! +``` + +See `[`Cmd`](@ref)` for additional keyword arguments. The [`setenv`](@ref) and [`addenv`](@ref) commands +provide another means for replacing or adding to the `Cmd` execution environment variables, respectively: + +```jldoctest +julia> run(setenv(`sh -c "echo foo \$HOWLONG"`, ("HOWLONG" => "ever!",))); +foo ever! + +julia> run(addenv(`sh -c "echo foo \$HOWLONG"`, "HOWLONG" => "ever!")); +foo ever! +``` diff --git a/doc/src/manual/stacktraces.md b/doc/src/manual/stacktraces.md index 50cdfd5b1ed64..40130d9e7dd44 100644 --- a/doc/src/manual/stacktraces.md +++ b/doc/src/manual/stacktraces.md @@ -185,7 +185,7 @@ ERROR: Whoops! [...] ``` -## Exception stacks and `catch_stack` +## Exception stacks and [`current_exceptions`](@ref) !!! compat "Julia 1.1" Exception stacks requires at least Julia 1.1. @@ -195,7 +195,7 @@ identify the root cause of a problem. The julia runtime supports this by pushing *exception stack* as it occurs. When the code exits a `catch` normally, any exceptions which were pushed onto the stack in the associated `try` are considered to be successfully handled and are removed from the stack. -The stack of current exceptions can be accessed using the experimental [`Base.catch_stack`](@ref) function. For example, +The stack of current exceptions can be accessed using the [`current_exceptions`](@ref) function. For example, ```julia-repl julia> try @@ -204,7 +204,7 @@ julia> try try error("(B) An exception while handling the exception") catch - for (exc, bt) in Base.catch_stack() + for (exc, bt) in current_exceptions() showerror(stdout, exc, bt) println(stdout) end @@ -233,7 +233,7 @@ exiting both catch blocks normally (i.e., without throwing a further exception) and are no longer accessible. The exception stack is stored on the `Task` where the exceptions occurred. When a task fails with uncaught exceptions, -`catch_stack(task)` may be used to inspect the exception stack for that task. +`current_exceptions(task)` may be used to inspect the exception stack for that task. ## Comparison with [`backtrace`](@ref) diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index f65a5526a8551..4b3c35d5b45f6 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -739,13 +739,16 @@ Some other useful functions include: There are situations when you want to construct a string or use string semantics, but the behavior of the standard string construct is not quite what is needed. For these kinds of situations, Julia -provides [non-standard string literals](@ref). A non-standard string literal looks like a regular -double-quoted string literal, but is immediately prefixed by an identifier, and doesn't behave -quite like a normal string literal. Regular expressions, byte array literals and version number -literals, as described below, are some examples of non-standard string literals. Other examples -are given in the [Metaprogramming](@ref) section. +provides non-standard string literals. A non-standard string literal looks like a regular +double-quoted string literal, +but is immediately prefixed by an identifier, and may behave differently from a normal string literal. -## Regular Expressions +[Regular expressions](@ref man-regex-literals), [byte array literals](@ref man-byte-array-literals), +and [version number literals](@ref man-version-number-literals), as described below, +are some examples of non-standard string literals. Users and packages may also define new non-standard string literals. +Further documentation is given in the [Metaprogramming](@ref meta-non-standard-string-literals) section. + +## [Regular Expressions](@id man-regex-literals) Julia has Perl-compatible regular expressions (regexes), as provided by the [PCRE](http://www.pcre.org/) library (a description of the syntax can be found [here](http://www.pcre.org/current/doc/html/pcre2syntax.html)). Regular expressions are related to strings in two ways: the obvious connection is that @@ -798,7 +801,7 @@ else end ``` -If a regular expression does match, the value returned by [`match`](@ref) is a `RegexMatch` +If a regular expression does match, the value returned by [`match`](@ref) is a [`RegexMatch`](@ref) object. These objects record how the expression matches, including the substring that the pattern matches and any captured substrings, if there are any. This example only captures the portion of the substring that matches, but perhaps we want to capture any non-blank text after the comment @@ -879,10 +882,10 @@ julia> m.offsets ``` It is convenient to have captures returned as an array so that one can use destructuring syntax -to bind them to local variables: +to bind them to local variables. As a convinience, the `RegexMatch` object implements iterator methods that pass through to the `captures` field, so you can destructure the match object directly: ```jldoctest acdmatch -julia> first, second, third = m.captures; first +julia> first, second, third = m; first "a" ``` diff --git a/doc/src/manual/style-guide.md b/doc/src/manual/style-guide.md index c62ad6a8a8848..3a94f263e9e65 100644 --- a/doc/src/manual/style-guide.md +++ b/doc/src/manual/style-guide.md @@ -134,6 +134,32 @@ a = Vector{Union{Int,AbstractString,Tuple,Array}}(undef, n) In this case `Vector{Any}(undef, n)` is better. It is also more helpful to the compiler to annotate specific uses (e.g. `a[i]::Int`) than to try to pack many alternatives into one type. +## Prefer exported methods over direct field access + +Idiomatic Julia code should generally treat a module's exported methods as the +interface to its types. An object's fields are generally considered +implementation details and user code should only access them directly if this +is stated to be the API. This has several benefits: + +- Package developers are freer to change the implementation without breaking + user code. +- Methods can be passed to higher-order constructs like [`map`](@ref) (e.g. + `map(imag, zs))` rather than `[z.im for z in zs]`). +- Methods can be defined on abstract types. +- Methods can describe a conceptual operation that can be shared across + disparate types (e.g. `real(z)` works on Complex numbers or Quaternions). + +Julia's dispatch system encourages this style because `play(x::MyType)` only +defines the `play` method on that particular type, leaving other types to +have their own implementation. + +Similarly, non-exported functions are typically internal and subject to change, +unless the documentations states otherwise. Names sometimes are given a `_` prefix +(or suffix) to further suggest that something is "internal" or an +implementation-detail, but it is not a rule. + +Counter-examples to this rule include [`NamedTuple`](@ref), [`RegexMatch`](@ref match), [`StatStruct`](@ref stat). + ## Use naming conventions consistent with Julia `base/` * modules and type names use capitalization and camel case: `module SparseArrays`, `struct UnitRange`. @@ -141,6 +167,7 @@ uses (e.g. `a[i]::Int`) than to try to pack many alternatives into one type. words squashed together ([`isequal`](@ref), [`haskey`](@ref)). When necessary, use underscores as word separators. Underscores are also used to indicate a combination of concepts ([`remotecall_fetch`](@ref) as a more efficient implementation of `fetch(remotecall(...))`) or as modifiers. + * functions mutating at least one of their arguments end in `!`. * conciseness is valued, but avoid abbreviation ([`indexin`](@ref) rather than `indxin`) as it becomes difficult to remember whether and how particular words are abbreviated. diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index 31ae3d7f26fe6..0be372d4fa612 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -1033,8 +1033,8 @@ The `where` keyword itself can be nested inside a more complex declaration. For consider the two types created by the following declarations: ```jldoctest -julia> const T1 = Array{Array{T,1} where T, 1} -Vector{Vector{T} where T} (alias for Array{Array{T, 1} where T, 1}) +julia> const T1 = Array{Array{T, 1} where T, 1} +Vector{Vector} (alias for Array{Array{T, 1} where T, 1}) julia> const T2 = Array{Array{T, 1}, 1} where T Array{Vector{T}, 1} where T diff --git a/doc/src/manual/variables-and-scoping.md b/doc/src/manual/variables-and-scoping.md index 906a6c6d06b43..2b0b23d95597a 100644 --- a/doc/src/manual/variables-and-scoping.md +++ b/doc/src/manual/variables-and-scoping.md @@ -103,14 +103,37 @@ Note that the interactive prompt (aka REPL) is in the global scope of the module ## Local Scope -A new local scope is introduced by most code blocks (see above [table](@ref man-scope-table) for a -complete list). Some programming languages require explicitly declaring new variables before using -them. Explicit declaration works in Julia too: in any local scope, writing `local x` declares a new -local variable in that scope, regardless of whether there is already a variable named `x` in an -outer scope or not. Declaring each new local like this is somewhat verbose and tedious, however, so -Julia, like many other languages, considers assignment to a new variable in a local scope to -implicitly declare that variable as a new local. Mostly this is pretty intuitive, but as with many -things that behave intuitively, the details are more subtle than one might naïvely imagine. +A new local scope is introduced by most code blocks (see above [table](@ref +man-scope-table) for a complete list). If such a block is syntactically nested +inside of another local scope, the scope it creates is nested inside of all the +local scopes that it appears within, which are all ultimately nested inside of +the global scope of the module in which the code is evaluated. Variables in +outer scopes are visible from any scope they contain — meaning that they can be +read and written in inner scopes — unless there is a local variable with the +same name that "shadows" the outer variable of the same name. This is true even +if the outer local is declared after (in the sense of textually below) an inner +block. When we say that a variable "exists" in a given scope, this means that a +variable by that name exists in any of the scopes that the current scope is +nested inside of, including the current one. + +Some programming languages require explicitly declaring new variables before +using them. Explicit declaration works in Julia too: in any local scope, writing +`local x` declares a new local variable in that scope, regardless of whether +there is already a variable named `x` in an outer scope or not. Declaring each +new variable like this is somewhat verbose and tedious, however, so Julia, like +many other languages, considers assignment to a variable name that doesn't +already exist to implicitly declare that variable. If the current scope is +global, the new variable is global; if the current scope is local, the new +variable is local to the innermost local scope and will be visible inside of +that scope but not outside of it. If you assign to an existing local, it +_always_ updates that existing local: you can only shadow a local by explicitly +declaring a new local in a nested scope with the `local` keyword. In particular, +this applies to variables assigned in inner functions, which may surprise users +coming from Python where assignment in an inner function creates a new local +unless the variable is explictly declared to be non-local. + +Mostly this is pretty intuitive, but as with many things that behave +intuitively, the details are more subtle than one might naïvely imagine. When `x = ` occurs in a local scope, Julia applies the following rules to decide what the expression means based on where the assignment expression occurs and what `x` already refers to at @@ -183,9 +206,15 @@ Since the `x` in `greet` is local, the value (or lack thereof) of the global `x` calling `greet`. The hard scope rule doesn't care whether a global named `x` exists or not: assignment to `x` in a hard scope is local (unless `x` is declared global). -The next clear cut situation we'll consider is when there is already a local variable named `x`, in -which case `x = ` always assigns to this existing local `x`. The function `sum_to` computes -the sum of the numbers from one up to `n`: +The next clear cut situation we'll consider is when there is already a local +variable named `x`, in which case `x = ` always assigns to this existing +local `x`. This is true whether the assignment occurs in the same local scope, +an inner local scope in the same function body, or in the body of a function +nested inside of another function, also known as a +[closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)). + +We'll use the `sum_to` function, which computes the sum of integers from one up +to `n`, as an example: ```julia function sum_to(n) @@ -252,6 +281,44 @@ introduces a hard scope, the assignment causes `t` to become a new local variabl where it appears, i.e. inside of the loop body. Even if there were a global named `t`, it would make no difference—the hard scope rule isn't affected by anything in global scope. +Note that the local scope of a for loop body is no different from the local +scope of an inner function. This means that we could rewrite this example so +that the loop body is implemented as a call to an inner helper function and it +behaves the same way: + +```jldoctest +julia> function sum_to_def_closure(n) + function loop_body(i) + t = s + i # new local `t` + s = t # assign same local `s` as below + end + s = 0 # new local + for i = 1:n + loop_body(i) + end + return s, @isdefined(t) + end +sum_to_def_closure (generic function with 1 method) + +julia> sum_to_def_closure(10) +(55, false) +``` + +This example illustrates a couple of key points: + +1. Inner function scopes are just like any other nested local scope. In + particular, if a variable is already a local outside of an inner function and + you assign to it in the inner function, the outer local variable is updated. + +2. It doesn't matter if the definition of an outer local happens below where it + is updated, the rule remains the same. The entire enclosing local scope is + parsed and its locals determined before inner local meanings are resolved. + +This design means that you can generally move code in or out of an inner +function without changing its meaning, which facilitates a number of common +idioms in the language using closures (see [do blocks](@ref +Do-Block-Syntax-for-Function-Arguments)). + Let's move onto some more ambiguous cases covered by the soft scope rule. We'll explore this by extracting the bodies of the `greet` and `sum_to_def` functions into soft scope contexts. First, let's put the body of `greet` in a `for` loop—which is soft, rather than hard—and evaluate it in the REPL: diff --git a/doc/src/manual/variables.md b/doc/src/manual/variables.md index c68fbd304d33a..004efb92dc0e5 100644 --- a/doc/src/manual/variables.md +++ b/doc/src/manual/variables.md @@ -90,7 +90,7 @@ julia> sqrt = 4 ERROR: cannot assign a value to variable Base.sqrt from module Main ``` -## Allowed Variable Names +## [Allowed Variable Names](@id man-allowed-variable-names) Variable names must begin with a letter (A-Z or a-z), underscore, or a subset of Unicode code points greater than 00A0; in particular, [Unicode character categories](http://www.fileformat.info/info/unicode/category/index.htm) @@ -110,6 +110,19 @@ A space is required between an operator that ends with a subscript/superscript l variable name. For example, if `+ᵃ` is an operator, then `+ᵃx` must be written as `+ᵃ x` to distinguish it from `+ ᵃx` where `ᵃx` is the variable name. + +A particular class of variable names is one that contains only underscores. These identifiers can only be assigned values but cannot be used to assign values to other variables. +More technically, they can only be used as an [L-value](https://en.wikipedia.org/wiki/Value_(computer_science)#lrvalue), but not as an + [R-value](https://en.wikipedia.org/wiki/R-value): + +```julia-repl +julia> x, ___ = size([2 2; 1 1]) +(2, 2) + +julia> y = ___ +ERROR: syntax: all-underscore identifier used as rvalue +``` + The only explicitly disallowed names for variables are the names of the built-in [Keywords](@ref): ```julia-repl @@ -123,9 +136,14 @@ ERROR: syntax: unexpected "=" Some Unicode characters are considered to be equivalent in identifiers. Different ways of entering Unicode combining characters (e.g., accents) are treated as equivalent (specifically, Julia identifiers are [NFC](http://www.macchiato.com/unicode/nfc-faq)-normalized). -The Unicode characters `ɛ` (U+025B: Latin small letter open e) -and `µ` (U+00B5: micro sign) are treated as equivalent to the corresponding -Greek letters, because the former are easily accessible via some input methods. +Julia also includes a few non-standard equivalences for characters that are +visually similar and are easily entered by some input methods. The Unicode +characters `ɛ` (U+025B: Latin small letter open e) and `µ` (U+00B5: micro sign) +are treated as equivalent to the corresponding Greek letters. The middle dot +`·` (U+00B7) and the Greek +[interpunct](https://en.wikipedia.org/wiki/Interpunct) `·` (U+0387) are both +treated as the mathematical dot operator `⋅` (U+22C5). +The minus sign `−` (U+2212) is treated as equivalent to the hyphen-minus sign `-` (U+002D). ## Stylistic Conventions diff --git a/src/Makefile b/src/Makefile index 6f2ee2960c7a2..89aa3fc44f49a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -140,11 +140,13 @@ DEBUGFLAGS += "-DJL_LIBJULIA_SONAME=\"libjulia-debug.$(JL_MAJOR_SHLIB_EXT)\"" "- ifeq ($(USE_CROSS_FLISP), 1) FLISPDIR := $(BUILDDIR)/flisp/host +FLISP_EXECUTABLE_debug := $(FLISPDIR)/flisp-debug$(BUILD_EXE) +FLISP_EXECUTABLE_release := $(FLISPDIR)/flisp$(BUILD_EXE) else FLISPDIR := $(BUILDDIR)/flisp +FLISP_EXECUTABLE_debug := $(FLISPDIR)/flisp-debug$(EXE) +FLISP_EXECUTABLE_release := $(FLISPDIR)/flisp$(EXE) endif -FLISP_EXECUTABLE_debug := $(FLISPDIR)/flisp-debug$(BUILD_EXE) -FLISP_EXECUTABLE_release := $(FLISPDIR)/flisp$(BUILD_EXE) ifeq ($(OS),WINNT) FLISP_EXECUTABLE := $(FLISP_EXECUTABLE_release) else diff --git a/src/abi_aarch64.cpp b/src/abi_aarch64.cpp index ce94cc66f0641..3a0a5c25dc859 100644 --- a/src/abi_aarch64.cpp +++ b/src/abi_aarch64.cpp @@ -16,20 +16,15 @@ struct ABI_AArch64Layout : AbiLayout { Type *get_llvm_vectype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - // `!dt->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields > 0` + // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields > 0` if (dt->layout == NULL || jl_is_layout_opaque(dt->layout)) return nullptr; size_t nfields = dt->layout->nfields; assert(nfields > 0); if (nfields < 2) return nullptr; -#if JL_LLVM_VERSION >= 110000 static Type *T_vec64 = FixedVectorType::get(T_int32, 2); static Type *T_vec128 = FixedVectorType::get(T_int32, 4); -#else - static Type *T_vec64 = VectorType::get(T_int32, 2); - static Type *T_vec128 = VectorType::get(T_int32, 4); -#endif Type *lltype; // Short vector should be either 8 bytes or 16 bytes. // Note that there are only two distinct fundamental types for @@ -67,7 +62,7 @@ Type *get_llvm_vectype(jl_datatype_t *dt) const Type *get_llvm_fptype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - // `!dt->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields == 0` + // `!dt->name->mutabl && dt->pointerfree && !dt->haspadding && dt->nfields == 0` Type *lltype; // Check size first since it's cheaper. switch (jl_datatype_size(dt)) { @@ -93,7 +88,7 @@ Type *get_llvm_fptype(jl_datatype_t *dt) const Type *get_llvm_fp_or_vectype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - if (dt->mutabl || dt->layout->npointers || dt->layout->haspadding) + if (dt->name->mutabl || dt->layout->npointers || dt->layout->haspadding) return nullptr; return dt->layout->nfields ? get_llvm_vectype(dt) : get_llvm_fptype(dt); } diff --git a/src/abi_arm.cpp b/src/abi_arm.cpp index 1a5d3d0651368..b0ae29a623abb 100644 --- a/src/abi_arm.cpp +++ b/src/abi_arm.cpp @@ -33,7 +33,7 @@ bool needPassByRef(jl_datatype_t *dt, AttrBuilder &ab) override Type *get_llvm_fptype(jl_datatype_t *dt) const { // Assume jl_is_datatype(dt) && !jl_is_abstracttype(dt) - if (dt->mutabl || jl_datatype_nfields(dt) != 0) + if (dt->name->mutabl || jl_datatype_nfields(dt) != 0) return NULL; Type *lltype; // Check size first since it's cheaper. diff --git a/src/abi_ppc64le.cpp b/src/abi_ppc64le.cpp index dd6f927d9c301..1564b79ce2332 100644 --- a/src/abi_ppc64le.cpp +++ b/src/abi_ppc64le.cpp @@ -134,11 +134,7 @@ Type *preferred_llvm_type(jl_datatype_t *dt, bool isret) const override jl_datatype_t *vecty = (jl_datatype_t*)jl_field_type(ty0, 0); assert(jl_is_datatype(vecty) && vecty->name == jl_vecelement_typename); Type *ety = bitstype_to_llvm(jl_tparam0(vecty)); -#if JL_LLVM_VERSION >= 110000 Type *vty = FixedVectorType::get(ety, jl_datatype_nfields(ty0)); -#else - Type *vty = VectorType::get(ety, jl_datatype_nfields(ty0)); -#endif return ArrayType::get(vty, hfa); } } diff --git a/src/aotcompile.cpp b/src/aotcompile.cpp index 5dbdf7000f5e7..93683d320e6b9 100644 --- a/src/aotcompile.cpp +++ b/src/aotcompile.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #if defined(USE_POLLY) #include #include @@ -47,9 +48,7 @@ #include #include #include -#if JL_LLVM_VERSION >= 100000 #include -#endif #include #include @@ -62,12 +61,6 @@ namespace llvm { extern Pass *createLowerSimdLoopPass(); } -#if JL_LLVM_VERSION < 100000 -static const TargetMachine::CodeGenFileType CGFT_ObjectFile = TargetMachine::CGFT_ObjectFile; -static const TargetMachine::CodeGenFileType CGFT_AssemblyFile = TargetMachine::CGFT_AssemblyFile; -#endif - - #include "julia.h" #include "julia_internal.h" #include "jitlayers.h" @@ -624,11 +617,20 @@ void addMachinePasses(legacy::PassManagerBase *PM, TargetMachine *TM) } + // this defines the set of optimization passes defined for Julia at various optimization levels. // it assumes that the TLI and TTI wrapper passes have already been added. void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, bool lower_intrinsics, bool dump_native) { + // Note: LLVM 12 disabled the hoisting of common instruction + // before loop vectorization (https://reviews.llvm.org/D84108). + // + // TODO: CommonInstruction hoisting/sinking enables AllocOpt + // to merge allocations and sometimes eliminate them, + // since AllocOpt does not handle PhiNodes. + // Enable this instruction hoisting because of this and Union benchmarks. + auto simplifyCFGOptions = SimplifyCFGOptions().hoistCommonInsts(true); #ifdef JL_DEBUG_BUILD PM->add(createGCInvariantVerifierPass(true)); PM->add(createVerifierPass()); @@ -636,7 +638,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, PM->add(createConstantMergePass()); if (opt_level < 2) { - PM->add(createCFGSimplificationPass()); + PM->add(createCFGSimplificationPass(simplifyCFGOptions)); if (opt_level == 1) { PM->add(createSROAPass()); PM->add(createInstructionCombiningPass()); @@ -680,7 +682,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, PM->add(createBasicAAWrapperPass()); } - PM->add(createCFGSimplificationPass()); + PM->add(createCFGSimplificationPass(simplifyCFGOptions)); PM->add(createDeadCodeEliminationPass()); PM->add(createSROAPass()); @@ -694,12 +696,13 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, PM->add(createAllocOptPass()); // consider AggressiveInstCombinePass at optlevel > 2 PM->add(createInstructionCombiningPass()); - PM->add(createCFGSimplificationPass()); + PM->add(createCFGSimplificationPass(simplifyCFGOptions)); if (dump_native) PM->add(createMultiVersioningPass()); PM->add(createSROAPass()); PM->add(createInstSimplifyLegacyPass()); PM->add(createJumpThreadingPass()); + PM->add(createCorrelatedValuePropagationPass()); PM->add(createReassociatePass()); @@ -751,6 +754,7 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, // loops over Union-typed arrays to vectorize. PM->add(createInstructionCombiningPass()); PM->add(createJumpThreadingPass()); + PM->add(createCorrelatedValuePropagationPass()); PM->add(createDeadStoreEliminationPass()); // More dead allocation (store) deletion before loop optimization @@ -759,12 +763,21 @@ void addOptimizationPasses(legacy::PassManagerBase *PM, int opt_level, // see if all of the constant folding has exposed more loops // to simplification and deletion // this helps significantly with cleaning up iteration - PM->add(createCFGSimplificationPass()); + PM->add(createCFGSimplificationPass()); // See note above, don't hoist instructions before LV PM->add(createLoopDeletionPass()); PM->add(createInstructionCombiningPass()); PM->add(createLoopVectorizePass()); PM->add(createLoopLoadEliminationPass()); - PM->add(createCFGSimplificationPass()); + // Cleanup after LV pass + PM->add(createInstructionCombiningPass()); + PM->add(createCFGSimplificationPass( // Aggressive CFG simplification + SimplifyCFGOptions() + .forwardSwitchCondToPhi(true) + .convertSwitchToLookupTable(true) + .needCanonicalLoops(false) + .hoistCommonInsts(true) + // .sinkCommonInsts(true) // FIXME: Causes assertion in llvm-late-lowering + )); PM->add(createSLPVectorizerPass()); // might need this after LLVM 11: //PM->add(createVectorCombinePass()); @@ -946,23 +959,14 @@ addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) { TargetPassConfig *PassConfig = TM->createPassConfig(PM); PassConfig->setDisableVerify(false); PM.add(PassConfig); -#if JL_LLVM_VERSION >= 100000 MachineModuleInfoWrapperPass *MMIWP = new MachineModuleInfoWrapperPass(TM); PM.add(MMIWP); -#else - MachineModuleInfo *MMI = new MachineModuleInfo(TM); - PM.add(MMI); -#endif if (PassConfig->addISelPasses()) return NULL; PassConfig->addMachinePasses(); PassConfig->setInitialized(); -#if JL_LLVM_VERSION >= 100000 return &MMIWP->getMMI().getContext(); -#else - return &MMI->getContext(); -#endif } void jl_strip_llvm_debug(Module *m); @@ -1003,11 +1007,7 @@ jl_value_t *jl_dump_llvm_asm(void *F, const char* asm_variant, const char *debug std::unique_ptr MAB(TM->getTarget().createMCAsmBackend( STI, MRI, TM->Options.MCOptions)); std::unique_ptr MCE; -#if JL_LLVM_VERSION >= 100000 auto FOut = std::make_unique(asmfile); -#else - auto FOut = llvm::make_unique(asmfile); -#endif std::unique_ptr S(TM->getTarget().createAsmStreamer( *Context, std::move(FOut), true, true, InstPrinter, diff --git a/src/ast.c b/src/ast.c index cb96ec51976d3..307d731109933 100644 --- a/src/ast.c +++ b/src/ast.c @@ -135,7 +135,7 @@ struct macroctx_stack { static jl_value_t *scm_to_julia(fl_context_t *fl_ctx, value_t e, jl_module_t *mod); static value_t julia_to_scm(fl_context_t *fl_ctx, jl_value_t *v); -static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world); +static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world, int throw_load_error); static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) { @@ -1031,7 +1031,7 @@ int jl_has_meta(jl_array_t *body, jl_sym_t *sym) JL_NOTSAFEPOINT return 0; } -static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule, jl_module_t **ctx, size_t world) +static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule, jl_module_t **ctx, size_t world, int throw_load_error) { jl_ptls_t ptls = jl_get_ptls_states(); JL_TIMING(MACRO_INVOCATION); @@ -1066,7 +1066,7 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule result = jl_invoke(margs[0], &margs[1], nargs - 1, mfunc); } JL_CATCH { - if (jl_loaderror_type == NULL) { + if ((jl_loaderror_type == NULL) || !throw_load_error) { jl_rethrow(); } else { @@ -1086,7 +1086,7 @@ static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule return result; } -static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world) +static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel, size_t world, int throw_load_error) { if (!expr || !jl_is_expr(expr)) return expr; @@ -1100,7 +1100,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str if (e->head == quote_sym && jl_expr_nargs(e) == 1) { expr = jl_call_scm_on_ast("julia-bq-macro", jl_exprarg(e, 0), inmodule); JL_GC_PUSH1(&expr); - expr = jl_expand_macros(expr, inmodule, macroctx, onelevel, world); + expr = jl_expand_macros(expr, inmodule, macroctx, onelevel, world, throw_load_error); JL_GC_POP(); return expr; } @@ -1110,7 +1110,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str JL_TYPECHK(hygienic-scope, module, (jl_value_t*)newctx.m); newctx.parent = macroctx; jl_value_t *a = jl_exprarg(e, 0); - jl_value_t *a2 = jl_expand_macros(a, inmodule, &newctx, onelevel, world); + jl_value_t *a2 = jl_expand_macros(a, inmodule, &newctx, onelevel, world, throw_load_error); if (a != a2) jl_array_ptr_set(e->args, 0, a2); return expr; @@ -1119,7 +1119,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str struct macroctx_stack newctx; newctx.m = macroctx ? macroctx->m : inmodule; newctx.parent = macroctx; - jl_value_t *result = jl_invoke_julia_macro(e->args, inmodule, &newctx.m, world); + jl_value_t *result = jl_invoke_julia_macro(e->args, inmodule, &newctx.m, world, throw_load_error); jl_value_t *wrap = NULL; JL_GC_PUSH3(&result, &wrap, &newctx.m); // copy and wrap the result in `(hygienic-scope ,result ,newctx) @@ -1129,7 +1129,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str wrap = (jl_value_t*)jl_exprn(hygienicscope_sym, 2); result = jl_copy_ast(result); if (!onelevel) - result = jl_expand_macros(result, inmodule, wrap ? &newctx : macroctx, onelevel, world); + result = jl_expand_macros(result, inmodule, wrap ? &newctx : macroctx, onelevel, world, throw_load_error); if (wrap) { jl_exprargset(wrap, 0, result); jl_exprargset(wrap, 1, newctx.m); @@ -1151,7 +1151,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str for (j = 2; j < nm; j++) { jl_exprargset(mc2, j+1, jl_exprarg(mc, j)); } - jl_value_t *ret = jl_expand_macros((jl_value_t*)mc2, inmodule, macroctx, onelevel, world); + jl_value_t *ret = jl_expand_macros((jl_value_t*)mc2, inmodule, macroctx, onelevel, world, throw_load_error); JL_GC_POP(); return ret; } @@ -1162,7 +1162,7 @@ static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, str size_t i; for (i = 0; i < jl_array_len(e->args); i++) { jl_value_t *a = jl_array_ptr_ref(e->args, i); - jl_value_t *a2 = jl_expand_macros(a, inmodule, macroctx, onelevel, world); + jl_value_t *a2 = jl_expand_macros(a, inmodule, macroctx, onelevel, world, throw_load_error); if (a != a2) jl_array_ptr_set(e->args, i, a2); } @@ -1174,7 +1174,7 @@ JL_DLLEXPORT jl_value_t *jl_macroexpand(jl_value_t *expr, jl_module_t *inmodule) JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); - expr = jl_expand_macros(expr, inmodule, NULL, 0, jl_world_counter); + expr = jl_expand_macros(expr, inmodule, NULL, 0, jl_world_counter, 0); expr = jl_call_scm_on_ast("jl-expand-macroscope", expr, inmodule); JL_GC_POP(); return expr; @@ -1185,7 +1185,7 @@ JL_DLLEXPORT jl_value_t *jl_macroexpand1(jl_value_t *expr, jl_module_t *inmodule JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); - expr = jl_expand_macros(expr, inmodule, NULL, 1, jl_world_counter); + expr = jl_expand_macros(expr, inmodule, NULL, 1, jl_world_counter, 0); expr = jl_call_scm_on_ast("jl-expand-macroscope", expr, inmodule); JL_GC_POP(); return expr; @@ -1211,7 +1211,7 @@ JL_DLLEXPORT jl_value_t *jl_expand_in_world(jl_value_t *expr, jl_module_t *inmod JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); - expr = jl_expand_macros(expr, inmodule, NULL, 0, world); + expr = jl_expand_macros(expr, inmodule, NULL, 0, world, 1); expr = jl_call_scm_on_ast_and_loc("jl-expand-to-thunk", expr, inmodule, file, line); JL_GC_POP(); return expr; @@ -1224,7 +1224,7 @@ JL_DLLEXPORT jl_value_t *jl_expand_with_loc_warn(jl_value_t *expr, jl_module_t * JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); - expr = jl_expand_macros(expr, inmodule, NULL, 0, ~(size_t)0); + expr = jl_expand_macros(expr, inmodule, NULL, 0, ~(size_t)0, 1); jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; JL_AST_PRESERVE_PUSH(ctx, old_roots, inmodule); @@ -1245,7 +1245,7 @@ JL_DLLEXPORT jl_value_t *jl_expand_stmt_with_loc(jl_value_t *expr, jl_module_t * JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); - expr = jl_expand_macros(expr, inmodule, NULL, 0, ~(size_t)0); + expr = jl_expand_macros(expr, inmodule, NULL, 0, ~(size_t)0, 1); expr = jl_call_scm_on_ast_and_loc("jl-expand-to-thunk-stmt", expr, inmodule, file, line); JL_GC_POP(); return expr; diff --git a/src/ast.scm b/src/ast.scm index 6ed530718e3db..d89cae95ad185 100644 --- a/src/ast.scm +++ b/src/ast.scm @@ -61,6 +61,12 @@ (else (string e)))) +(define (deparse-semicolons n) + ; concatenate n semicolons + (if (<= n 0) + "" + (string ";" (deparse-semicolons (1- n))))) + (define (deparse e (ilvl 0)) (cond ((or (symbol? e) (number? e)) (string e)) ((string? e) (print-to-string e)) @@ -134,7 +140,14 @@ ((hcat) (string #\[ (deparse-arglist (cdr e) " ") #\])) ((typed_hcat) (string (deparse (cadr e)) (deparse (cons 'hcat (cddr e))))) + ((ncat) (string #\[ (deparse-arglist (cddr e) (string (deparse-semicolons (cadr e)) " ")) + (if (= (length (cddr e)) 1) + (deparse-semicolons (cadr e)) + "") #\])) + ((typed_ncat) (string (deparse (cadr e)) + (deparse (cons 'ncat (cddr e))))) ((row) (deparse-arglist (cdr e) " ")) + ((nrow) (deparse-arglist (cddr e) (string (deparse-semicolons (cadr e)) " "))) ((braces) (string #\{ (deparse-arglist (cdr e) ", ") #\})) ((bracescat) (string #\{ (deparse-arglist (cdr e) "; ") #\})) ((string) diff --git a/src/builtins.c b/src/builtins.c index c6abe4b8e602d..37471bbb7a718 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -183,7 +183,7 @@ static int egal_types(jl_value_t *a, jl_value_t *b, jl_typeenv_t *env, int tvar_ } if (dt == jl_symbol_type) return 0; - assert(!dt->mutabl); + assert(!dt->name->mutabl); return jl_egal__bits(a, b, dt); } @@ -324,7 +324,7 @@ static uintptr_t type_object_id_(jl_value_t *v, jl_varidx_t *env) JL_NOTSAFEPOIN } if (tv == jl_symbol_type) return ((jl_sym_t*)v)->hash; - assert(!tv->mutabl); + assert(!tv->name->mutabl); return immut_id_(tv, v, tv->hash); } @@ -358,7 +358,7 @@ static uintptr_t immut_id_(jl_datatype_t *dt, jl_value_t *v, uintptr_t h) JL_NOT uint8_t sel = ((uint8_t*)vo)[jl_field_size(dt, f) - 1]; fieldtype = (jl_datatype_t*)jl_nth_union_component((jl_value_t*)fieldtype, sel); } - assert(jl_is_datatype(fieldtype) && !fieldtype->abstract && !fieldtype->mutabl); + assert(jl_is_datatype(fieldtype) && !fieldtype->name->abstract && !fieldtype->name->mutabl); int32_t first_ptr = fieldtype->layout->first_ptr; if (first_ptr >= 0 && ((jl_value_t**)vo)[first_ptr] == NULL) { // If the field is a inline immutable that can be can be undef @@ -391,7 +391,7 @@ static uintptr_t NOINLINE jl_object_id__cold(jl_datatype_t *dt, jl_value_t *v) J return memhash32_seed(jl_string_data(v), jl_string_len(v), 0xedc3b677); #endif } - if (dt->mutabl) + if (dt->name->mutabl) return inthash((uintptr_t)v); return immut_id_(dt, v, dt->hash); } @@ -451,7 +451,7 @@ JL_CALLABLE(jl_f_sizeof) if (jl_is_datatype(x)) { jl_datatype_t *dx = (jl_datatype_t*)x; if (dx->layout == NULL) { - if (dx->abstract) + if (dx->name->abstract) jl_errorf("Abstract type %s does not have a definite size.", jl_symbol_name(dx->name->name)); else jl_errorf("Argument is an incomplete %s type and does not have a definite size.", jl_symbol_name(dx->name->name)); @@ -473,7 +473,7 @@ JL_CALLABLE(jl_f_sizeof) return jl_box_long((1+jl_svec_len(x))*sizeof(void*)); jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(x); assert(jl_is_datatype(dt)); - assert(!dt->abstract); + assert(!dt->name->abstract); return jl_box_long(jl_datatype_size(dt)); } @@ -840,7 +840,7 @@ JL_CALLABLE(jl_f_setfield) assert(jl_is_datatype(st)); if (st == jl_module_type) jl_error("cannot assign variables in other modules"); - if (!st->mutabl) + if (!st->name->mutabl) jl_errorf("setfield! immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name)); size_t idx; if (jl_is_long(args[1])) { @@ -1337,6 +1337,32 @@ static int equiv_field_types(jl_value_t *old, jl_value_t *ft) return 1; } +static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT +{ + if (jl_is_uniontype(p)) + return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) || + references_name(((jl_uniontype_t*)p)->b, name, affects_layout); + if (jl_is_unionall(p)) + return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) || + references_name(((jl_unionall_t*)p)->body, name, affects_layout); + if (jl_is_typevar(p)) + return references_name(((jl_tvar_t*)p)->ub, name, 0) || + references_name(((jl_tvar_t*)p)->lb, name, 0); + if (jl_is_datatype(p)) { + jl_datatype_t *dp = (jl_datatype_t*)p; + if (affects_layout && dp->name == name) + return 1; + affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0; + size_t i, l = jl_nparams(p); + for (i = 0; i < l; i++) { + if (references_name(jl_tparam(p, i), name, affects_layout)) + return 1; + } + } + return 0; +} + + JL_CALLABLE(jl_f__typebody) { JL_NARGS(_typebody!, 1, 2); @@ -1361,6 +1387,16 @@ JL_CALLABLE(jl_f__typebody) else { dt->types = (jl_svec_t*)ft; jl_gc_wb(dt, ft); + size_t i, nf = jl_svec_len(ft); + for (i = 0; i < nf; i++) { + jl_value_t *fld = jl_svecref(ft, i); + if (references_name(fld, dt->name, 1)) { + dt->name->references_self = 1; + break; + } + } + if (!dt->name->mutabl && !dt->name->references_self) + dt->name->mayinlinealloc = 1; } } @@ -1386,8 +1422,6 @@ static int equiv_type(jl_value_t *ta, jl_value_t *tb) jl_datatype_t *dtb = (jl_datatype_t*)jl_unwrap_unionall(tb); if (!(jl_typeof(dta) == jl_typeof(dtb) && dta->name->name == dtb->name->name && - dta->abstract == dtb->abstract && - dta->mutabl == dtb->mutabl && (jl_svec_len(jl_field_names(dta)) != 0 || dta->size == dtb->size) && dta->ninitialized == dtb->ninitialized && jl_egal((jl_value_t*)jl_field_names(dta), (jl_value_t*)jl_field_names(dtb)) && diff --git a/src/ccall.cpp b/src/ccall.cpp index 66ab84c264f3a..00a6403d6434b 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -493,7 +493,7 @@ static Value *julia_to_native( assert(!byRef); // don't expect any ABI to pass pointers by pointer return boxed(ctx, jvinfo); } - assert(jl_is_datatype(jlto) && julia_struct_has_layout((jl_datatype_t*)jlto, jlto_env)); + assert(jl_is_datatype(jlto) && julia_struct_has_layout((jl_datatype_t*)jlto)); typeassert_input(ctx, jvinfo, jlto, jlto_env, argn); if (!byRef) @@ -1065,7 +1065,7 @@ std::string generate_func_sig(const char *fname) } } - t = _julia_struct_to_llvm(ctx, tti, unionall_env, &isboxed, llvmcall); + t = _julia_struct_to_llvm(ctx, tti, &isboxed, llvmcall); if (t == NULL || t == T_void) { return make_errmsg(fname, i + 1, " doesn't correspond to a C type"); } @@ -1211,7 +1211,7 @@ static const std::string verify_ccall_sig(jl_value_t *&rt, jl_value_t *at, rt = (jl_value_t*)jl_any_type; } - lrt = _julia_struct_to_llvm(ctx, rt, unionall_env, &retboxed, llvmcall); + lrt = _julia_struct_to_llvm(ctx, rt, &retboxed, llvmcall); if (lrt == NULL) return "return type doesn't correspond to a C type"; @@ -1405,7 +1405,7 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) isboxed = false; } else { - largty = _julia_struct_to_llvm(&ctx.emission_context, tti, unionall, &isboxed, llvmcall); + largty = _julia_struct_to_llvm(&ctx.emission_context, tti, &isboxed, llvmcall); } if (isboxed) { ary = boxed(ctx, argv[0]); @@ -1717,19 +1717,11 @@ static jl_cgval_t emit_ccall(jl_codectx_t &ctx, jl_value_t **args, size_t nargs) ctx.builder.CreateMemCpy( emit_inttoptr(ctx, destp, T_pint8), -#if JL_LLVM_VERSION >= 100000 MaybeAlign(1), -#else - 1, -#endif emit_inttoptr(ctx, emit_unbox(ctx, T_size, src, (jl_value_t*)jl_voidpointer_type), T_pint8), -#if JL_LLVM_VERSION >= 100000 MaybeAlign(0), -#else - 0, -#endif emit_unbox(ctx, T_size, n, (jl_value_t*)jl_ulong_type), false); JL_GC_POP(); diff --git a/src/cgmemmgr.cpp b/src/cgmemmgr.cpp index 8684178ab02a6..23d8b7437b823 100644 --- a/src/cgmemmgr.cpp +++ b/src/cgmemmgr.cpp @@ -10,6 +10,7 @@ #ifdef _OS_LINUX_ # include # include +# include #endif #ifndef _OS_WINDOWS_ # include @@ -22,6 +23,7 @@ #endif #ifdef _OS_FREEBSD_ # include +# include #endif #include "julia_assert.h" @@ -206,10 +208,24 @@ static intptr_t get_anon_hdl(void) static size_t map_offset = 0; // Multiple of 128MB. // Hopefully no one will set a ulimit for this to be a problem... -static constexpr size_t map_size_inc = 128 * 1024 * 1024; +static constexpr size_t map_size_inc_default = 128 * 1024 * 1024; static size_t map_size = 0; static jl_mutex_t shared_map_lock; +static size_t get_map_size_inc() +{ + rlimit rl; + if (getrlimit(RLIMIT_FSIZE, &rl) != -1) { + if (rl.rlim_cur != RLIM_INFINITY) { + return std::min(map_size_inc_default, rl.rlim_cur); + } + if (rl.rlim_max != RLIM_INFINITY) { + return std::min(map_size_inc_default, rl.rlim_max); + } + } + return map_size_inc_default; +} + static void *create_shared_map(size_t size, size_t id) { void *addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, @@ -224,7 +240,7 @@ static intptr_t init_shared_map() if (anon_hdl == -1) return -1; map_offset = 0; - map_size = map_size_inc; + map_size = get_map_size_inc(); int ret = ftruncate(anon_hdl, map_size); if (ret != 0) { perror(__func__); @@ -238,6 +254,7 @@ static void *alloc_shared_page(size_t size, size_t *id, bool exec) assert(size % jl_page_size == 0); size_t off = jl_atomic_fetch_add(&map_offset, size); *id = off; + size_t map_size_inc = get_map_size_inc(); if (__unlikely(off + size > map_size)) { JL_LOCK_NOGC(&shared_map_lock); size_t old_size = map_size; diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 04522edd9c31c..7f88d2d2fff4b 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -475,7 +475,7 @@ static Value *emit_struct_gep(jl_codectx_t &ctx, Type *lty, Value *base, unsigne return ctx.builder.CreateConstInBoundsGEP2_32(lty, base, 0, idx); } -static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_unionall_t *ua, bool *isboxed, bool llvmcall=false); +static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, bool *isboxed, bool llvmcall=false); static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, bool *isboxed) { @@ -486,7 +486,7 @@ static Type *_julia_type_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, bool if (jl_is_concrete_immutable(jt)) { if (jl_datatype_nbits(jt) == 0) return T_void; - Type *t = _julia_struct_to_llvm(ctx, jt, NULL, isboxed); + Type *t = _julia_struct_to_llvm(ctx, jt, isboxed); assert(t != NULL); return t; } @@ -542,23 +542,10 @@ static bool jl_type_hasptr(jl_value_t* typ) return jl_is_datatype(typ) && ((jl_datatype_t*)typ)->layout->npointers > 0; } -// compute whether all concrete subtypes of this type have the same layout -// (which is conservatively approximated here by asking whether the types of any of the -// fields depend on any of the parameters of the containing type) -static bool julia_struct_has_layout(jl_datatype_t *dt, jl_unionall_t *ua) +// return whether all concrete subtypes of this type have the same layout +static bool julia_struct_has_layout(jl_datatype_t *dt) { - if (dt->layout) - return true; - if (ua) { - jl_svec_t *types = jl_get_fieldtypes(dt); - size_t i, ntypes = jl_svec_len(types); - for (i = 0; i < ntypes; i++) { - jl_value_t *ty = jl_svecref(types, i); - if (jl_has_typevar_from_unionall(ty, ua)) - return false; - } - } - return true; + return dt->layout || jl_has_fixed_layout(dt); } static unsigned jl_field_align(jl_datatype_t *dt, size_t i) @@ -569,7 +556,7 @@ static unsigned jl_field_align(jl_datatype_t *dt, size_t i) return std::min({al, (unsigned)jl_datatype_align(dt), (unsigned)JL_HEAP_ALIGNMENT}); } -static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_unionall_t *ua_env, bool *isboxed, bool llvmcall) +static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, bool *isboxed, bool llvmcall) { // this function converts a Julia Type into the equivalent LLVM struct // use this where C-compatible (unboxed) structs are desired @@ -584,7 +571,12 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ bool isTuple = jl_is_tuple_type(jt); jl_svec_t *ftypes = jl_get_fieldtypes(jst); size_t i, ntypes = jl_svec_len(ftypes); - if (ntypes == 0 || (jst->layout && jl_datatype_nbits(jst) == 0)) + if (!julia_struct_has_layout(jst)) + return NULL; // caller should have checked jl_type_mappable_to_c already, but we'll be nice + if (jst->layout == NULL) + jl_compute_field_offsets(jst); + assert(jst->layout); + if (ntypes == 0 || jl_datatype_nbits(jst) == 0) return T_void; Type *_struct_decl = NULL; // TODO: we should probably make a temporary root for `jst` somewhere @@ -592,8 +584,6 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ Type *&struct_decl = (ctx && !llvmcall ? ctx->llvmtypes[jst] : _struct_decl); if (struct_decl) return struct_decl; - if (!julia_struct_has_layout(jst, ua_env)) - return NULL; std::vector latypes(0); bool isarray = true; bool isvector = true; @@ -605,14 +595,8 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ if (jlasttype != NULL && ty != jlasttype) isvector = false; jlasttype = ty; - size_t fsz = 0, al = 0; - bool isptr = !jl_islayout_inline(ty, &fsz, &al); - if (jst->layout) { - assert(isptr == jl_field_isptr(jst, i)); - assert((isptr ? sizeof(void*) : fsz + jl_is_uniontype(ty)) == jl_field_size(jst, i)); - } Type *lty; - if (isptr) { + if (jl_field_isptr(jst, i)) { lty = T_prjlvalue; isvector = false; } @@ -623,17 +607,15 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ // pick an Integer type size such that alignment will generally be correct, // and always end with an Int8 (selector byte). // We may need to insert padding first to get to the right offset + size_t fsz = 0, al = 0; + bool isptr = !jl_islayout_inline(ty, &fsz, &al); + assert(!isptr && fsz == jl_field_size(jst, i) - 1); (void)isptr; if (al > MAX_ALIGN) { Type *AlignmentType; -#if JL_LLVM_VERSION >= 110000 AlignmentType = ArrayType::get(FixedVectorType::get(T_int8, al), 0); -#else - AlignmentType = ArrayType::get(VectorType::get(T_int8, al), 0); -#endif latypes.push_back(AlignmentType); al = MAX_ALIGN; } - assert(al <= jl_field_align(jst, i)); Type *AlignmentType = IntegerType::get(jl_LLVMContext, 8 * al); unsigned NumATy = fsz / al; unsigned remainder = fsz % al; @@ -648,8 +630,9 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ continue; } else { - lty = _julia_struct_to_llvm(ctx, ty, NULL, &isptr, llvmcall); - assert(!isptr); + bool isptr; + lty = _julia_struct_to_llvm(ctx, ty, &isptr, llvmcall); + assert(lty && !isptr); } if (lasttype != NULL && lasttype != lty) isarray = false; @@ -669,11 +652,7 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ } else if (isarray && !type_is_ghost(lasttype)) { if (isTuple && isvector && jl_special_vector_alignment(ntypes, jlasttype) != 0) -#if JL_LLVM_VERSION >= 110000 struct_decl = FixedVectorType::get(lasttype, ntypes); -#else - struct_decl = VectorType::get(lasttype, ntypes); -#endif else if (isTuple || !llvmcall) struct_decl = ArrayType::get(lasttype, ntypes); else @@ -708,16 +687,9 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, jl_ return T_prjlvalue; } -static Type *julia_struct_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, jl_unionall_t *ua, bool *isboxed) -{ - return _julia_struct_to_llvm(&ctx.emission_context, jt, ua, isboxed); -} - -bool jl_type_mappable_to_c(jl_value_t *ty) +static Type *julia_struct_to_llvm(jl_codectx_t &ctx, jl_value_t *jt, bool *isboxed) { - jl_codegen_params_t params; - bool toboxed; - return _julia_struct_to_llvm(¶ms, ty, NULL, &toboxed) != NULL; + return _julia_struct_to_llvm(&ctx.emission_context, jt, isboxed); } static bool is_datatype_all_pointers(jl_datatype_t *dt) @@ -987,10 +959,13 @@ static Value *emit_sizeof(jl_codectx_t &ctx, const jl_cgval_t &p) static Value *emit_datatype_mutabl(jl_codectx_t &ctx, Value *dt) { - Value *Ptr = emit_bitcast(ctx, decay_derived(ctx, dt), T_pint8); - Value *Idx = ConstantInt::get(T_size, offsetof(jl_datatype_t, mutabl)); + Value *Ptr = emit_bitcast(ctx, decay_derived(ctx, dt), T_ppint8); + Value *Idx = ConstantInt::get(T_size, offsetof(jl_datatype_t, name)); + Value *Nam = tbaa_decorate(tbaa_const, + ctx.builder.CreateAlignedLoad(T_pint8, ctx.builder.CreateInBoundsGEP(T_pint8, Ptr, Idx), Align(sizeof(int8_t*)))); + Value *Idx2 = ConstantInt::get(T_size, offsetof(jl_typename_t, name)); Value *mutabl = tbaa_decorate(tbaa_const, - ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Ptr, Idx), Align(1))); + ctx.builder.CreateAlignedLoad(T_int8, ctx.builder.CreateInBoundsGEP(T_int8, Nam, Idx2), Align(1))); return ctx.builder.CreateTrunc(mutabl, T_int1); } @@ -1116,7 +1091,7 @@ static bool _can_optimize_isa(jl_value_t *type, int &counter) if (jl_is_concrete_type(type)) return true; jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(type); - if (jl_is_datatype(dt) && !dt->abstract && jl_subtype(dt->name->wrapper, type)) + if (jl_is_datatype(dt) && !dt->name->abstract && jl_subtype(dt->name->wrapper, type)) return true; return false; } @@ -1232,7 +1207,7 @@ static std::pair emit_isa(jl_codectx_t &ctx, const jl_cgval_t &x, track_pjlvalue(ctx, literal_pointer_val(ctx, intersected_type))), false); } jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(intersected_type); - if (jl_is_datatype(dt) && !dt->abstract && jl_subtype(dt->name->wrapper, type)) { + if (jl_is_datatype(dt) && !dt->name->abstract && jl_subtype(dt->name->wrapper, type)) { // intersection is a supertype of all instances of its constructor, // so the isa test reduces to a comparison of the typename by pointer return std::make_pair( @@ -1577,11 +1552,7 @@ static void emit_memcpy_llvm(jl_codectx_t &ctx, Value *dst, MDNode *tbaa_dst, Va // for the load part (x.tbaa) and the store part (tbaa_stack). // since the tbaa lattice has to be a tree we have unfortunately // x.tbaa ∪ tbaa_stack = tbaa_root if x.tbaa != tbaa_stack -#if JL_LLVM_VERSION >= 100000 ctx.builder.CreateMemCpy(dst, MaybeAlign(align), src, MaybeAlign(0), sz, is_volatile, MDNode::getMostGenericTBAA(tbaa_dst, tbaa_src)); -#else - ctx.builder.CreateMemCpy(dst, align, src, 0, sz, is_volatile, MDNode::getMostGenericTBAA(tbaa_dst, tbaa_src)); -#endif } static void emit_memcpy_llvm(jl_codectx_t &ctx, Value *dst, MDNode *tbaa_dst, Value *src, MDNode *tbaa_src, @@ -1591,11 +1562,7 @@ static void emit_memcpy_llvm(jl_codectx_t &ctx, Value *dst, MDNode *tbaa_dst, Va emit_memcpy_llvm(ctx, dst, tbaa_dst, src, tbaa_src, const_sz->getZExtValue(), align, is_volatile); return; } -#if JL_LLVM_VERSION >= 100000 ctx.builder.CreateMemCpy(dst, MaybeAlign(align), src, MaybeAlign(0), sz, is_volatile, MDNode::getMostGenericTBAA(tbaa_dst, tbaa_src)); -#else - ctx.builder.CreateMemCpy(dst, align, src, 0, sz, is_volatile, MDNode::getMostGenericTBAA(tbaa_dst, tbaa_src)); -#endif } template @@ -1726,7 +1693,7 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, assert(jl_is_concrete_type(jft)); idx = idx0(); Value *ptr = maybe_decay_tracked(ctx, data_pointer(ctx, strct)); - if (!stt->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type || + if (!stt->name->mutabl && !(maybe_null && (jft == (jl_value_t*)jl_bool_type || ((jl_datatype_t*)jft)->layout->npointers))) { // just compute the pointer and let user load it when necessary Type *fty = julia_type_to_llvm(ctx, jft); @@ -1819,7 +1786,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st // ConstantAsMetadata::get(ConstantInt::get(T_int8, 0)), // ConstantAsMetadata::get(ConstantInt::get(T_int8, union_max)) })); Value *tindex = ctx.builder.CreateNUWAdd(ConstantInt::get(T_int8, 1), tindex0); - if (jt->mutabl) { + if (jt->name->mutabl) { // move value to an immutable stack slot (excluding tindex) Type *ET = IntegerType::get(jl_LLVMContext, 8 * al); AllocaInst *lv = emit_static_alloca(ctx, ET); @@ -1830,7 +1797,7 @@ static jl_cgval_t emit_getfield_knownidx(jl_codectx_t &ctx, const jl_cgval_t &st return mark_julia_slot(addr, jfty, tindex, tbaa); } assert(jl_is_concrete_type(jfty)); - if (!jt->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type || + if (!jt->name->mutabl && !(maybe_null && (jfty == (jl_value_t*)jl_bool_type || ((jl_datatype_t*)jfty)->layout->npointers))) { // just compute the pointer and let user load it when necessary return mark_julia_slot(addr, jfty, NULL, tbaa); @@ -2445,7 +2412,7 @@ static Value *_boxed_special(jl_codectx_t &ctx, const jl_cgval_t &vinfo, Type *t v = ctx.builder.CreateExtractValue(v, makeArrayRef(&zero, 1)); box = call_with_attrs(ctx, box_ssavalue_func, v); } - else if (!jb->abstract && jl_datatype_nbits(jb) == 0) { + else if (!jb->name->abstract && jl_datatype_nbits(jb) == 0) { // singleton assert(jb->instance != NULL); return track_pjlvalue(ctx, literal_pointer_val(ctx, jb->instance)); @@ -2469,6 +2436,27 @@ static Value *compute_box_tindex(jl_codectx_t &ctx, Value *datatype, jl_value_t return tindex; } +// Returns typeof(v), or null if v is a null pointer at run time. +// This is used when the value might have come from an undefined variable, +// yet we try to read its type to compute a union index when moving the value. +static Value *emit_typeof_or_null(jl_codectx_t &ctx, Value *v) +{ + BasicBlock *nonnull = BasicBlock::Create(jl_LLVMContext, "nonnull", ctx.f); + BasicBlock *postBB = BasicBlock::Create(jl_LLVMContext, "postnull", ctx.f); + Value *isnull = ctx.builder.CreateICmpEQ(v, Constant::getNullValue(v->getType())); + ctx.builder.CreateCondBr(isnull, postBB, nonnull); + BasicBlock *entry = ctx.builder.GetInsertBlock(); + ctx.builder.SetInsertPoint(nonnull); + Value *typof = emit_typeof(ctx, v); + ctx.builder.CreateBr(postBB); + nonnull = ctx.builder.GetInsertBlock(); // could have changed + ctx.builder.SetInsertPoint(postBB); + PHINode *ti = ctx.builder.CreatePHI(typof->getType(), 2); + ti->addIncoming(Constant::getNullValue(typof->getType()), entry); + ti->addIncoming(typof, nonnull); + return ti; +} + // get the runtime tindex value, assuming val is already converted to type typ if it has a TIndex static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, jl_value_t *typ) { @@ -2479,9 +2467,12 @@ static Value *compute_tindex_unboxed(jl_codectx_t &ctx, const jl_cgval_t &val, j if (val.TIndex) return ctx.builder.CreateAnd(val.TIndex, ConstantInt::get(T_int8, 0x7f)); - if (val.isboxed) - return compute_box_tindex(ctx, emit_typeof_boxed(ctx, val), val.typ, typ); - return compute_box_tindex(ctx, emit_typeof_boxed(ctx, val), val.typ, typ); + Value *typof; + if (val.isboxed && !jl_is_concrete_type(val.typ) && !jl_is_type_type(val.typ)) + typof = emit_typeof_or_null(ctx, val.V); + else + typof = emit_typeof_boxed(ctx, val); + return compute_box_tindex(ctx, typof, val.typ, typ); } static void union_alloca_type(jl_uniontype_t *ut, @@ -2649,13 +2640,7 @@ static void emit_unionmove(jl_codectx_t &ctx, Value *dest, MDNode *tbaa_dst, con { if (AllocaInst *ai = dyn_cast(dest)) // TODO: make this a lifetime_end & dereferencable annotation? - ctx.builder.CreateAlignedStore(UndefValue::get(ai->getAllocatedType()), ai, -#if JL_LLVM_VERSION >= 110000 - ai->getAlign() -#else - ai->getAlignment() -#endif - ); + ctx.builder.CreateAlignedStore(UndefValue::get(ai->getAllocatedType()), ai, ai->getAlign()); if (jl_is_concrete_type(src.typ) || src.constant) { jl_value_t *typ = src.constant ? jl_typeof(src.constant) : src.typ; Type *store_ty = julia_type_to_llvm(ctx, typ); @@ -2831,7 +2816,7 @@ static void emit_setfield(jl_codectx_t &ctx, jl_datatype_t *sty, const jl_cgval_t &strct, size_t idx0, const jl_cgval_t &rhs, bool checked, bool wb) { - if (sty->mutabl || !checked) { + if (sty->name->mutabl || !checked) { assert(strct.ispointer()); size_t byte_offset = jl_field_offset(sty, idx0); Value *addr = data_pointer(ctx, strct); @@ -2887,7 +2872,7 @@ static jl_cgval_t emit_new_struct(jl_codectx_t &ctx, jl_value_t *ty, size_t narg assert(jl_is_concrete_type(ty)); jl_datatype_t *sty = (jl_datatype_t*)ty; size_t nf = jl_datatype_nfields(sty); - if (nf > 0 || sty->mutabl) { + if (nf > 0 || sty->name->mutabl) { if (deserves_stack(ty)) { Type *lt = julia_type_to_llvm(ctx, ty); unsigned na = nargs < nf ? nargs : nf; diff --git a/src/clangsa/GCChecker.cpp b/src/clangsa/GCChecker.cpp index 51b457b7acb88..b7cc89f210548 100644 --- a/src/clangsa/GCChecker.cpp +++ b/src/clangsa/GCChecker.cpp @@ -26,12 +26,7 @@ #define USED_FUNC #endif -#if LLVM_VERSION_MAJOR >= 10 using std::make_unique; -#else -using llvm::make_unique; -#define PathSensitiveBugReport BugReport -#endif namespace { using namespace clang; @@ -42,11 +37,7 @@ using namespace ento; static const Stmt *getStmtForDiagnostics(const ExplodedNode *N) { -#if LLVM_VERSION_MAJOR >= 10 return N->getStmtForDiagnostics(); -#else - return PathDiagnosticLocation::getStmt(N); -#endif } diff --git a/src/codegen.cpp b/src/codegen.cpp index f0edf7b19fa29..4944356a73dbb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -608,7 +608,10 @@ static const auto jlegal_func = new JuliaFunction{ [](LLVMContext &C) { Type *T = PointerType::get(T_jlvalue, AddressSpace::CalleeRooted); return FunctionType::get(T_int32, {T, T}, false); }, - nullptr, + [](LLVMContext &C) { return AttributeList::get(C, + Attributes(C, {Attribute::ReadOnly, Attribute::NoUnwind, Attribute::ArgMemOnly}), + AttributeSet(), + None); }, }; static const auto jl_alloc_obj_func = new JuliaFunction{ "julia.gc_alloc_obj", @@ -917,11 +920,11 @@ static bool jl_is_pointerfree(jl_value_t* t) // these queries are usually related, but we split them out here // for convenience and clarity (and because it changes the calling convention) -static bool deserves_stack(jl_value_t* t, bool pointerfree=false) +static bool deserves_stack(jl_value_t* t) { if (!jl_is_concrete_immutable(t)) return false; - return ((jl_datatype_t*)t)->isinlinealloc; + return jl_datatype_isinlinealloc((jl_datatype_t*)t, 0); } static bool deserves_argbox(jl_value_t* t) { @@ -1359,7 +1362,7 @@ static inline jl_cgval_t update_julia_type(jl_codectx_t &ctx, const jl_cgval_t & if (jl_is_concrete_type(utyp)) alwaysboxed = !jl_is_pointerfree(utyp); else - alwaysboxed = !((jl_datatype_t*)utyp)->abstract && ((jl_datatype_t*)utyp)->mutabl; + alwaysboxed = !((jl_datatype_t*)utyp)->name->abstract && ((jl_datatype_t*)utyp)->name->mutabl; if (alwaysboxed) { // discovered that this union-split type must actually be isboxed if (v.Vboxed) { @@ -1504,11 +1507,13 @@ static jl_cgval_t convert_julia_type_union(jl_codectx_t &ctx, const jl_cgval_t & // actually need it. Value *union_box_dt = NULL; BasicBlock *union_isaBB = NULL; + BasicBlock *post_union_isaBB = NULL; auto maybe_setup_union_isa = [&]() { if (!union_isaBB) { union_isaBB = BasicBlock::Create(jl_LLVMContext, "union_isa", ctx.f); ctx.builder.SetInsertPoint(union_isaBB); - union_box_dt = emit_typeof(ctx, v.Vboxed); + union_box_dt = emit_typeof_or_null(ctx, v.Vboxed); + post_union_isaBB = ctx.builder.GetInsertBlock(); } }; @@ -1540,7 +1545,7 @@ static jl_cgval_t convert_julia_type_union(jl_codectx_t &ctx, const jl_cgval_t & ctx.builder.SetInsertPoint(postBB); PHINode *tindex_phi = ctx.builder.CreatePHI(T_int8, 2); tindex_phi->addIncoming(new_tindex, currBB); - tindex_phi->addIncoming(union_box_tindex, union_isaBB); + tindex_phi->addIncoming(union_box_tindex, post_union_isaBB); new_tindex = tindex_phi; } } @@ -1684,7 +1689,7 @@ static void jl_setup_module(Module *m, const jl_cgparams_t *params = &jl_default m->addModuleFlag(llvm::Module::Warning, "Dwarf Version", dwarf_version); } if (!m->getModuleFlag("Debug Info Version")) - m->addModuleFlag(llvm::Module::Error, "Debug Info Version", + m->addModuleFlag(llvm::Module::Warning, "Debug Info Version", llvm::DEBUG_METADATA_VERSION); m->setDataLayout(jl_data_layout); m->setTargetTriple(jl_TargetMachine->getTargetTriple().str()); @@ -1713,11 +1718,15 @@ static void jl_init_function(Function *F) F->setHasUWTable(); // force NeedsWinEH #endif #ifdef JL_DISABLE_FPO -#if LLVM_VERSION_MAJOR >= 8 F->addFnAttr("frame-pointer", "all"); -#else - F->addFnAttr("no-frame-pointer-elim", "true"); #endif +#if !defined(JL_ASAN_ENABLED) && !defined(_OS_WINDOWS_) + // ASAN won't like us accessing undefined memory causing spurious issues, + // and Windows has platform-specific handling which causes it to mishandle + // this annotation. Other platforms should just ignore this if they don't + // implement it. + F->addFnAttr("probe-stack", "inline-asm"); + //F->addFnAttr("stack-probe-size", 4096); // can use this to change the default #endif } @@ -3033,6 +3042,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, jl_value_t *jt = jl_tparam0(utt); if (jl_is_vararg(jt)) jt = jl_unwrap_vararg(jt); + assert(jl_is_datatype(jt)); Value *vidx = emit_unbox(ctx, T_size, fld, (jl_value_t*)jl_long_type); // This is not necessary for correctness, but allows to omit // the extra code for getting the length of the tuple @@ -3044,7 +3054,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, emit_datatype_nfields(ctx, emit_typeof_boxed(ctx, obj)), jl_true); } - bool isboxed = !jl_datatype_isinlinealloc(jt); + bool isboxed = !jl_datatype_isinlinealloc((jl_datatype_t*)jt, 0); Value *ptr = maybe_decay_tracked(ctx, data_pointer(ctx, obj)); *ret = typed_load(ctx, ptr, vidx, isboxed ? (jl_value_t*)jl_any_type : jt, @@ -3140,7 +3150,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, else if (f == jl_builtin_sizeof && nargs == 1) { const jl_cgval_t &obj = argv[1]; jl_datatype_t *sty = (jl_datatype_t*)jl_unwrap_unionall(obj.typ); - assert(jl_string_type->mutabl); + assert(jl_string_type->name->mutabl); if (sty == jl_string_type || sty == jl_simplevector_type) { if (obj.constant) { size_t sz; @@ -3789,30 +3799,14 @@ static jl_cgval_t emit_varinfo(jl_codectx_t &ctx, jl_varinfo_t &vi, jl_sym_t *va ssaslot->insertAfter(varslot); if (vi.isVolatile) { Value *unbox = ctx.builder.CreateAlignedLoad(ssaslot->getAllocatedType(), varslot, -#if JL_LLVM_VERSION >= 110000 varslot->getAlign(), -#else - varslot->getAlignment(), -#endif true); - ctx.builder.CreateAlignedStore(unbox, ssaslot, -#if JL_LLVM_VERSION >= 110000 - ssaslot->getAlign() -#else - ssaslot->getAlignment() -#endif - ); + ctx.builder.CreateAlignedStore(unbox, ssaslot, ssaslot->getAlign()); } else { const DataLayout &DL = jl_data_layout; uint64_t sz = DL.getTypeStoreSize(T); - emit_memcpy(ctx, ssaslot, tbaa_stack, vi.value, sz, -#if JL_LLVM_VERSION >= 110000 - ssaslot->getAlign().value() -#else - ssaslot->getAlignment() -#endif - ); + emit_memcpy(ctx, ssaslot, tbaa_stack, vi.value, sz, ssaslot->getAlign().value()); } Value *tindex = NULL; if (vi.pTIndex) @@ -3963,11 +3957,7 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) Value *isboxed = ctx.builder.CreateICmpNE( ctx.builder.CreateAnd(Tindex_phi, ConstantInt::get(T_int8, 0x80)), ConstantInt::get(T_int8, 0)); -#if JL_LLVM_VERSION >= 100000 ctx.builder.CreateMemCpy(phi, MaybeAlign(min_align), dest, MaybeAlign(0), nbytes, false); -#else - ctx.builder.CreateMemCpy(phi, min_align, dest, 0, nbytes, false); -#endif ctx.builder.CreateLifetimeEnd(dest); Value *ptr = ctx.builder.CreateSelect(isboxed, maybe_bitcast(ctx, decay_derived(ctx, ptr_phi), T_pint8), @@ -4007,15 +3997,9 @@ static void emit_phinode_assign(jl_codectx_t &ctx, ssize_t idx, jl_value_t *r) // here it's moved into phi in the successor (from dest) dest = emit_static_alloca(ctx, vtype); Value *phi = emit_static_alloca(ctx, vtype); -#if JL_LLVM_VERSION >= 100000 ctx.builder.CreateMemCpy(phi, MaybeAlign(julia_alignment(phiType)), dest, MaybeAlign(0), jl_datatype_size(phiType), false); -#else - ctx.builder.CreateMemCpy(phi, julia_alignment(phiType), - dest, 0, - jl_datatype_size(phiType), false); -#endif ctx.builder.CreateLifetimeEnd(dest); slot = mark_julia_slot(phi, phiType, NULL, tbaa_stack); } @@ -5441,10 +5425,7 @@ static jl_cgval_t emit_cfunction(jl_codectx_t &ctx, jl_value_t *output_type, con // some sanity checking and check whether there's a vararg size_t nargt = jl_svec_len(argt); bool isVa = (nargt > 0 && jl_is_vararg(jl_svecref(argt, nargt - 1))); - if (isVa) { - emit_error(ctx, "cfunction: Vararg syntax not allowed for argument list"); - return jl_cgval_t(); - } + assert(!isVa); jl_array_t *closure_types = NULL; jl_value_t *sigt = NULL; // dispatch-sig = type signature with Ref{} annotations removed and applied to the env @@ -5593,7 +5574,7 @@ const char *jl_generate_ccallable(void *llvmmod, void *sysimg_handle, jl_value_t crt = (jl_value_t*)jl_any_type; } bool toboxed; - Type *lcrt = _julia_struct_to_llvm(¶ms, crt, NULL, &toboxed); + Type *lcrt = _julia_struct_to_llvm(¶ms, crt, &toboxed); if (toboxed) lcrt = T_prjlvalue; size_t nargs = jl_nparams(sigt)-1; @@ -6297,20 +6278,7 @@ static std::pair, jl_llvm_functions_t> } } - /* - // step 6. (optional) check for stack overflow (the slower way) - Value *cur_sp = - ctx.builder.CreateCall(Intrinsic::getDeclaration(M, - Intrinsic::frameaddress), - ConstantInt::get(T_int32, 0)); - Value *sp_ok = - ctx.builder.CreateICmpUGT(cur_sp, - ConstantInt::get(T_size, - (uptrint_t)jl_stack_lo)); - error_unless(ctx, sp_ok, "stack overflow"); - */ - - // step 7. set up GC frame + // step 6. set up GC frame allocate_gc_frame(ctx, b0); Value *last_age = NULL; emit_last_age_field(ctx); @@ -6318,7 +6286,7 @@ static std::pair, jl_llvm_functions_t> last_age = tbaa_decorate(tbaa_gcframe, ctx.builder.CreateAlignedLoad(ctx.world_age_field, Align(sizeof(size_t)))); } - // step 8. allocate local variables slots + // step 7. allocate local variables slots // must be in the first basic block for the llvm mem2reg pass to work auto allocate_local = [&](jl_varinfo_t &varinfo, jl_sym_t *s) { jl_value_t *jt = varinfo.value.typ; @@ -6355,7 +6323,7 @@ static std::pair, jl_llvm_functions_t> if (allunbox) return; } - else if (deserves_stack(jt, true)) { + else if (deserves_stack(jt)) { bool isboxed; Type *vtype = julia_type_to_llvm(ctx, jt, &isboxed); assert(!isboxed); @@ -6436,7 +6404,7 @@ static std::pair, jl_llvm_functions_t> } } - // step 9. move args into local variables + // step 8. move args into local variables Function::arg_iterator AI = f->arg_begin(); auto get_specsig_arg = [&](jl_value_t *argType, Type *llvmArgType, bool isboxed) { @@ -6566,7 +6534,7 @@ static std::pair, jl_llvm_functions_t> } } - // step 10. allocate rest argument + // step 9. allocate rest argument CallInst *restTuple = NULL; if (va && ctx.vaSlot != -1) { jl_varinfo_t &vi = ctx.slots[ctx.vaSlot]; @@ -6608,7 +6576,7 @@ static std::pair, jl_llvm_functions_t> } } - // step 11. Compute properties for each statements + // step 10. Compute properties for each statements // This needs to be computed by iterating in the IR order // instead of control flow order. auto in_user_mod = [] (jl_module_t *mod) { @@ -6730,7 +6698,7 @@ static std::pair, jl_llvm_functions_t> Instruction &prologue_end = ctx.builder.GetInsertBlock()->back(); - // step 12. Do codegen in control flow order + // step 11. Do codegen in control flow order std::vector workstack; std::map BB; std::map come_from_bb; @@ -7288,7 +7256,7 @@ static std::pair, jl_llvm_functions_t> PN->eraseFromParent(); } - // step 13. Perform any delayed instantiations + // step 12. Perform any delayed instantiations if (ctx.debug_enabled) { bool in_prologue = true; for (auto &BB : *ctx.f) { @@ -7960,6 +7928,10 @@ extern "C" void jl_init_llvm(void) // and to ensure that it is 16-byte aligned for out-going calls, // to ensure compatibility with GCC codes options.StackAlignmentOverride = 16; +#endif +#ifdef JL_DEBUG_BUILD + // LLVM defaults to tls stack guard, which causes issues with Julia's tls implementation + options.StackProtectorGuard = StackProtectorGuards::Global; #endif Triple TheTriple(sys::getProcessTriple()); #if defined(FORCE_ELF) @@ -8122,12 +8094,12 @@ extern "C" void jl_dump_llvm_mfunction(void *v) extern void jl_write_bitcode_func(void *F, char *fname) { std::error_code EC; - raw_fd_ostream OS(fname, EC, sys::fs::F_None); + raw_fd_ostream OS(fname, EC, sys::fs::OF_None); llvm::WriteBitcodeToFile(*((llvm::Function*)F)->getParent(), OS); } extern void jl_write_bitcode_module(void *M, char *fname) { std::error_code EC; - raw_fd_ostream OS(fname, EC, sys::fs::F_None); + raw_fd_ostream OS(fname, EC, sys::fs::OF_None); llvm::WriteBitcodeToFile(*(llvm::Module*)M, OS); } diff --git a/src/codegen_shared.h b/src/codegen_shared.h index ee11870874688..f56854d2b4ca5 100644 --- a/src/codegen_shared.h +++ b/src/codegen_shared.h @@ -29,13 +29,8 @@ struct CountTrackedPointers { CountTrackedPointers(llvm::Type *T); }; -#if JL_LLVM_VERSION >= 110000 unsigned TrackWithShadow(llvm::Value *Src, llvm::Type *T, bool isptr, llvm::Value *Dst, llvm::IRBuilder<> &irbuilder); std::vector ExtractTrackedValues(llvm::Value *Src, llvm::Type *STy, bool isptr, llvm::IRBuilder<> &irbuilder, llvm::ArrayRef perm_offsets={}); -#else -unsigned TrackWithShadow(llvm::Value *Src, llvm::Type *T, bool isptr, llvm::Value *Dst, llvm::IRBuilder<> irbuilder); -std::vector ExtractTrackedValues(llvm::Value *Src, llvm::Type *STy, bool isptr, llvm::IRBuilder<> irbuilder, llvm::ArrayRef perm_offsets={}); -#endif static inline void llvm_dump(llvm::Value *v) { diff --git a/src/datatype.c b/src/datatype.c index 86ad3170a701e..b65c8a602bfcf 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -60,7 +60,7 @@ JL_DLLEXPORT jl_methtable_t *jl_new_method_table(jl_sym_t *name, jl_module_t *mo return mt; } -JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *module) +JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *module, int abstract, int mutabl) { jl_ptls_t ptls = jl_get_ptls_states(); jl_typename_t *tn = @@ -73,6 +73,10 @@ JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *modu tn->linearcache = jl_emptysvec; tn->names = NULL; tn->hash = bitmix(bitmix(module ? module->build_id : 0, name->hash), 0xa1ada1da); + tn->abstract = abstract; + tn->mutabl = mutabl; + tn->references_self = 0; + tn->mayinlinealloc = 0; tn->mt = NULL; tn->partial = NULL; return tn; @@ -94,7 +98,6 @@ jl_datatype_t *jl_new_uninitialized_datatype(void) t->isdispatchtuple = 0; t->isbitstype = 0; t->zeroinit = 0; - t->isinlinealloc = 0; t->has_concrete_subtype = 1; t->cached_by_hash = 0; t->name = NULL; @@ -220,8 +223,8 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t) STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d) { - return (!d->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename && - d->isconcretetype && !d->mutabl); + return (!d->name->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename && + d->isconcretetype && !d->name->mutabl); } STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) @@ -235,6 +238,22 @@ STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) } } +int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOINT +{ + if (ty->name->mayinlinealloc && ty->layout) { + if (ty->layout->npointers > 0) { + if (pointerfree) + return 0; + if (ty->ninitialized != jl_svec_len(ty->types)) + return 0; + if (ty->layout->fielddesc_type > 1) // GC only implements support for 8 and 16 (not array32) + return 0; + } + return 1; + } + return 0; +} + static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbytes, size_t *align, int asfield) JL_NOTSAFEPOINT { if (jl_is_uniontype(ty)) { @@ -246,7 +265,7 @@ static unsigned union_isinlinable(jl_value_t *ty, int pointerfree, size_t *nbyte return 0; return na + nb; } - if (jl_is_datatype(ty) && jl_datatype_isinlinealloc(ty) && (!pointerfree || ((jl_datatype_t*)ty)->layout->npointers == 0)) { + if (jl_is_datatype(ty) && jl_datatype_isinlinealloc((jl_datatype_t*)ty, pointerfree)) { size_t sz = jl_datatype_size(ty); size_t al = jl_datatype_align(ty); // primitive types in struct slots need their sizes aligned. issue #37974 @@ -314,31 +333,6 @@ int jl_pointer_egal(jl_value_t *t) return 0; } -static int references_name(jl_value_t *p, jl_typename_t *name, int affects_layout) JL_NOTSAFEPOINT -{ - if (jl_is_uniontype(p)) - return references_name(((jl_uniontype_t*)p)->a, name, affects_layout) || - references_name(((jl_uniontype_t*)p)->b, name, affects_layout); - if (jl_is_unionall(p)) - return references_name((jl_value_t*)((jl_unionall_t*)p)->var, name, 0) || - references_name(((jl_unionall_t*)p)->body, name, affects_layout); - if (jl_is_typevar(p)) - return references_name(((jl_tvar_t*)p)->ub, name, 0) || - references_name(((jl_tvar_t*)p)->lb, name, 0); - if (jl_is_datatype(p)) { - jl_datatype_t *dp = (jl_datatype_t*)p; - if (affects_layout && dp->name == name) - return 1; - affects_layout = dp->types == NULL || jl_svec_len(dp->types) != 0; - size_t i, l = jl_nparams(p); - for (i = 0; i < l; i++) { - if (references_name(jl_tparam(p, i), name, affects_layout)) - return 1; - } - } - return 0; -} - static void throw_ovf(int should_malloc, void *desc, jl_datatype_t* st, int offset) { if (should_malloc) @@ -351,16 +345,11 @@ void jl_compute_field_offsets(jl_datatype_t *st) const uint64_t max_offset = (((uint64_t)1) << 32) - 1; const uint64_t max_size = max_offset >> 1; - if (st->types == NULL || st->name->wrapper == NULL) - return; - if ((jl_is_tuple_type(st) || jl_is_namedtuple_type(st)) && !jl_is_concrete_type((jl_value_t*)st)) - return; + if (st->name->wrapper == NULL) + return; // we got called too early--we'll be back jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper); - if (w->types == NULL) // we got called too early--we'll be back - return; + assert(st->types && w->types); size_t i, nfields = jl_svec_len(st->types); - int isinlinealloc = st->isconcretetype && !st->mutabl; - int isbitstype = isinlinealloc; assert(st->ninitialized <= nfields); if (st == w && st->layout) { // this check allows us to force re-computation of the layout for some types during init @@ -409,32 +398,16 @@ void jl_compute_field_offsets(jl_datatype_t *st) st->has_concrete_subtype = !jl_is_datatype(fld) || ((jl_datatype_t *)fld)->has_concrete_subtype; } // compute layout for the wrapper object if the field types have no free variables - if (!st->isconcretetype) { - if (st != w) - return; // otherwise we would leak memory - for (i = 0; i < nfields; i++) { - if (jl_has_free_typevars(jl_field_type(st, i))) - return; // not worthwhile computing the rest - } + if (!st->isconcretetype && !jl_has_fixed_layout(st)) { + assert(st == w); // otherwise caller should not have requested this layout + return; } } - // compute whether this type may ever be inlined - // based solely on whether its definition is self-referential - if (isinlinealloc) { - size_t i, nf = jl_svec_len(w->types); - for (i = 0; i < nf; i++) { - jl_value_t *fld = jl_svecref(w->types, i); - if (references_name(fld, w->name, 1)) { - isinlinealloc = 0; - isbitstype = 0; - break; - } - } - for (i = 0; isbitstype && i < nfields; i++) { - jl_value_t *fld = jl_field_type(st, i); - isbitstype = jl_isbits(fld); - } + int isbitstype = st->isconcretetype && st->name->mayinlinealloc; + for (i = 0; isbitstype && i < nfields; i++) { + jl_value_t *fld = jl_field_type(st, i); + isbitstype = jl_isbits(fld); } // if we didn't reuse the layout above, compute it now @@ -548,14 +521,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) } // now finish deciding if this instantiation qualifies for special properties assert(!isbitstype || st->layout->npointers == 0); // the definition of isbits - if (isinlinealloc && st->layout->npointers > 0) { - if (st->ninitialized != nfields) - isinlinealloc = 0; - else if (st->layout->fielddesc_type > 1) // GC only implements support for 8 and 16 (not array32) - isinlinealloc = 0; - } st->isbitstype = isbitstype; - st->isinlinealloc = isinlinealloc; jl_maybe_allocate_singleton_instance(st); return; } @@ -592,8 +558,6 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( jl_gc_wb(t, t->parameters); t->types = ftypes; if (ftypes != NULL) jl_gc_wb(t, t->types); - t->abstract = abstract; - t->mutabl = mutabl; t->ninitialized = ninitialized; t->size = 0; @@ -601,9 +565,11 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( if (jl_is_typename(name)) { // This code-path is used by the Serialization module to by-pass normal expectations tn = (jl_typename_t*)name; + tn->abstract = abstract; + tn->mutabl = mutabl; } else { - tn = jl_new_typename_in((jl_sym_t*)name, module); + tn = jl_new_typename_in((jl_sym_t*)name, module, abstract, mutabl); if (super == jl_function_type || super == jl_builtin_type || is_anonfn_typename(jl_symbol_name(name))) { // Callable objects (including compiler-generated closures) get independent method tables // as an optimization @@ -630,10 +596,12 @@ JL_DLLEXPORT jl_datatype_t *jl_new_datatype( t->name->wrapper = jl_new_struct(jl_unionall_type, jl_svecref(parameters, i), t->name->wrapper); jl_gc_wb(t->name, t->name->wrapper); } + if (!mutabl && !abstract && ftypes != NULL) + tn->mayinlinealloc = 1; } jl_precompute_memoized_dt(t, 0); - if (!abstract) + if (!abstract && t->types != NULL) jl_compute_field_offsets(t); JL_GC_POP(); @@ -650,7 +618,7 @@ JL_DLLEXPORT jl_datatype_t *jl_new_primitivetype(jl_value_t *name, jl_module_t * uint32_t alignm = next_power_of_two(nbytes); if (alignm > MAX_ALIGN) alignm = MAX_ALIGN; - bt->isbitstype = bt->isinlinealloc = (parameters == jl_emptysvec); + bt->isbitstype = (parameters == jl_emptysvec); bt->size = nbytes; bt->layout = jl_get_layout(0, 0, alignm, 0, NULL, NULL); bt->instance = NULL; @@ -685,6 +653,12 @@ JL_DLLEXPORT jl_datatype_t * jl_new_foreign_type(jl_sym_t *name, return bt; } +JL_DLLEXPORT int jl_is_foreign_type(jl_datatype_t *dt) +{ + return jl_is_datatype(dt) && dt->layout && dt->layout->fielddesc_type == 3; +} + + // bits constructors ---------------------------------------------------------- JL_DLLEXPORT jl_value_t *jl_new_bits(jl_value_t *dt, void *data) diff --git a/src/debuginfo.cpp b/src/debuginfo.cpp index b0243b2f3f4ff..95b562311b25b 100644 --- a/src/debuginfo.cpp +++ b/src/debuginfo.cpp @@ -236,15 +236,9 @@ class JuliaJITEventListener: public JITEventListener object::section_iterator EndSection = debugObj.section_end(); std::map loadedSections; for (const object::SectionRef &lSection: Object.sections()) { -#if JL_LLVM_VERSION >= 100000 auto sName = lSection.getName(); if (sName) loadedSections[*sName] = lSection; -#else - StringRef sName; - if (!lSection.getName(sName)) - loadedSections[sName] = lSection; -#endif } auto getLoadAddress = [&] (const StringRef &sName) -> uint64_t { auto search = loadedSections.find(sName); @@ -265,21 +259,12 @@ class JuliaJITEventListener: public JITEventListener istext = true; } else { -#if JL_LLVM_VERSION >= 100000 auto sName = section.getName(); if (!sName) continue; if (sName.get() != ".ARM.exidx") { continue; } -#else - StringRef sName; - if (section.getName(sName)) - continue; - if (sName != ".ARM.exidx") { - continue; - } -#endif } uint64_t loadaddr = L.getSectionLoadAddress(section); size_t seclen = section.getSize(); @@ -333,11 +318,7 @@ class JuliaJITEventListener: public JITEventListener auto Section = cantFail(sym_iter.getSection()); assert(Section != EndSection && Section->isText()); uint64_t SectionAddr = Section->getAddress(); -#if JL_LLVM_VERSION >= 100000 sName = cantFail(Section->getName()); -#else - Section->getName(sName); -#endif uint64_t SectionLoadAddr = getLoadAddress(sName); assert(SectionLoadAddr); if (SectionAddrCheck) // assert that all of the Sections are at the same location @@ -387,12 +368,7 @@ class JuliaJITEventListener: public JITEventListener if (Section == EndSection) continue; if (!Section->isText()) continue; uint64_t SectionAddr = Section->getAddress(); -#if JL_LLVM_VERSION >= 100000 StringRef secName = cantFail(Section->getName()); -#else - StringRef secName; - Section->getName(secName); -#endif uint64_t SectionLoadAddr = getLoadAddress(secName); Addr -= SectionAddr - SectionLoadAddr; StringRef sName = cantFail(sym_iter.getName()); @@ -622,13 +598,8 @@ static debug_link_info getDebuglink(const object::ObjectFile &Obj) JL_NOTSAFEPOI { debug_link_info info = {}; for (const object::SectionRef &Section: Obj.sections()) { -#if JL_LLVM_VERSION >= 100000 Expected sName = Section.getName(); if (sName && *sName == ".gnu_debuglink") -#else - StringRef sName; - if (!Section.getName(sName) && sName == ".gnu_debuglink") -#endif { auto found = Section.getContents(); if (found) { diff --git a/src/disasm.cpp b/src/disasm.cpp index 000f6916ec2bb..28e0178e11654 100644 --- a/src/disasm.cpp +++ b/src/disasm.cpp @@ -249,7 +249,7 @@ void DILineInfoPrinter::emit_lineinfo(raw_ostream &Out, std::vector if (frame.Line != UINT_MAX && frame.Line != 0) Out << ":" << frame.Line; StringRef method = StringRef(frame.FunctionName).rtrim(';'); - Out << " within `" << method << "'"; + Out << " within `" << method << "`"; if (collapse_recursive) { while (nctx < nframes) { const DILineInfo &frame = DI.at(nframes - 1 - nctx); @@ -470,7 +470,8 @@ static void jl_dump_asm_internal( DIContext *di_ctx, raw_ostream &rstream, const char* asm_variant, - const char* debuginfo); + const char* debuginfo, + bool binary); // This isn't particularly fast, but neither is printing assembly, and they're only used for interactive mode static uint64_t compute_obj_symsize(object::SectionRef Section, uint64_t offset) @@ -506,7 +507,7 @@ static uint64_t compute_obj_symsize(object::SectionRef Section, uint64_t offset) // print a native disassembly for the function starting at fptr extern "C" JL_DLLEXPORT -jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo) +jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo, char binary) { assert(fptr != 0); jl_ptls_t ptls = jl_get_ptls_states(); @@ -543,7 +544,8 @@ jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, Section, context, stream, asm_variant, - debuginfo); + debuginfo, + binary); jl_gc_safe_leave(ptls, gc_state); return jl_pchar_to_string(stream.str().data(), stream.str().size()); @@ -739,6 +741,33 @@ static int OpInfoLookup(void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Si } } // namespace +// Stringify raw bytes as a comment string. +std::string rawCodeComment(const llvm::ArrayRef& Memory, const llvm::Triple& Triple) +{ + std::string Buffer{"; "}; + llvm::raw_string_ostream Stream{Buffer}; + auto Address = reinterpret_cast(Memory.data()); + // write abbreviated address + llvm::write_hex(Stream, Address & 0xffff, HexPrintStyle::Lower, 4); + Stream << ":"; + auto Arch = Triple.getArch(); + bool FixedLength = !(Arch == Triple::x86 || Arch == Triple::x86_64); + if (FixedLength) + Stream << " "; + if (FixedLength && Triple.isLittleEndian()) { + for (auto Iter = Memory.rbegin(); Iter != Memory.rend(); ++Iter) + llvm::write_hex(Stream, *Iter, HexPrintStyle::Lower, 2); + } + else { + // variable-length or (fixed-length) big-endian format + for (auto Byte : Memory) { + if (!FixedLength) + Stream << " "; + llvm::write_hex(Stream, Byte, HexPrintStyle::Lower, 2); + } + } + return Stream.str(); +} static void jl_dump_asm_internal( uintptr_t Fptr, size_t Fsize, int64_t slide, @@ -746,7 +775,8 @@ static void jl_dump_asm_internal( DIContext *di_ctx, raw_ostream &rstream, const char* asm_variant, - const char* debuginfo) + const char* debuginfo, + bool binary) { // GC safe // Get the host information @@ -763,11 +793,8 @@ static void jl_dump_asm_internal( SourceMgr SrcMgr; MCTargetOptions Options; - std::unique_ptr MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TheTriple.str()), TheTriple.str() -#if JL_LLVM_VERSION >= 100000 - , Options -#endif - )); + std::unique_ptr MAI( + TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TheTriple.str()), TheTriple.str(), Options)); assert(MAI && "Unable to create target asm info!"); std::unique_ptr MRI(TheTarget->createMCRegInfo(TheTriple.str())); @@ -845,6 +872,16 @@ static void jl_dump_asm_internal( } } + if (binary) { + // Print the complete address and the size at the top (instruction addresses are abbreviated) + std::string Buffer{"; code origin: "}; + llvm::raw_string_ostream Stream{Buffer}; + auto Address = reinterpret_cast(memoryObject.data()); + llvm::write_hex(Stream, Address, HexPrintStyle::Lower, 16); + Stream << ", code size: " << memoryObject.size(); + Streamer->emitRawText(Stream.str()); + } + // Take two passes: In the first pass we record all branch labels, // in the second we actually perform the output for (int pass = 0; pass < 2; ++ pass) { @@ -878,11 +915,7 @@ static void jl_dump_asm_internal( std::string buf; dbgctx.emit_lineinfo(buf, di_lineIter->second); if (!buf.empty()) { -#if JL_LLVM_VERSION >= 110000 Streamer->emitRawText(buf); -#else - Streamer->EmitRawText(buf); -#endif } } } @@ -898,11 +931,7 @@ static void jl_dump_asm_internal( if (di_ctx) { std::string buf; DILineInfoSpecifier infoSpec( -#if JL_LLVM_VERSION >= 110000 DILineInfoSpecifier::FileLineInfoKind::RawValue, -#else - DILineInfoSpecifier::FileLineInfoKind::Default, -#endif DILineInfoSpecifier::FunctionNameKind::ShortName); DIInliningInfo dbg = di_ctx->getInliningInfoForAddress(makeAddress(Section, Index + Fptr + slide), infoSpec); if (dbg.getNumberOfFrames()) { @@ -912,11 +941,7 @@ static void jl_dump_asm_internal( dbgctx.emit_lineinfo(buf, di_lineIter->second); } if (!buf.empty()) { -#if JL_LLVM_VERSION >= 110000 Streamer->emitRawText(buf); -#else - Streamer->EmitRawText(buf); -#endif } nextLineAddr = (++di_lineIter)->first; } @@ -928,11 +953,7 @@ static void jl_dump_asm_internal( // stream << Index << ": "; MCSymbol *symbol = DisInfo.lookupSymbol(Fptr+Index); if (symbol) { -#if JL_LLVM_VERSION >= 110000 Streamer->emitLabel(symbol); -#else - Streamer->EmitLabel(symbol); -#endif } } @@ -940,9 +961,6 @@ static void jl_dump_asm_internal( MCDisassembler::DecodeStatus S; FuncMCView view = memoryObject.slice(Index); S = DisAsm->getInstruction(Inst, insSize, view, 0, -#if JL_LLVM_VERSION < 100000 - /*VStream*/ nulls(), -#endif /*CStream*/ pass != 0 ? Streamer->GetCommentOS() : nulls()); if (pass != 0 && Streamer->GetCommentOS().tell() > 0) Streamer->GetCommentOS() << '\n'; @@ -967,21 +985,13 @@ static void jl_dump_asm_internal( llvm::write_hex(buf, *(uint8_t*)(Fptr + Index + i), HexPrintStyle::PrefixLower, 2); } } -#if JL_LLVM_VERSION >= 110000 Streamer->emitRawText(StringRef(buf.str())); -#else - Streamer->EmitRawText(StringRef(buf.str())); -#endif } break; case MCDisassembler::SoftFail: if (pass != 0) { -#if JL_LLVM_VERSION >= 110000 Streamer->emitRawText(StringRef("potentially undefined instruction encoding:")); -#else - Streamer->EmitRawText(StringRef("potentially undefined instruction encoding:")); -#endif } // Fall through @@ -1014,11 +1024,9 @@ static void jl_dump_asm_internal( } } } -#if JL_LLVM_VERSION >= 110000 + if (binary) + Streamer->emitRawText(rawCodeComment(memoryObject.slice(Index, insSize), TheTriple)); Streamer->emitInstruction(Inst, *STI); -#else - Streamer->EmitInstruction(Inst, *STI); -#endif } break; } @@ -1032,11 +1040,7 @@ static void jl_dump_asm_internal( std::string buf; dbgctx.emit_finish(buf); if (!buf.empty()) { -#if JL_LLVM_VERSION >= 110000 Streamer->emitRawText(buf); -#else - Streamer->EmitRawText(buf); -#endif } } } diff --git a/src/dlload.c b/src/dlload.c index ecb34d2be57e3..df03d9d8e900f 100644 --- a/src/dlload.c +++ b/src/dlload.c @@ -120,7 +120,6 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI needsSymRefreshModuleList = 1; return lib; #else - dlerror(); /* Reset error status. */ return dlopen(filename, (flags & JL_RTLD_NOW ? RTLD_NOW : RTLD_LAZY) | JL_RTLD(flags, LOCAL) @@ -144,16 +143,20 @@ JL_DLLEXPORT void *jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOI JL_DLLEXPORT int jl_dlclose(void *handle) JL_NOTSAFEPOINT { #ifdef _OS_WINDOWS_ - if (!handle) return -1; + if (!handle) { + return -1; + } return !FreeLibrary((HMODULE) handle); #else - dlerror(); /* Reset error status. */ - if (!handle) return -1; + if (!handle) { + dlerror(); /* Reset error status. */ + return -1; + } return dlclose(handle); #endif } -JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) JL_NOTSAFEPOINT // (or throw) +JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, int throw_err) { char path[PATHBUF], relocated[PATHBUF]; int i; @@ -175,20 +178,12 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)(uintptr_t)(&jl_load_dynamic_library), (HMODULE*)&handle)) { -#ifndef __clang_analyzer__ - // Hide the error throwing from the analyser since there isn't a way to express - // "safepoint only when throwing error" currently. jl_error("could not load base module"); -#endif } #else Dl_info info; if (!dladdr((void*)(uintptr_t)&jl_load_dynamic_library, &info) || !info.dli_fname) { -#ifndef __clang_analyzer__ - // Hide the error throwing from the analyser since there isn't a way to express - // "safepoint only when throwing error" currently. jl_error("could not load base module"); -#endif } handle = dlopen(info.dli_fname, RTLD_NOW); #endif @@ -271,11 +266,7 @@ JL_DLLEXPORT void *jl_load_dynamic_library(const char *modname, unsigned flags, #else const char *reason = dlerror(); #endif -#ifndef __clang_analyzer__ - // Hide the error throwing from the analyser since there isn't a way to express - // "safepoint only when throwing error" currently. jl_errorf("could not load library \"%s\"\n%s", modname, reason); -#endif } handle = NULL; @@ -291,19 +282,26 @@ JL_DLLEXPORT int jl_dlsym(void *handle, const char *symbol, void ** value, int t #ifdef _OS_WINDOWS_ *value = GetProcAddress((HMODULE) handle, symbol); #else - dlerror(); /* Reset error status. */ *value = dlsym(handle, symbol); #endif - /* Next, check for errors. On Windows, a NULL pointer means the symbol - * was not found. On everything else, we can have NULL symbols, so we check - * for non-NULL returns from dlerror(). Note that means we unconditionally - * call dlerror() on POSIX systems.*/ -#ifdef _OS_WINDOWS_ + /* Next, check for errors. On Windows, a NULL pointer means the symbol was + * not found. On everything else, we can have NULL symbols, so we check for + * non-NULL returns from dlerror(). Since POSIX doesn't require `dlerror` + * to be implemented safely, FreeBSD doesn't (unlike everyone else, who + * realized decades ago that threads are here to stay), so we avoid calling + * `dlerror` unless we need to get the error message. + * https://github.com/freebsd/freebsd-src/blob/12db51d20823a5e3b9e5f8a2ea73156fe1cbfc28/libexec/rtld-elf/rtld.c#L198 + */ symbol_found = *value != NULL; -#else - const char *err = dlerror(); - symbol_found = err == NULL; +#ifndef _OS_WINDOWS_ + const char *err; + if (!symbol_found) { + dlerror(); /* Reset error status. */ + *value = dlsym(handle, symbol); + err = dlerror(); + symbol_found = *value != NULL || err == NULL; + } #endif if (!symbol_found && throw_err) { diff --git a/src/dump.c b/src/dump.c index 484c31a93bac6..5d9924497a7c4 100644 --- a/src/dump.c +++ b/src/dump.c @@ -8,6 +8,7 @@ #include "julia.h" #include "julia_internal.h" +#include "julia_gcext.h" #include "builtin_proto.h" #include "serialize.h" @@ -270,16 +271,15 @@ static void jl_serialize_datatype(jl_serializer_state *s, jl_datatype_t *dt) JL_ write_int32(s->s, dt->size); int has_instance = (dt->instance != NULL); int has_layout = (dt->layout != NULL); - write_uint8(s->s, dt->abstract | (dt->mutabl << 1) | (has_layout << 2) | (has_instance << 3)); + write_uint8(s->s, dt->name->abstract | (has_layout << 1) | (has_instance << 2)); write_uint8(s->s, dt->hasfreetypevars | (dt->isconcretetype << 1) | (dt->isdispatchtuple << 2) | (dt->isbitstype << 3) | (dt->zeroinit << 4) - | (dt->isinlinealloc << 5) - | (dt->has_concrete_subtype << 6) - | (dt->cached_by_hash << 7)); - if (!dt->abstract) { + | (dt->has_concrete_subtype << 5) + | (dt->cached_by_hash << 6)); + if (!dt->name->abstract) { write_uint16(s->s, dt->ninitialized); } write_int32(s->s, dt->hash); @@ -815,10 +815,15 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li jl_serialize_value(s, tn->wrapper); jl_serialize_value(s, tn->mt); ios_write(s->s, (char*)&tn->hash, sizeof(tn->hash)); + write_uint8(s->s, tn->abstract | (tn->mutabl << 1) | (tn->references_self << 2) | (tn->mayinlinealloc << 3)); } return; } + if (jl_is_foreign_type(t)) { + jl_error("Cannot serialize instances of foreign datatypes"); + } + char *data = (char*)jl_data_ptr(v); size_t i, j, np = t->layout->npointers; uint32_t nf = t->layout->nfields; @@ -833,7 +838,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li ios_write(s->s, last, prevptr - last); jl_value_t *e = *(jl_value_t**)prevptr; JL_GC_PROMISE_ROOTED(e); - if (t->mutabl && e && jl_field_isptr(t, i - 1) && jl_is_cpointer(e) && + if (t->name->mutabl && e && jl_field_isptr(t, i - 1) && jl_is_cpointer(e) && jl_unbox_voidpointer(e) != (void*)-1 && jl_unbox_voidpointer(e) != NULL) // reset Ptr fields to C_NULL (but keep MAP_FAILED / INVALID_HANDLE) jl_serialize_cnull(s, jl_typeof(e)); @@ -849,7 +854,7 @@ static void jl_serialize_value_(jl_serializer_state *s, jl_value_t *v, int as_li } if (i == nf) break; - if (t->mutabl && jl_is_cpointer_type(jl_field_type(t, i)) && *(void**)ptr != (void*)-1) { + if (t->name->mutabl && jl_is_cpointer_type(jl_field_type(t, i)) && *(void**)ptr != (void*)-1) { if (ptr > last) ios_write(s->s, last, ptr - last); char *n = NULL; @@ -910,7 +915,7 @@ static int jl_collect_methcache_from_mod(jl_typemap_entry_t *ml, void *closure) size_t i, l = jl_svec_len(specializations); for (i = 0; i < l; i++) { jl_method_instance_t *callee = (jl_method_instance_t*)jl_svecref(specializations, i); - if (callee != NULL) + if ((jl_value_t*)callee != jl_nothing) collect_backedges(callee); } } @@ -1263,22 +1268,20 @@ static jl_value_t *jl_deserialize_datatype(jl_serializer_state *s, int pos, jl_v uint8_t flags = read_uint8(s->s); uint8_t memflags = read_uint8(s->s); dt->size = size; - dt->abstract = flags & 1; - dt->mutabl = (flags >> 1) & 1; - int has_layout = (flags >> 2) & 1; - int has_instance = (flags >> 3) & 1; + int abstract = flags & 1; + int has_layout = (flags >> 1) & 1; + int has_instance = (flags >> 2) & 1; dt->hasfreetypevars = memflags & 1; dt->isconcretetype = (memflags >> 1) & 1; dt->isdispatchtuple = (memflags >> 2) & 1; dt->isbitstype = (memflags >> 3) & 1; dt->zeroinit = (memflags >> 4) & 1; - dt->isinlinealloc = (memflags >> 5) & 1; - dt->has_concrete_subtype = (memflags >> 6) & 1; - dt->cached_by_hash = (memflags >> 7) & 1; - if (!dt->abstract) - dt->ninitialized = read_uint16(s->s); - else + dt->has_concrete_subtype = (memflags >> 5) & 1; + dt->cached_by_hash = (memflags >> 6) & 1; + if (abstract) dt->ninitialized = 0; + else + dt->ninitialized = read_uint16(s->s); dt->hash = read_int32(s->s); if (has_layout) { @@ -1728,6 +1731,11 @@ static jl_value_t *jl_deserialize_value_any(jl_serializer_state *s, uint8_t tag, tn->mt = (jl_methtable_t*)jl_deserialize_value(s, (jl_value_t**)&tn->mt); jl_gc_wb(tn, tn->mt); ios_read(s->s, (char*)&tn->hash, sizeof(tn->hash)); + int8_t flags = read_int8(s->s); + tn->abstract = flags & 1; + tn->mutabl = (flags>>1) & 1; + tn->references_self = (flags>>2) & 1; + tn->mayinlinealloc = (flags>>3) & 1; } else { jl_datatype_t *dt = (jl_datatype_t*)jl_unwrap_unionall(jl_get_global(m, sym)); diff --git a/src/features_aarch64.h b/src/features_aarch64.h index 6a834610f0cde..88d988a35f03f 100644 --- a/src/features_aarch64.h +++ b/src/features_aarch64.h @@ -35,11 +35,11 @@ JL_FEATURE_DEF(fp16fml, 23, 0) // HWCAP_ASIMDFHM, ARMv8.2-FHM JL_FEATURE_DEF(dit, 24, 0) // HWCAP_DIT, ARMv8.4-DIT. Required in ARMv8.4 // JL_FEATURE_DEF(uscat, 25, UINT32_MAX) // HWCAP_USCAT, ARMv8.4-LSE JL_FEATURE_DEF_NAME(rcpc_immo, 26, 0, "rcpc-immo") // HWCAP_ILRCPC, ARMv8.4-RCPC. Required in ARMv8.4 -JL_FEATURE_DEF(fmi, 27, 0) // HWCAP_FLAGM, ARMv8.4-CondM. Requird in ARMv8.4 +JL_FEATURE_DEF(flagm, 27, 120000) // HWCAP_FLAGM, ARMv8.4-CondM. Required in ARMv8.4 JL_FEATURE_DEF(ssbs, 28, 0) // HWCAP_SSBS JL_FEATURE_DEF(sb, 29, 0) // HWCAP_SB. Required in ARMv8.5 -JL_FEATURE_DEF(pa, 30, 0) // HWCAP_PACA -// JL_FEATURE_DEF(pa, 31, 0) // HWCAP_PACG. Merged with `pa`. +JL_FEATURE_DEF(pauth, 30, 120000) // HWCAP_PACA +// JL_FEATURE_DEF(pa, 31, 0) // HWCAP_PACG. Merged with `pauth`. // hwcap2 JL_FEATURE_DEF(ccdp, 32 + 0, 0) // HWCAP2_DCPODP, ARMv8.2-DCCVADP. Required in ARMv8.5 diff --git a/src/flisp/julia_charmap.h b/src/flisp/julia_charmap.h index bed88a9ace4cd..59f408ce012c9 100644 --- a/src/flisp/julia_charmap.h +++ b/src/flisp/julia_charmap.h @@ -4,4 +4,7 @@ static const uint32_t charmap[][2] = { { 0x025B, 0x03B5 }, // latin small letter open e -> greek small letter epsilon { 0x00B5, 0x03BC }, // micro sign -> greek small letter mu + { 0x00B7, 0x22C5 }, // middot char -> dot operator (#25098) + { 0x0387, 0x22C5 }, // Greek interpunct -> dot operator (#25098) + { 0x2212, 0x002D }, // minus -> hyphen-minus (#26193) }; diff --git a/src/flisp/julia_extensions.c b/src/flisp/julia_extensions.c index e6ffcfcde131c..dbe94e1388069 100644 --- a/src/flisp/julia_extensions.c +++ b/src/flisp/julia_extensions.c @@ -351,6 +351,15 @@ value_t fl_accum_julia_symbol(fl_context_t *fl_ctx, value_t *args, uint32_t narg return symbol(fl_ctx, allascii ? str.buf : normalize(fl_ctx, str.buf)); } +/* convert a string to a symbol, first applying normalization */ +value_t fl_string2normsymbol(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) +{ + argcount(fl_ctx, "string->normsymbol", nargs, 1); + if (!fl_isstring(fl_ctx, args[0])) + type_error(fl_ctx, "string->normsymbol", "string", args[0]); + return symbol(fl_ctx, normalize(fl_ctx, (char*)cvalue_data(args[0]))); +} + static const builtinspec_t julia_flisp_func_info[] = { { "skip-ws", fl_skipws }, { "accum-julia-symbol", fl_accum_julia_symbol }, @@ -360,6 +369,7 @@ static const builtinspec_t julia_flisp_func_info[] = { { "op-suffix-char?", fl_julia_op_suffix_char }, { "strip-op-suffix", fl_julia_strip_op_suffix }, { "underscore-symbol?", fl_julia_underscore_symbolp }, + { "string->normsymbol", fl_string2normsymbol }, { NULL, NULL } }; diff --git a/src/gc.c b/src/gc.c index 94f5a80fd0cbe..df06d7e5a6e7f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -480,9 +480,9 @@ void jl_gc_run_all_finalizers(jl_ptls_t ptls) run_finalizers(ptls); } -static void gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) +static void gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT { - int8_t gc_state = jl_gc_unsafe_enter(ptls); + assert(ptls->gc_state == 0); arraylist_t *a = &ptls->finalizers; // This acquire load and the release store at the end are used to // synchronize with `finalize_object` on another thread. Apart from the GC, @@ -506,15 +506,14 @@ static void gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) items[oldlen] = v; items[oldlen + 1] = f; jl_atomic_store_release(&a->len, oldlen + 2); - jl_gc_unsafe_leave(ptls, gc_state); } -JL_DLLEXPORT void jl_gc_add_ptr_finalizer(jl_ptls_t ptls, jl_value_t *v, void *f) +JL_DLLEXPORT void jl_gc_add_ptr_finalizer(jl_ptls_t ptls, jl_value_t *v, void *f) JL_NOTSAFEPOINT { gc_add_finalizer_(ptls, (void*)(((uintptr_t)v) | 1), f); } -JL_DLLEXPORT void jl_gc_add_finalizer_th(jl_ptls_t ptls, jl_value_t *v, jl_function_t *f) +JL_DLLEXPORT void jl_gc_add_finalizer_th(jl_ptls_t ptls, jl_value_t *v, jl_function_t *f) JL_NOTSAFEPOINT { if (__unlikely(jl_typeis(f, jl_voidpointer_type))) { jl_gc_add_ptr_finalizer(ptls, v, jl_unbox_voidpointer(f)); diff --git a/src/gf.c b/src/gf.c index abc6ac775b644..5bdf7c8ec29b0 100644 --- a/src/gf.c +++ b/src/gf.c @@ -69,9 +69,6 @@ void jl_call_tracer(tracer_cb callback, jl_value_t *tracee) /// ----- Definitions for various internal TypeMaps ----- /// -static struct jl_typemap_info method_defs = {1}; -static struct jl_typemap_info lambda_cache = {1}; - static int8_t jl_cachearg_offset(jl_methtable_t *mt) { return mt->offs; @@ -125,7 +122,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J JL_GC_PUSH1(&specializations); // clang-sa doesn't realize this loop uses specializations for (i = cl; i > 0; i--) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i - 1]); - if (mi == NULL) + if ((jl_value_t*)mi == jl_nothing) break; if (jl_types_equal(mi->specTypes, type)) { if (locked) @@ -146,19 +143,20 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J jl_method_instance_t **data = (jl_method_instance_t**)jl_svec_data(specializations); for (i = 0; i < cl; i++) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i]); - if (mi == NULL) + if ((jl_value_t*)mi == jl_nothing) break; assert(!jl_types_equal(mi->specTypes, type)); } } jl_method_instance_t *mi = jl_get_specialized(m, type, sparams); JL_GC_PUSH1(&mi); - if (hv ? (i + 1 >= cl || jl_svecref(specializations, i + 1) != NULL) : (i <= 1 || jl_svecref(specializations, i - 2) != NULL)) { + if (hv ? (i + 1 >= cl || jl_svecref(specializations, i + 1) != jl_nothing) : (i <= 1 || jl_svecref(specializations, i - 2) != jl_nothing)) { size_t ncl = cl < 8 ? 8 : (cl*3)>>1; jl_svec_t *nc = jl_alloc_svec_uninit(ncl); if (i > 0) memcpy((char*)jl_svec_data(nc), jl_svec_data(specializations), sizeof(void*) * i); - memset((char*)jl_svec_data(nc) + sizeof(void*) * i, 0, sizeof(void*) * (ncl - cl)); + for (int j = 0; j < ncl - cl; j++) + jl_svecset(nc, j+i, jl_nothing); if (i < cl) memcpy((char*)jl_svec_data(nc) + sizeof(void*) * (i + ncl - cl), (char*)jl_svec_data(specializations) + sizeof(void*) * i, @@ -171,7 +169,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_specializations_get_linfo(jl_method_t *m J } if (!hv) i -= 1; - assert(jl_svecref(specializations, i) == NULL); + assert(jl_svecref(specializations, i) == jl_nothing); jl_svecset(specializations, i, mi); // jl_atomic_store_release? if (hv) { // TODO: fuse lookup and insert steps? @@ -243,7 +241,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a jl_methtable_t *mt = dt->name->mt; newentry = jl_typemap_alloc(jl_anytuple_type, NULL, jl_emptysvec, (jl_value_t*)mi, 1, ~(size_t)0); - jl_typemap_insert(&mt->cache, (jl_value_t*)mt, newentry, 0, &lambda_cache); + jl_typemap_insert(&mt->cache, (jl_value_t*)mt, newentry, 0); mt->frozen = 1; JL_GC_POP(); @@ -416,7 +414,7 @@ static int get_method_unspec_list(jl_typemap_entry_t *def, void *closure) size_t i, l = jl_svec_len(specializations); for (i = 0; i < l; i++) { jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); - if (mi) { + if ((jl_value_t*)mi != jl_nothing) { assert(jl_is_method_instance(mi)); if (jl_rettype_inferred(mi, jl_world_counter, jl_world_counter) == jl_nothing) jl_array_ptr_1d_push((jl_array_t*)closure, (jl_value_t*)mi); @@ -1090,7 +1088,7 @@ static jl_method_instance_t *cache_method( guards++; // alternative approach: insert sentinel entry //jl_typemap_insert(cache, parent, (jl_tupletype_t*)matc->spec_types, - // NULL, jl_emptysvec, /*guard*/NULL, jl_cachearg_offset(mt), &lambda_cache, other->min_world, other->max_world); + // NULL, jl_emptysvec, /*guard*/NULL, jl_cachearg_offset(mt), other->min_world, other->max_world); } } } @@ -1165,7 +1163,7 @@ static jl_method_instance_t *cache_method( jl_gc_wb(mt, mt->leafcache); } else { - jl_typemap_insert(cache, parent, newentry, offs, &lambda_cache); + jl_typemap_insert(cache, parent, newentry, offs); } JL_GC_POP(); @@ -1370,7 +1368,7 @@ static void invalidate_method_instance(jl_method_instance_t *replaced, size_t ma } if (!jl_is_method(replaced->def.method)) return; // shouldn't happen, but better to be safe - JL_LOCK_NOGC(&replaced->def.method->writelock); + JL_LOCK(&replaced->def.method->writelock); jl_code_instance_t *codeinst = replaced->cache; while (codeinst) { if (codeinst->max_world == ~(size_t)0) { @@ -1390,13 +1388,13 @@ static void invalidate_method_instance(jl_method_instance_t *replaced, size_t ma invalidate_method_instance(replaced, max_world, depth + 1); } } - JL_UNLOCK_NOGC(&replaced->def.method->writelock); + JL_UNLOCK(&replaced->def.method->writelock); } // invalidate cached methods that overlap this definition static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_world, const char *why) { - JL_LOCK_NOGC(&replaced_mi->def.method->writelock); + JL_LOCK(&replaced_mi->def.method->writelock); jl_array_t *backedges = replaced_mi->backedges; if (backedges) { // invalidate callers (if any) @@ -1407,7 +1405,7 @@ static void invalidate_backedges(jl_method_instance_t *replaced_mi, size_t max_w invalidate_method_instance(replaced[i], max_world, 1); } } - JL_UNLOCK_NOGC(&replaced_mi->def.method->writelock); + JL_UNLOCK(&replaced_mi->def.method->writelock); if (why && _jl_debug_method_invalidation) { jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)replaced_mi); jl_value_t *loctag = jl_cstr_to_string(why); @@ -1564,7 +1562,7 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_typemap_entry_t *m l = jl_svec_len(specializations); for (i = 0; i < l; i++) { jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); - if (mi) { + if ((jl_value_t*)mi != jl_nothing) { invalidated = 1; invalidate_external(mi, methodentry->max_world); invalidate_backedges(mi, methodentry->max_world, "jl_method_table_disable"); @@ -1641,7 +1639,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method // then add our new entry newentry = jl_typemap_alloc((jl_tupletype_t*)type, simpletype, jl_emptysvec, (jl_value_t*)method, method->primary_world, method->deleted_world); - jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, 0, &method_defs); + jl_typemap_insert(&mt->defs, (jl_value_t*)mt, newentry, 0); if (oldentry) { jl_method_t *m = oldentry->func.method; method_overwrite(newentry, m); @@ -1731,7 +1729,7 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method enum morespec_options ambig = morespec_unknown; for (i = 0; i < l; i++) { jl_method_instance_t *mi = jl_atomic_load_relaxed(&data[i]); - if (mi == NULL) + if ((jl_value_t*)mi == jl_nothing) continue; isect3 = jl_type_intersection(m->sig, (jl_value_t*)mi->specTypes); if (jl_type_intersection2(type, isect3, &isect, &isect2)) { diff --git a/src/init.c b/src/init.c index f66403c58199c..7ed1a200eb2a5 100644 --- a/src/init.c +++ b/src/init.c @@ -628,7 +628,7 @@ static void restore_fp_env(void) } } -void _julia_init(JL_IMAGE_SEARCH rel) +JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) { jl_init_timing(); // Make sure we finalize the tls callback before starting any threads. @@ -687,22 +687,26 @@ void _julia_init(JL_IMAGE_SEARCH rel) #endif #endif -#if defined(JL_USE_INTEL_JITEVENTS) +#if \ + defined(JL_USE_INTEL_JITEVENTS) || \ + defined(JL_USE_OPROFILE_JITEVENTS) || \ + defined(JL_USE_PERF_JITEVENTS) const char *jit_profiling = getenv("ENABLE_JITPROFILING"); +#endif + +#if defined(JL_USE_INTEL_JITEVENTS) if (jit_profiling && atoi(jit_profiling)) { jl_using_intel_jitevents = 1; } #endif #if defined(JL_USE_OPROFILE_JITEVENTS) - const char *jit_profiling = getenv("ENABLE_JITPROFILING"); if (jit_profiling && atoi(jit_profiling)) { jl_using_oprofile_jitevents = 1; } #endif #if defined(JL_USE_PERF_JITEVENTS) - const char *jit_profiling = getenv("ENABLE_JITPROFILING"); if (jit_profiling && atoi(jit_profiling)) { jl_using_perf_jitevents= 1; } diff --git a/src/interpreter.c b/src/interpreter.c index 5401cec75932f..008886f1c99c9 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -302,7 +302,8 @@ static jl_value_t *eval_value(jl_value_t *e, interpreter_state *s) else if (head == boundscheck_sym) { return jl_true; } - else if (head == meta_sym || head == coverageeffect_sym || head == inbounds_sym || head == loopinfo_sym) { + else if (head == meta_sym || head == coverageeffect_sym || head == inbounds_sym || head == loopinfo_sym || + head == aliasscope_sym || head == popaliasscope_sym) { return jl_nothing; } else if (head == gc_preserve_begin_sym || head == gc_preserve_end_sym) { diff --git a/src/intrinsics.cpp b/src/intrinsics.cpp index c0ee6ffad0ab8..173a9bb429c08 100644 --- a/src/intrinsics.cpp +++ b/src/intrinsics.cpp @@ -58,7 +58,6 @@ static void jl_init_intrinsic_functions_codegen(void) float_func[lt_float_fast] = true; float_func[le_float_fast] = true; float_func[fpiseq] = true; - float_func[fpislt] = true; float_func[abs_float] = true; float_func[copysign_float] = true; float_func[ceil_llvm] = true; @@ -150,7 +149,7 @@ static Constant *julia_const_to_llvm(jl_codectx_t &ctx, const void *ptr, jl_data if (bt == jl_bool_type) return ConstantInt::get(T_int8, (*(const uint8_t*)ptr) ? 1 : 0); - Type *lt = julia_struct_to_llvm(ctx, (jl_value_t*)bt, NULL, NULL); + Type *lt = julia_struct_to_llvm(ctx, (jl_value_t*)bt, NULL); if (jl_is_vecelement_type((jl_value_t*)bt) && !jl_is_uniontype(jl_tparam0(bt))) bt = (jl_datatype_t*)jl_tparam0(bt); @@ -199,16 +198,13 @@ static Constant *julia_const_to_llvm(jl_codectx_t &ctx, const void *ptr, jl_data unsigned llvm_idx = isa(lt) ? convert_struct_offset(lt, offs) : i; while (fields.size() < llvm_idx) fields.push_back( -#if JL_LLVM_VERSION >= 110000 UndefValue::get(GetElementPtrInst::getTypeAtIndex(lt, fields.size()))); -#else - UndefValue::get(cast(lt)->getTypeAtIndex(fields.size()))); -#endif const uint8_t *ov = (const uint8_t*)ptr + offs; if (jl_is_uniontype(ft)) { // compute the same type layout as julia_struct_to_llvm - size_t fsz = jl_field_size(bt, i); - size_t al = jl_field_align(bt, i); + size_t fsz = 0, al = 0; + (void)jl_islayout_inline(ft, &fsz, &al); + fsz = jl_field_size(bt, i); uint8_t sel = ((const uint8_t*)ptr)[offs + fsz - 1]; jl_value_t *active_ty = jl_nth_union_component(ft, sel); size_t active_sz = jl_datatype_size(active_ty); @@ -1165,26 +1161,6 @@ static Value *emit_untyped_intrinsic(jl_codectx_t &ctx, intrinsic f, Value **arg ctx.builder.CreateICmpEQ(xi, yi)); } - case fpislt: { - *newtyp = jl_bool_type; - Type *it = INTT(t); - Value *xi = ctx.builder.CreateBitCast(x, it); - Value *yi = ctx.builder.CreateBitCast(y, it); - return ctx.builder.CreateOr( - ctx.builder.CreateAnd( - ctx.builder.CreateFCmpORD(x, x), - ctx.builder.CreateFCmpUNO(y, y)), - ctx.builder.CreateAnd( - ctx.builder.CreateFCmpORD(x, y), - ctx.builder.CreateOr( - ctx.builder.CreateAnd( - ctx.builder.CreateICmpSGE(xi, ConstantInt::get(it, 0)), - ctx.builder.CreateICmpSLT(xi, yi)), - ctx.builder.CreateAnd( - ctx.builder.CreateICmpSLT(xi, ConstantInt::get(it, 0)), - ctx.builder.CreateICmpUGT(xi, yi))))); - } - case and_int: return ctx.builder.CreateAnd(x, y); case or_int: return ctx.builder.CreateOr(x, y); case xor_int: return ctx.builder.CreateXor(x, y); diff --git a/src/intrinsics.h b/src/intrinsics.h index 1558769eb3643..a639e06a6316e 100644 --- a/src/intrinsics.h +++ b/src/intrinsics.h @@ -45,7 +45,6 @@ ALIAS(lt_float_fast, lt_float) \ ALIAS(le_float_fast, le_float) \ ADD_I(fpiseq, 2) \ - ADD_I(fpislt, 2) \ /* bitwise operators */ \ ADD_I(and_int, 2) \ ADD_I(or_int, 2) \ diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 3ac092d53fbc6..e86d6109ff427 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -264,8 +264,6 @@ int jl_compile_extern_c(void *llvmmod, void *p, void *sysimg, jl_value_t *declrt return success; } -bool jl_type_mappable_to_c(jl_value_t *ty); - // declare a C-callable entry point; called during code loading from the toplevel extern "C" JL_DLLEXPORT void jl_extern_c(jl_value_t *declrt, jl_tupletype_t *sigt) @@ -292,7 +290,7 @@ void jl_extern_c(jl_value_t *declrt, jl_tupletype_t *sigt) size_t i, nargs = jl_nparams(sigt); for (i = 1; i < nargs; i++) { jl_value_t *ati = jl_tparam(sigt, i); - if (!jl_is_concrete_type(ati) || jl_is_kind(ati)) + if (!jl_is_concrete_type(ati) || jl_is_kind(ati) || !jl_type_mappable_to_c(ati)) jl_error("@ccallable: argument types must be concrete"); } @@ -409,14 +407,14 @@ void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec) // get a native disassembly for a compiled method extern "C" JL_DLLEXPORT jl_value_t *jl_dump_method_asm(jl_method_instance_t *mi, size_t world, - int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo) + int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) { // printing via disassembly jl_code_instance_t *codeinst = jl_generate_fptr(mi, world); if (codeinst) { uintptr_t fptr = (uintptr_t)codeinst->invoke; if (getwrapper) - return jl_dump_fptr_asm(fptr, raw_mc, asm_variant, debuginfo); + return jl_dump_fptr_asm(fptr, raw_mc, asm_variant, debuginfo, binary); uintptr_t specfptr = (uintptr_t)codeinst->specptr.fptr; if (fptr == (uintptr_t)&jl_fptr_const_return && specfptr == 0) { // normally we prevent native code from being generated for these functions, @@ -455,7 +453,7 @@ jl_value_t *jl_dump_method_asm(jl_method_instance_t *mi, size_t world, JL_UNLOCK(&codegen_lock); } if (specfptr != 0) - return jl_dump_fptr_asm(specfptr, raw_mc, asm_variant, debuginfo); + return jl_dump_fptr_asm(specfptr, raw_mc, asm_variant, debuginfo, binary); } // whatever, that didn't work - use the assembler output instead @@ -586,11 +584,13 @@ CompilerResultT JuliaOJIT::CompilerT::operator()(Module &M) JL_TIMING(LLVM_OPT); int optlevel; + int optlevel_min; if (jl_generating_output()) { optlevel = 0; } else { optlevel = jl_options.opt_level; + optlevel_min = jl_options.opt_level_min; for (auto &F : M.functions()) { if (!F.getBasicBlockList().empty()) { Attribute attr = F.getFnAttribute("julia-optimization-level"); @@ -602,6 +602,7 @@ CompilerResultT JuliaOJIT::CompilerT::operator()(Module &M) } } } + optlevel = std::max(optlevel, optlevel_min); } if (optlevel == 0) jit.PM0.run(M); @@ -944,8 +945,7 @@ void jl_merge_module(Module *dest, std::unique_ptr src) // continue; //} else { - assert(dG->isDeclaration() || (dG->getInitializer() == sG->getInitializer() && - dG->isConstant() && sG->isConstant())); + assert(dG->isDeclaration() || dG->getInitializer() == sG->getInitializer()); dG->replaceAllUsesWith(sG); dG->eraseFromParent(); } diff --git a/src/jitlayers.h b/src/jitlayers.h index b517711185e45..e3cc9245932ac 100644 --- a/src/jitlayers.h +++ b/src/jitlayers.h @@ -144,11 +144,7 @@ typedef JITSymbol JL_SymbolInfo; using RTDyldObjHandleT = orc::VModuleKey; #endif -#if JL_LLVM_VERSION >= 100000 using CompilerResultT = Expected>; -#else -using CompilerResultT = std::unique_ptr; -#endif class JuliaOJIT { struct CompilerT : public orc::IRCompileLayer::IRCompiler { diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index bf56eb19564a5..d37dd43bfb04a 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -1,12 +1,6 @@ #define JL_EXPORTED_FUNCS(XX) \ - XX(jl_) \ - XX(jl_abs_float) \ - XX(jl_abs_float_withtype) \ XX(jl_active_task_stack) \ - XX(jl_add_float) \ - XX(jl_add_int) \ XX(jl_add_optimization_passes) \ - XX(jl_add_ptr) \ XX(jl_add_standard_imports) \ XX(jl_alignment) \ XX(jl_alloc_array_1d) \ @@ -16,7 +10,6 @@ XX(jl_alloc_svec) \ XX(jl_alloc_svec_uninit) \ XX(jl_alloc_vec_any) \ - XX(jl_and_int) \ XX(jl_apply_array_type) \ XX(jl_apply_generic) \ XX(jl_apply_tuple_type) \ @@ -50,7 +43,6 @@ XX(jl_array_to_string) \ XX(jl_array_typetagdata) \ XX(jl_arrayunset) \ - XX(jl_ashr_int) \ XX(jl_astaggedvalue) \ XX(jl_atexit_hook) \ XX(jl_backtrace_from_here) \ @@ -81,8 +73,6 @@ XX(jl_box_uint8) \ XX(jl_box_uint8pointer) \ XX(jl_box_voidpointer) \ - XX(jl_breakpoint) \ - XX(jl_bswap_int) \ XX(jl_call) \ XX(jl_call0) \ XX(jl_call1) \ @@ -96,16 +86,6 @@ XX(jl_cglobal) \ XX(jl_cglobal_auto) \ XX(jl_checked_assignment) \ - XX(jl_checked_sadd_int) \ - XX(jl_checked_sdiv_int) \ - XX(jl_checked_smul_int) \ - XX(jl_checked_srem_int) \ - XX(jl_checked_ssub_int) \ - XX(jl_checked_uadd_int) \ - XX(jl_checked_udiv_int) \ - XX(jl_checked_umul_int) \ - XX(jl_checked_urem_int) \ - XX(jl_checked_usub_int) \ XX(jl_clear_implicit_imports) \ XX(jl_clear_malloc_data) \ XX(jl_clock_now) \ @@ -117,9 +97,6 @@ XX(jl_compute_fieldtypes) \ XX(jl_copy_ast) \ XX(jl_copy_code_info) \ - XX(jl_copysign_float) \ - XX(jl_cpuid) \ - XX(jl_cpuidex) \ XX(jl_cpu_pause) \ XX(jl_cpu_threads) \ XX(jl_cpu_wake) \ @@ -127,15 +104,11 @@ XX(jl_create_native) \ XX(jl_create_system_image) \ XX(jl_cstr_to_string) \ - XX(jl_ctlz_int) \ - XX(jl_ctpop_int) \ - XX(jl_cttz_int) \ XX(jl_current_exception) \ XX(jl_debug_method_invalidation) \ XX(jl_declare_constant) \ XX(jl_defines_or_exports_p) \ XX(jl_deprecate_binding) \ - XX(jl_div_float) \ XX(jl_dlclose) \ XX(jl_dlopen) \ XX(jl_dlsym) \ @@ -154,8 +127,6 @@ XX(jl_enter_threaded_region) \ XX(jl_environ) \ XX(jl_eof_error) \ - XX(jl_eq_float) \ - XX(jl_eq_int) \ XX(jl_eqtable_get) \ XX(jl_eqtable_nextind) \ XX(jl_eqtable_pop) \ @@ -178,83 +149,6 @@ XX(jl_expand_with_loc) \ XX(jl_expand_with_loc_warn) \ XX(jl_extern_c) \ - XX(jl_f__abstracttype) \ - XX(jl_f__apply) \ - XX(jl_f__apply_iterate) \ - XX(jl_f__apply_pure) \ - XX(jl_f__call_in_world) \ - XX(jl_f__call_latest) \ - XX(jl_f_applicable) \ - XX(jl_f_apply_type) \ - XX(jl_f_arrayref) \ - XX(jl_f_arrayset) \ - XX(jl_f_arraysize) \ - XX(jl_f_const_arrayref) \ - XX(jl_f__equiv_typedef) \ - XX(jl_f__expr) \ - XX(jl_f_fieldtype) \ - XX(jl_f_getfield) \ - XX(jl_field_index) \ - XX(jl_field_isdefined) \ - XX(jl_f_ifelse) \ - XX(jl_finalize) \ - XX(jl_finalize_th) \ - XX(jl_find_free_typevars) \ - XX(jl_f_intrinsic_call) \ - XX(jl_f_invoke) \ - XX(jl_f_invoke_kwsorter) \ - XX(jl_first_argument_datatype) \ - XX(jl_f_is) \ - XX(jl_f_isa) \ - XX(jl_f_isdefined) \ - XX(jl_f_issubtype) \ - XX(jl_flipsign_int) \ - XX(jl_floor_llvm) \ - XX(jl_floor_llvm_withtype) \ - XX(jl_fl_parse) \ - XX(jl_flush_cstdio) \ - XX(jl_fma_float) \ - XX(jl_f_new_module) \ - XX(jl_f_nfields) \ - XX(jl_forceclose_uv) \ - XX(jl_format_filename) \ - XX(jl_fpext) \ - XX(jl_fpiseq) \ - XX(jl_fpislt) \ - XX(jl_f__primitivetype) \ - XX(jl_fptosi) \ - XX(jl_fptoui) \ - XX(jl_fptr_args) \ - XX(jl_fptr_const_return) \ - XX(jl_fptr_interpret_call) \ - XX(jl_fptr_sparam) \ - XX(jl_fptrunc) \ - XX(jl_free) \ - XX(jl_free_stack) \ - XX(jl_fs_access) \ - XX(jl_fs_chmod) \ - XX(jl_fs_chown) \ - XX(jl_fs_close) \ - XX(jl_f_setfield) \ - XX(jl_f__setsuper) \ - XX(jl_f_sizeof) \ - XX(jl_fs_read) \ - XX(jl_fs_read_byte) \ - XX(jl_fs_rename) \ - XX(jl_fs_sendfile) \ - XX(jl_fs_symlink) \ - XX(jl_fstat) \ - XX(jl_f__structtype) \ - XX(jl_fs_unlink) \ - XX(jl_f_svec) \ - XX(jl_fs_write) \ - XX(jl_f_throw) \ - XX(jl_ftruncate) \ - XX(jl_f_tuple) \ - XX(jl_f_typeassert) \ - XX(jl_f__typebody) \ - XX(jl_f_typeof) \ - XX(jl_f__typevar) \ XX(jl_gc_add_finalizer) \ XX(jl_gc_add_finalizer_th) \ XX(jl_gc_add_ptr_finalizer) \ @@ -311,7 +205,6 @@ XX(jl_generating_output) \ XX(jl_generic_function_def) \ XX(jl_gensym) \ - XX(jl_getaddrinfo) \ XX(jl_getallocationgranularity) \ XX(jl_get_ARCH) \ XX(jl_get_backtrace) \ @@ -380,6 +273,8 @@ XX(jl_idtable_rehash) \ XX(jl_infer_thunk) \ XX(jl_init_restored_modules) \ + XX(jl_init) \ + XX(jl_init_with_image) \ XX(jl_init__threading) \ XX(jl_init_with_image__threading) \ XX(jl_install_sigint_handler) \ @@ -419,12 +314,7 @@ XX(jl_is_unary_and_binary_operator) \ XX(jl_is_unary_operator) \ XX(jl_lazy_load_and_lookup) \ - XX(jl_le_float) \ XX(jl_lisp_prompt) \ - XX(jl_LLVMCreateDisasm) \ - XX(jl_LLVMDisasmInstruction) \ - XX(jl_LLVMFlipSign) \ - XX(jl_LLVMSMod) \ XX(jl_load) \ XX(jl_load_) \ XX(jl_load_and_lookup) \ @@ -432,9 +322,7 @@ XX(jl_load_file_string) \ XX(jl_lookup_code_address) \ XX(jl_lseek) \ - XX(jl_lshr_int) \ XX(jl_lstat) \ - XX(jl_lt_float) \ XX(jl_macroexpand) \ XX(jl_macroexpand1) \ XX(jl_malloc) \ @@ -449,7 +337,6 @@ XX(jl_method_table_insert) \ XX(jl_methtable_lookup) \ XX(jl_mi_cache_insert) \ - XX(jl_mmap) \ XX(jl_module_build_id) \ XX(jl_module_export) \ XX(jl_module_exports_p) \ @@ -462,16 +349,8 @@ XX(jl_module_using) \ XX(jl_module_usings) \ XX(jl_module_uuid) \ - XX(jl_muladd_float) \ - XX(jl_mul_float) \ - XX(jl_mul_int) \ XX(jl_native_alignment) \ XX(jl_nb_available) \ - XX(jl_ne_float) \ - XX(jl_neg_float) \ - XX(jl_neg_float_withtype) \ - XX(jl_neg_int) \ - XX(jl_ne_int) \ XX(jl_new_array) \ XX(jl_new_bits) \ XX(jl_new_code_info_uninit) \ @@ -493,13 +372,11 @@ XX(jl_next_from_addrinfo) \ XX(jl_no_exc_handler) \ XX(jl_normalize_to_compilable_sig) \ - XX(jl_not_int) \ XX(jl_object_id) \ XX(jl_object_id_) \ XX(jl_obvious_subtype) \ XX(jl_operator_precedence) \ XX(jl_op_suffix_char) \ - XX(jl_or_int) \ XX(jl_parse) \ XX(jl_parse_all) \ XX(jl_parse_input_line) \ @@ -527,15 +404,12 @@ XX(jl_ptrarrayref) \ XX(jl_ptr_to_array) \ XX(jl_ptr_to_array_1d) \ - XX(jl_pwrite) \ XX(jl_queue_work) \ XX(jl_raise_debugger) \ XX(jl_readuntil) \ XX(jl_read_verify_header) \ XX(jl_realloc) \ XX(jl_register_newmeth_tracer) \ - XX(jl_rem_float) \ - XX(jl_repl_raise_sigtstp) \ XX(jl_reshape_array) \ XX(jl_restore_excstack) \ XX(jl_restore_incremental) \ @@ -545,14 +419,11 @@ XX(jl_rethrow) \ XX(jl_rethrow_other) \ XX(jl_rettype_inferred) \ - XX(jl_rint_llvm) \ - XX(jl_rint_llvm_withtype) \ XX(jl_running_on_valgrind) \ XX(jl_safe_printf) \ XX(jl_save_incremental) \ XX(jl_save_system_image) \ XX(jl_SC_CLK_TCK) \ - XX(jl_sdiv_int) \ XX(jl_set_ARGS) \ XX(jl_set_const) \ XX(jl_set_errno) \ @@ -571,52 +442,14 @@ XX(jl_set_task_tid) \ XX(jl_set_typeinf_func) \ XX(jl_set_zero_subnormals) \ - XX(jl_sext_int) \ - XX(jl_shl_int) \ XX(jl_sigatomic_begin) \ XX(jl_sigatomic_end) \ XX(jl_sig_throw) \ - XX(jl_sitofp) \ - XX(jl_sizeof_ios_t) \ - XX(jl_sizeof_jl_options) \ - XX(jl_sizeof_mode_t) \ - XX(jl_sizeof_off_t) \ - XX(jl_sizeof_stat) \ - XX(jl_sizeof_uv_fs_t) \ - XX(jl_sle_int) \ - XX(jl_slt_int) \ - XX(jl_smod_int) \ - XX(jl_sockaddr_from_addrinfo) \ - XX(jl_sockaddr_host4) \ - XX(jl_sockaddr_host6) \ - XX(jl_sockaddr_is_ip4) \ - XX(jl_sockaddr_is_ip6) \ - XX(jl_sockaddr_port4) \ - XX(jl_sockaddr_port6) \ - XX(jl_sockaddr_set_port) \ XX(jl_spawn) \ XX(jl_specializations_get_linfo) \ XX(jl_specializations_lookup) \ - XX(jl_sqrt_llvm) \ - XX(jl_sqrt_llvm_fast) \ - XX(jl_sqrt_llvm_fast_withtype) \ - XX(jl_sqrt_llvm_withtype) \ - XX(jl_srem_int) \ - XX(jl_stat) \ - XX(jl_stat_blksize) \ - XX(jl_stat_blocks) \ - XX(jl_stat_ctime) \ - XX(jl_stat_dev) \ - XX(jl_stat_gid) \ XX(jl_static_show) \ XX(jl_static_show_func_sig) \ - XX(jl_stat_ino) \ - XX(jl_stat_mode) \ - XX(jl_stat_mtime) \ - XX(jl_stat_nlink) \ - XX(jl_stat_rdev) \ - XX(jl_stat_size) \ - XX(jl_stat_uid) \ XX(jl_stderr_obj) \ XX(jl_stderr_stream) \ XX(jl_stdin_stream) \ @@ -627,9 +460,6 @@ XX(jl_string_to_array) \ XX(jl_strtod_c) \ XX(jl_strtof_c) \ - XX(jl_sub_float) \ - XX(jl_sub_int) \ - XX(jl_sub_ptr) \ XX(jl_substrtod) \ XX(jl_substrtof) \ XX(jl_subtype) \ @@ -653,12 +483,6 @@ XX(jl_take_buffer) \ XX(jl_task_get_next) \ XX(jl_task_stack_buffer) \ - XX(jl_tcp_bind) \ - XX(jl_tcp_connect) \ - XX(jl_tcp_getpeername) \ - XX(jl_tcp_getsockname) \ - XX(jl_tcp_quickack) \ - XX(jl_tcp_reuseport) \ XX(jl_test_cpu_feature) \ XX(jl_threadid) \ XX(jl_threading_enabled) \ @@ -668,9 +492,6 @@ XX(jl_too_many_args) \ XX(jl_toplevel_eval) \ XX(jl_toplevel_eval_in) \ - XX(jl_trunc_int) \ - XX(jl_trunc_llvm) \ - XX(jl_trunc_llvm_withtype) \ XX(jl_try_substrtod) \ XX(jl_try_substrtof) \ XX(jl_tty_set_mode) \ @@ -683,7 +504,6 @@ XX(jl_typeinf_end) \ XX(jl_type_intersection) \ XX(jl_type_intersection_with_env) \ - XX(jl_typemax_uint) \ XX(jl_type_morespecific) \ XX(jl_type_morespecific_no_subtype) \ XX(jl_typename_str) \ @@ -693,12 +513,6 @@ XX(jl_type_to_llvm) \ XX(jl_type_union) \ XX(jl_type_unionall) \ - XX(jl_udiv_int) \ - XX(jl_udp_bind) \ - XX(jl_udp_send) \ - XX(jl_uitofp) \ - XX(jl_ule_int) \ - XX(jl_ult_int) \ XX(jl_unbox_bool) \ XX(jl_unbox_float32) \ XX(jl_unbox_float64) \ @@ -716,36 +530,6 @@ XX(jl_uncompress_argnames) \ XX(jl_uncompress_ir) \ XX(jl_undefined_var_error) \ - XX(jl_urem_int) \ - XX(jl_uv_associate_julia_struct) \ - XX(jl_uv_buf_base) \ - XX(jl_uv_buf_len) \ - XX(jl_uv_buf_set_base) \ - XX(jl_uv_buf_set_len) \ - XX(jl_uv_connect_handle) \ - XX(jl_uv_disassociate_julia_struct) \ - XX(jl_uv_file_handle) \ - XX(jl_uv_flush) \ - XX(jl_uv_fs_t_path) \ - XX(jl_uv_fs_t_ptr) \ - XX(jl_uv_handle) \ - XX(jl_uv_handle_data) \ - XX(jl_uv_handle_type) \ - XX(jl_uv_interface_addresses) \ - XX(jl_uv_interface_address_is_internal) \ - XX(jl_uv_interface_address_sockaddr) \ - XX(jl_uv_process_data) \ - XX(jl_uv_process_pid) \ - XX(jl_uv_putb) \ - XX(jl_uv_putc) \ - XX(jl_uv_puts) \ - XX(jl_uv_req_data) \ - XX(jl_uv_req_set_data) \ - XX(jl_uv_sizeof_interface_address) \ - XX(jl_uv_unix_fd_is_watched) \ - XX(jl_uv_write) \ - XX(jl_uv_writecb) \ - XX(jl_uv_write_handle) \ XX(jl_valueof) \ XX(jl_value_ptr) \ XX(jl_ver_is_release) \ @@ -756,6 +540,5 @@ XX(jl_vexceptionf) \ XX(jl_vprintf) \ XX(jl_wakeup_thread) \ - XX(jl_xor_int) \ XX(jl_yield) \ - XX(jl_zext_int) + XX(jl_print_backtrace) diff --git a/src/jl_uv.c b/src/jl_uv.c index 35f83b3314e91..78238bf07e8eb 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -207,14 +207,15 @@ JL_DLLEXPORT int jl_process_events(void) { jl_ptls_t ptls = jl_get_ptls_states(); uv_loop_t *loop = jl_io_loop; + jl_gc_safepoint_(ptls); if (loop && (_threadedregion || ptls->tid == 0)) { - jl_gc_safepoint_(ptls); if (jl_atomic_load(&jl_uv_n_waiters) == 0 && jl_mutex_trylock(&jl_uv_mutex)) { loop->stop_flag = 0; int r = uv_run(loop, UV_RUN_NOWAIT); JL_UV_UNLOCK(); return r; } + jl_gc_safepoint_(ptls); } return 0; } diff --git a/src/jlapi.c b/src/jlapi.c index d27f7e03d958c..669cce270c2d7 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -91,6 +91,19 @@ JL_DLLEXPORT void jl_init(void) free(libbindir); } +// HACK: remove this for Julia 1.8 (see ) +JL_DLLEXPORT void jl_init__threading(void) +{ + jl_init(); +} + +// HACK: remove this for Julia 1.8 (see ) +JL_DLLEXPORT void jl_init_with_image__threading(const char *julia_bindir, + const char *image_relative_path) +{ + jl_init_with_image(julia_bindir, image_relative_path); +} + JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str) { jl_value_t *r; @@ -500,8 +513,7 @@ static int exec_program(char *program) jl_load(jl_main_module, program); } JL_CATCH { - // TODO: It is possible for this output - // to be mangled due to `jlbacktrace` + // TODO: It is possible for this output to be mangled due to `jl_print_backtrace` // printing directly to STDERR_FILENO. int shown_err = 0; jl_printf(JL_STDERR, "error during bootstrap:\n"); @@ -520,32 +532,13 @@ static int exec_program(char *program) jl_static_show((JL_STREAM*)STDERR_FILENO, exc); jl_printf((JL_STREAM*)STDERR_FILENO, "\n"); } - jlbacktrace(); // written to STDERR_FILENO + jl_print_backtrace(); // written to STDERR_FILENO jl_printf((JL_STREAM*)STDERR_FILENO, "\n"); return 1; } return 0; } -#ifdef JL_GF_PROFILE -static void print_profile(void) -{ - size_t i; - void **table = jl_base_module->bindings.table; - for(i=1; i < jl_base_module->bindings.size; i+=2) { - if (table[i] != HT_NOTFOUND) { - jl_binding_t *b = (jl_binding_t*)table[i]; - if (b->value != NULL && jl_is_function(b->value) && - jl_is_gf(b->value)) { - jl_printf(JL_STDERR, "%d\t%s\n", - jl_gf_mtable(b->value)->ncalls, - jl_gf_name(b->value)->name); - } - } - } -} -#endif - static NOINLINE int true_main(int argc, char *argv[]) { jl_set_ARGS(argc, argv); @@ -573,9 +566,9 @@ static NOINLINE int true_main(int argc, char *argv[]) } } - ios_puts("WARNING: Base._start not defined, falling back to economy mode repl.\n", ios_stdout); + jl_printf(JL_STDOUT, "WARNING: Base._start not defined, falling back to economy mode repl.\n"); if (!jl_errorexception_type) - ios_puts("WARNING: jl_errorexception_type not defined; any errors will be fatal.\n", ios_stdout); + jl_printf(JL_STDOUT, "WARNING: jl_errorexception_type not defined; any errors will be fatal.\n"); while (!ios_eof(ios_stdin)) { char *volatile line = NULL; @@ -597,7 +590,7 @@ static NOINLINE int true_main(int argc, char *argv[]) jl_printf(JL_STDOUT, "\n"); free(line); line = NULL; - uv_run(jl_global_event_loop(),UV_RUN_NOWAIT); + jl_process_events(); } JL_CATCH { if (line) { @@ -607,7 +600,7 @@ static NOINLINE int true_main(int argc, char *argv[]) jl_printf((JL_STREAM*)STDERR_FILENO, "\nparser error:\n"); jl_static_show((JL_STREAM*)STDERR_FILENO, jl_current_exception()); jl_printf((JL_STREAM*)STDERR_FILENO, "\n"); - jlbacktrace(); // written to STDERR_FILENO + jl_print_backtrace(); // written to STDERR_FILENO } } return 0; @@ -665,7 +658,7 @@ static void rr_detach_teleport(void) { #endif } -JL_DLLEXPORT int repl_entrypoint(int argc, char *argv[]) +JL_DLLEXPORT int jl_repl_entrypoint(int argc, char *argv[]) { // no-op on Windows, note that the caller must have already converted // from `wchar_t` to `UTF-8` already if we're running on Windows. diff --git a/src/jloptions.c b/src/jloptions.c index cc5c85a06f034..4fbf83e8f5e30 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -47,6 +47,7 @@ jl_options_t jl_options = { 0, // quiet 0, // code_coverage 0, // malloc_log 2, // opt_level + 0, // opt_level_min #ifdef JL_DEBUG_BUILD 2, // debug_level [debug build] #else @@ -122,6 +123,7 @@ static const char opts[] = // code generation options " -C, --cpu-target Limit usage of CPU features up to ; set to \"help\" to see the available options\n" " -O, --optimize={0,1,2,3} Set the optimization level (default level is 2 if unspecified or 3 if used without a level)\n" + " --min-optlevel={0,1,2,3} Set a lower bound on the optimization level (default is 0)\n" " -g, -g Enable / Set the level of debug info generation" #ifdef JL_DEBUG_BUILD " (default level for julia-debug is 2 if unspecified or if used without a level)\n" @@ -190,6 +192,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_worker, opt_bind_to, opt_handle_signals, + opt_optlevel_min, opt_output_o, opt_output_asm, opt_output_ji, @@ -236,6 +239,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "code-coverage", optional_argument, 0, opt_code_coverage }, { "track-allocation",optional_argument, 0, opt_track_allocation }, { "optimize", optional_argument, 0, 'O' }, + { "min-optlevel", optional_argument, 0, opt_optlevel_min }, { "check-bounds", required_argument, 0, opt_check_bounds }, { "output-bc", required_argument, 0, opt_output_bc }, { "output-unopt-bc", required_argument, 0, opt_output_unopt_bc }, @@ -536,6 +540,24 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) jl_options.opt_level = 3; } break; + case opt_optlevel_min: // minimum module optimize level + if (optarg != NULL) { + if (!strcmp(optarg,"0")) + jl_options.opt_level_min = 0; + else if (!strcmp(optarg,"1")) + jl_options.opt_level_min = 1; + else if (!strcmp(optarg,"2")) + jl_options.opt_level_min = 2; + else if (!strcmp(optarg,"3")) + jl_options.opt_level_min = 3; + else + jl_errorf("julia: invalid argument to --min-optlevel (%s)", optarg); + break; + } + else { + jl_options.opt_level_min = 0; + } + break; case 'i': // isinteractive jl_options.isinteractive = 1; break; diff --git a/src/jltypes.c b/src/jltypes.c index 61541c54a808b..496ce3dbe9286 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -35,6 +35,45 @@ static int typeenv_has(jl_typeenv_t *env, jl_tvar_t *v) JL_NOTSAFEPOINT return 0; } +static int layout_uses_free_typevars(jl_value_t *v, jl_typeenv_t *env) +{ + if (jl_typeis(v, jl_tvar_type)) + return !typeenv_has(env, (jl_tvar_t*)v); + if (jl_is_uniontype(v)) + return layout_uses_free_typevars(((jl_uniontype_t*)v)->a, env) || + layout_uses_free_typevars(((jl_uniontype_t*)v)->b, env); + if (jl_is_vararg(v)) { + jl_vararg_t *vm = (jl_vararg_t*)v; + if (vm->T) { + if (layout_uses_free_typevars(vm->T, env)) + return 1; + if (vm->N && layout_uses_free_typevars(vm->N, env)) + return 1; + } + return 0; + } + if (jl_is_unionall(v)) { + jl_unionall_t *ua = (jl_unionall_t*)v; + jl_typeenv_t newenv = { ua->var, NULL, env }; + return layout_uses_free_typevars(ua->body, &newenv); + } + if (jl_is_datatype(v)) { + jl_datatype_t *dt = (jl_datatype_t*)v; + if (dt->layout || dt->isconcretetype || !dt->name->mayinlinealloc) + return 0; + jl_svec_t *types = jl_get_fieldtypes(dt); + size_t i, l = jl_svec_len(types); + for (i = 0; i < l; i++) { + jl_value_t *ft = jl_svecref(types, i); + if (layout_uses_free_typevars(ft, env)) { + // This might be inline-alloc, but we don't know the layout + return 1; + } + } + } + return 0; +} + static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT { if (jl_typeis(v, jl_tvar_type)) { @@ -62,9 +101,8 @@ static int has_free_typevars(jl_value_t *v, jl_typeenv_t *env) JL_NOTSAFEPOINT if (expect == 0 || env == NULL) return expect; size_t i; - for (i=0; i < jl_nparams(v); i++) { - if (has_free_typevars(jl_tparam(v,i), env)) { - assert(expect); + for (i = 0; i < jl_nparams(v); i++) { + if (has_free_typevars(jl_tparam(v, i), env)) { return 1; } } @@ -181,6 +219,35 @@ JL_DLLEXPORT int jl_has_typevar_from_unionall(jl_value_t *t, jl_unionall_t *ua) return _jl_has_typevar_from_ua(t, ua, NULL); } +int jl_has_fixed_layout(jl_datatype_t *dt) +{ + if (dt->layout || dt->isconcretetype) + return 1; + if (jl_is_tuple_type(dt)) + return 0; // TODO: relax more? + jl_svec_t *types = jl_get_fieldtypes(dt); + size_t i, l = jl_svec_len(types); + for (i = 0; i < l; i++) { + jl_value_t *ft = jl_svecref(types, i); + if (layout_uses_free_typevars(ft, NULL)) { + // This might be inline-alloc, but we don't know the layout + return 0; + } + } + return 1; +} + +int jl_type_mappable_to_c(jl_value_t *ty) +{ + assert(!jl_is_typevar(ty) && jl_is_type(ty)); + if (jl_is_structtype(ty)) { + jl_datatype_t *jst = (jl_datatype_t*)ty; + return jst->layout || jl_has_fixed_layout(jst); + } + if (jl_is_tuple_type(jl_unwrap_unionall(ty))) + return 0; // TODO: relax some? + return 1; // as boxed or primitive +} // Return true for any type (Integer or Unsigned) that can fit in a // size_t and pass back value, else return false @@ -1082,7 +1149,7 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) { int istuple = (dt->name == jl_tuple_typename); dt->hasfreetypevars = 0; - dt->isconcretetype = !dt->abstract; + dt->isconcretetype = !dt->name->abstract; dt->isdispatchtuple = istuple; size_t i, l = jl_nparams(dt); for (i = 0; i < l; i++) { @@ -1099,6 +1166,13 @@ void jl_precompute_memoized_dt(jl_datatype_t *dt, int cacheable) ((!jl_is_kind(p) && ((jl_datatype_t*)p)->isconcretetype) || (((jl_datatype_t*)p)->name == jl_type_typename && !((jl_datatype_t*)p)->hasfreetypevars)); } + if (istuple && dt->has_concrete_subtype) { + if (jl_is_vararg(p)) + p = ((jl_vararg_t*)p)->T; + // tuple types like Tuple{:x} cannot have instances + if (p && !jl_is_type(p) && !jl_is_typevar(p)) + dt->has_concrete_subtype = 0; + } } if (dt->name == jl_type_typename) cacheable = 0; // the cache for Type ignores parameter normalization, so it can't be used as a regular hash @@ -1153,6 +1227,92 @@ static jl_value_t *extract_wrapper(jl_value_t *t JL_PROPAGATES_ROOT) JL_GLOBALLY return NULL; } +int _may_substitute_ub(jl_value_t *v, jl_tvar_t *var, int inside_inv, int *cov_count) JL_NOTSAFEPOINT +{ + if (v == (jl_value_t*)var) { + if (inside_inv) { + return 0; + } + else { + (*cov_count)++; + return *cov_count <= 1 || jl_is_concrete_type(var->ub); + } + } + else if (jl_is_uniontype(v)) { + return _may_substitute_ub(((jl_uniontype_t*)v)->a, var, inside_inv, cov_count) && + _may_substitute_ub(((jl_uniontype_t*)v)->b, var, inside_inv, cov_count); + } + else if (jl_is_unionall(v)) { + jl_unionall_t *ua = (jl_unionall_t*)v; + if (ua->var == var) + return 1; + return _may_substitute_ub(ua->var->lb, var, inside_inv, cov_count) && + _may_substitute_ub(ua->var->ub, var, inside_inv, cov_count) && + _may_substitute_ub(ua->body, var, inside_inv, cov_count); + } + else if (jl_is_datatype(v)) { + int invar = inside_inv || !jl_is_tuple_type(v); + for (size_t i = 0; i < jl_nparams(v); i++) { + if (!_may_substitute_ub(jl_tparam(v,i), var, invar, cov_count)) + return 0; + } + } + else if (jl_is_vararg(v)) { + jl_vararg_t *va = (jl_vararg_t*)v; + int old_count = *cov_count; + if (va->T && !_may_substitute_ub(va->T, var, inside_inv, cov_count)) + return 0; + if (*cov_count > old_count && !jl_is_concrete_type(var->ub)) + return 0; + if (va->N && !_may_substitute_ub(va->N, var, 1, cov_count)) + return 0; + } + return 1; +} + +// Check whether `var` may be replaced with its upper bound `ub` in `v where var<:ub` +// Conditions: +// * `var` does not appear in invariant position +// * `var` appears at most once (in covariant position) and not in a `Vararg` +// unless the upper bound is concrete (diagonal rule) +int may_substitute_ub(jl_value_t *v, jl_tvar_t *var) JL_NOTSAFEPOINT +{ + int cov_count = 0; + return _may_substitute_ub(v, var, 0, &cov_count); +} + +jl_value_t *normalize_unionalls(jl_value_t *t) +{ + JL_GC_PUSH1(&t); + if (jl_is_uniontype(t)) { + jl_uniontype_t *u = (jl_uniontype_t*)t; + jl_value_t *a = NULL; + jl_value_t *b = NULL; + JL_GC_PUSH2(&a, &b); + a = normalize_unionalls(u->a); + b = normalize_unionalls(u->b); + if (a != u->a || b != u->b) { + t = jl_new_struct(jl_uniontype_type, a, b); + } + JL_GC_POP(); + } + else if (jl_is_unionall(t)) { + jl_unionall_t *u = (jl_unionall_t*)t; + jl_value_t *body = normalize_unionalls(u->body); + if (body != u->body) { + JL_GC_PUSH1(&body); + t = jl_new_struct(jl_unionall_type, u->var, body); + JL_GC_POP(); + u = (jl_unionall_t*)t; + } + + if (u->var->lb == u->var->ub || may_substitute_ub(body, u->var)) + t = jl_instantiate_unionall(u, u->var->ub); + } + JL_GC_POP(); + return t; +} + static jl_value_t *_jl_instantiate_type_in_env(jl_value_t *ty, jl_unionall_t *env, jl_value_t **vals, jl_typeenv_t *prev, jl_typestack_t *stack); static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value_t **iparams, size_t ntp, @@ -1162,6 +1322,11 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_typename_t *tn = dt->name; int istuple = (tn == jl_tuple_typename); int isnamedtuple = (tn == jl_namedtuple_typename); + if (dt->name != jl_type_typename) { + for (size_t i = 0; i < ntp; i++) + iparams[i] = normalize_unionalls(iparams[i]); + } + // check type cache if (cacheable) { size_t i; @@ -1307,8 +1472,6 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value ndt->types = jl_emptysvec; } } - ndt->mutabl = dt->mutabl; - ndt->abstract = dt->abstract; ndt->size = 0; jl_precompute_memoized_dt(ndt, cacheable); if (istuple) @@ -1321,7 +1484,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value if (jl_is_primitivetype(dt)) { ndt->size = dt->size; ndt->layout = dt->layout; - ndt->isbitstype = ndt->isinlinealloc = ndt->isconcretetype; + ndt->isbitstype = ndt->isconcretetype; } jl_datatype_t *primarydt = ((jl_datatype_t*)jl_unwrap_unionall(tn->wrapper)); @@ -1346,7 +1509,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value } else if (!isnamedtuple && !istuple) { assert(ftypes != jl_emptysvec || jl_field_names(ndt) == jl_emptysvec); - assert(ftypes == jl_emptysvec || !ndt->abstract); + assert(ftypes == jl_emptysvec || !ndt->name->abstract); if (ftypes == jl_emptysvec) { ndt->types = ftypes; } @@ -1361,8 +1524,11 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value } // now publish the finished result + // XXX: if the stack was used, this will publish in the wrong order, + // leading to incorrect layouts and data races (#40050: the A{T} should be + // an isbitstype singleton of size 0) if (cacheable) { - if (!jl_is_primitivetype(dt) && ndt->types != NULL && !ndt->abstract) { + if (!jl_is_primitivetype(dt) && ndt->types != NULL && ndt->isconcretetype) { jl_compute_field_offsets(ndt); } jl_cache_type_(ndt); @@ -1793,11 +1959,12 @@ void jl_init_types(void) JL_GC_DISABLED jl_type_typename->mt = jl_type_type_mt; // initialize them. lots of cycles. - jl_datatype_type->name = jl_new_typename_in(jl_symbol("DataType"), core); + // NOTE: types are not actually mutable, but we want to ensure they are heap-allocated with stable addresses + jl_datatype_type->name = jl_new_typename_in(jl_symbol("DataType"), core, 0, 1); jl_datatype_type->name->wrapper = (jl_value_t*)jl_datatype_type; jl_datatype_type->super = (jl_datatype_t*)jl_type_type; jl_datatype_type->parameters = jl_emptysvec; - jl_datatype_type->name->names = jl_perm_symsvec(20, + jl_datatype_type->name->names = jl_perm_symsvec(17, "name", "super", "parameters", @@ -1808,17 +1975,14 @@ void jl_init_types(void) JL_GC_DISABLED "size", "ninitialized", "hash", - "abstract", - "mutable", "hasfreetypevars", "isconcretetype", "isdispatchtuple", "isbitstype", "zeroinit", - "isinlinealloc", "has_concrete_subtype", "cached_by_hash"); - jl_datatype_type->types = jl_svec(20, + jl_datatype_type->types = jl_svec(17, jl_typename_type, jl_datatype_type, jl_simplevector_type, @@ -1826,32 +1990,28 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, // instance jl_any_type, jl_any_type, jl_any_type, jl_any_type, // properties jl_any_type, jl_any_type, jl_any_type, jl_any_type, - jl_any_type, jl_any_type, jl_any_type, jl_any_type, - jl_any_type, jl_any_type); - jl_datatype_type->abstract = 0; - // NOTE: types are not actually mutable, but we want to ensure they are heap-allocated with stable addresses - jl_datatype_type->mutabl = 1; + jl_any_type, jl_any_type, jl_any_type); jl_datatype_type->ninitialized = 3; jl_precompute_memoized_dt(jl_datatype_type, 1); - jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core); + jl_typename_type->name = jl_new_typename_in(jl_symbol("TypeName"), core, 0, 1); jl_typename_type->name->wrapper = (jl_value_t*)jl_typename_type; jl_typename_type->name->mt = jl_nonfunction_mt; jl_typename_type->super = jl_any_type; jl_typename_type->parameters = jl_emptysvec; - jl_typename_type->name->names = jl_perm_symsvec(9, "name", "module", + jl_typename_type->name->names = jl_perm_symsvec(13, "name", "module", "names", "wrapper", "cache", "linearcache", - "hash", "mt", "partial"); - jl_typename_type->types = jl_svec(9, jl_symbol_type, jl_any_type, jl_simplevector_type, + "hash", "abstract", "mutable", "references_self", "mayinlinealloc", + "mt", "partial"); + jl_typename_type->types = jl_svec(13, jl_symbol_type, jl_any_type, jl_simplevector_type, jl_type_type, jl_simplevector_type, jl_simplevector_type, - jl_any_type, jl_methtable_type, jl_any_type); - jl_typename_type->abstract = 0; - jl_typename_type->mutabl = 1; + jl_any_type, jl_any_type, jl_any_type, jl_any_type, jl_any_type, + jl_methtable_type, jl_any_type); jl_typename_type->ninitialized = 2; jl_precompute_memoized_dt(jl_typename_type, 1); - jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core); + jl_methtable_type->name = jl_new_typename_in(jl_symbol("MethodTable"), core, 0, 1); jl_methtable_type->name->wrapper = (jl_value_t*)jl_methtable_type; jl_methtable_type->name->mt = jl_nonfunction_mt; jl_methtable_type->super = jl_any_type; @@ -1865,12 +2025,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_any_type/*module*/, jl_any_type/*any vector*/, jl_any_type/*long*/, jl_any_type/*int32*/, jl_any_type/*uint8*/, jl_any_type/*uint8*/); - jl_methtable_type->abstract = 0; - jl_methtable_type->mutabl = 1; jl_methtable_type->ninitialized = 5; jl_precompute_memoized_dt(jl_methtable_type, 1); - jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core); + jl_symbol_type->name = jl_new_typename_in(jl_symbol("Symbol"), core, 0, 1); jl_symbol_type->name->wrapper = (jl_value_t*)jl_symbol_type; jl_symbol_type->name->mt = jl_nonfunction_mt; jl_symbol_type->super = jl_any_type; @@ -1878,20 +2036,16 @@ void jl_init_types(void) JL_GC_DISABLED jl_symbol_type->name->names = jl_emptysvec; jl_symbol_type->types = jl_emptysvec; jl_symbol_type->size = 0; - jl_symbol_type->abstract = 0; - jl_symbol_type->mutabl = 1; jl_symbol_type->ninitialized = 0; jl_precompute_memoized_dt(jl_symbol_type, 1); - jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core); + jl_simplevector_type->name = jl_new_typename_in(jl_symbol("SimpleVector"), core, 0, 1); jl_simplevector_type->name->wrapper = (jl_value_t*)jl_simplevector_type; jl_simplevector_type->name->mt = jl_nonfunction_mt; jl_simplevector_type->super = jl_any_type; jl_simplevector_type->parameters = jl_emptysvec; jl_simplevector_type->name->names = jl_emptysvec; jl_simplevector_type->types = jl_emptysvec; - jl_simplevector_type->abstract = 0; - jl_simplevector_type->mutabl = 1; jl_simplevector_type->ninitialized = 0; jl_precompute_memoized_dt(jl_simplevector_type, 1); @@ -2426,12 +2580,13 @@ void jl_init_types(void) JL_GC_DISABLED jl_svecset(jl_datatype_type->types, 14, jl_bool_type); jl_svecset(jl_datatype_type->types, 15, jl_bool_type); jl_svecset(jl_datatype_type->types, 16, jl_bool_type); - jl_svecset(jl_datatype_type->types, 17, jl_bool_type); - jl_svecset(jl_datatype_type->types, 18, jl_bool_type); - jl_svecset(jl_datatype_type->types, 19, jl_bool_type); jl_svecset(jl_typename_type->types, 1, jl_module_type); - jl_svecset(jl_typename_type->types, 6, jl_long_type); jl_svecset(jl_typename_type->types, 3, jl_type_type); + jl_svecset(jl_typename_type->types, 6, jl_long_type); + jl_svecset(jl_typename_type->types, 7, jl_bool_type); + jl_svecset(jl_typename_type->types, 8, jl_bool_type); + jl_svecset(jl_typename_type->types, 9, jl_bool_type); + jl_svecset(jl_typename_type->types, 10, jl_bool_type); jl_svecset(jl_methtable_type->types, 4, jl_long_type); jl_svecset(jl_methtable_type->types, 6, jl_module_type); jl_svecset(jl_methtable_type->types, 7, jl_array_any_type); @@ -2462,10 +2617,10 @@ void jl_init_types(void) JL_GC_DISABLED jl_compute_field_offsets(jl_symbol_type); // override the preferred layout for a couple types - jl_lineinfonode_type->isinlinealloc = 0; // FIXME: assumed to be a pointer by codegen + jl_lineinfonode_type->name->mayinlinealloc = 0; // FIXME: assumed to be a pointer by codegen // It seems like we probably usually end up needing the box for kinds (used in an Any context)--but is that true? - jl_uniontype_type->isinlinealloc = 0; - jl_unionall_type->isinlinealloc = 0; + jl_uniontype_type->name->mayinlinealloc = 0; + jl_unionall_type->name->mayinlinealloc = 0; } #ifdef __cplusplus diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 0b3f52ca61647..f68e0d2c4ebb5 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -4,24 +4,24 @@ (define (add-dots ops) (append! ops (map (lambda (op) (symbol (string "." op))) ops))) (define prec-assignment - (append! (add-dots '(= += -= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻= ≔ ⩴ ≕)) + (append! (add-dots '(= += -= −= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻= ≔ ⩴ ≕)) (add-dots '(~)) '(:= $=))) ;; comma - higher than assignment outside parentheses, lower when inside (define prec-pair (add-dots '(=>))) (define prec-conditional '(?)) (define prec-arrow (add-dots '(← → ↔ ↚ ↛ ↞ ↠ ↢ ↣ ↦ ↤ ↮ ⇎ ⇍ ⇏ ⇐ ⇒ ⇔ ⇴ ⇶ ⇷ ⇸ ⇹ ⇺ ⇻ ⇼ ⇽ ⇾ ⇿ ⟵ ⟶ ⟷ ⟹ ⟺ ⟻ ⟼ ⟽ ⟾ ⟿ ⤀ ⤁ ⤂ ⤃ ⤄ ⤅ ⤆ ⤇ ⤌ ⤍ ⤎ ⤏ ⤐ ⤑ ⤔ ⤕ ⤖ ⤗ ⤘ ⤝ ⤞ ⤟ ⤠ ⥄ ⥅ ⥆ ⥇ ⥈ ⥊ ⥋ ⥎ ⥐ ⥒ ⥓ ⥖ ⥗ ⥚ ⥛ ⥞ ⥟ ⥢ ⥤ ⥦ ⥧ ⥨ ⥩ ⥪ ⥫ ⥬ ⥭ ⥰ ⧴ ⬱ ⬰ ⬲ ⬳ ⬴ ⬵ ⬶ ⬷ ⬸ ⬹ ⬺ ⬻ ⬼ ⬽ ⬾ ⬿ ⭀ ⭁ ⭂ ⭃ ⭄ ⭇ ⭈ ⭉ ⭊ ⭋ ⭌ ← → ⇜ ⇝ ↜ ↝ ↩ ↪ ↫ ↬ ↼ ↽ ⇀ ⇁ ⇄ ⇆ ⇇ ⇉ ⇋ ⇌ ⇚ ⇛ ⇠ ⇢ ↷ ↶ ↺ ↻ --> <-- <-->))) -(define prec-lazy-or '(|\|\||)) -(define prec-lazy-and '(&&)) +(define prec-lazy-or (add-dots '(|\|\||))) +(define prec-lazy-and (add-dots '(&&))) (define prec-comparison (append! '(in isa) - (add-dots '(> < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁ ≃ ≂ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱ ⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫ ⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⋿ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯ ⩰ ⩱ ⩲ ⩳ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔ ⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸ ⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸ ⫹ ⫺ ⊢ ⊣ ⟂ <: >:)))) + (add-dots '(> < >= ≥ <= ≤ == === ≡ != ≠ !== ≢ ∈ ∉ ∋ ∌ ⊆ ⊈ ⊂ ⊄ ⊊ ∝ ∊ ∍ ∥ ∦ ∷ ∺ ∻ ∽ ∾ ≁ ≃ ≂ ≄ ≅ ≆ ≇ ≈ ≉ ≊ ≋ ≌ ≍ ≎ ≐ ≑ ≒ ≓ ≖ ≗ ≘ ≙ ≚ ≛ ≜ ≝ ≞ ≟ ≣ ≦ ≧ ≨ ≩ ≪ ≫ ≬ ≭ ≮ ≯ ≰ ≱ ≲ ≳ ≴ ≵ ≶ ≷ ≸ ≹ ≺ ≻ ≼ ≽ ≾ ≿ ⊀ ⊁ ⊃ ⊅ ⊇ ⊉ ⊋ ⊏ ⊐ ⊑ ⊒ ⊜ ⊩ ⊬ ⊮ ⊰ ⊱ ⊲ ⊳ ⊴ ⊵ ⊶ ⊷ ⋍ ⋐ ⋑ ⋕ ⋖ ⋗ ⋘ ⋙ ⋚ ⋛ ⋜ ⋝ ⋞ ⋟ ⋠ ⋡ ⋢ ⋣ ⋤ ⋥ ⋦ ⋧ ⋨ ⋩ ⋪ ⋫ ⋬ ⋭ ⋲ ⋳ ⋴ ⋵ ⋶ ⋷ ⋸ ⋹ ⋺ ⋻ ⋼ ⋽ ⋾ ⋿ ⟈ ⟉ ⟒ ⦷ ⧀ ⧁ ⧡ ⧣ ⧤ ⧥ ⩦ ⩧ ⩪ ⩫ ⩬ ⩭ ⩮ ⩯ ⩰ ⩱ ⩲ ⩳ ⩵ ⩶ ⩷ ⩸ ⩹ ⩺ ⩻ ⩼ ⩽ ⩾ ⩿ ⪀ ⪁ ⪂ ⪃ ⪄ ⪅ ⪆ ⪇ ⪈ ⪉ ⪊ ⪋ ⪌ ⪍ ⪎ ⪏ ⪐ ⪑ ⪒ ⪓ ⪔ ⪕ ⪖ ⪗ ⪘ ⪙ ⪚ ⪛ ⪜ ⪝ ⪞ ⪟ ⪠ ⪡ ⪢ ⪣ ⪤ ⪥ ⪦ ⪧ ⪨ ⪩ ⪪ ⪫ ⪬ ⪭ ⪮ ⪯ ⪰ ⪱ ⪲ ⪳ ⪴ ⪵ ⪶ ⪷ ⪸ ⪹ ⪺ ⪻ ⪼ ⪽ ⪾ ⪿ ⫀ ⫁ ⫂ ⫃ ⫄ ⫅ ⫆ ⫇ ⫈ ⫉ ⫊ ⫋ ⫌ ⫍ ⫎ ⫏ ⫐ ⫑ ⫒ ⫓ ⫔ ⫕ ⫖ ⫗ ⫘ ⫙ ⫷ ⫸ ⫹ ⫺ ⊢ ⊣ ⟂ ⫪ ⫫ <: >:)))) (define prec-pipe< '(|.<\|| |<\||)) (define prec-pipe> '(|.\|>| |\|>|)) (define prec-colon (append! '(: |..|) (add-dots '(… ⁝ ⋮ ⋱ ⋰ ⋯)))) (define prec-plus (append! '($) - (add-dots '(+ - ¦ |\|| ⊕ ⊖ ⊞ ⊟ |++| ∪ ∨ ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣)))) -(define prec-times (add-dots '(* / ⌿ ÷ % & ⋅ ∘ × |\\| ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗ ⨟))) + (add-dots '(+ - − ¦ |\|| ⊕ ⊖ ⊞ ⊟ |++| ∪ ∨ ⊔ ± ∓ ∔ ∸ ≏ ⊎ ⊻ ⊽ ⋎ ⋓ ⧺ ⧻ ⨈ ⨢ ⨣ ⨤ ⨥ ⨦ ⨧ ⨨ ⨩ ⨪ ⨫ ⨬ ⨭ ⨮ ⨹ ⨺ ⩁ ⩂ ⩅ ⩊ ⩌ ⩏ ⩐ ⩒ ⩔ ⩖ ⩗ ⩛ ⩝ ⩡ ⩢ ⩣)))) +(define prec-times (add-dots '(* / ⌿ ÷ % & · · ⋅ ∘ × |\\| ∩ ∧ ⊗ ⊘ ⊙ ⊚ ⊛ ⊠ ⊡ ⊓ ∗ ∙ ∤ ⅋ ≀ ⊼ ⋄ ⋆ ⋇ ⋉ ⋊ ⋋ ⋌ ⋏ ⋒ ⟑ ⦸ ⦼ ⦾ ⦿ ⧶ ⧷ ⨇ ⨰ ⨱ ⨲ ⨳ ⨴ ⨵ ⨶ ⨷ ⨸ ⨻ ⨼ ⨽ ⩀ ⩃ ⩄ ⩋ ⩍ ⩎ ⩑ ⩓ ⩕ ⩘ ⩚ ⩜ ⩞ ⩟ ⩠ ⫛ ⊍ ▷ ⨝ ⟕ ⟖ ⟗ ⨟))) (define prec-rational (add-dots '(//))) (define prec-bitshift (add-dots '(<< >> >>>))) ;; `where` @@ -101,6 +101,8 @@ (define unary-op? (Set unary-ops)) +(define radical-op? (Set '(√ ∛ ∜))) + ; operators that are both unary and binary (define unary-and-binary-ops (append! '($ & ~) (add-dots '(+ - ⋆ ± ∓)))) @@ -109,8 +111,8 @@ ; operators that are special forms, not function names (define syntactic-operators - (append! (add-dots '(= += -= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻=)) - '(:= $= && |\|\|| |.| ... ->))) + (append! (add-dots '(&& |\|\|| = += -= *= /= //= |\\=| ^= ÷= %= <<= >>= >>>= |\|=| &= ⊻=)) + '(:= $= |.| ... ->))) (define syntactic-unary-operators '($ & |::|)) (define syntactic-op? (Set syntactic-operators)) @@ -232,7 +234,7 @@ (if (and (eqv? c0 #\*) (eqv? (peek-char port) #\*)) (error "use \"x^y\" instead of \"x**y\" for exponentiation, and \"x...\" instead of \"**x\" for splatting.")) (if (or (eof-object? (peek-char port)) (not (op-or-sufchar? (peek-char port)))) - (symbol (string c0)) ; 1-char operator + (string->normsymbol (string c0)) ; 1-char operator (let ((str (let loop ((str (string c0)) (c (peek-char port)) (in-suffix? #f)) @@ -265,7 +267,7 @@ (loop newop (peek-char port) sufchar?)) str)) str)))))) - (string->symbol str)))) + (string->normsymbol str)))) (define (accum-digits c pred port _-digit-sep) (let loop ((str '()) @@ -375,13 +377,17 @@ (and (eq? pred char-hex?) ispP) (memv c '(#\e #\E #\f))) (begin (read-char port) - (let ((d (peek-char port))) + (let* ((d (peek-char port)) + (is-minus-sign (or (eqv? d #\-) (eqv? d #\u2212)))) (if (and (not (eof-object? d)) - (or (char-numeric? d) (eqv? d #\+) (eqv? d #\-))) + (or (char-numeric? d) (eqv? d #\+) is-minus-sign)) (begin (set! is-float32-literal (eqv? c #\f)) (set! is-hex-float-literal ispP) (write-char c str) - (write-char (read-char port) str) + (if is-minus-sign + (begin (read-char port) + (write-char #\- str)) + (write-char (read-char port) str)) (read-digs #t #f) (disallow-dot)) (io.ungetc port c))))) @@ -973,7 +979,7 @@ (not (memv t '(#\( #\[ #\{)))) ) (not (ts:space? s)) - (not (operator? t)) + (or (not (operator? t)) (radical-op? t)) (not (closing-token? t)) (not (newline? t)) (or (and (not (string? expr)) (not (eqv? t #\"))) @@ -996,7 +1002,7 @@ (begin #;(if (and (number? ex) (= ex 0)) (error "juxtaposition with literal \"0\"")) - (let ((next (parse-factor s))) + (let ((next (if (radical-op? next) (parse-unary s) (parse-factor s)))) (loop `(call * ,ex ,next) (cons next args)))) (if (length= args 1) @@ -1216,6 +1222,8 @@ (loop (list* 'typed_vcat ex (cdr al)))) ((comprehension) (loop (list* 'typed_comprehension ex (cdr al)))) + ((ncat) + (loop (list* 'typed_ncat ex (cdr al)))) (else (error "unknown parse-cat result (internal error)"))))))) ((|.|) (disallow-space s ex t) @@ -1847,60 +1855,125 @@ (take-token s)) `(comprehension ,gen)))) -(define (parse-matrix s first closer gotnewline last-end-symbol) - (define (fix head v) (cons head (reverse v))) - (define (update-outer v outer) - (cond ((null? v) outer) - ((null? (cdr v)) (cons (car v) outer)) - (else (cons (fix 'row v) outer)))) - (define semicolon (eqv? (peek-token s) #\;)) +(define (parse-array s first closer gotnewline last-end-symbol) + (define (fix head v) + (cons head (reverse v))) + (define (unfixrow l) + (cons (reverse (cdaar l)) (if (and (null? (cdar l)) (null? (cdr l))) + '() + (cons (cdar l) (cdr l))))) + (define (fixcat head d v) + (cons head (cons d (reverse v)))) + (define (ncons a n l) + (if (< n 1) + l + (ncons a (1- n) (cons a l)))) + (define (fix-level ah n) + (if (length= ah 1) + (car ah) + (if (= n 1) + (fix 'row ah) + (fixcat 'nrow (1- n) ah)))) + (define (collapse-level n l i) + (if (> n 0) + (let* ((lhfix (fix-level (car l) i)) + (lnew (if (null? (cdr l)) + (list (list lhfix)) + (cons (cons lhfix (cadr l)) (cddr l))))) + (collapse-level (1- n) lnew (1+ i))) + l)) + (define (parse-array-inner s a is-row-first semicolon-count max-level closer gotnewline gotlinesep) + (define (process-semicolon next) + (set! semicolon-count (1+ semicolon-count)) + (set! max-level (max max-level semicolon-count)) + (if (and (null? is-row-first) (= semicolon-count 2) (not (eqv? next #\;))) + ; finding ;; that isn't a row-separator makes it column-first + (set! is-row-first #f)) + (set! a (collapse-level 1 a semicolon-count))) + (define (restore-lower-dim-lists next) + (if (and (not gotlinesep) (not (memv next (list #\; 'for closer #\newline)))) + (set! a (ncons '() semicolon-count a)))) + (let ((t (if (or gotnewline (eqv? (peek-token s) #\newline)) + #\newline + (require-token s)))) + (if (eqv? t closer) + (begin + (take-token s) + (set! a (collapse-level (- max-level semicolon-count) a (1+ semicolon-count))) + (cond ((= max-level 0) + (if (length= (car a) 1) + (fix 'vect (car a)) + (fix 'hcat (car a)))) + ((= max-level 1) + (fix 'vcat (car a))) + (else + (fixcat 'ncat max-level (car a))))) + (case t + ((#\newline) + (or gotnewline (take-token s)) + (let ((next (peek-token s))) + (if (and (> semicolon-count 0) (eqv? next #\;)) + (error (string "semicolons may appear before or after a line break in an array expression, " + "but not both"))) + (if (and (= semicolon-count 0) + (not (memv next (list #\; 'for closer #\newline)))) + ; treat a linebreak prior to a value as a semicolon if no previous semicolons observed + (process-semicolon next)) + (restore-lower-dim-lists next) + (parse-array-inner s a is-row-first semicolon-count max-level closer #f gotlinesep))) + ((#\;) + (or gotnewline (take-token s)) + (if (and (> semicolon-count 0) (ts:space? s)) ; disallow [a; ;b] + (error "multiple semicolons must be adjacent in an array expression")) + (let ((next (peek-token s))) + (let ((is-line-sep + (if (and (not (null? is-row-first)) is-row-first (= semicolon-count 1)) + (cond ((eqv? next #\newline) #t) ; [a b ;;... + ((not (or (eof-object? next) (eqv? next #\;))) ; [a b ;;... + (error (string "cannot mix space and ;; separators in an array expression, " + "except to wrap a line"))) + (else #f)) ; [a b ;; for REPL, [a ;;... + #f))) ; [a ; b ;; c ; d... + (if is-line-sep + (begin (set! a (unfixrow a)) + (set! max-level + (if (null? (cdr a)) + 0 ; no prior single semicolon + max-level))) + (begin (process-semicolon next) + (restore-lower-dim-lists next))) + (parse-array-inner s a is-row-first semicolon-count max-level closer #f is-line-sep)))) + ((#\,) + (error "unexpected comma in array expression")) + ((#\] #\}) + (error (string "unexpected \"" t "\""))) + ((for) + (if (and (length= (car a) 1) + (null? (cdr a))) + (begin ;; if we get here, there must have been some kind of space or separator + ;;(expect-space-before s 'for) + (take-token s) + (parse-comprehension s (caar a) closer)) + (error "invalid comprehension syntax"))) + (else + (if (and (not gotlinesep) (pair? (car a)) (not (ts:space? s))) + (error (string "expected \"" closer "\" or separator in arguments to \"" + (if (eqv? closer #\]) #\[ #\{) " " closer + "\"; got \"" + (deparse (caar a)) t "\""))) + (let ((u (parse-eq* s))) + (set! a (cons (cons u (car a)) (cdr a))) + (if (= (length (car a)) 2) + ; at least 2 elements separated by space found [a b...], [a; b c...] + (if (null? is-row-first) + (set! is-row-first #t) + (if (not is-row-first) + (error (string "cannot mix space and \";;\" separators in an array expression, " + "except to wrap a line")))))) + (parse-array-inner s a is-row-first 0 max-level closer #f #f)))))) ;; if a [ ] expression is a cat expression, `end` is not special (with-bindings ((end-symbol last-end-symbol)) - (let loop ((vec (list first)) - (outer '())) - (let ((t (if (or (eqv? (peek-token s) #\newline) gotnewline) - #\newline - (require-token s)))) - (if (eqv? t closer) - (begin (take-token s) - (if (pair? outer) - (fix 'vcat (update-outer vec outer)) - (if (or (null? vec) (null? (cdr vec))) - (fix 'vect vec) ; [x] => (vect x) - (fix 'hcat vec)))) ; [x y] => (hcat x y) - (case t - ((#\;) - (take-token s) - (if (eqv? (peek-token s) #\;) - (parser-depwarn s (string "Multiple semicolons in an array concatenation expression currently have no effect, " - "but may have a new meaning in a future version of Julia.") - "Please remove extra semicolons to preserve forward compatibility e.g. [1;;3] => [1;3].")) - (set! gotnewline #f) - (loop '() (update-outer vec outer))) - ((#\newline) - (or gotnewline (take-token s)) - (set! gotnewline #f) - (loop '() (update-outer vec outer))) - ((#\,) - (error "unexpected comma in matrix expression")) - ((#\] #\}) - (error (string "unexpected \"" t "\""))) - ((for) - (if (and (not semicolon) - (length= outer 1) - (null? vec)) - (begin ;; if we get here, there must have been some kind of space or separator - ;;(expect-space-before s 'for) - (take-token s) - (parse-comprehension s (car outer) closer)) - (error "invalid comprehension syntax"))) - (else - (if (and (pair? vec) (not (ts:space? s))) - (error (string "expected \"" closer "\" or separator in arguments to \"" - (if (eqv? closer #\]) #\[ #\{) " " closer - "\"; got \"" - (deparse (car vec)) t "\""))) - (loop (cons (parse-eq* s) vec) outer)))))))) + (parse-array-inner s (list (list first)) '() 0 0 closer gotnewline #f))) (define (expect-space-before s t) (if (not (ts:space? s)) @@ -1927,9 +2000,9 @@ (take-token s) (if (memv (peek-token s) (list #\, closer)) (parse-vect s first closer) - (parse-matrix s first closer #t last-end-symbol))) + (parse-array s first closer #t last-end-symbol))) (else - (parse-matrix s first closer #f last-end-symbol))))))) + (parse-array s first closer #f last-end-symbol))))))) (define (kw-to-= e) (if (kwarg? e) (cons '= (cdr e)) e)) (define (=-to-kw e) (if (assignment? e) (cons 'kw (cdr e)) e)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 6dfe3c514c75d..49404891267da 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -431,7 +431,9 @@ (body (blockify body)) (ftype (decl-type (car pargl))) ;; 1-element list of vararg argument, or empty if none - (vararg (let ((l (if (null? pargl) '() (last pargl)))) + (vararg (let* ((l (if (null? pargl) '() (last pargl))) + ;; handle vararg with default value + (l (if (kwarg? l) (cadr l) l))) (if (or (vararg? l) (varargexpr? l)) (list l) '()))) ;; positional args with vararg @@ -1599,7 +1601,7 @@ ,(expand-update-operator op op= (car e) rhs T)))) (else (if (and (pair? lhs) (eq? op= '=) - (not (memq (car lhs) '(|.| tuple vcat typed_hcat typed_vcat)))) + (not (memq (car lhs) '(|.| tuple vcat ncat typed_hcat typed_vcat typed_ncat)))) (error (string "invalid assignment location \"" (deparse lhs) "\""))) (expand-update-operator- op op= lhs rhs declT)))) @@ -1804,6 +1806,10 @@ e)))) ((and (pair? e) (eq? (car e) 'comparison)) (dot-to-fuse (expand-compare-chain (cdr e)) top)) + ((and (pair? e) (eq? (car e) '.&&)) + (make-fuse '(top andand) (cdr e))) + ((and (pair? e) (eq? (car e) '|.\|\||)) + (make-fuse '(top oror) (cdr e))) (else e))) (let ((e (dot-to-fuse rhs #t)) ; an expression '(fuse func args) if expr is a dot call (lhs-view (ref-to-view lhs))) ; x[...] expressions on lhs turn in to view(x, ...) to update x in-place @@ -1972,6 +1978,113 @@ ,@(apply append rows)))) `(call ,@vcat ,@a)))))) +(define (expand-ncat e (hvncat '((top hvncat)))) + (define (is-row a) (and (pair? a) + (or (eq? (car a) 'row) + (eq? (car a) 'nrow)))) + (define (is-1d a) (not (any is-row a))) + (define (sum xs) (foldl + 0 xs)) + (define (get-shape a is-row-first d) + (define (zip xss) (apply map list xss)) + (define (get-next x) + (cond ((or (not (is-row x)) + (and (eq? (car x) 'nrow) (> d (1+ (cadr x)))) + (and (eq? (car x) 'row) (> d 1))) + (list x)) + ((eq? (car x) 'nrow) (cddr x)) + (else (cdr x)))) + ; describe the shape of the concatenation + (cond ((or (= d 0) + (and (not is-row-first) (= d 1))) + (length a)) + ((and is-row-first (= d 3)) + (get-shape a is-row-first (1- d))) + (else + (let ((ashape + (map (lambda (x) + (get-shape (get-next x) is-row-first (1- d))) + a))) + (if (pair? (car ashape)) + (let ((zipashape (zip ashape))) + (cons (sum (car zipashape)) + (cons (car zipashape) + (map (lambda (x) + (apply append x)) + (cdr zipashape))))) + (list (sum ashape) ashape)))))) + (define (get-dims a is-row-first d) + (cond ((and (< d 2) (not (is-row (car a)))) + (list (length a))) + ((= d 1) + (list (car (get-dims (cdar a) is-row-first 0)) (length a))) + ((and (= d 3) is-row-first) + (get-dims a is-row-first 2)) + (else + (let ((anext (if (and (pair? (car a)) + (eq? (caar a) 'nrow) + (= d (1+ (cadar a)))) + (cddar a) + (list (car a))))) + (cons (length a) (get-dims anext is-row-first (1- d))))))) + (define (is-balanced s) + ; determine whether there are exactly the same number of elements along each axis + (= 0 (sum (map (lambda (x y) + (sum (map (lambda (z) + (- z y)) + x))) + (cdr s) (map car (cdr s)))))) + (define (hasrows-flatten a) + ; (car ) stores if a row was observed + (foldl (lambda (x y) + (let ((r (car y)) + (yt (cdr y))) + (if (is-row x) + (if (eq? (car x) 'nrow) + (let* ((raflat (append (hasrows-flatten (cddr x)))) + (aflat (cdr raflat)) + (rinner (car raflat)) + (r (if (null? (or r rinner)) + (and r rinner) + r))) + (if (and (not (null? r)) + (or (null? rinner) (and (not r) rinner)) + (and (= (cadr x) 2) r)) + (error "cannot mix space and ;; separators in an array expression, except to wrap a line")) + (cons (if (and (= (cadr x) 2) (null? r)) + #f + r) + (append aflat yt))) + (if (or (null? r) r) + (cons #t (append (reverse (cdr x)) yt)) + (error "cannot mix space and ;; separators in an array expression, except to wrap a line"))) + (cons r (cons x yt))))) + (list '()) a)) + (define (tf a) (if a '(true) '(false))) + (define (tuplize s) + (cons 'tuple (reverse (map (lambda (x) + (cons 'tuple x)) + (cons (list (car s)) (cdr s)))))) + (let* ((d (cadr e)) + (a (cddr e)) + (raflat (hasrows-flatten a)) + (r (car raflat)) + (is-row-first (if (null? r) #f r)) + (aflat (reverse (cdr raflat)))) + (if (any assignment? aflat) + (error (string "misplaced assignment statement in \"" (deparse e) "\""))) + (if (has-parameters? aflat) + (error "unexpected parameters in array expression")) + (expand-forms + (if (is-1d a) + `(call ,@hvncat ,d ,@aflat) + (if (any vararg? aflat) + (error (string "Splatting ... in an hvncat with multiple dimensions is not supported")) + (let ((shape (get-shape a is-row-first d))) + (if (is-balanced shape) + (let ((dims `(tuple ,@(reverse (get-dims a is-row-first d))))) + `(call ,@hvncat ,dims ,(tf is-row-first) ,@aflat)) + `(call ,@hvncat ,(tuplize shape) ,(tf is-row-first) ,@aflat)))))))) + (define (expand-property-destruct lhss x) (if (not (length= lhss 1)) (error (string "invalid assignment location \"" (deparse lhs) "\""))) @@ -2032,22 +2145,40 @@ (- n 1) n)) n)) - (st (gensy))) + (st (gensy)) + (end '())) `(block ,@(if (> n 0) `((local ,st)) '()) ,@ini ,@(map (lambda (i lhs) - (expand-forms - (if (vararg? lhs) - `(= ,(cadr lhs) (call (top rest) ,xx ,@(if (eq? i 0) '() `(,st)))) - (lower-tuple-assignment - (if (= i (- n 1)) - (list lhs) - (list lhs st)) - `(call (top indexed_iterate) - ,xx ,(+ i 1) ,@(if (eq? i 0) '() `(,st))))))) + (let ((lhs- (cond ((or (symbol? lhs) (ssavalue? lhs)) + lhs) + ((vararg? lhs) + (let ((lhs- (cadr lhs))) + (if (or (symbol? lhs-) (ssavalue? lhs-)) + lhs + `(|...| ,(if (eventually-call? lhs-) + (gensy) + (make-ssavalue)))))) + ;; can't use ssavalues if it's a function definition + ((eventually-call? lhs) (gensy)) + (else (make-ssavalue))))) + (if (not (eq? lhs lhs-)) + (if (vararg? lhs) + (set! end (cons (expand-forms `(= ,(cadr lhs) ,(cadr lhs-))) end)) + (set! end (cons (expand-forms `(= ,lhs ,lhs-)) end)))) + (expand-forms + (if (vararg? lhs-) + `(= ,(cadr lhs-) (call (top rest) ,xx ,@(if (eq? i 0) '() `(,st)))) + (lower-tuple-assignment + (if (= i (- n 1)) + (list lhs-) + (list lhs- st)) + `(call (top indexed_iterate) + ,xx ,(+ i 1) ,@(if (eq? i 0) '() `(,st)))))))) (iota n) lhss) + ,@(reverse end) (unnecessary ,xx)))))) ;; move an assignment into the last statement of a block to keep more statements at top level @@ -2125,6 +2256,11 @@ ;; e = (|.| f x) (expand-fuse-broadcast '() e))) + '.&& + (lambda (e) (expand-fuse-broadcast '() e)) + '|.\|\|| + (lambda (e) (expand-fuse-broadcast '() e)) + '.= (lambda (e) (expand-fuse-broadcast (cadr e) (caddr e))) @@ -2211,7 +2347,7 @@ (expand-tuple-destruct lhss x)))) ((typed_hcat) (error "invalid spacing in left side of indexed assignment")) - ((typed_vcat) + ((typed_vcat typed_ncat) (error "unexpected \";\" in left side of indexed assignment")) ((ref) ;; (= (ref a . idxs) rhs) @@ -2248,7 +2384,7 @@ `(block ,@(cdr e) (decl ,(car e) ,T) (= ,(car e) ,rhs)))))) - ((vcat) + ((vcat ncat) ;; (= (vcat . args) rhs) (error "use \"(a, b) = ...\" to assign multiple values")) (else @@ -2384,11 +2520,12 @@ 'string (lambda (e) (expand-forms - `(call (top string) ,@(map (lambda (s) - (if (and (pair? s) (eq? (car s) 'string)) - (cadr s) - s)) - (cdr e))))) + `(call (top string) + ,@(map (lambda (s) + (if (and (length= s 2) (eq? (car s) 'string) (string? (cadr s))) + (cadr s) + s)) + (cdr e))))) '|::| (lambda (e) @@ -2483,6 +2620,8 @@ 'vcat expand-vcat + 'ncat expand-ncat + 'typed_hcat (lambda (e) (if (any assignment? (cddr e)) @@ -2495,6 +2634,12 @@ (e (cdr e))) (expand-vcat e `((top typed_vcat) ,t) `((top typed_hvcat) ,t) `((top typed_hvcat_rows) ,t)))) + 'typed_ncat + (lambda (e) + (let ((t (cadr e)) + (e (cdr e))) + (expand-ncat e `((top typed_hvncat) ,t)))) + '|'| (lambda (e) (expand-forms `(call |'| ,(cadr e)))) 'generator @@ -4067,13 +4212,14 @@ f(x) = yt(x) (else #f))) (case (car e) ((call new splatnew foreigncall cfunction new_opaque_closure) + (define (atom-or-not-tuple-call? fptr) + (or (atom? fptr) + (not (tuple-call? fptr)))) (let* ((args (cond ((eq? (car e) 'foreigncall) ;; NOTE: 2nd to 5th arguments of ccall must be left in place ;; the 1st should be compiled if an atom. - (append (if (let ((fptr (cadr e))) - (or (atom? fptr) - (not (tuple-call? fptr)))) + (append (if (atom-or-not-tuple-call? (cadr e)) (compile-args (list (cadr e)) break-labels) (list (cadr e))) (list-head (cddr e) 4) @@ -4092,12 +4238,15 @@ f(x) = yt(x) (compile-args (list-head (cdr e) 4) break-labels) (list (append (butlast oc_method) (list lambda))) (compile-args (list-tail (cdr e) 5) break-labels)))) - ;; TODO: evaluate first argument to cglobal some other way + ;; NOTE: 1st argument to cglobal treated same as for ccall ((and (length> e 2) (or (eq? (cadr e) 'cglobal) (equal? (cadr e) '(outerref cglobal)))) - (list* (cadr e) (caddr e) - (compile-args (cdddr e) break-labels))) + (append (list (cadr e)) + (if (atom-or-not-tuple-call? (caddr e)) + (compile-args (list (caddr e)) break-labels) + (list (caddr e))) + (compile-args (cdddr e) break-labels))) (else (compile-args (cdr e) break-labels)))) (callex (cons (car e) args))) diff --git a/src/julia.expmap b/src/julia.expmap index d9d255cc8c547..5f03eccbfcad6 100644 --- a/src/julia.expmap +++ b/src/julia.expmap @@ -37,7 +37,6 @@ _IO_stdin_used; __ZN4llvm23createLowerSimdLoopPassEv; LLVMExtra*; - repl_entrypoint; /* freebsd */ environ; diff --git a/src/julia.h b/src/julia.h index 3b28558fcd695..1d9d735c10d06 100644 --- a/src/julia.h +++ b/src/julia.h @@ -429,6 +429,10 @@ typedef struct { jl_svec_t *cache; // sorted array jl_svec_t *linearcache; // unsorted array intptr_t hash; + uint8_t abstract; + uint8_t mutabl; + uint8_t references_self; + uint8_t mayinlinealloc; struct _jl_methtable_t *mt; jl_array_t *partial; // incomplete instantiations of this type } jl_typename_t; @@ -489,15 +493,12 @@ typedef struct _jl_datatype_t { int32_t size; // TODO: move to _jl_datatype_layout_t int32_t ninitialized; uint32_t hash; - uint8_t abstract; - uint8_t mutabl; // memoized properties uint8_t hasfreetypevars; // majority part of isconcrete computation uint8_t isconcretetype; // whether this type can have instances uint8_t isdispatchtuple; // aka isleaftupletype uint8_t isbitstype; // relevant query for C-api and type-parameters uint8_t zeroinit; // if one or more fields requires zero-initialization - uint8_t isinlinealloc; // if this is allocated inline uint8_t has_concrete_subtype; // If clear, no value will have this datatype uint8_t cached_by_hash; // stored in hash-based set cache (instead of linear cache) } jl_datatype_t; @@ -838,7 +839,8 @@ typedef enum { JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t); -JL_DLLEXPORT void jl_gc_add_finalizer(jl_value_t *v, jl_function_t *f); +JL_DLLEXPORT void jl_gc_add_finalizer(jl_value_t *v, jl_function_t *f) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_gc_add_ptr_finalizer(jl_ptls_t ptls, jl_value_t *v, void *f) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_finalize(jl_value_t *o); JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value); JL_DLLEXPORT jl_value_t *jl_gc_alloc_0w(void); @@ -1046,7 +1048,6 @@ STATIC_INLINE jl_value_t *jl_field_type_concrete(jl_datatype_t *st JL_PROPAGATES #define jl_datatype_align(t) (((jl_datatype_t*)t)->layout->alignment) #define jl_datatype_nbits(t) ((((jl_datatype_t*)t)->size)*8) #define jl_datatype_nfields(t) (((jl_datatype_t*)(t))->layout->nfields) -#define jl_datatype_isinlinealloc(t) (((jl_datatype_t *)(t))->isinlinealloc) JL_DLLEXPORT void *jl_symbol_name(jl_sym_t *s); // inline version with strong type check to detect typos in a `->name` chain @@ -1135,10 +1136,10 @@ static inline int jl_is_layout_opaque(const jl_datatype_layout_t *l) JL_NOTSAFEP #define jl_is_svec(v) jl_typeis(v,jl_simplevector_type) #define jl_is_simplevector(v) jl_is_svec(v) #define jl_is_datatype(v) jl_typeis(v,jl_datatype_type) -#define jl_is_mutable(t) (((jl_datatype_t*)t)->mutabl) -#define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->mutabl)) -#define jl_is_immutable(t) (!((jl_datatype_t*)t)->mutabl) -#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->mutabl)) +#define jl_is_mutable(t) (((jl_datatype_t*)t)->name->mutabl) +#define jl_is_mutable_datatype(t) (jl_is_datatype(t) && (((jl_datatype_t*)t)->name->mutabl)) +#define jl_is_immutable(t) (!((jl_datatype_t*)t)->name->mutabl) +#define jl_is_immutable_datatype(t) (jl_is_datatype(t) && (!((jl_datatype_t*)t)->name->mutabl)) #define jl_is_uniontype(v) jl_typeis(v,jl_uniontype_type) #define jl_is_typevar(v) jl_typeis(v,jl_tvar_type) #define jl_is_unionall(v) jl_typeis(v,jl_unionall_type) @@ -1207,7 +1208,7 @@ STATIC_INLINE int jl_is_primitivetype(void *v) JL_NOTSAFEPOINT STATIC_INLINE int jl_is_structtype(void *v) JL_NOTSAFEPOINT { return (jl_is_datatype(v) && - !((jl_datatype_t*)(v))->abstract && + !((jl_datatype_t*)(v))->name->abstract && !jl_is_primitivetype(v)); } @@ -1223,7 +1224,7 @@ STATIC_INLINE int jl_is_datatype_singleton(jl_datatype_t *d) JL_NOTSAFEPOINT STATIC_INLINE int jl_is_abstracttype(void *v) JL_NOTSAFEPOINT { - return (jl_is_datatype(v) && ((jl_datatype_t*)(v))->abstract); + return (jl_is_datatype(v) && ((jl_datatype_t*)(v))->name->abstract); } STATIC_INLINE int jl_is_array_type(void *t) JL_NOTSAFEPOINT @@ -1314,7 +1315,7 @@ STATIC_INLINE int jl_egal_(jl_value_t *a JL_MAYBE_UNROOTED, jl_value_t *b JL_MAY jl_datatype_t *dt = (jl_datatype_t*)jl_typeof(a); if (dt != (jl_datatype_t*)jl_typeof(b)) return 0; - if (dt->mutabl) { + if (dt->name->mutabl) { if (dt == jl_simplevector_type || dt == jl_string_type || dt == jl_datatype_type) return jl_egal__special(a, b, dt); return 0; @@ -1354,7 +1355,7 @@ STATIC_INLINE int jl_is_concrete_type(jl_value_t *v) JL_NOTSAFEPOINT JL_DLLEXPORT int jl_isa_compileable_sig(jl_tupletype_t *type, jl_method_t *definition); // type constructors -JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule); +JL_DLLEXPORT jl_typename_t *jl_new_typename_in(jl_sym_t *name, jl_module_t *inmodule, int abstract, int mutabl); JL_DLLEXPORT jl_tvar_t *jl_new_typevar(jl_sym_t *name, jl_value_t *lb, jl_value_t *ub); JL_DLLEXPORT jl_value_t *jl_instantiate_unionall(jl_unionall_t *u, jl_value_t *p); JL_DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_value_t **params, size_t n); @@ -1531,11 +1532,10 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_or_error(jl_module_t *m, jl_sym_t *var JL_DLLEXPORT jl_value_t *jl_module_globalref(jl_module_t *m, jl_sym_t *var); // get binding for assignment JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int error); -JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, - jl_sym_t *var); +JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var); -JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var) JL_NOTSAFEPOINT; -JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) JL_NOTSAFEPOINT; +JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var); +JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT int jl_is_const(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT jl_value_t *jl_get_global(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *var, jl_value_t *val JL_ROOTED_ARGUMENT); @@ -1549,7 +1549,7 @@ JL_DLLEXPORT void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t JL_DLLEXPORT void jl_module_import_as(jl_module_t *to, jl_module_t *from, jl_sym_t *s, jl_sym_t *asname); JL_DLLEXPORT void jl_module_export(jl_module_t *from, jl_sym_t *s); JL_DLLEXPORT int jl_is_imported(jl_module_t *m, jl_sym_t *s); -JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) JL_NOTSAFEPOINT; +JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var); JL_DLLEXPORT void jl_add_standard_imports(jl_module_t *m); STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) { @@ -1639,10 +1639,6 @@ typedef enum { JL_IMAGE_JULIA_HOME = 1, //JL_IMAGE_LIBJULIA = 2, } JL_IMAGE_SEARCH; -// this helps turn threading compilation mismatches into linker errors -#define julia_init julia_init__threading -#define jl_init jl_init__threading -#define jl_init_with_image jl_init_with_image__threading JL_DLLEXPORT const char *jl_get_libdir(void); JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel); @@ -1703,7 +1699,7 @@ enum JL_RTLD_CONSTANT { #define JL_RTLD_DEFAULT (JL_RTLD_LAZY | JL_RTLD_DEEPBIND) typedef void *jl_uv_libhandle; // compatible with dlopen (void*) / LoadLibrary (HMODULE) -JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned flags, int throw_err) JL_NOTSAFEPOINT; +JL_DLLEXPORT jl_uv_libhandle jl_load_dynamic_library(const char *fname, unsigned flags, int throw_err); JL_DLLEXPORT jl_uv_libhandle jl_dlopen(const char *filename, unsigned flags) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_dlclose(jl_uv_libhandle handle) JL_NOTSAFEPOINT; JL_DLLEXPORT int jl_dlsym(jl_uv_libhandle handle, const char *symbol, void ** value, int throw_err) JL_NOTSAFEPOINT; @@ -1965,7 +1961,8 @@ JL_DLLEXPORT jl_value_t *jl_stdout_obj(void) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_value_t *jl_stderr_obj(void) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) JL_NOTSAFEPOINT; JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT; +JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT; // deprecated // Mainly for debugging, use `void*` so that no type cast is needed in C++. JL_DLLEXPORT void jl_(void *jl_value) JL_NOTSAFEPOINT; @@ -1991,6 +1988,7 @@ typedef struct { int8_t code_coverage; int8_t malloc_log; int8_t opt_level; + int8_t opt_level_min; int8_t debug_level; int8_t check_bounds; int8_t depwarn; diff --git a/src/julia_gcext.h b/src/julia_gcext.h index 3ca729e722dba..6787dafb4b7ee 100644 --- a/src/julia_gcext.h +++ b/src/julia_gcext.h @@ -49,6 +49,8 @@ JL_DLLEXPORT jl_datatype_t *jl_new_foreign_type( int haspointers, int large); +JL_DLLEXPORT int jl_is_foreign_type(jl_datatype_t *dt); + JL_DLLEXPORT size_t jl_gc_max_internal_obj_size(void); JL_DLLEXPORT size_t jl_gc_external_obj_hdr_size(void); diff --git a/src/julia_internal.h b/src/julia_internal.h index 96b01f153760f..a07c8e8568ab6 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -499,6 +499,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_args_t fptr) JL_GC_DISABLED; int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); +int jl_has_fixed_layout(jl_datatype_t *t); +int jl_type_mappable_to_c(jl_value_t *ty); jl_svec_t *jl_outer_unionall_vars(jl_value_t *u); jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty); jl_value_t *jl_type_intersection_env(jl_value_t *a, jl_value_t *b, jl_svec_t **penv); @@ -532,6 +534,7 @@ void jl_foreach_reachable_mtable(void (*visit)(jl_methtable_t *mt, void *env), v void jl_init_main_module(void); int jl_is_submodule(jl_module_t *child, jl_module_t *parent) JL_NOTSAFEPOINT; jl_array_t *jl_get_loaded_modules(void); +int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree); jl_value_t *jl_toplevel_eval_flex(jl_module_t *m, jl_value_t *e, int fast, int expanded); @@ -563,7 +566,7 @@ void jl_compute_field_offsets(jl_datatype_t *st); jl_array_t *jl_new_array_for_deserialization(jl_value_t *atype, uint32_t ndims, size_t *dims, int isunboxed, int hasptr, int isunion, int elsz); void jl_module_run_initializer(jl_module_t *m); -jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_NOTSAFEPOINT; +jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var); void jl_binding_deprecation_warning(jl_module_t *m, jl_binding_t *b); extern jl_array_t *jl_module_init_order JL_GLOBALLY_ROOTED; extern htable_t jl_current_modules JL_GLOBALLY_ROOTED; @@ -676,8 +679,6 @@ void jl_init_int32_int64_cache(void); void jl_teardown_codegen(void); -void _julia_init(JL_IMAGE_SEARCH rel); - void jl_set_base_ctx(char *__stk); extern ssize_t jl_tls_offset; @@ -745,9 +746,9 @@ static inline void jl_set_gc_and_wait(void) void jl_gc_set_permalloc_region(void *start, void *end); JL_DLLEXPORT jl_value_t *jl_dump_method_asm(jl_method_instance_t *linfo, size_t world, - int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo); + int raw_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary); JL_DLLEXPORT void *jl_get_llvmf_defn(jl_method_instance_t *linfo, size_t world, char getwrapper, char optimize, const jl_cgparams_t params); -JL_DLLEXPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo); +JL_DLLEXPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant, const char *debuginfo, char binary); JL_DLLEXPORT jl_value_t *jl_dump_llvm_asm(void *F, const char* asm_variant, const char *debuginfo); JL_DLLEXPORT jl_value_t *jl_dump_function_ir(void *f, char strip_ir_metadata, char dump_module, const char *debuginfo); @@ -1043,10 +1044,9 @@ extern void *jl_crtdll_handle; extern void *jl_winsock_handle; #endif -void *jl_get_library_(const char *f_lib, int throw_err) JL_NOTSAFEPOINT; +void *jl_get_library_(const char *f_lib, int throw_err); #define jl_get_library(f_lib) jl_get_library_(f_lib, 1) -JL_DLLEXPORT void *jl_load_and_lookup(const char *f_lib, const char *f_name, - void **hnd) JL_NOTSAFEPOINT; +JL_DLLEXPORT void *jl_load_and_lookup(const char *f_lib, const char *f_name, void **hnd); JL_DLLEXPORT void *jl_lazy_load_and_lookup(jl_value_t *lib_val, const char *f_name); JL_DLLEXPORT jl_value_t *jl_get_cfunction_trampoline( jl_value_t *fobj, jl_datatype_t *result, htable_t *cache, jl_svec_t *fill, @@ -1115,7 +1115,6 @@ JL_DLLEXPORT jl_value_t *jl_ne_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_lt_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_le_float(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_fpiseq(jl_value_t *a, jl_value_t *b); -JL_DLLEXPORT jl_value_t *jl_fpislt(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_value_t *jl_not_int(jl_value_t *a); JL_DLLEXPORT jl_value_t *jl_and_int(jl_value_t *a, jl_value_t *b); @@ -1189,16 +1188,8 @@ void jl_smallintset_insert(jl_array_t **pcache, jl_value_t *parent, smallintset_ // -- typemap.c -- // -// a descriptor of a jl_typemap_t that gets -// passed around as self-documentation of the parameters of the type -struct jl_typemap_info { - int8_t unsorted; // whether this should be unsorted - jl_datatype_t **jl_contains; // the type that is being put in this -}; - void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent, - jl_typemap_entry_t *newrec, int8_t offs, - const struct jl_typemap_info *tparams); + jl_typemap_entry_t *newrec, int8_t offs); jl_typemap_entry_t *jl_typemap_alloc( jl_tupletype_t *type, jl_tupletype_t *simpletype, jl_svec_t *guardsigs, jl_value_t *newvalue, size_t min_world, size_t max_world); diff --git a/src/llvm-alloc-opt.cpp b/src/llvm-alloc-opt.cpp index 3bb11988b730e..ec7060bd10a5e 100644 --- a/src/llvm-alloc-opt.cpp +++ b/src/llvm-alloc-opt.cpp @@ -24,9 +24,7 @@ #include #include -#if JL_LLVM_VERSION >= 100000 #include -#endif #include "codegen_shared.h" #include "julia.h" @@ -64,13 +62,8 @@ static bool hasObjref(Type *ty) { if (auto ptrty = dyn_cast(ty)) return ptrty->getAddressSpace() == AddressSpace::Tracked; -#if JL_LLVM_VERSION >= 110000 if (isa(ty) || isa(ty)) return hasObjref(GetElementPtrInst::getTypeAtIndex(ty, (uint64_t)0)); -#else - if (auto seqty = dyn_cast(ty)) - return hasObjref(seqty->getElementType()); -#endif if (auto structty = dyn_cast(ty)) { for (auto elty: structty->elements()) { if (hasObjref(elty)) { @@ -1289,11 +1282,7 @@ void Optimizer::splitOnStack(CallInst *orig_inst) val = newload; } // TODO: should we use `load->clone()`, or manually copy any other metadata? -#if JL_LLVM_VERSION >= 100000 newload->setAlignment(load->getAlign()); -#else - newload->setAlignment(load->getAlignment()); -#endif // since we're moving heap-to-stack, it is safe to downgrade the atomic level to NotAtomic newload->setOrdering(AtomicOrdering::NotAtomic); load->replaceAllUsesWith(val); @@ -1333,11 +1322,7 @@ void Optimizer::splitOnStack(CallInst *orig_inst) newstore = builder.CreateStore(store_val, slot_gep(slot, offset, store_ty, builder)); } // TODO: should we use `store->clone()`, or manually copy any other metadata? -#if JL_LLVM_VERSION >= 100000 newstore->setAlignment(store->getAlign()); -#else - newstore->setAlignment(store->getAlignment()); -#endif // since we're moving heap-to-stack, it is safe to downgrade the atomic level to NotAtomic newstore->setOrdering(AtomicOrdering::NotAtomic); store->eraseFromParent(); @@ -1383,11 +1368,7 @@ void Optimizer::splitOnStack(CallInst *orig_inst) auto sub_size = std::min(slot.offset + slot.size, offset + size) - std::max(offset, slot.offset); // TODO: alignment computation -#if JL_LLVM_VERSION >= 100000 builder.CreateMemSet(ptr8, val_arg, sub_size, MaybeAlign(0)); -#else - builder.CreateMemSet(ptr8, val_arg, sub_size, 0); -#endif } call->eraseFromParent(); return; diff --git a/src/llvm-api.cpp b/src/llvm-api.cpp index db8f6f94dc781..56ec131556f98 100644 --- a/src/llvm-api.cpp +++ b/src/llvm-api.cpp @@ -16,9 +16,6 @@ #include #include #include -#if JL_LLVM_VERSION < 110000 -#include -#endif #include #include #include diff --git a/src/llvm-gc-invariant-verifier.cpp b/src/llvm-gc-invariant-verifier.cpp index c1386efef8e72..1c584f3852e9e 100644 --- a/src/llvm-gc-invariant-verifier.cpp +++ b/src/llvm-gc-invariant-verifier.cpp @@ -19,9 +19,6 @@ #include #include #include -#if JL_LLVM_VERSION < 110000 -#include -#endif #include #include #include diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 99ff45cf61815..ef30966b4cc5a 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -16,9 +16,6 @@ #include #include #include -#if JL_LLVM_VERSION < 110000 -#include -#endif #include #include #include @@ -29,9 +26,7 @@ #include #include -#if JL_LLVM_VERSION >= 100000 #include -#endif #include "codegen_shared.h" #include "julia.h" @@ -427,11 +422,7 @@ void TrackCompositeType(Type *T, std::vector &Idxs, std::vector= 110000 Type *ElT = GetElementPtrInst::getTypeAtIndex(T, Idx); -#else - Type *ElT = cast(T)->getTypeAtIndex(Idx); -#endif TrackCompositeType(ElT, Idxs, Numberings); Idxs.pop_back(); } @@ -576,11 +567,7 @@ Value *LateLowerGCFrame::MaybeExtractScalar(State &S, std::pair ValE Type *FinalT = ExtractValueInst::getIndexedType(V->getType(), IdxsNotVec); bool IsVector = isa(FinalT); PointerType *T = cast( -#if JL_LLVM_VERSION >= 110000 GetElementPtrInst::getTypeAtIndex(FinalT, Idxs.back())); -#else - cast(FinalT)->getTypeAtIndex(Idxs.back())); -#endif if (T->getAddressSpace() != AddressSpace::Tracked) { // if V isn't tracked, get the shadow def auto Numbers = NumberAllBase(S, V); @@ -1670,11 +1657,7 @@ State LateLowerGCFrame::LocalScan(Function &F) { return S; } -#if JL_LLVM_VERSION >= 110000 static Value *ExtractScalar(Value *V, Type *VTy, bool isptr, ArrayRef Idxs, IRBuilder<> &irbuilder) { -#else -static Value *ExtractScalar(Value *V, Type *VTy, bool isptr, ArrayRef Idxs, IRBuilder<> irbuilder) { -#endif Type *T_int32 = Type::getInt32Ty(V->getContext()); if (isptr) { std::vector IdxList{Idxs.size() + 1}; @@ -1717,11 +1700,7 @@ static unsigned getFieldOffset(const DataLayout &DL, Type *STy, ArrayRef= 110000 std::vector ExtractTrackedValues(Value *Src, Type *STy, bool isptr, IRBuilder<> &irbuilder, ArrayRef perm_offsets) { -#else -std::vector ExtractTrackedValues(Value *Src, Type *STy, bool isptr, IRBuilder<> irbuilder, ArrayRef perm_offsets) { -#endif auto Tracked = TrackCompositeType(STy); std::vector Ptrs; unsigned perm_idx = 0; @@ -1754,11 +1733,7 @@ std::vector ExtractTrackedValues(Value *Src, Type *STy, bool isptr, IRBu return Ptrs; } -#if JL_LLVM_VERSION >= 110000 unsigned TrackWithShadow(Value *Src, Type *STy, bool isptr, Value *Dst, IRBuilder<> &irbuilder) { -#else -unsigned TrackWithShadow(Value *Src, Type *STy, bool isptr, Value *Dst, IRBuilder<> irbuilder) { -#endif auto Ptrs = ExtractTrackedValues(Src, STy, isptr, irbuilder); for (unsigned i = 0; i < Ptrs.size(); ++i) { Value *Elem = Ptrs[i]; @@ -2275,11 +2250,7 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S) { // to remove write barrier because of it. // We pretty much only load using `T_size` so try our best to strip // as many cast as possible. -#if JL_LLVM_VERSION >= 100000 auto tag = CI->getArgOperand(2)->stripPointerCastsAndAliases(); -#else - auto tag = CI->getArgOperand(2)->stripPointerCasts(); -#endif if (auto C = dyn_cast(tag)) { if (C->getOpcode() == Instruction::IntToPtr) { tag = C->getOperand(0); @@ -2305,13 +2276,7 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S) { auto tag_type = tag->getType(); if (tag_type->isPointerTy()) { auto &DL = CI->getModule()->getDataLayout(); -#if JL_LLVM_VERSION >= 110000 auto align = tag->getPointerAlignment(DL).value(); -#elif JL_LLVM_VERSION >= 100000 - auto align = tag->getPointerAlignment(DL).valueOrOne().value(); -#else - auto align = tag->getPointerAlignment(DL); -#endif if (align < 16) { // On 5 <= LLVM < 12, it is illegal to call this on // non-integral pointer. This relies on stripping the diff --git a/src/llvm-propagate-addrspaces.cpp b/src/llvm-propagate-addrspaces.cpp index 95182f144d6ec..6cfa66ddca6ff 100644 --- a/src/llvm-propagate-addrspaces.cpp +++ b/src/llvm-propagate-addrspaces.cpp @@ -16,9 +16,6 @@ #include #include #include -#if JL_LLVM_VERSION < 110000 -#include -#endif #include #include #include diff --git a/src/llvm-remove-addrspaces.cpp b/src/llvm-remove-addrspaces.cpp index de5633b905762..ada10c8d5f1f9 100644 --- a/src/llvm-remove-addrspaces.cpp +++ b/src/llvm-remove-addrspaces.cpp @@ -92,14 +92,7 @@ class AddrspaceRemoveTypeRemapper : public ValueMapTypeRemapper { DstTy = ArrayType::get( remapType(Ty->getElementType()), Ty->getNumElements()); else if (auto Ty = dyn_cast(SrcTy)) - DstTy = VectorType::get(remapType(Ty->getElementType()), -#if JL_LLVM_VERSION >= 110000 - Ty -#else - Ty->getNumElements(), - Ty->isScalable() -#endif - ); + DstTy = VectorType::get(remapType(Ty->getElementType()), Ty); if (DstTy != SrcTy) LLVM_DEBUG( diff --git a/src/llvm-version.h b/src/llvm-version.h index 0b8a086e60b40..f59f7826c334d 100644 --- a/src/llvm-version.h +++ b/src/llvm-version.h @@ -9,11 +9,8 @@ #define JL_LLVM_VERSION (LLVM_VERSION_MAJOR * 10000 + LLVM_VERSION_MINOR * 100 \ + LLVM_VERSION_PATCH) -#if JL_LLVM_VERSION < 90000 - #error Only LLVM versions >= 9.0.0 are supported by Julia -#endif -#if JL_LLVM_VERSION < 100000 -#define Align(a) (a) +#if JL_LLVM_VERSION < 110000 + #error Only LLVM versions >= 11.0.0 are supported by Julia #endif #ifndef LLVM_DISABLE_ABI_BREAKING_CHECKS_ENFORCING diff --git a/src/macroexpand.scm b/src/macroexpand.scm index 882fe88a2e648..5e55c7bbb29c1 100644 --- a/src/macroexpand.scm +++ b/src/macroexpand.scm @@ -210,7 +210,8 @@ ((atom? v) '()) (else (case (car v) - ((... kw |::| =) (try-arg-name (cadr v))) + ((|::|) (if (length= v 2) '() (try-arg-name (cadr v)))) + ((... kw =) (try-arg-name (cadr v))) ((escape) (list v)) ((hygienic-scope) (try-arg-name (cadr v))) ((meta) ;; allow certain per-argument annotations @@ -324,7 +325,7 @@ m parent-scope inarg)) (define (resolve-expansion-vars- e env m parent-scope inarg) - (cond ((or (eq? e 'end) (eq? e 'ccall) (eq? e 'cglobal)) + (cond ((or (eq? e 'begin) (eq? e 'end) (eq? e 'ccall) (eq? e 'cglobal) (underscore-symbol? e)) e) ((symbol? e) (let ((a (assq e env))) diff --git a/src/method.c b/src/method.c index 1d3a593e638ed..b972d98ef1260 100644 --- a/src/method.c +++ b/src/method.c @@ -21,6 +21,25 @@ extern jl_value_t *jl_builtin_tuple; jl_method_t *jl_make_opaque_closure_method(jl_module_t *module, jl_value_t *name, jl_value_t *nargs, jl_value_t *functionloc, jl_code_info_t *ci); +static void check_c_types(const char *where, jl_value_t *rt, jl_value_t *at) +{ + if (jl_is_svec(rt)) + jl_errorf("%s: missing return type", where); + JL_TYPECHKS(where, type, rt); + if (!jl_type_mappable_to_c(rt)) + jl_errorf("%s: return type doesn't correspond to a C type", where); + JL_TYPECHKS(where, simplevector, at); + int i, l = jl_svec_len(at); + for (i = 0; i < l; i++) { + jl_value_t *ati = jl_svecref(at, i); + if (jl_is_vararg(ati)) + jl_errorf("%s: Vararg not allowed for argument list", where); + JL_TYPECHKS(where, type, ati); + if (!jl_type_mappable_to_c(ati)) + jl_errorf("%s: argument %d type doesn't correspond to a C type", where, i + 1); + } +} + // Resolve references to non-locally-defined variables to become references to global // variables in `module` (unless the rvalue is one of the type parameters in `sparam_vals`). static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals, @@ -120,10 +139,7 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve } jl_exprargset(e, 3, at); } - if (jl_is_svec(rt)) - jl_error("cfunction: missing return type"); - JL_TYPECHK(cfunction method definition, type, rt); - JL_TYPECHK(cfunction method definition, simplevector, at); + check_c_types("cfunction method definition", rt, at); JL_TYPECHK(cfunction method definition, quotenode, jl_exprarg(e, 4)); JL_TYPECHK(cfunction method definition, symbol, *(jl_value_t**)jl_exprarg(e, 4)); return expr; @@ -156,10 +172,7 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_module_t *module, jl_sve } jl_exprargset(e, 2, at); } - if (jl_is_svec(rt)) - jl_error("ccall: missing return type"); - JL_TYPECHK(ccall method definition, type, rt); - JL_TYPECHK(ccall method definition, simplevector, at); + check_c_types("ccall method definition", rt, at); JL_TYPECHK(ccall method definition, long, jl_exprarg(e, 3)); JL_TYPECHK(ccall method definition, quotenode, jl_exprarg(e, 4)); JL_TYPECHK(ccall method definition, symbol, *(jl_value_t**)jl_exprarg(e, 4)); diff --git a/src/module.c b/src/module.c index 20c119bedc27c..231efbb357653 100644 --- a/src/module.c +++ b/src/module.c @@ -150,7 +150,7 @@ static jl_binding_t *new_binding(jl_sym_t *name) // get binding for assignment JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var, int error) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t **bp = (jl_binding_t**)ptrhash_bp(&m->bindings, var); jl_binding_t *b = *bp; @@ -160,7 +160,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, b->owner = m; } else if (error) { - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); jl_errorf("cannot assign a value to variable %s.%s from module %s", jl_symbol_name(b->owner->name), jl_symbol_name(var), jl_symbol_name(m->name)); } @@ -170,10 +170,11 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_wr(jl_module_t *m JL_PROPAGATES_ROOT, b = new_binding(var); b->owner = m; *bp = b; + JL_GC_PROMISE_ROOTED(b); jl_gc_wb_buf(m, b, sizeof(jl_binding_t)); } - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b; } @@ -208,7 +209,7 @@ JL_DLLEXPORT jl_module_t *jl_get_module_of_binding(jl_module_t *m, jl_sym_t *var // like jl_get_binding_wr, but has different error paths JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_t *var) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t **bp = _jl_get_module_binding_bp(m, var); jl_binding_t *b = *bp; @@ -218,7 +219,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ b->owner = m; } else { - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); jl_binding_t *b2 = jl_get_binding(b->owner, b->name); if (b2 == NULL || b2->value == NULL) jl_errorf("invalid method definition: imported function %s.%s does not exist", @@ -239,7 +240,7 @@ JL_DLLEXPORT jl_binding_t *jl_get_binding_for_method_def(jl_module_t *m, jl_sym_ jl_gc_wb_buf(m, b, sizeof(jl_binding_t)); } - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b; } @@ -583,33 +584,33 @@ JL_DLLEXPORT int jl_boundp(jl_module_t *m, jl_sym_t *var) JL_DLLEXPORT int jl_defines_or_exports_p(jl_module_t *m, jl_sym_t *var) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t *b = (jl_binding_t*)ptrhash_get(&m->bindings, var); - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b != HT_NOTFOUND && (b->exportp || b->owner==m); } -JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) JL_NOTSAFEPOINT +JL_DLLEXPORT int jl_module_exports_p(jl_module_t *m, jl_sym_t *var) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t *b = _jl_get_module_binding(m, var); - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b != HT_NOTFOUND && b->exportp; } -JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) JL_NOTSAFEPOINT +JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t *b = _jl_get_module_binding(m, var); - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b != HT_NOTFOUND && b->owner != NULL; } -JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) JL_NOTSAFEPOINT +JL_DLLEXPORT jl_binding_t *jl_get_module_binding(jl_module_t *m JL_PROPAGATES_ROOT, jl_sym_t *var) { - JL_LOCK_NOGC(&m->lock); + JL_LOCK(&m->lock); jl_binding_t *b = _jl_get_module_binding(m, var); - JL_UNLOCK_NOGC(&m->lock); + JL_UNLOCK(&m->lock); return b == HT_NOTFOUND ? NULL : b; } @@ -626,7 +627,6 @@ JL_DLLEXPORT void jl_set_global(jl_module_t *m JL_ROOTING_ARGUMENT, jl_sym_t *va JL_TYPECHK(jl_set_global, module, (jl_value_t*)m); JL_TYPECHK(jl_set_global, symbol, (jl_value_t*)var); jl_binding_t *bp = jl_get_binding_wr(m, var, 1); - JL_GC_PROMISE_ROOTED(bp); jl_checked_assignment(bp, val); } diff --git a/src/opaque_closure.c b/src/opaque_closure.c index a7298e3805218..9f2662f32eb25 100644 --- a/src/opaque_closure.c +++ b/src/opaque_closure.c @@ -53,7 +53,7 @@ JL_CALLABLE(jl_new_opaque_closure_jlcall) // check whether the specified number of arguments is compatible with the -// specified number of paramters of the tuple type +// specified number of parameters of the tuple type STATIC_INLINE int jl_tupletype_length_compat(jl_value_t *v, size_t nargs) JL_NOTSAFEPOINT { v = jl_unwrap_unionall(v); diff --git a/src/precompile.c b/src/precompile.c index 886a0677b1899..9f6fa1a79e8a6 100644 --- a/src/precompile.c +++ b/src/precompile.c @@ -353,9 +353,9 @@ static int precompile_enq_all_specializations__(jl_typemap_entry_t *def, void *c jl_svec_t *specializations = def->func.method->specializations; size_t i, l = jl_svec_len(specializations); for (i = 0; i < l; i++) { - jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); - if (mi != NULL) - precompile_enq_specialization_(mi, closure); + jl_value_t *mi = jl_svecref(specializations, i); + if (mi != jl_nothing) + precompile_enq_specialization_((jl_method_instance_t*)mi, closure); } } if (m->ccallable) diff --git a/src/processor_arm.cpp b/src/processor_arm.cpp index f15f205118773..a411314e34e9d 100644 --- a/src/processor_arm.cpp +++ b/src/processor_arm.cpp @@ -215,7 +215,7 @@ static constexpr FeatureDep deps[] = { {ccdp, ccpp}, {sve, fullfp16}, {fp16fml, fullfp16}, - {altnzcv, fmi}, + {altnzcv, flagm}, {sve2, sve}, {sve2_aes, sve2}, {sve2_aes, aes}, @@ -237,7 +237,7 @@ constexpr auto armv8_2a = armv8_1a | get_feature_masks(v8_2a, ccpp); constexpr auto armv8_2a_crypto = armv8_2a | get_feature_masks(aes, sha2); constexpr auto armv8_3a = armv8_2a | get_feature_masks(v8_3a, jsconv, complxnum, rcpc); constexpr auto armv8_3a_crypto = armv8_3a | get_feature_masks(aes, sha2); -constexpr auto armv8_4a = armv8_3a | get_feature_masks(v8_4a, dit, rcpc_immo, fmi); +constexpr auto armv8_4a = armv8_3a | get_feature_masks(v8_4a, dit, rcpc_immo, flagm); constexpr auto armv8_4a_crypto = armv8_4a | get_feature_masks(aes, sha2); constexpr auto armv8_5a = armv8_4a | get_feature_masks(v8_5a, sb, ccdp, altnzcv, fptoint); constexpr auto armv8_6a = armv8_5a | get_feature_masks(v8_6a, i8mm, bf16); @@ -256,7 +256,7 @@ constexpr auto armv8_6a = armv8_5a | get_feature_masks(v8_6a, i8mm, bf16); // .SM4: sm4 // .DP: dotprod // .FHM: fp16fml -// .TS: fmi, altnzcz +// .TS: flagm, altnzcz // .RNDR: rand // ID_AA64ISAR1_EL1 @@ -1191,7 +1191,7 @@ static NOINLINE std::pair> _get_host_cpu() features[1] = (uint32_t)jl_getauxval(AT_HWCAP2); #ifdef _CPU_AARCH64_ if (test_nbit(features, 31)) // HWCAP_PACG - set_bit(features, Feature::pa, true); + set_bit(features, Feature::pauth, true); #endif auto cpuinfo = get_cpuinfo(); auto arch = get_elf_arch(); @@ -1419,7 +1419,7 @@ static inline void enable_depends(FeatureList &features) if (test_nbit(features, Feature::v8_4a)) { set_bit(features, Feature::dit, true); set_bit(features, Feature::rcpc_immo, true); - set_bit(features, Feature::fmi, true); + set_bit(features, Feature::flagm, true); } if (test_nbit(features, Feature::v8_5a)) { set_bit(features, Feature::sb, true); @@ -1623,10 +1623,8 @@ get_llvm_target_noext(const TargetData &data) feature_strs.push_back(std::string("-") + fename_str); } } -#if JL_LLVM_VERSION >= 110000 if (test_nbit(features, Feature::v8_6a)) feature_strs.push_back("+v8.6a"); -#endif if (test_nbit(features, Feature::v8_5a)) feature_strs.push_back("+v8.5a"); if (test_nbit(features, Feature::v8_4a)) @@ -1760,13 +1758,7 @@ const std::pair &jl_get_llvm_disasm_target(void) auto max_feature = get_max_feature(); static const auto res = get_llvm_target_str(TargetData{host_cpu_name(), #ifdef _CPU_AARCH64_ -# if JL_LLVM_VERSION > 110000 - "+ecv," -# endif -# if JL_LLVM_VERSION > 100000 - "+tme," -# endif - "+am,+specrestrict,+predres,+lor,+perfmon,+spe,+tracev8.4", + "+ecv,+tme,+am,+specrestrict,+predres,+lor,+perfmon,+spe,+tracev8.4", #else "+dotprod", #endif @@ -1810,6 +1802,8 @@ extern "C" int jl_test_cpu_feature(jl_cpu_feature_t feature) #ifdef _CPU_AARCH64_ // FPCR FZ, bit [24] static constexpr uint32_t fpcr_fz_mask = 1 << 24; +// FPCR FZ16, bit [19] +static constexpr uint32_t fpcr_fz16_mask = 1 << 19; // FPCR DN, bit [25] static constexpr uint32_t fpcr_dn_mask = 1 << 25; @@ -1833,7 +1827,8 @@ extern "C" JL_DLLEXPORT int32_t jl_get_zero_subnormals(void) extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero) { uint32_t fpcr = get_fpcr_aarch64(); - fpcr = isZero ? (fpcr | fpcr_fz_mask) : (fpcr & ~fpcr_fz_mask); + static uint32_t mask = fpcr_fz_mask | (jl_test_cpu_feature(JL_AArch64_fullfp16) ? fpcr_fz16_mask : 0); + fpcr = isZero ? (fpcr | mask) : (fpcr & ~mask); set_fpcr_aarch64(fpcr); return 0; } diff --git a/src/rtutils.c b/src/rtutils.c index 99fce51128345..98dc68dfa02f3 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -354,7 +354,7 @@ JL_DLLEXPORT jl_value_t *jl_value_ptr(jl_value_t *a) JL_DLLEXPORT void jl_set_nth_field(jl_value_t *v, size_t idx0, jl_value_t *rhs) { jl_datatype_t *st = (jl_datatype_t*)jl_typeof(v); - if (!st->mutabl) + if (!st->name->mutabl) jl_errorf("setfield! immutable struct of type %s cannot be changed", jl_symbol_name(st->name->name)); if (idx0 >= jl_datatype_nfields(st)) jl_bounds_error_int(v, idx0 + 1); diff --git a/src/runtime_ccall.cpp b/src/runtime_ccall.cpp index 307acc9c28cd1..050347513aa45 100644 --- a/src/runtime_ccall.cpp +++ b/src/runtime_ccall.cpp @@ -27,9 +27,8 @@ using namespace llvm; static std::map libMap; static jl_mutex_t libmap_lock; extern "C" -void *jl_get_library_(const char *f_lib, int throw_err) JL_NOTSAFEPOINT +void *jl_get_library_(const char *f_lib, int throw_err) { - void *hnd; if (f_lib == NULL) return jl_RTLD_DEFAULT_handle; #ifdef _OS_WINDOWS_ @@ -40,23 +39,22 @@ void *jl_get_library_(const char *f_lib, int throw_err) JL_NOTSAFEPOINT if (strcmp(f_lib, JL_LIBJULIA_DL_LIBNAME) == 0) return jl_libjulia_handle; #endif - JL_LOCK_NOGC(&libmap_lock); + JL_LOCK(&libmap_lock); // This is the only operation we do on the map, which doesn't invalidate // any references or iterators. void **map_slot = &libMap[f_lib]; - JL_UNLOCK_NOGC(&libmap_lock); - hnd = jl_atomic_load_acquire(map_slot); - if (hnd != NULL) - return hnd; - // We might run this concurrently on two threads but it doesn't matter. - hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT, throw_err); - if (hnd != NULL) - jl_atomic_store_release(map_slot, hnd); + void *hnd = *map_slot; + if (hnd == NULL) { + hnd = jl_load_dynamic_library(f_lib, JL_RTLD_DEFAULT, throw_err); + if (hnd != NULL) + *map_slot = hnd; + } + JL_UNLOCK(&libmap_lock); return hnd; } extern "C" JL_DLLEXPORT -void *jl_load_and_lookup(const char *f_lib, const char *f_name, void **hnd) JL_NOTSAFEPOINT +void *jl_load_and_lookup(const char *f_lib, const char *f_name, void **hnd) { void *handle = jl_atomic_load_acquire(hnd); if (!handle) @@ -210,11 +208,11 @@ extern "C" JL_DLLEXPORT char *jl_format_filename(const char *output_pattern) } -static jl_mutex_t trampoline_lock; // for accesses to the cache and freelist +static jl_mutex_t trampoline_lock; // for accesses to the cache and freelist static void *trampoline_freelist; -static void *trampoline_alloc() // lock taken by caller +static void *trampoline_alloc() JL_NOTSAFEPOINT // lock taken by caller { const int sz = 64; // oversized for most platforms. todo: use precise value? if (!trampoline_freelist) { @@ -235,6 +233,7 @@ static void *trampoline_alloc() // lock taken by caller #endif errno = last_errno; void *next = NULL; + assert(sz < jl_page_size); for (size_t i = 0; i + sz <= jl_page_size; i += sz) { void **curr = (void**)((char*)mem + i); *curr = next; @@ -272,6 +271,8 @@ static void trampoline_deleter(void **f) JL_UNLOCK_NOGC(&trampoline_lock); } +typedef void *(*init_trampoline_t)(void *tramp, void **nval) JL_NOTSAFEPOINT; + // Use of `cache` is not clobbered in JL_TRY JL_GCC_IGNORE_START("-Wclobbered") extern "C" JL_DLLEXPORT @@ -282,7 +283,7 @@ jl_value_t *jl_get_cfunction_trampoline( // call-site constants: htable_t *cache, // weakref htable indexed by (fobj, vals) jl_svec_t *fill, - void *(*init_trampoline)(void *tramp, void **nval), + init_trampoline_t init_trampoline, jl_unionall_t *env, jl_value_t **vals) { @@ -339,11 +340,8 @@ jl_value_t *jl_get_cfunction_trampoline( ((void**)result)[1] = (void*)fobj; } if (!permanent) { - void *ptr_finalizer[2] = { - (void*)jl_voidpointer_type, - (void*)&trampoline_deleter - }; - jl_gc_add_finalizer(result, (jl_value_t*)&ptr_finalizer[1]); + jl_ptls_t ptls = jl_get_ptls_states(); + jl_gc_add_ptr_finalizer(ptls, result, (void*)(uintptr_t)&trampoline_deleter); ((void**)result)[2] = (void*)cache; ((void**)result)[3] = (void*)nval; } diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 2337abe7d5704..22c3a8988b580 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -834,33 +834,11 @@ fpiseq_n(double, 64) #define fpiseq(a,b) \ sizeof(a) == sizeof(float) ? fpiseq32(a, b) : fpiseq64(a, b) -#define fpislt_n(c_type, nbits) \ - static inline int fpislt##nbits(c_type a, c_type b) JL_NOTSAFEPOINT \ - { \ - bits##nbits ua, ub; \ - ua.f = a; \ - ub.f = b; \ - if (!isnan(a) && isnan(b)) \ - return 1; \ - if (isnan(a) || isnan(b)) \ - return 0; \ - if (ua.d >= 0 && ua.d < ub.d) \ - return 1; \ - if (ua.d < 0 && ua.ud > ub.ud) \ - return 1; \ - return 0; \ - } -fpislt_n(float, 32) -fpislt_n(double, 64) -#define fpislt(a, b) \ - sizeof(a) == sizeof(float) ? fpislt32(a, b) : fpislt64(a, b) - bool_fintrinsic(eq,eq_float) bool_fintrinsic(ne,ne_float) bool_fintrinsic(lt,lt_float) bool_fintrinsic(le,le_float) bool_fintrinsic(fpiseq,fpiseq) -bool_fintrinsic(fpislt,fpislt) // bitwise operators #define and_op(a,b) a & b diff --git a/src/stackwalk.c b/src/stackwalk.c index a00980fdf81ec..790b7583cc587 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -335,7 +335,7 @@ JL_DLLEXPORT jl_value_t *jl_get_backtrace(void) // interleaved. JL_DLLEXPORT jl_value_t *jl_get_excstack(jl_task_t* task, int include_bt, int max_entries) { - JL_TYPECHK(catch_stack, task, (jl_value_t*)task); + JL_TYPECHK(current_exceptions, task, (jl_value_t*)task); jl_ptls_t ptls = jl_get_ptls_states(); if (task != ptls->current_task && task->_state == JL_TASK_STATE_RUNNABLE) { jl_error("Inspecting the exception stack of a task which might " @@ -774,6 +774,11 @@ JL_DLLEXPORT void jlbacktracet(jl_task_t *t) } } +JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT +{ + jlbacktrace(); +} + #ifdef __cplusplus } #endif diff --git a/src/staticdata.c b/src/staticdata.c index 44b6f33d05e7a..1fc1797f35fdd 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -901,7 +901,7 @@ static void jl_write_values(jl_serializer_state *s) write_padding(s->s, offset - tot); tot = offset; size_t fsz = jl_field_size(t, i); - if (t->mutabl && jl_is_cpointer_type(jl_field_type(t, i))) { + if (t->name->mutabl && jl_is_cpointer_type(jl_field_type(t, i))) { // reset Ptr fields to C_NULL assert(!jl_field_isptr(t, i)); write_pointer(s->s); diff --git a/src/subtype.c b/src/subtype.c index 90f5438cfd1b6..0d87532e73c39 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -646,7 +646,7 @@ static int is_leaf_bound(jl_value_t *v) JL_NOTSAFEPOINT if (v == jl_bottom_type) return 1; if (jl_is_datatype(v)) { - if (((jl_datatype_t*)v)->abstract) { + if (((jl_datatype_t*)v)->name->abstract) { if (jl_is_type_type(v)) return 1;//!jl_has_free_typevars(jl_tparam0(v)); return 0; diff --git a/src/sys.c b/src/sys.c index 684e000026c6d..664489397977b 100644 --- a/src/sys.c +++ b/src/sys.c @@ -13,6 +13,7 @@ #include "julia.h" #include "julia_internal.h" +#include "llvm-version.h" #ifdef _OS_WINDOWS_ #include @@ -668,7 +669,13 @@ JL_DLLEXPORT jl_value_t *jl_get_libllvm(void) JL_NOTSAFEPOINT { HMODULE mod; // FIXME: GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS on LLVMContextCreate, // but that just points to libjulia.dll - if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, "LLVM", &mod)) +#if JL_LLVM_VERSION <= 110000 + const char* libLLVM = "LLVM"; +#else + const char* libLLVM = "libLLVM"; +#endif + + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, libLLVM, &mod)) return jl_nothing; char path[MAX_PATH]; diff --git a/src/task.c b/src/task.c index 4d38d30f5cc56..54aaf5fdc530f 100644 --- a/src/task.c +++ b/src/task.c @@ -312,11 +312,6 @@ NOINLINE static void record_backtrace(jl_ptls_t ptls, int skip) JL_NOTSAFEPOINT ptls->bt_size = rec_backtrace(ptls->bt_data, JL_MAX_BT_SIZE, skip + 1); } -JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) -{ - _julia_init(rel); -} - JL_DLLEXPORT void jl_set_next_task(jl_task_t *task) JL_NOTSAFEPOINT { jl_get_ptls_states()->next_task = task; diff --git a/src/threading.c b/src/threading.c index 01fe98e041a87..85855ed5b7e09 100644 --- a/src/threading.c +++ b/src/threading.c @@ -81,6 +81,8 @@ jl_get_ptls_states_func jl_get_ptls_states_getter(void) // for codegen return &jl_get_ptls_states_fast; } + +JL_DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f) { } #elif defined(_OS_WINDOWS_) // Apparently windows doesn't have a static TLS model (or one that can be // reliably used from a shared library) either..... Use `TLSAlloc` instead. @@ -138,6 +140,8 @@ jl_get_ptls_states_func jl_get_ptls_states_getter(void) // for codegen return &jl_get_ptls_states; } + +JL_DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f) { } #else // We use the faster static version in the main executable to replace // the slower version in the shared object. The code in different libraries @@ -398,8 +402,8 @@ void jl_init_threading(void) } if (jl_n_threads <= 0) jl_n_threads = 1; - jl_measure_compile_time = (uint8_t*)realloc(jl_measure_compile_time, jl_n_threads * sizeof(*jl_measure_compile_time)); - jl_cumulative_compile_time = (uint64_t*)realloc(jl_cumulative_compile_time, jl_n_threads * sizeof(*jl_cumulative_compile_time)); + jl_measure_compile_time = (uint8_t*)calloc(jl_n_threads, sizeof(*jl_measure_compile_time)); + jl_cumulative_compile_time = (uint64_t*)calloc(jl_n_threads, sizeof(*jl_cumulative_compile_time)); #ifndef __clang_analyzer__ jl_all_tls_states = (jl_ptls_t*)calloc(jl_n_threads, sizeof(void*)); #endif diff --git a/src/typemap.c b/src/typemap.c index 50fb9635ff210..b546aadee77ac 100644 --- a/src/typemap.c +++ b/src/typemap.c @@ -65,7 +65,7 @@ static int jl_type_extract_name_precise(jl_value_t *t1, int invariant) } else if (jl_is_datatype(t1)) { jl_datatype_t *dt = (jl_datatype_t*)t1; - if ((invariant || !dt->abstract) && !jl_is_kind(t1)) + if ((invariant || !dt->name->abstract) && !jl_is_kind(t1)) return 1; return 0; } @@ -1087,10 +1087,7 @@ static unsigned jl_typemap_list_count_locked(jl_typemap_entry_t *ml) JL_NOTSAFEP return count; } -static void jl_typemap_level_insert_(jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, const struct jl_typemap_info *tparams); -static void jl_typemap_list_insert_sorted( - jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent, - jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams); +static void jl_typemap_level_insert_(jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs); static jl_typemap_level_t *jl_new_typemap_level(void) { @@ -1108,8 +1105,7 @@ static jl_typemap_level_t *jl_new_typemap_level(void) } static jl_typemap_level_t *jl_method_convert_list_to_cache( - jl_typemap_t *map, jl_typemap_entry_t *ml, int8_t offs, - const struct jl_typemap_info *tparams) + jl_typemap_t *map, jl_typemap_entry_t *ml, int8_t offs) { jl_typemap_level_t *cache = jl_new_typemap_level(); jl_typemap_entry_t *next = NULL; @@ -1118,7 +1114,7 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache( next = ml->next; ml->next = (jl_typemap_entry_t*)jl_nothing; // TODO: is it safe to be doing this concurrently with lookups? - jl_typemap_level_insert_(map, cache, ml, offs, tparams); + jl_typemap_level_insert_(map, cache, ml, offs); ml = next; } JL_GC_POP(); @@ -1127,26 +1123,29 @@ static jl_typemap_level_t *jl_method_convert_list_to_cache( static void jl_typemap_list_insert_( jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent, - jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) + jl_typemap_entry_t *newrec) { - if (*pml == (void*)jl_nothing || newrec->isleafsig || (tparams && tparams->unsorted)) { - newrec->next = *pml; - jl_gc_wb(newrec, newrec->next); - jl_atomic_store_release(pml, newrec); - jl_gc_wb(parent, newrec); - } - else { - jl_typemap_list_insert_sorted(map, pml, parent, newrec, tparams); + jl_typemap_entry_t *l = *pml; + while ((jl_value_t*)l != jl_nothing) { + if (newrec->isleafsig || !l->isleafsig) + if (newrec->issimplesig || !l->issimplesig) + break; + pml = &l->next; + parent = (jl_value_t*)l; + l = l->next; } + newrec->next = l; + jl_gc_wb(newrec, newrec->next); + jl_atomic_store_release(pml, newrec); + jl_gc_wb(parent, newrec); } static void jl_typemap_insert_generic( jl_typemap_t *map, jl_typemap_t **pml, jl_value_t *parent, - jl_typemap_entry_t *newrec, int8_t offs, - const struct jl_typemap_info *tparams) + jl_typemap_entry_t *newrec, int8_t offs) { if (jl_typeof(*pml) == (jl_value_t*)jl_typemap_level_type) { - jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs, tparams); + jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs); return; } @@ -1154,31 +1153,29 @@ static void jl_typemap_insert_generic( if (count > MAX_METHLIST_COUNT) { *pml = (jl_typemap_t*)jl_method_convert_list_to_cache( map, (jl_typemap_entry_t *)*pml, - offs, tparams); + offs); jl_gc_wb(parent, *pml); - jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs, tparams); + jl_typemap_level_insert_(map, (jl_typemap_level_t*)*pml, newrec, offs); return; } jl_typemap_list_insert_(map, (jl_typemap_entry_t **)pml, - parent, newrec, tparams); + parent, newrec); } static void jl_typemap_array_insert_( jl_typemap_t *map, jl_array_t **cache, jl_value_t *key, jl_typemap_entry_t *newrec, - jl_value_t *parent, int8_t offs, - const struct jl_typemap_info *tparams) + jl_value_t *parent, int8_t offs) { jl_typemap_t **pml = mtcache_hash_lookup_bp(*cache, key); if (pml != NULL) - jl_typemap_insert_generic(map, pml, (jl_value_t*)*cache, newrec, offs+1, tparams); + jl_typemap_insert_generic(map, pml, (jl_value_t*)*cache, newrec, offs+1); else mtcache_hash_insert(cache, parent, key, (jl_typemap_t*)newrec); } static void jl_typemap_level_insert_( - jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs, - const struct jl_typemap_info *tparams) + jl_typemap_t *map, jl_typemap_level_t *cache, jl_typemap_entry_t *newrec, int8_t offs) { jl_value_t *ttypes = jl_unwrap_unionall((jl_value_t*)newrec->sig); size_t l = jl_nparams(ttypes); @@ -1205,7 +1202,7 @@ static void jl_typemap_level_insert_( t1 = (jl_value_t*)jl_assume(jl_typeofbottom_type)->super; // If the type at `offs` is Any, put it in the Any list if (t1 && jl_is_any(t1)) { - jl_typemap_insert_generic(map, &cache->any, (jl_value_t*)cache, newrec, offs+1, tparams); + jl_typemap_insert_generic(map, &cache->any, (jl_value_t*)cache, newrec, offs+1); return; } // Don't put Varargs in the optimized caches (too hard to handle in lookup and bp) @@ -1216,12 +1213,12 @@ static void jl_typemap_level_insert_( // and we use the table indexed for that purpose. jl_value_t *a0 = jl_tparam0(t1); if (is_cache_leaf(a0, 1)) { - jl_typemap_array_insert_(map, &cache->targ, a0, newrec, (jl_value_t*)cache, offs, tparams); + jl_typemap_array_insert_(map, &cache->targ, a0, newrec, (jl_value_t*)cache, offs); return; } } if (is_cache_leaf(t1, 0)) { - jl_typemap_array_insert_(map, &cache->arg1, t1, newrec, (jl_value_t*)cache, offs, tparams); + jl_typemap_array_insert_(map, &cache->arg1, t1, newrec, (jl_value_t*)cache, offs); return; } @@ -1231,16 +1228,16 @@ static void jl_typemap_level_insert_( if (jl_is_type_type(t1)) { a0 = jl_type_extract_name(jl_tparam0(t1)); jl_datatype_t *super = a0 ? (jl_datatype_t*)jl_unwrap_unionall(((jl_typename_t*)a0)->wrapper) : jl_any_type; - jl_typemap_array_insert_(map, &cache->tname, (jl_value_t*)super->name, newrec, (jl_value_t*)cache, offs, tparams); + jl_typemap_array_insert_(map, &cache->tname, (jl_value_t*)super->name, newrec, (jl_value_t*)cache, offs); return; } a0 = jl_type_extract_name(t1); if (a0 && a0 != (jl_value_t*)jl_any_type->name) { - jl_typemap_array_insert_(map, &cache->name1, a0, newrec, (jl_value_t*)cache, offs, tparams); + jl_typemap_array_insert_(map, &cache->name1, a0, newrec, (jl_value_t*)cache, offs); return; } } - jl_typemap_list_insert_(map, &cache->linear, (jl_value_t*)cache, newrec, tparams); + jl_typemap_list_insert_(map, &cache->linear, (jl_value_t*)cache, newrec); } jl_typemap_entry_t *jl_typemap_alloc( @@ -1289,43 +1286,9 @@ jl_typemap_entry_t *jl_typemap_alloc( } void jl_typemap_insert(jl_typemap_t **cache, jl_value_t *parent, - jl_typemap_entry_t *newrec, int8_t offs, - const struct jl_typemap_info *tparams) -{ - jl_typemap_insert_generic(*cache, cache, parent, newrec, offs, tparams); -} - -static void jl_typemap_list_insert_sorted( - jl_typemap_t *map, jl_typemap_entry_t **pml, jl_value_t *parent, - jl_typemap_entry_t *newrec, const struct jl_typemap_info *tparams) + jl_typemap_entry_t *newrec, int8_t offs) { - jl_typemap_entry_t *l, **pl; - pl = pml; - l = *pml; - jl_value_t *pa = parent; - while ((jl_value_t*)l != jl_nothing) { - if (!l->isleafsig) { // quickly ignore all of the leafsig entries (these were handled by caller) - if (jl_type_morespecific((jl_value_t*)newrec->sig, (jl_value_t*)l->sig)) { - if (l->simplesig == (void*)jl_nothing || - newrec->simplesig != (void*)jl_nothing || - !jl_types_equal((jl_value_t*)l->sig, (jl_value_t*)newrec->sig)) { - // might need to insert multiple entries for a lookup differing only by their simplesig - // when simplesig contains a kind - // TODO: make this test more correct or figure out a better way to compute this - break; - } - } - } - pl = &l->next; - pa = (jl_value_t*)l; - l = l->next; - } - - // insert newrec at the first point it is more specific than the following method - newrec->next = l; - jl_gc_wb(newrec, l); - jl_atomic_store_release(pl, newrec); - jl_gc_wb(pa, newrec); + jl_typemap_insert_generic(*cache, cache, parent, newrec, offs); } #ifdef __cplusplus diff --git a/stdlib/.gitignore b/stdlib/.gitignore index 59354288f912c..891eda58c689d 100644 --- a/stdlib/.gitignore +++ b/stdlib/.gitignore @@ -13,5 +13,7 @@ /Tar /NetworkOptions-* /NetworkOptions +/SuiteSparse-* +/SuiteSparse /*_jll/StdlibArtifacts.toml /*/Manifest.toml diff --git a/stdlib/Artifacts/src/Artifacts.jl b/stdlib/Artifacts/src/Artifacts.jl index fd65494782d92..218f879c767ac 100644 --- a/stdlib/Artifacts/src/Artifacts.jl +++ b/stdlib/Artifacts/src/Artifacts.jl @@ -418,7 +418,7 @@ collapsed artifact. Returns `nothing` if no mapping can be found. """ function artifact_hash(name::String, artifacts_toml::String; platform::AbstractPlatform = HostPlatform(), - pkg_uuid::Union{Base.UUID,Nothing}=nothing) + pkg_uuid::Union{Base.UUID,Nothing}=nothing)::Union{Nothing, SHA1} meta = artifact_meta(name, artifacts_toml; platform=platform) if meta === nothing return nothing diff --git a/stdlib/Artifacts/test/runtests.jl b/stdlib/Artifacts/test/runtests.jl index 36b5a0d3281ff..7527b548061ce 100644 --- a/stdlib/Artifacts/test/runtests.jl +++ b/stdlib/Artifacts/test/runtests.jl @@ -157,3 +157,10 @@ end end end end + +@testset "`Artifacts.artifact_names` and friends" begin + n = length(Artifacts.artifact_names) + @test length(Base.project_names) == n + @test length(Base.manifest_names) == n + @test length(Base.preferences_names) == n +end diff --git a/stdlib/CompilerSupportLibraries_jll/Project.toml b/stdlib/CompilerSupportLibraries_jll/Project.toml index 87c7bd506a4f5..95366df955720 100644 --- a/stdlib/CompilerSupportLibraries_jll/Project.toml +++ b/stdlib/CompilerSupportLibraries_jll/Project.toml @@ -1,6 +1,6 @@ name = "CompilerSupportLibraries_jll" uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" -version = "0.4.0+0" +version = "0.4.3+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" diff --git a/stdlib/Dates/docs/src/index.md b/stdlib/Dates/docs/src/index.md index c34be7b9ebef4..3c52eaf1d9dee 100644 --- a/stdlib/Dates/docs/src/index.md +++ b/stdlib/Dates/docs/src/index.md @@ -125,6 +125,17 @@ julia> dt2 = Date("2015-01-02",df) 2015-01-02 ``` +Alternatively, use broadcasting: + +```jldoctest +julia> years = ["2015", "2016"]; + +julia> Date.(years, DateFormat("yyyy")) +2-element Vector{Date}: + 2015-01-01 + 2016-01-01 +``` + You can also use the `dateformat""` string macro. This macro creates the `DateFormat` object once when the macro is expanded and uses the same `DateFormat` object even if a code snippet is run multiple times. ```jldoctest @@ -847,6 +858,15 @@ Months of the Year: | `November` | `Nov` | 11 | | `December` | `Dec` | 12 | +#### Common Date Formatters + +```@docs +ISODateTimeFormat +ISODateFormat +ISOTimeFormat +RFC1123Format +``` + ```@meta DocTestSetup = nothing ``` diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 721e36deef7a8..3de39f05e0e33 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -367,8 +367,9 @@ When parsing a time with a `p` specifier, any hour (either `H` or `I`) is interp as a 12-hour clock, so the `I` code is mainly useful for output. Creating a DateFormat object is expensive. Whenever possible, create it once and use it many times -or try the `dateformat""` string macro. Using this macro creates the DateFormat object once at -macro expansion time and reuses it later. see [`@dateformat_str`](@ref). +or try the [`dateformat""`](@ref @dateformat_str) string macro. Using this macro creates the DateFormat +object once at macro expansion time and reuses it later. There are also several [pre-defined formatters](@ref +Common-Date-Formatters), listed later. See [`DateTime`](@ref) and [`format`](@ref) for how to use a DateFormat object to parse and write Date strings respectively. @@ -443,14 +444,63 @@ macro dateformat_str(str) end # Standard formats + +""" + Dates.ISODateTimeFormat + +Describes the ISO8601 formatting for a date and time. This is the default value for `Dates.format` +of a `DateTime`. + +# Example +```jldoctest +julia> Dates.format(DateTime(2018, 8, 8, 12, 0, 43, 1), ISODateTimeFormat) +"2018-08-08T12:00:43.001" +``` +""" const ISODateTimeFormat = DateFormat("yyyy-mm-dd\\THH:MM:SS.s") +default_format(::Type{DateTime}) = ISODateTimeFormat + +""" + Dates.ISODateFormat + +Describes the ISO8601 formatting for a date. This is the default value for `Dates.format` of a `Date`. + +# Example +```jldoctest +julia> Dates.format(Date(2018, 8, 8), ISODateFormat) +"2018-08-08" +``` +""" const ISODateFormat = DateFormat("yyyy-mm-dd") +default_format(::Type{Date}) = ISODateFormat + +""" + Dates.ISOTimeFormat + +Describes the ISO8601 formatting for a time. This is the default value for `Dates.format` of a `Time`. + +# Example +```jldoctest +julia> Dates.format(Time(12, 0, 43, 1), ISOTimeFormat) +"12:00:43.001" +``` +""" const ISOTimeFormat = DateFormat("HH:MM:SS.s") +default_format(::Type{Time}) = ISOTimeFormat + +""" + Dates.RFC1123Format + +Describes the RFC1123 formatting for a date and time. + +# Example +```jldoctest +julia> Dates.format(DateTime(2018, 8, 8, 12, 0, 43, 1), RFC1123Format) +"Wed, 08 Aug 2018 12:00:43" +``` +""" const RFC1123Format = DateFormat("e, dd u yyyy HH:MM:SS") -default_format(::Type{DateTime}) = ISODateTimeFormat -default_format(::Type{Date}) = ISODateFormat -default_format(::Type{Time}) = ISOTimeFormat ### API diff --git a/stdlib/Dates/src/parse.jl b/stdlib/Dates/src/parse.jl index 07a65a73b70c3..a5bbc686c955d 100644 --- a/stdlib/Dates/src/parse.jl +++ b/stdlib/Dates/src/parse.jl @@ -282,7 +282,7 @@ function Base.parse(::Type{T}, str::AbstractString, df::DateFormat=default_forma val = tryparsenext_internal(T, str, pos, len, df, true) @assert val !== nothing values, endpos = val - return T(values...) + return T(values...)::T end function Base.tryparse(::Type{T}, str::AbstractString, df::DateFormat=default_format(T)) where T<:TimeType @@ -292,7 +292,7 @@ function Base.tryparse(::Type{T}, str::AbstractString, df::DateFormat=default_fo values, endpos = res if validargs(T, values...) === nothing # TODO: validargs gets called twice, since it's called again in the T constructor - return T(values...) + return T(values...)::T end return nothing end diff --git a/stdlib/Dates/test/io.jl b/stdlib/Dates/test/io.jl index 11a02af9e1255..822d0101c28ba 100644 --- a/stdlib/Dates/test/io.jl +++ b/stdlib/Dates/test/io.jl @@ -572,4 +572,14 @@ end end end +@testset "inference with dynamic dateformat string" begin + datetime = DateTime(2020, 4, 7) + f1() = DateTime("2020-04-07", "yyyy-mm-dd") + f2() = DateTime("2020-04-07", DateFormat("yyyy-mm-dd")) + f3() = parse(DateTime, "2020-04-07", DateFormat("yyyy-mm-dd")) + @test (@inferred f1()) == (@inferred f2()) == (@inferred f3()) == datetime + g() = tryparse(DateTime, "2020-04-07", DateFormat("yyyy-mm-dd")) + @test (@inferred Nothing g()) == datetime +end + end diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index bf88c12ea9cf2..3091fed79fee8 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -190,8 +190,9 @@ Specifying `skipstart` will ignore the corresponding number of initial lines fro If `skipblanks` is `true`, blank lines in the input will be ignored. If `use_mmap` is `true`, the file specified by `source` is memory mapped for potential -speedups. Default is `true` except on Windows. On Windows, you may want to specify `true` if -the file is large, and is only read once and not written to. +speedups if the file is large. Default is `false'. On a Windows filesystem, `use_mmap` should not be set +to `true` unless the file is only read once and is also not written to. +Some edge cases exist where an OS is Unix-like but the filesystem is Windows-like. If `quotes` is `true`, columns enclosed within double-quote (\") characters are allowed to contain new lines and column delimiters. Double-quote characters within a quoted field must @@ -232,7 +233,7 @@ readdlm_auto(input::IO, dlm::AbstractChar, T::Type, eol::AbstractChar, auto::Boo function readdlm_auto(input::AbstractString, dlm::AbstractChar, T::Type, eol::AbstractChar, auto::Bool; opts...) isfile(input) || throw(ArgumentError("Cannot open \'$input\': not a file")) optsd = val_opts(opts) - use_mmap = get(optsd, :use_mmap, Sys.iswindows() ? false : true) + use_mmap = get(optsd, :use_mmap, false) fsz = filesize(input) if use_mmap && fsz > 0 && fsz < typemax(Int) a = open(input, "r") do f diff --git a/stdlib/Distributed/docs/src/index.md b/stdlib/Distributed/docs/src/index.md index 1b1675eccc1a2..dc8cef5e22d92 100644 --- a/stdlib/Distributed/docs/src/index.md +++ b/stdlib/Distributed/docs/src/index.md @@ -1,4 +1,4 @@ -# Distributed Computing +# [Distributed Computing](@id man-distributed) ```@docs Distributed.addprocs diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index 7329e1b91d37b..f485384aa1fec 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -160,17 +160,18 @@ function check_worker_state(w::Worker) else w.ct_time = time() if myid() > w.id - @async exec_conn_func(w) + t = @async exec_conn_func(w) else # route request via node 1 - @async remotecall_fetch((p,to_id) -> remotecall_fetch(exec_conn_func, p, to_id), 1, w.id, myid()) + t = @async remotecall_fetch((p,to_id) -> remotecall_fetch(exec_conn_func, p, to_id), 1, w.id, myid()) end + errormonitor(t) wait_for_conn(w) end end end -exec_conn_func(id::Int) = exec_conn_func(worker_from_id(id)) +exec_conn_func(id::Int) = exec_conn_func(worker_from_id(id)::Worker) function exec_conn_func(w::Worker) try f = notnothing(w.conn_func) @@ -242,10 +243,10 @@ function start_worker(out::IO, cookie::AbstractString=readline(stdin); close_std else sock = listen(interface, LPROC.bind_port) end - @async while isopen(sock) + errormonitor(@async while isopen(sock) client = accept(sock) process_messages(client, client, true) - end + end) print(out, "julia_worker:") # print header print(out, "$(string(LPROC.bind_port))#") # print port print(out, LPROC.bind_addr) @@ -274,7 +275,7 @@ end function redirect_worker_output(ident, stream) - @async while !eof(stream) + t = @async while !eof(stream) line = readline(stream) if startswith(line, " From worker ") # stdout's of "additional" workers started from an initial worker on a host are not available @@ -284,6 +285,7 @@ function redirect_worker_output(ident, stream) println(" From worker $(ident):\t$line") end end + errormonitor(t) end struct LaunchWorkerError <: Exception @@ -849,7 +851,7 @@ julia> nprocs() 3 julia> workers() -5-element Array{Int64,1}: +2-element Array{Int64,1}: 2 3 ``` diff --git a/stdlib/Distributed/src/clusterserialize.jl b/stdlib/Distributed/src/clusterserialize.jl index 3fde2bb4c2bd6..e37987c5bf875 100644 --- a/stdlib/Distributed/src/clusterserialize.jl +++ b/stdlib/Distributed/src/clusterserialize.jl @@ -102,19 +102,6 @@ function serialize(s::ClusterSerializer, t::Core.TypeName) nothing end -function serialize(s::ClusterSerializer, t::Task) - serialize_cycle(s, t) && return - if istaskstarted(t) && !istaskdone(t) - error("cannot serialize a running Task") - end - writetag(s.io, TASK_TAG) - serialize(s, t.code) - serialize(s, t.storage) - serialize(s, t._state) - serialize(s, t.result) - serialize(s, t._isexception) -end - function serialize(s::ClusterSerializer, g::GlobalRef) # Record if required and then invoke the default GlobalRef serializer. sym = g.name @@ -244,17 +231,6 @@ function deserialize(s::ClusterSerializer, t::Type{<:CapturedException}) return CapturedException(capex, bt) end -function deserialize(s::ClusterSerializer, ::Type{Task}) - t = Task(nothing) - deserialize_cycle(s, t) - t.code = deserialize(s) - t.storage = deserialize(s) - t._state = deserialize(s)::UInt8 - t.result = deserialize(s) - t._isexception = deserialize(s) - t -end - """ clear!(syms, pids=workers(); mod=Main) diff --git a/stdlib/Distributed/src/macros.jl b/stdlib/Distributed/src/macros.jl index b53890017d4de..6603d627c3409 100644 --- a/stdlib/Distributed/src/macros.jl +++ b/stdlib/Distributed/src/macros.jl @@ -279,9 +279,10 @@ function preduce(reducer, f, R) end function pfor(f, R) - @async @sync for c in splitrange(Int(firstindex(R)), Int(lastindex(R)), nworkers()) + t = @async @sync for c in splitrange(Int(firstindex(R)), Int(lastindex(R)), nworkers()) @spawnat :any f(R, first(c), last(c)) end + errormonitor(t) end function make_preduce_body(var, body) diff --git a/stdlib/Distributed/src/managers.jl b/stdlib/Distributed/src/managers.jl index 3519259190fbc..ce99d85801e17 100644 --- a/stdlib/Distributed/src/managers.jl +++ b/stdlib/Distributed/src/managers.jl @@ -158,22 +158,15 @@ default_addprocs_params(::SSHManager) = function launch(manager::SSHManager, params::Dict, launched::Array, launch_ntfy::Condition) # Launch one worker on each unique host in parallel. Additional workers are launched later. # Wait for all launches to complete. - launch_tasks = Vector{Any}(undef, length(manager.machines)) - - for (i, (machine, cnt)) in enumerate(manager.machines) + @sync for (i, (machine, cnt)) in enumerate(manager.machines) let machine=machine, cnt=cnt - launch_tasks[i] = @async try - launch_on_machine(manager, machine, cnt, params, launched, launch_ntfy) - catch e - print(stderr, "exception launching on machine $(machine) : $(e)\n") - end + @async try + launch_on_machine(manager, $machine, $cnt, params, launched, launch_ntfy) + catch e + print(stderr, "exception launching on machine $(machine) : $(e)\n") + end end end - - for t in launch_tasks - wait(t::Task) - end - notify(launch_ntfy) end diff --git a/stdlib/Distributed/src/messages.jl b/stdlib/Distributed/src/messages.jl index 1424855ec1995..47f70e044a2c0 100644 --- a/stdlib/Distributed/src/messages.jl +++ b/stdlib/Distributed/src/messages.jl @@ -8,7 +8,7 @@ abstract type AbstractMsg end # Each message has three parts, which are written in order to the worker's stream. # 1) A header of type MsgHeader is serialized to the stream (via `serialize`). # 2) A message of type AbstractMsg is then serialized. -# 3) Finally, a fixed bounday of 10 bytes is written. +# 3) Finally, a fixed boundary of 10 bytes is written. # Message header stored separately from body to be able to send back errors if # a deserialization error occurs when reading the message body. @@ -80,18 +80,18 @@ for (idx, tname) in enumerate(msgtypes) end end -let msg_cases = :(@assert false) +let msg_cases = :(@assert false "Message type index ($idx) expected to be between 1:$($(length(msgtypes)))") for i = length(msgtypes):-1:1 mti = msgtypes[i] msg_cases = :(if idx == $i - return $(Expr(:call, QuoteNode(mti), fill(:(deserialize(s)), fieldcount(mti))...)) + $(Expr(:call, QuoteNode(mti), fill(:(deserialize(s)), fieldcount(mti))...)) else $msg_cases end) end @eval function deserialize_msg(s::AbstractSerializer) idx = read(s.io, UInt8) - $msg_cases + return $msg_cases end end diff --git a/stdlib/Distributed/src/process_messages.jl b/stdlib/Distributed/src/process_messages.jl index 3216a4e1c73c6..8d5dac5af571e 100644 --- a/stdlib/Distributed/src/process_messages.jl +++ b/stdlib/Distributed/src/process_messages.jl @@ -78,7 +78,7 @@ function schedule_call(rid, thunk) rv = RemoteValue(def_rv_channel()) (PGRP::ProcessGroup).refs[rid] = rv push!(rv.clientset, rid.whence) - @async run_work_thunk(rv, thunk) + errormonitor(@async run_work_thunk(rv, thunk)) return rv end end @@ -111,7 +111,7 @@ end ## message event handlers ## function process_messages(r_stream::TCPSocket, w_stream::TCPSocket, incoming::Bool=true) - @async process_tcp_streams(r_stream, w_stream, incoming) + errormonitor(@async process_tcp_streams(r_stream, w_stream, incoming)) end function process_tcp_streams(r_stream::TCPSocket, w_stream::TCPSocket, incoming::Bool) @@ -141,7 +141,7 @@ Julia version number to perform the authentication handshake. See also [`cluster_cookie`](@ref). """ function process_messages(r_stream::IO, w_stream::IO, incoming::Bool=true) - @async message_handler_loop(r_stream, w_stream, incoming) + errormonitor(@async message_handler_loop(r_stream, w_stream, incoming)) end function message_handler_loop(r_stream::IO, w_stream::IO, incoming::Bool) @@ -274,7 +274,7 @@ function handle_msg(msg::CallMsg{:call}, header, r_stream, w_stream, version) schedule_call(header.response_oid, ()->msg.f(msg.args...; msg.kwargs...)) end function handle_msg(msg::CallMsg{:call_fetch}, header, r_stream, w_stream, version) - @async begin + errormonitor(@async begin v = run_work_thunk(()->msg.f(msg.args...; msg.kwargs...), false) if isa(v, SyncTake) try @@ -285,18 +285,20 @@ function handle_msg(msg::CallMsg{:call_fetch}, header, r_stream, w_stream, versi else deliver_result(w_stream, :call_fetch, header.notify_oid, v) end - end + nothing + end) end function handle_msg(msg::CallWaitMsg, header, r_stream, w_stream, version) - @async begin + errormonitor(@async begin rv = schedule_call(header.response_oid, ()->msg.f(msg.args...; msg.kwargs...)) deliver_result(w_stream, :call_wait, header.notify_oid, fetch(rv.c)) - end + nothing + end) end function handle_msg(msg::RemoteDoMsg, header, r_stream, w_stream, version) - @async run_work_thunk(()->msg.f(msg.args...; msg.kwargs...), true) + errormonitor(@async run_work_thunk(()->msg.f(msg.args...; msg.kwargs...), true)) end function handle_msg(msg::ResultMsg, header, r_stream, w_stream, version) @@ -330,8 +332,7 @@ function handle_msg(msg::JoinPGRPMsg, header, r_stream, w_stream, version) lazy = msg.lazy PGRP.lazy = lazy - wait_tasks = Task[] - for (connect_at, rpid) in msg.other_workers + @sync for (connect_at, rpid) in msg.other_workers wconfig = WorkerConfig() wconfig.connect_at = connect_at @@ -340,14 +341,11 @@ function handle_msg(msg::JoinPGRPMsg, header, r_stream, w_stream, version) # The constructor registers the object with a global registry. Worker(rpid, ()->connect_to_peer(cluster_manager, rpid, wconfig)) else - t = @async connect_to_peer(cluster_manager, rpid, wconfig) - push!(wait_tasks, t) + @async connect_to_peer(cluster_manager, rpid, wconfig) end end end - for wt in wait_tasks; Base.wait(wt); end - send_connection_hdr(controller, false) send_msg_now(controller, MsgHeader(RRID(0,0), header.notify_oid), JoinCompleteMsg(Sys.CPU_THREADS, getpid())) end diff --git a/stdlib/Distributed/src/remotecall.jl b/stdlib/Distributed/src/remotecall.jl index f4845221a611a..91e5de36736bd 100644 --- a/stdlib/Distributed/src/remotecall.jl +++ b/stdlib/Distributed/src/remotecall.jl @@ -192,7 +192,7 @@ or to use a local [`Channel`](@ref) as a proxy: ```julia p = 1 f = Future(p) -@async put!(f, remotecall_fetch(long_computation, p)) +errormonitor(@async put!(f, remotecall_fetch(long_computation, p))) isready(f) # will not block ``` """ @@ -249,17 +249,17 @@ end const any_gc_flag = Condition() function start_gc_msgs_task() - @async while true + errormonitor(@async while true wait(any_gc_flag) flush_gc_msgs() - end + end) end function send_del_client(rr) if rr.where == myid() del_client(rr) elseif id_in_procs(rr.where) # process only if a valid worker - w = worker_from_id(rr.where) + w = worker_from_id(rr.where)::Worker push!(w.del_msgs, (remoteref_id(rr), myid())) w.gcflag = true notify(any_gc_flag) diff --git a/stdlib/Distributed/test/distributed_exec.jl b/stdlib/Distributed/test/distributed_exec.jl index c36a79600773c..606b7fa81c3e7 100644 --- a/stdlib/Distributed/test/distributed_exec.jl +++ b/stdlib/Distributed/test/distributed_exec.jl @@ -1675,7 +1675,7 @@ let e = @test_throws RemoteException pmap(1) do _ es = sprint(showerror, e.value) @test contains(es, ":\nTaskFailedException\nStacktrace:\n") @test contains(es, "\n\n nested task error:") - @test_broken contains(es, "\n\n nested task error: 42\n") + @test contains(es, "\n\n nested task error: 42\n") end # issue #27429, propagate relative `include` path to workers diff --git a/stdlib/Downloads.version b/stdlib/Downloads.version index 9dc2783a1389b..c11c56068a51a 100644 --- a/stdlib/Downloads.version +++ b/stdlib/Downloads.version @@ -1,2 +1,2 @@ DOWNLOADS_BRANCH = master -DOWNLOADS_SHA1 = 6bb83068bd796c4890baaeb39628ff79a4979374 +DOWNLOADS_SHA1 = c0e5cbdef011ea4b87c56efaf5e9b1d16500ce71 diff --git a/stdlib/InteractiveUtils/docs/src/index.md b/stdlib/InteractiveUtils/docs/src/index.md index 6b996fb333fc5..71499744ecb1d 100644 --- a/stdlib/InteractiveUtils/docs/src/index.md +++ b/stdlib/InteractiveUtils/docs/src/index.md @@ -1,4 +1,4 @@ -# Interactive Utilities +# [Interactive Utilities](@id man-interactive-utils) This module is intended for interactive work. It is loaded automaticaly in [interactive mode](@ref command-line-options). diff --git a/stdlib/InteractiveUtils/src/InteractiveUtils.jl b/stdlib/InteractiveUtils/src/InteractiveUtils.jl index 9d989148878fb..459cad76e7d60 100644 --- a/stdlib/InteractiveUtils/src/InteractiveUtils.jl +++ b/stdlib/InteractiveUtils/src/InteractiveUtils.jl @@ -81,6 +81,8 @@ Print information about the version of Julia in use. The output is controlled with boolean keyword arguments: - `verbose`: print all additional information + +See also: [`VERSION`](@ref). """ function versioninfo(io::IO=stdout; verbose::Bool=false) println(io, "Julia Version $VERSION") @@ -261,6 +263,8 @@ subtypes(m::Module, x::Type) = _subtypes_in([m], x) Return a list of immediate subtypes of DataType `T`. Note that all currently loaded subtypes are included, including those not visible in the current module. +See also [`supertype`](@ref), [`supertypes`](@ref), [`methodswith`](@ref). + # Examples ```jldoctest julia> subtypes(Integer) @@ -279,6 +283,8 @@ Return a tuple `(T, ..., Any)` of `T` and all its supertypes, as determined by successive calls to the [`supertype`](@ref) function, listed in order of `<:` and terminated by `Any`. +See also [`subtypes`](@ref). + # Examples ```jldoctest julia> supertypes(Int) @@ -297,7 +303,7 @@ end function dumptype(io::IO, @nospecialize(x), n::Int, indent) print(io, x) n == 0 && return # too deeply nested - isa(x, DataType) && x.abstract && dumpsubtypes(io, x, Main, n, indent) + isa(x, DataType) && x.name.abstract && dumpsubtypes(io, x, Main, n, indent) nothing end @@ -396,9 +402,12 @@ function report_bug(kind) mktempdir() do tmp old_load_path = copy(LOAD_PATH) push!(empty!(LOAD_PATH), joinpath(tmp, "Project.toml")) + old_active_project = Base.ACTIVE_PROJECT[] + Base.ACTIVE_PROJECT[] = nothing Pkg.add(Pkg.PackageSpec(BugReportingId.name, BugReportingId.uuid)) BugReporting = Base.require(BugReportingId) append!(empty!(LOAD_PATH), old_load_path) + Base.ACTIVE_PROJECT[] = old_active_project end end else diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index da72fae8daeb0..3cb792c75b9b4 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -127,7 +127,8 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(t); debuginfo::Sy print(io, "Body") warntype_type_printer(io, rettype, true) println(io) - Base.IRShow.show_ir(lambda_io, src, lineprinter(src), warntype_type_printer) + irshow_config = Base.IRShow.IRShowConfig(lineprinter(src), warntype_type_printer) + Base.IRShow.show_ir(lambda_io, src, irshow_config) println(io) end nothing @@ -140,7 +141,7 @@ import Base.CodegenParams # Printing code representations in IR and assembly function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrapper::Bool, strip_ir_metadata::Bool, dump_module::Bool, syntax::Symbol, - optimize::Bool, debuginfo::Symbol, + optimize::Bool, debuginfo::Symbol, binary::Bool, params::CodegenParams=CodegenParams()) ccall(:jl_is_in_pure_context, Bool, ()) && error("code reflection cannot be used from generated functions") if isa(f, Core.Builtin) @@ -152,7 +153,7 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe linfo = Core.Compiler.specialize_method(match) # get the code for it if native - str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo) + str = _dump_function_linfo_native(linfo, world, wrapper, syntax, debuginfo, binary) else str = _dump_function_linfo_llvm(linfo, world, wrapper, strip_ir_metadata, dump_module, optimize, debuginfo, params) end @@ -161,7 +162,7 @@ function _dump_function(@nospecialize(f), @nospecialize(t), native::Bool, wrappe return str end -function _dump_function_linfo_native(linfo::Core.MethodInstance, world::UInt, wrapper::Bool, syntax::Symbol, debuginfo::Symbol) +function _dump_function_linfo_native(linfo::Core.MethodInstance, world::UInt, wrapper::Bool, syntax::Symbol, debuginfo::Symbol, binary::Bool) if syntax !== :att && syntax !== :intel throw(ArgumentError("'syntax' must be either :intel or :att")) end @@ -171,8 +172,8 @@ function _dump_function_linfo_native(linfo::Core.MethodInstance, world::UInt, wr throw(ArgumentError("'debuginfo' must be either :source or :none")) end str = ccall(:jl_dump_method_asm, Ref{String}, - (Any, UInt, Cint, Bool, Ptr{UInt8}, Ptr{UInt8}), - linfo, world, 0, wrapper, syntax, debuginfo) + (Any, UInt, Cint, Bool, Ptr{UInt8}, Ptr{UInt8}, Bool), + linfo, world, 0, wrapper, syntax, debuginfo, binary) return str end @@ -207,7 +208,7 @@ Keyword argument `debuginfo` may be one of source (default) or none, to specify """ function code_llvm(io::IO, @nospecialize(f), @nospecialize(types), raw::Bool, dump_module::Bool=false, optimize::Bool=true, debuginfo::Symbol=:default) - d = _dump_function(f, types, false, false, !raw, dump_module, :att, optimize, debuginfo) + d = _dump_function(f, types, false, false, !raw, dump_module, :att, optimize, debuginfo, false) if highlighting[:llvm] && get(io, :color, false) print_llvm(io, d) else @@ -221,24 +222,25 @@ code_llvm(@nospecialize(f), @nospecialize(types=Tuple); raw=false, dump_module=f """ - code_native([io=stdout,], f, types; syntax=:att, debuginfo=:default) + code_native([io=stdout,], f, types; syntax=:att, debuginfo=:default, binary=false) Prints the native assembly instructions generated for running the method matching the given generic function and type signature to `io`. Switch assembly syntax using `syntax` symbol parameter set to `:att` for AT&T syntax or `:intel` for Intel syntax. Keyword argument `debuginfo` may be one of source (default) or none, to specify the verbosity of code comments. +If `binary` is `true`, it also prints the binary machine code for each instruction precedented by an abbreviated address. """ function code_native(io::IO, @nospecialize(f), @nospecialize(types=Tuple); - syntax::Symbol=:att, debuginfo::Symbol=:default) - d = _dump_function(f, types, true, false, false, false, syntax, true, debuginfo) + syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) + d = _dump_function(f, types, true, false, false, false, syntax, true, debuginfo, binary) if highlighting[:native] && get(io, :color, false) print_native(io, d) else print(io, d) end end -code_native(@nospecialize(f), @nospecialize(types=Tuple); syntax::Symbol=:att, debuginfo::Symbol=:default) = - code_native(stdout, f, types; syntax=syntax, debuginfo=debuginfo) +code_native(@nospecialize(f), @nospecialize(types=Tuple); syntax::Symbol=:att, debuginfo::Symbol=:default, binary::Bool=false) = + code_native(stdout, f, types; syntax=syntax, debuginfo=debuginfo, binary=binary) code_native(::IO, ::Any, ::Symbol) = error("illegal code_native call") # resolve ambiguous call ## colorized IR and assembly printing diff --git a/stdlib/InteractiveUtils/src/editless.jl b/stdlib/InteractiveUtils/src/editless.jl index 4c18682d671b3..cc3de27e9a4d9 100644 --- a/stdlib/InteractiveUtils/src/editless.jl +++ b/stdlib/InteractiveUtils/src/editless.jl @@ -192,7 +192,7 @@ Edit a file or directory optionally providing a line number to edit the file at. Return to the `julia` prompt when you quit the editor. The editor can be changed by setting `JULIA_EDITOR`, `VISUAL` or `EDITOR` as an environment variable. -See also: [`define_editor`](@ref) +See also [`define_editor`](@ref). """ function edit(path::AbstractString, line::Integer=0) path isa String || (path = convert(String, path)) @@ -222,9 +222,16 @@ method to edit. For modules, open the main source file. The module needs to be l To ensure that the file can be opened at the given line, you may need to call `define_editor` first. """ -edit(f) = edit(functionloc(f)...) -edit(f, @nospecialize t) = edit(functionloc(f,t)...) -edit(file, line::Integer) = error("could not find source file for function") +function edit(@nospecialize f) + ms = methods(f).ms + length(ms) == 1 && edit(functionloc(ms[1])...) + length(ms) > 1 && return ms + length(ms) == 0 && functionloc(f) # throws + nothing +end +edit(@nospecialize(f), idx::Integer) = edit(methods(f).ms[idx]) +edit(f, t) = (@nospecialize; edit(functionloc(f, t)...)) +edit(file::Nothing, line::Integer) = error("could not find source file for function") edit(m::Module) = edit(pathof(m)) # terminal pager diff --git a/stdlib/InteractiveUtils/src/macros.jl b/stdlib/InteractiveUtils/src/macros.jl index 011a0034378b2..8d70af708cab5 100644 --- a/stdlib/InteractiveUtils/src/macros.jl +++ b/stdlib/InteractiveUtils/src/macros.jl @@ -4,7 +4,7 @@ import Base: typesof, insert! -separate_kwargs(args...; kwargs...) = (args, kwargs.data) +separate_kwargs(args...; kwargs...) = (args, values(kwargs)) """ Transform a dot expression into one where each argument has been replaced by a @@ -247,7 +247,9 @@ It calls out to the `functionloc` function. Applied to a function or macro call, it evaluates the arguments to the specified call, and returns the `Method` object for the method that would be called for those arguments. Applied to a variable, it returns the module in which the variable was bound. It calls out to the -`which` function. +[`which`](@ref) function. + +See also: [`@less`](@ref), [`@edit`](@ref). """ :@which @@ -256,6 +258,8 @@ to a variable, it returns the module in which the variable was bound. It calls o Evaluates the arguments to the function or macro call, determines their types, and calls the `less` function on the resulting expression. + +See also: [`@edit`](@ref), [`@which`](@ref), [`@code_lowered`](@ref). """ :@less @@ -264,6 +268,8 @@ function on the resulting expression. Evaluates the arguments to the function or macro call, determines their types, and calls the `edit` function on the resulting expression. + +See also: [`@less`](@ref), [`@which`](@ref). """ :@edit diff --git a/stdlib/InteractiveUtils/test/runtests.jl b/stdlib/InteractiveUtils/test/runtests.jl index b272f46f14794..bf32ea0eb6159 100644 --- a/stdlib/InteractiveUtils/test/runtests.jl +++ b/stdlib/InteractiveUtils/test/runtests.jl @@ -60,7 +60,7 @@ end Base.getindex(A::Stable, i) = A.A[i] Base.getindex(A::Unstable, i) = A.A[i] -tag = "ARRAY{FLOAT64, N}" +tag = "ARRAY" @test warntype_hastag(getindex, Tuple{Unstable{Float64},Int}, tag) @test !warntype_hastag(getindex, Tuple{Stable{Float64,2},Int}, tag) @test warntype_hastag(getindex, Tuple{Stable{Float64},Int}, tag) @@ -442,23 +442,36 @@ if Sys.ARCH === :x86_64 || occursin(ix86, string(Sys.ARCH)) rgx = r"%" buf = IOBuffer() - output = "" #test that the string output is at&t syntax by checking for occurrences of '%'s code_native(buf, linear_foo, (), syntax = :att, debuginfo = :none) output = String(take!(buf)) - @test occursin(rgx, output) #test that the code output is intel syntax by checking it has no occurrences of '%' code_native(buf, linear_foo, (), syntax = :intel, debuginfo = :none) output = String(take!(buf)) - @test !occursin(rgx, output) code_native(buf, linear_foo, ()) output = String(take!(buf)) - @test occursin(rgx, output) + + @testset "binary" begin + # check the RET instruction (opcode: C3) + ret = r"^; [0-9a-f]{4}: c3$"m + + # without binary flag (default) + code_native(buf, linear_foo, ()) + output = String(take!(buf)) + @test !occursin(ret, output) + + # with binary flag + for binary in false:true + code_native(buf, linear_foo, (), binary = binary) + output = String(take!(buf)) + @test occursin(ret, output) == binary + end + end end @testset "error message" begin diff --git a/stdlib/LibGit2/src/error.jl b/stdlib/LibGit2/src/error.jl index 3e56999d5a52c..d742cde1605b8 100644 --- a/stdlib/LibGit2/src/error.jl +++ b/stdlib/LibGit2/src/error.jl @@ -77,7 +77,7 @@ end struct GitError <: Exception class::Class code::Code - msg::AbstractString + msg::String end Base.show(io::IO, err::GitError) = print(io, "GitError(Code:$(err.code), Class:$(err.class), $(err.msg))") @@ -95,8 +95,8 @@ function last_error() return (err_class, err_msg) end -function GitError(code::Integer) - err_code = Code(code) +GitError(err_code::Integer) = GitError(Code(err_code)) +function GitError(err_code::Code) err_class, err_msg = last_error() return GitError(err_class, err_code, err_msg) end diff --git a/stdlib/LibGit2/src/gitcredential.jl b/stdlib/LibGit2/src/gitcredential.jl index 0a442337531a7..1b97c29cd933e 100644 --- a/stdlib/LibGit2/src/gitcredential.jl +++ b/stdlib/LibGit2/src/gitcredential.jl @@ -30,7 +30,12 @@ function GitCredential(cfg::GitConfig, url::AbstractString) fill!(cfg, parse(GitCredential, url)) end -GitCredential(cred::UserPasswordCredential, url::AbstractString) = parse(GitCredential, url) +function GitCredential(user_pass_cred::UserPasswordCredential, url::AbstractString) + cred = parse(GitCredential, url) + cred.username = user_pass_cred.user + cred.password = deepcopy(user_pass_cred.pass) + return cred +end Base.:(==)(c1::GitCredential, c2::GitCredential) = (c1.protocol, c1.host, c1.path, c1.username, c1.password, c1.use_http_path) == (c2.protocol, c2.host, c2.path, c2.username, c2.password, c2.use_http_path) diff --git a/stdlib/LibGit2/src/types.jl b/stdlib/LibGit2/src/types.jl index 129f526812926..9ffcaa3646127 100644 --- a/stdlib/LibGit2/src/types.jl +++ b/stdlib/LibGit2/src/types.jl @@ -192,7 +192,7 @@ The fields represent: perfdata_cb::Ptr{Cvoid} = C_NULL perfdata_payload::Any = Nothing end -@assert CheckoutOptions.isinlinealloc +@assert Base.allocatedinline(CheckoutOptions) """ LibGit2.TransferProgress @@ -209,7 +209,7 @@ Matches the [`git_indexer_progress`](https://libgit2.org/libgit2/#HEAD/type/git_ indexed_deltas::Cuint = Cuint(0) received_bytes::Csize_t = Csize_t(0) end -@assert TransferProgress.isinlinealloc +@assert Base.allocatedinline(TransferProgress) """ LibGit2.RemoteCallbacks @@ -235,7 +235,7 @@ Matches the [`git_remote_callbacks`](https://libgit2.org/libgit2/#HEAD/type/git_ resolve_url::Ptr{Cvoid} = C_NULL end end -@assert RemoteCallbacks.isinlinealloc +@assert Base.allocatedinline(RemoteCallbacks) """ LibGit2.Callbacks @@ -313,7 +313,7 @@ julia> fetch(remote, "master", options=fo) certificate_cb::Ptr{Cvoid} = certificate_cb() payload::Any = nothing end -@assert ProxyOptions.isinlinealloc +@assert Base.allocatedinline(ProxyOptions) """ LibGit2.FetchOptions @@ -347,7 +347,7 @@ The fields represent: custom_headers::StrArrayStruct = StrArrayStruct() end end -@assert FetchOptions.isinlinealloc +@assert Base.allocatedinline(FetchOptions) """ @@ -384,7 +384,7 @@ The fields represent: remote_cb::Ptr{Cvoid} = C_NULL remote_cb_payload::Any = nothing end -@assert CloneOptions.isinlinealloc +@assert Base.allocatedinline(CloneOptions) """ LibGit2.DiffOptionsStruct @@ -438,7 +438,7 @@ The fields represent: old_prefix::Cstring = Cstring(C_NULL) new_prefix::Cstring = Cstring(C_NULL) end -@assert DiffOptionsStruct.isinlinealloc +@assert Base.allocatedinline(DiffOptionsStruct) """ LibGit2.DescribeOptions @@ -468,7 +468,7 @@ The fields represent: only_follow_first_parent::Cint = Cint(0) show_commit_oid_as_fallback::Cint = Cint(0) end -@assert DescribeOptions.isinlinealloc +@assert Base.allocatedinline(DescribeOptions) """ LibGit2.DescribeFormatOptions @@ -487,7 +487,7 @@ The fields represent: always_use_long_format::Cint = Cint(0) dirty_suffix::Cstring = Cstring(C_NULL) end -@assert DescribeFormatOptions.isinlinealloc +@assert Base.allocatedinline(DescribeFormatOptions) """ LibGit2.DiffFile @@ -617,7 +617,7 @@ The fields represent: file_favor::GIT_MERGE_FILE_FAVOR = Consts.MERGE_FILE_FAVOR_NORMAL file_flags::GIT_MERGE_FILE = Consts.MERGE_FILE_DEFAULT end -@assert MergeOptions.isinlinealloc +@assert Base.allocatedinline(MergeOptions) """ LibGit2.BlameOptions @@ -647,7 +647,7 @@ The fields represent: min_line::Csize_t = Csize_t(1) max_line::Csize_t = Csize_t(0) end -@assert BlameOptions.isinlinealloc +@assert Base.allocatedinline(BlameOptions) """ @@ -678,7 +678,7 @@ The fields represent: custom_headers::StrArrayStruct = StrArrayStruct() end end -@assert PushOptions.isinlinealloc +@assert Base.allocatedinline(PushOptions) """ @@ -701,7 +701,7 @@ The fields represent: merge_opts::MergeOptions = MergeOptions() checkout_opts::CheckoutOptions = CheckoutOptions() end -@assert CherrypickOptions.isinlinealloc +@assert Base.allocatedinline(CherrypickOptions) """ @@ -771,7 +771,7 @@ The fields represent: end checkout_opts::CheckoutOptions = CheckoutOptions() end -@assert RebaseOptions.isinlinealloc +@assert Base.allocatedinline(RebaseOptions) """ LibGit2.RebaseOperation @@ -834,7 +834,7 @@ The fields represent: baseline::Ptr{Cvoid} = C_NULL end end -@assert StatusOptions.isinlinealloc +@assert Base.allocatedinline(StatusOptions) """ LibGit2.StatusEntry @@ -902,7 +902,7 @@ Matches the [`git_config_entry`](https://libgit2.org/libgit2/#HEAD/type/git_conf free::Ptr{Cvoid} = C_NULL payload::Any = nothing end -@assert ConfigEntry.isinlinealloc +@assert Base.allocatedinline(ConfigEntry) function Base.show(io::IO, ce::ConfigEntry) print(io, "ConfigEntry(\"", unsafe_string(ce.name), "\", \"", unsafe_string(ce.value), "\")") @@ -1136,7 +1136,7 @@ The fields represent: boundary::Char = '\0' end -@assert BlameHunk.isinlinealloc +@assert Base.allocatedinline(BlameHunk) """ with(f::Function, obj) diff --git a/stdlib/LibGit2/test/libgit2.jl b/stdlib/LibGit2/test/libgit2.jl index 93e530aee5d8e..892fb8bb6f3fe 100644 --- a/stdlib/LibGit2/test/libgit2.jl +++ b/stdlib/LibGit2/test/libgit2.jl @@ -600,6 +600,23 @@ end github_regex_test("ssh://git@github.com/$user/$repo", user, repo) @test !occursin(LibGit2.GITHUB_REGEX, "git@notgithub.com/$user/$repo.git") end + + @testset "UserPasswordCredential/url constructor" begin + user_pass_cred = LibGit2.UserPasswordCredential("user", "*******") + url = "https://github.com" + expected_cred = LibGit2.GitCredential("https", "github.com", nothing, "user", "*******") + + cred = LibGit2.GitCredential(user_pass_cred, url) + @test cred == expected_cred + + # Shredding the UserPasswordCredential shouldn't result in information being lost + # inside of a GitCredential. + Base.shred!(user_pass_cred) + @test cred == expected_cred + + Base.shred!(cred) + Base.shred!(expected_cred) + end end mktempdir() do dir @@ -2133,6 +2150,50 @@ mktempdir() do dir end end end + + @testset "approve/reject with UserPasswordCredential" begin + # In order to use the "store" credential helper `git` needs to be installed and + # on the path. + if GIT_INSTALLED + config_path = joinpath(dir, config_file) + isfile(config_path) && rm(config_path) + + credential_path = joinpath(dir, ".git-credentials") + isfile(credential_path) && rm(credential_path) + + LibGit2.with(LibGit2.GitConfig(config_path, LibGit2.Consts.CONFIG_LEVEL_APP)) do cfg + query = LibGit2.GitCredential("https", "mygithost") + filled = LibGit2.GitCredential("https", "mygithost", nothing, "alice", "1234") + user_pass_cred = LibGit2.UserPasswordCredential("alice", "1234") + url = "https://mygithost" + + # Requires `git` to be installed and available on the path. + LibGit2.set!(cfg, "credential.helper", "store --file \"$credential_path\"") + helper = only(LibGit2.credential_helpers(cfg, query)) + + @test !isfile(credential_path) + + Base.shred!(LibGit2.fill!(helper, deepcopy(query))) do result + @test result == query + end + + LibGit2.approve(cfg, user_pass_cred, url) + @test isfile(credential_path) + Base.shred!(LibGit2.fill!(helper, deepcopy(query))) do result + @test result == filled + end + + LibGit2.reject(cfg, user_pass_cred, url) + Base.shred!(LibGit2.fill!(helper, deepcopy(query))) do result + @test result == query + end + + Base.shred!(query) + Base.shred!(filled) + Base.shred!(user_pass_cred) + end + end + end end # The following tests require that we can fake a TTY so that we can provide passwords diff --git a/stdlib/LinearAlgebra/docs/src/index.md b/stdlib/LinearAlgebra/docs/src/index.md index 52e7860999287..baafe762cea3f 100644 --- a/stdlib/LinearAlgebra/docs/src/index.md +++ b/stdlib/LinearAlgebra/docs/src/index.md @@ -410,6 +410,7 @@ LinearAlgebra.nullspace Base.kron Base.kron! LinearAlgebra.exp(::StridedMatrix{<:LinearAlgebra.BlasFloat}) +Base.cis(::AbstractMatrix) Base.:^(::AbstractMatrix, ::Number) Base.:^(::Number, ::AbstractMatrix) LinearAlgebra.log(::StridedMatrix) @@ -576,6 +577,7 @@ LinearAlgebra.BLAS.trmv LinearAlgebra.BLAS.trsv! LinearAlgebra.BLAS.trsv LinearAlgebra.BLAS.set_num_threads +LinearAlgebra.BLAS.get_num_threads ``` ## LAPACK functions diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 8f3e5c10663db..07bb954807361 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -35,6 +35,7 @@ export BunchKaufman, Cholesky, CholeskyPivoted, + ColumnNorm, Eigen, GeneralizedEigen, GeneralizedSVD, @@ -42,12 +43,14 @@ export Hessenberg, LU, LDLt, + NoPivot, QR, QRPivoted, LQ, Schur, SVD, Hermitian, + RowMaximum, Symmetric, LowerTriangular, UpperTriangular, @@ -164,6 +167,10 @@ abstract type Algorithm end struct DivideAndConquer <: Algorithm end struct QRIteration <: Algorithm end +abstract type PivotingStrategy end +struct NoPivot <: PivotingStrategy end +struct RowMaximum <: PivotingStrategy end +struct ColumnNorm <: PivotingStrategy end # Check that stride of matrix/vector is 1 # Writing like this to avoid splatting penalty when called with multiple arguments, @@ -374,6 +381,7 @@ include("cholesky.jl") include("lu.jl") include("bunchkaufman.jl") include("diagonal.jl") +include("symmetriceigen.jl") include("bidiag.jl") include("uniformscaling.jl") include("hessenberg.jl") @@ -389,6 +397,63 @@ const ⋅ = dot const × = cross export ⋅, × +## convenience methods +## return only the solution of a least squares problem while avoiding promoting +## vectors to matrices. +_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x +_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X + +## append right hand side with zeros if necessary +_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n)) +_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2)) + +# General fallback definition for handling under- and overdetermined system as well as square problems +# While this definition is pretty general, it does e.g. promote to common element type of lhs and rhs +# which is required by LAPACK but not SuiteSpase which allows real-complex solves in some cases. Hence, +# we restrict this method to only the LAPACK factorizations in LinearAlgebra. +# The definition is put here since it explicitly references all the Factorizion structs so it has +# to be located after all the files that define the structs. +const LAPACKFactorizations{T,S} = Union{ + BunchKaufman{T,S}, + Cholesky{T,S}, + LQ{T,S}, + LU{T,S}, + QR{T,S}, + QRCompactWY{T,S}, + QRPivoted{T,S}, + SVD{T,<:Real,S}} +function (\)(F::Union{<:LAPACKFactorizations,Adjoint{<:Any,<:LAPACKFactorizations}}, B::AbstractVecOrMat) + require_one_based_indexing(B) + m, n = size(F) + if m != size(B, 1) + throw(DimensionMismatch("arguments must have the same number of rows")) + end + + TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) + FF = Factorization{TFB}(F) + + # For wide problem we (often) compute a minimum norm solution. The solution + # is larger than the right hand side so we use size(F, 2). + BB = _zeros(TFB, B, n) + + if n > size(B, 1) + # Underdetermined + copyto!(view(BB, 1:m, :), B) + else + copyto!(BB, B) + end + + ldiv!(FF, BB) + + # For tall problems, we compute a least squares solution so only part + # of the rhs should be returned from \ while ldiv! uses (and returns) + # the complete rhs + return _cut_B(BB, 1:n) +end +# disambiguate +(\)(F::LAPACKFactorizations{T}, B::VecOrMat{Complex{T}}) where {T<:BlasReal} = + invoke(\, Tuple{Factorization{T}, VecOrMat{Complex{T}}}, F, B) + """ LinearAlgebra.peakflops(n::Integer=2000; parallel::Bool=false) diff --git a/stdlib/LinearAlgebra/src/adjtrans.jl b/stdlib/LinearAlgebra/src/adjtrans.jl index 56942930d7aa7..dac216f0f072a 100644 --- a/stdlib/LinearAlgebra/src/adjtrans.jl +++ b/stdlib/LinearAlgebra/src/adjtrans.jl @@ -34,10 +34,6 @@ julia> adjoint(A) """ struct Adjoint{T,S} <: AbstractMatrix{T} parent::S - function Adjoint{T,S}(A::S) where {T,S} - checkeltype_adjoint(T, eltype(A)) - new(A) - end end """ Transpose @@ -65,30 +61,6 @@ julia> transpose(A) """ struct Transpose{T,S} <: AbstractMatrix{T} parent::S - function Transpose{T,S}(A::S) where {T,S} - checkeltype_transpose(T, eltype(A)) - new(A) - end -end - -function checkeltype_adjoint(::Type{ResultEltype}, ::Type{ParentEltype}) where {ResultEltype,ParentEltype} - Expected = Base.promote_op(adjoint, ParentEltype) - ResultEltype === Expected || error(string( - "Element type mismatch. Tried to create an `Adjoint{", ResultEltype, "}` ", - "from an object with eltype `", ParentEltype, "`, but the element type of ", - "the adjoint of an object with eltype `", ParentEltype, "` must be ", - "`", Expected, "`.")) - return nothing -end - -function checkeltype_transpose(::Type{ResultEltype}, ::Type{ParentEltype}) where {ResultEltype, ParentEltype} - Expected = Base.promote_op(transpose, ParentEltype) - ResultEltype === Expected || error(string( - "Element type mismatch. Tried to create a `Transpose{", ResultEltype, "}` ", - "from an object with eltype `", ParentEltype, "`, but the element type of ", - "the transpose of an object with eltype `", ParentEltype, "` must be ", - "`", Expected, "`.")) - return nothing end # basic outer constructors @@ -185,7 +157,9 @@ end # some aliases for internal convenience use const AdjOrTrans{T,S} = Union{Adjoint{T,S},Transpose{T,S}} where {T,S} const AdjointAbsVec{T} = Adjoint{T,<:AbstractVector} +const AdjointAbsMat{T} = Adjoint{T,<:AbstractMatrix} const TransposeAbsVec{T} = Transpose{T,<:AbstractVector} +const TransposeAbsMat{T} = Transpose{T,<:AbstractMatrix} const AdjOrTransAbsVec{T} = AdjOrTrans{T,<:AbstractVector} const AdjOrTransAbsMat{T} = AdjOrTrans{T,<:AbstractMatrix} @@ -201,8 +175,8 @@ axes(v::AdjOrTransAbsVec) = (Base.OneTo(1), axes(v.parent)...) axes(A::AdjOrTransAbsMat) = reverse(axes(A.parent)) IndexStyle(::Type{<:AdjOrTransAbsVec}) = IndexLinear() IndexStyle(::Type{<:AdjOrTransAbsMat}) = IndexCartesian() -@propagate_inbounds getindex(v::AdjOrTransAbsVec, i::Int) = wrapperop(v)(v.parent[i-1+first(axes(v.parent)[1])]) -@propagate_inbounds getindex(A::AdjOrTransAbsMat, i::Int, j::Int) = wrapperop(A)(A.parent[j, i]) +@propagate_inbounds getindex(v::AdjOrTransAbsVec{T}, i::Int) where {T} = wrapperop(v)(v.parent[i-1+first(axes(v.parent)[1])])::T +@propagate_inbounds getindex(A::AdjOrTransAbsMat{T}, i::Int, j::Int) where {T} = wrapperop(A)(A.parent[j, i])::T @propagate_inbounds setindex!(v::AdjOrTransAbsVec, x, i::Int) = (setindex!(v.parent, wrapperop(v)(x), i-1+first(axes(v.parent)[1])); v) @propagate_inbounds setindex!(A::AdjOrTransAbsMat, x, i::Int, j::Int) = (setindex!(A.parent, wrapperop(A)(x), j, i); A) # AbstractArray interface, additional definitions to retain wrapper over vectors where appropriate @@ -238,7 +212,7 @@ similar(A::AdjOrTrans, ::Type{T}, dims::Dims{N}) where {T,N} = similar(A.parent, # sundry basic definitions parent(A::AdjOrTrans) = A.parent -vec(v::TransposeAbsVec) = parent(v) +vec(v::TransposeAbsVec{<:Number}) = parent(v) vec(v::AdjointAbsVec{<:Real}) = parent(v) ### concatenation @@ -275,6 +249,25 @@ Broadcast.broadcast_preserving_zero_d(f, avs::Union{Number,AdjointAbsVec}...) = Broadcast.broadcast_preserving_zero_d(f, tvs::Union{Number,TransposeAbsVec}...) = transpose(broadcast((xs...) -> transpose(f(transpose.(xs)...)), quasiparentt.(tvs)...)) # TODO unify and allow mixed combinations with a broadcast style + +### reductions +# faster to sum the Array than to work through the wrapper +Base._mapreduce_dim(f, op, init::Base._InitialValue, A::Transpose, dims::Colon) = + transpose(Base._mapreduce_dim(_sandwich(transpose, f), _sandwich(transpose, op), init, parent(A), dims)) +Base._mapreduce_dim(f, op, init::Base._InitialValue, A::Adjoint, dims::Colon) = + adjoint(Base._mapreduce_dim(_sandwich(adjoint, f), _sandwich(adjoint, op), init, parent(A), dims)) +# sum(A'; dims) +Base.mapreducedim!(f, op, B::AbstractArray, A::TransposeAbsMat) = + transpose(Base.mapreducedim!(_sandwich(transpose, f), _sandwich(transpose, op), transpose(B), parent(A))) +Base.mapreducedim!(f, op, B::AbstractArray, A::AdjointAbsMat) = + adjoint(Base.mapreducedim!(_sandwich(adjoint, f), _sandwich(adjoint, op), adjoint(B), parent(A))) + +_sandwich(adj::Function, fun) = (xs...,) -> adj(fun(map(adj, xs)...)) +for fun in [:identity, :add_sum, :mul_prod] #, :max, :min] + @eval _sandwich(::Function, ::typeof(Base.$fun)) = Base.$fun +end + + ### linear algebra (-)(A::Adjoint) = Adjoint( -A.parent) diff --git a/stdlib/LinearAlgebra/src/bidiag.jl b/stdlib/LinearAlgebra/src/bidiag.jl index 69fbaa476de73..ff6598451509f 100644 --- a/stdlib/LinearAlgebra/src/bidiag.jl +++ b/stdlib/LinearAlgebra/src/bidiag.jl @@ -635,8 +635,6 @@ end const UpperOrUnitUpperTriangular = Union{UpperTriangular, UnitUpperTriangular} const LowerOrUnitLowerTriangular = Union{LowerTriangular, UnitLowerTriangular} -const AdjOrTransUpperOrUnitUpperTriangular = Union{Adjoint{<:Any, <:UpperOrUnitUpperTriangular}, Transpose{<:Any, <:UpperOrUnitUpperTriangular}} -const AdjOrTransLowerOrUnitLowerTriangular = Union{Adjoint{<:Any, <:LowerOrUnitLowerTriangular}, Transpose{<:Any, <:LowerOrUnitLowerTriangular}} function *(A::UpperOrUnitUpperTriangular, B::Bidiagonal) TS = promote_op(matprod, eltype(A), eltype(B)) @@ -647,15 +645,6 @@ function *(A::UpperOrUnitUpperTriangular, B::Bidiagonal) end end -function *(A::AdjOrTransUpperOrUnitUpperTriangular, B::Bidiagonal) - TS = promote_op(matprod, eltype(A), eltype(B)) - if B.uplo == 'L' - A_mul_B_td!(LowerTriangular(zeros(TS, size(A)...)), A, B) - else - A_mul_B_td!(zeros(TS, size(A)...), A, B) - end -end - function *(A::LowerOrUnitLowerTriangular, B::Bidiagonal) TS = promote_op(matprod, eltype(A), eltype(B)) if B.uplo == 'L' @@ -665,15 +654,6 @@ function *(A::LowerOrUnitLowerTriangular, B::Bidiagonal) end end -function *(A::AdjOrTransLowerOrUnitLowerTriangular, B::Bidiagonal) - TS = promote_op(matprod, eltype(A), eltype(B)) - if B.uplo == 'U' - A_mul_B_td!(UpperTriangular(zeros(TS, size(A)...)), A, B) - else - A_mul_B_td!(zeros(TS, size(A)...), A, B) - end -end - function *(A::Union{SymTridiagonal, Tridiagonal}, B::AbstractTriangular) TS = promote_op(matprod, eltype(A), eltype(B)) A_mul_B_td!(zeros(TS, size(A)...), A, B) @@ -688,15 +668,6 @@ function *(A::Bidiagonal, B::UpperOrUnitUpperTriangular) end end -function *(A::Bidiagonal, B::AdjOrTransUpperOrUnitUpperTriangular) - TS = promote_op(matprod, eltype(A), eltype(B)) - if A.uplo == 'L' - A_mul_B_td!(LowerTriangular(zeros(TS, size(A)...)), A, B) - else - A_mul_B_td!(zeros(TS, size(A)...), A, B) - end -end - function *(A::Bidiagonal, B::LowerOrUnitLowerTriangular) TS = promote_op(matprod, eltype(A), eltype(B)) if A.uplo == 'L' @@ -706,15 +677,6 @@ function *(A::Bidiagonal, B::LowerOrUnitLowerTriangular) end end -function *(A::Bidiagonal, B::AdjOrTransLowerOrUnitLowerTriangular) - TS = promote_op(matprod, eltype(A), eltype(B)) - if A.uplo == 'U' - A_mul_B_td!(UpperTriangular(zeros(TS, size(A)...)), A, B) - else - A_mul_B_td!(zeros(TS, size(A)...), A, B) - end -end - function *(A::BiTri, B::Diagonal) TS = promote_op(matprod, eltype(A), eltype(B)) A_mul_B_td!(similar(A, TS), A, B) diff --git a/stdlib/LinearAlgebra/src/blas.jl b/stdlib/LinearAlgebra/src/blas.jl index 0ef4f14d092b5..57fd5c03342d7 100644 --- a/stdlib/LinearAlgebra/src/blas.jl +++ b/stdlib/LinearAlgebra/src/blas.jl @@ -218,15 +218,21 @@ end """ scal!(n, a, X, incx) + scal!(a, X) Overwrite `X` with `a*X` for the first `n` elements of array `X` with stride `incx`. Returns `X`. + +If `n` and `incx` are not provided, `length(X)` and `stride(X,1)` are used. """ function scal! end """ scal(n, a, X, incx) + scal(a, X) Return `X` scaled by `a` for the first `n` elements of array `X` with stride `incx`. + +If `n` and `incx` are not provided, `length(X)` and `stride(X,1)` are used. """ function scal end @@ -242,9 +248,12 @@ for (fname, elty) in ((:dscal_,:Float64), n, DA, DX, incx) DX end + + scal!(DA::$elty, DX::AbstractArray{$elty}) = scal!(length(DX),DA,DX,stride(DX,1)) end end scal(n, DA, DX, incx) = scal!(n, DA, copy(DX), incx) +scal(DA, DX) = scal!(DA, copy(DX)) ## dot diff --git a/stdlib/LinearAlgebra/src/bunchkaufman.jl b/stdlib/LinearAlgebra/src/bunchkaufman.jl index ead62ab0bc528..75fb9ae7bf04e 100644 --- a/stdlib/LinearAlgebra/src/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/src/bunchkaufman.jl @@ -167,6 +167,11 @@ julia> d, u, p = S; # destructuring via iteration julia> d == S.D && u == S.U && p == S.p true +julia> S.U*S.D*S.U' - S.P*A*S.P' +2×2 Matrix{Float64}: + 0.0 0.0 + 0.0 0.0 + julia> S = bunchkaufman(Symmetric(A, :L)) BunchKaufman{Float64, Matrix{Float64}} D factor: @@ -181,21 +186,24 @@ permutation: 2-element Vector{Int64}: 2 1 + +julia> S.L*S.D*S.L' - A[S.p, S.p] +2×2 Matrix{Float64}: + 0.0 0.0 + 0.0 0.0 ``` """ bunchkaufman(A::AbstractMatrix{T}, rook::Bool=false; check::Bool = true) where {T} = bunchkaufman!(copy_oftype(A, typeof(sqrt(oneunit(T)))), rook; check = check) -convert(::Type{BunchKaufman{T}}, B::BunchKaufman{T}) where {T} = B -convert(::Type{BunchKaufman{T}}, B::BunchKaufman) where {T} = +BunchKaufman{T}(B::BunchKaufman) where {T} = BunchKaufman(convert(Matrix{T}, B.LD), B.ipiv, B.uplo, B.symmetric, B.rook, B.info) -convert(::Type{Factorization{T}}, B::BunchKaufman{T}) where {T} = B -convert(::Type{Factorization{T}}, B::BunchKaufman) where {T} = convert(BunchKaufman{T}, B) +Factorization{T}(B::BunchKaufman) where {T} = BunchKaufman{T}(B) size(B::BunchKaufman) = size(getfield(B, :LD)) size(B::BunchKaufman, d::Integer) = size(getfield(B, :LD), d) issymmetric(B::BunchKaufman) = B.symmetric -ishermitian(B::BunchKaufman) = !B.symmetric +ishermitian(B::BunchKaufman{T}) where T = T<:Real || !B.symmetric function _ipiv2perm_bk(v::AbstractVector{T}, maxi::Integer, uplo::AbstractChar, rook::Bool) where T require_one_based_indexing(v) @@ -226,62 +234,6 @@ function _ipiv2perm_bk(v::AbstractVector{T}, maxi::Integer, uplo::AbstractChar, return p end -""" - getproperty(B::BunchKaufman, d::Symbol) - -Extract the factors of the Bunch-Kaufman factorization `B`. The factorization can take the -two forms `P'*L*D*L'*P` or `P'*U*D*U'*P` (or `L*D*transpose(L)` in the complex symmetric case) -where `P` is a (symmetric) permutation matrix, `L` is a [`UnitLowerTriangular`](@ref) matrix, `U` is a -[`UnitUpperTriangular`](@ref), and `D` is a block diagonal symmetric or Hermitian matrix with -1x1 or 2x2 blocks. The argument `d` can be - -- `:D`: the block diagonal matrix -- `:U`: the upper triangular factor (if factorization is `U*D*U'`) -- `:L`: the lower triangular factor (if factorization is `L*D*L'`) -- `:p`: permutation vector -- `:P`: permutation matrix - -# Examples -```jldoctest -julia> A = [1 2 3; 2 1 2; 3 2 1] -3×3 Matrix{Int64}: - 1 2 3 - 2 1 2 - 3 2 1 - -julia> F = bunchkaufman(Symmetric(A, :L)) -BunchKaufman{Float64, Matrix{Float64}} -D factor: -3×3 Tridiagonal{Float64, Vector{Float64}}: - 1.0 3.0 ⋅ - 3.0 1.0 0.0 - ⋅ 0.0 -1.0 -L factor: -3×3 UnitLowerTriangular{Float64, Matrix{Float64}}: - 1.0 ⋅ ⋅ - 0.0 1.0 ⋅ - 0.5 0.5 1.0 -permutation: -3-element Vector{Int64}: - 1 - 3 - 2 - -julia> F.L*F.D*F.L' - A[F.p, F.p] -3×3 Matrix{Float64}: - 0.0 0.0 0.0 - 0.0 0.0 0.0 - 0.0 0.0 0.0 - -julia> F = bunchkaufman(Symmetric(A)); - -julia> F.U*F.D*F.U' - F.P*A*F.P' -3×3 Matrix{Float64}: - 0.0 0.0 0.0 - 0.0 0.0 0.0 - 0.0 0.0 0.0 -``` -""" function getproperty(B::BunchKaufman{T}, d::Symbol) where {T<:BlasFloat} n = size(B, 1) if d === :p @@ -325,6 +277,14 @@ Base.propertynames(B::BunchKaufman, private::Bool=false) = issuccess(B::BunchKaufman) = B.info == 0 +function adjoint(B::BunchKaufman) + if ishermitian(B) + return B + else + throw(ArgumentError("adjoint not implemented for complex symmetric matrices")) + end +end + function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, B::BunchKaufman) if issuccess(B) summary(io, B); println(io) diff --git a/stdlib/LinearAlgebra/src/cholesky.jl b/stdlib/LinearAlgebra/src/cholesky.jl index 18ee4cb5c7dd9..6e381243faf43 100644 --- a/stdlib/LinearAlgebra/src/cholesky.jl +++ b/stdlib/LinearAlgebra/src/cholesky.jl @@ -529,6 +529,8 @@ Base.propertynames(F::CholeskyPivoted, private::Bool=false) = issuccess(C::Union{Cholesky,CholeskyPivoted}) = C.info == 0 +adjoint(C::Union{Cholesky,CholeskyPivoted}) = C + function show(io::IO, mime::MIME{Symbol("text/plain")}, C::Cholesky{<:Any,<:AbstractMatrix}) if issuccess(C) summary(io, C); println(io) diff --git a/stdlib/LinearAlgebra/src/dense.jl b/stdlib/LinearAlgebra/src/dense.jl index ad288bef1ddc7..6be5ac1bb0c56 100644 --- a/stdlib/LinearAlgebra/src/dense.jl +++ b/stdlib/LinearAlgebra/src/dense.jl @@ -75,7 +75,8 @@ isposdef!(A::AbstractMatrix) = Test whether a matrix is positive definite (and Hermitian) by trying to perform a Cholesky factorization of `A`. -See also [`isposdef!`](@ref) + +See also [`isposdef!`](@ref), [`cholesky`](@ref). # Examples ```jldoctest @@ -205,6 +206,8 @@ diagind(m::Integer, n::Integer, k::Integer=0) = An `AbstractRange` giving the indices of the `k`th diagonal of the matrix `M`. +See also: [`diag`](@ref), [`diagm`](@ref), [`Diagonal`](@ref). + # Examples ```jldoctest julia> A = [1 2 3; 4 5 6; 7 8 9] @@ -227,7 +230,7 @@ end The `k`th diagonal of a matrix, as a vector. -See also: [`diagm`](@ref) +See also [`diagm`](@ref), [`diagind`](@ref), [`Diagonal`](@ref), [`isdiag`](@ref). # Examples ```jldoctest @@ -556,6 +559,28 @@ julia> exp(A) """ exp(A::StridedMatrix{<:BlasFloat}) = exp!(copy(A)) exp(A::StridedMatrix{<:Union{Integer,Complex{<:Integer}}}) = exp!(float.(A)) +exp(A::Adjoint{<:Any,<:AbstractMatrix}) = adjoint(exp(parent(A))) +exp(A::Transpose{<:Any,<:AbstractMatrix}) = transpose(exp(parent(A))) + +""" + cis(A::AbstractMatrix) + +Compute ``\\exp(i A)`` for a square matrix ``A``. + +!!! compat "Julia 1.7" + Support for using `cis` with matrices was added in Julia 1.7. + +# Examples +```jldoctest +julia> cis([π 0; 0 π]) ≈ -I +true +``` +""" +Base.cis(A::AbstractMatrix) = exp(im * A) # fallback +Base.cis(A::AbstractMatrix{<:Base.HWNumber}) = exp_maybe_inplace(float.(im .* A)) + +exp_maybe_inplace(A::StridedMatrix{<:Union{ComplexF32, ComplexF64}}) = exp!(A) +exp_maybe_inplace(A) = exp(A) """ ^(b::Number, A::AbstractMatrix) @@ -592,7 +617,6 @@ function exp!(A::StridedMatrix{T}) where T<:BlasFloat end ilo, ihi, scale = LAPACK.gebal!('B', A) # modifies A nA = opnorm(A, 1) - Inn = Matrix{T}(I, n, n) ## For sufficiently small nA, use lower order Padé-Approximations if (nA <= 2.1) if nA > 0.95 @@ -609,17 +633,21 @@ function exp!(A::StridedMatrix{T}) where T<:BlasFloat C = T[120.,60.,12.,1.] end A2 = A * A - P = copy(Inn) - U = C[2] * P - V = C[1] * P - for k in 1:(div(size(C, 1), 2) - 1) + # Compute U and V: Even/odd terms in Padé numerator & denom + # Expansion of k=1 in for loop + P = A2 + U = mul!(C[4]*P, true, C[2]*I, true, true) #U = C[2]*I + C[4]*P + V = mul!(C[3]*P, true, C[1]*I, true, true) #V = C[1]*I + C[3]*P + for k in 2:(div(size(C, 1), 2) - 1) k2 = 2 * k P *= A2 - U += C[k2 + 2] * P - V += C[k2 + 1] * P + mul!(U, C[k2 + 2], P, true, true) # U += C[k2+2]*P + mul!(V, C[k2 + 1], P, true, true) # V += C[k2+1]*P end + U = A * U X = V + U + # Padé approximant: (V-U)\(V+U) LAPACK.gesv!(V-U, X) else s = log2(nA/5.4) # power of 2 later reversed by squaring @@ -635,10 +663,26 @@ function exp!(A::StridedMatrix{T}) where T<:BlasFloat A2 = A * A A4 = A2 * A2 A6 = A2 * A4 - U = A * (A6 * (CC[14].*A6 .+ CC[12].*A4 .+ CC[10].*A2) .+ - CC[8].*A6 .+ CC[6].*A4 .+ CC[4].*A2 .+ CC[2].*Inn) - V = A6 * (CC[13].*A6 .+ CC[11].*A4 .+ CC[9].*A2) .+ - CC[7].*A6 .+ CC[5].*A4 .+ CC[3].*A2 .+ CC[1].*Inn + Ut = mul!(CC[4]*A2, true,CC[2]*I, true, true); # Ut = CC[4]*A2+CC[2]*I + # Allocation economical version of: + #U = A * (A6 * (CC[14].*A6 .+ CC[12].*A4 .+ CC[10].*A2) .+ + # CC[8].*A6 .+ CC[6].*A4 .+ Ut) + U = mul!(CC[8].*A6 .+ CC[6].*A4 .+ Ut, + A6, + CC[14].*A6 .+ CC[12].*A4 .+ CC[10].*A2, + true, true) + U = A*U + + # Allocation economical version of: Vt = CC[3]*A2 (recycle Ut) + Vt = mul!(Ut, CC[3], A2, true, false) + mul!(Vt, true, CC[1]*I, true, true); # Vt += CC[1]*I + # Allocation economical version of: + #V = A6 * (CC[13].*A6 .+ CC[11].*A4 .+ CC[9].*A2) .+ + # CC[7].*A6 .+ CC[5].*A4 .+ Vt + V = mul!(CC[7].*A6 .+ CC[5].*A4 .+ Vt, + A6, + CC[13].*A6 .+ CC[11].*A4 .+ CC[9].*A2, + true, true) X = V + U LAPACK.gesv!(V-U, X) @@ -739,6 +783,9 @@ function log(A::StridedMatrix) end end +log(A::Adjoint{<:Any,<:AbstractMatrix}) = adjoint(log(parent(A))) +log(A::Transpose{<:Any,<:AbstractMatrix}) = transpose(log(parent(A))) + """ sqrt(A::AbstractMatrix) @@ -814,6 +861,9 @@ function sqrt(A::StridedMatrix{T}) where {T<:Union{Real,Complex}} end end +sqrt(A::Adjoint{<:Any,<:AbstractMatrix}) = adjoint(sqrt(parent(A))) +sqrt(A::Transpose{<:Any,<:AbstractMatrix}) = transpose(sqrt(parent(A))) + function inv(A::StridedMatrix{T}) where T checksquare(A) S = typeof((one(T)*zero(T) + one(T)*zero(T))/one(T)) @@ -1321,7 +1371,7 @@ function factorize(A::StridedMatrix{T}) where T end return lu(A) end - qr(A, Val(true)) + qr(A, ColumnNorm()) end factorize(A::Adjoint) = adjoint(factorize(parent(A))) factorize(A::Transpose) = transpose(factorize(parent(A))) @@ -1378,31 +1428,23 @@ function pinv(A::AbstractMatrix{T}; atol::Real = 0.0, rtol::Real = (eps(real(flo m, n = size(A) Tout = typeof(zero(T)/sqrt(one(T) + one(T))) if m == 0 || n == 0 - return Matrix{Tout}(undef, n, m) + return similar(A, Tout, (n, m)) end - if istril(A) - if istriu(A) - maxabsA = maximum(abs.(diag(A))) - tol = max(rtol*maxabsA, atol) - B = zeros(Tout, n, m) - for i = 1:min(m, n) - if abs(A[i,i]) > tol - Aii = inv(A[i,i]) - if isfinite(Aii) - B[i,i] = Aii - end - end - end - return B - end + if isdiag(A) + ind = diagind(A) + dA = view(A, ind) + maxabsA = maximum(abs, dA) + tol = max(rtol * maxabsA, atol) + B = fill!(similar(A, Tout, (n, m)), 0) + B[ind] .= (x -> abs(x) > tol ? pinv(x) : zero(x)).(dA) + return B end SVD = svd(A, full = false) tol = max(rtol*maximum(SVD.S), atol) Stype = eltype(SVD.S) - Sinv = zeros(Stype, length(SVD.S)) + Sinv = fill!(similar(A, Stype, length(SVD.S)), 0) index = SVD.S .> tol - Sinv[index] = one(Stype) ./ SVD.S[index] - Sinv[findall(.!isfinite.(Sinv))] .= zero(Stype) + Sinv[index] .= pinv.(view(SVD.S, index)) return SVD.Vt' * (Diagonal(Sinv) * SVD.U') end function pinv(x::Number) diff --git a/stdlib/LinearAlgebra/src/diagonal.jl b/stdlib/LinearAlgebra/src/diagonal.jl index 10e8e64e01ae7..464e85facc640 100644 --- a/stdlib/LinearAlgebra/src/diagonal.jl +++ b/stdlib/LinearAlgebra/src/diagonal.jl @@ -14,46 +14,55 @@ Diagonal(v::AbstractVector{T}) where {T} = Diagonal{T,typeof(v)}(v) Diagonal{T}(v::AbstractVector) where {T} = Diagonal(convert(AbstractVector{T}, v)::AbstractVector{T}) """ - Diagonal(A::AbstractMatrix) + Diagonal(V::AbstractVector) -Construct a matrix from the diagonal of `A`. +Construct a matrix with `V` as its diagonal. + +See also [`diag`](@ref), [`diagm`](@ref). # Examples ```jldoctest -julia> A = [1 2 3; 4 5 6; 7 8 9] -3×3 Matrix{Int64}: - 1 2 3 - 4 5 6 - 7 8 9 - -julia> Diagonal(A) -3×3 Diagonal{Int64, Vector{Int64}}: - 1 ⋅ ⋅ - ⋅ 5 ⋅ - ⋅ ⋅ 9 +julia> Diagonal([1, 10, 100]) +3×3 Diagonal{$Int, Vector{$Int}}: + 1 ⋅ ⋅ + ⋅ 10 ⋅ + ⋅ ⋅ 100 + +julia> diagm([7, 13]) +2×2 Matrix{$Int}: + 7 0 + 0 13 ``` """ -Diagonal(A::AbstractMatrix) = Diagonal(diag(A)) +Diagonal(V::AbstractVector) """ - Diagonal(V::AbstractVector) + Diagonal(A::AbstractMatrix) -Construct a matrix with `V` as its diagonal. +Construct a matrix from the diagonal of `A`. # Examples ```jldoctest -julia> V = [1, 2] -2-element Vector{Int64}: - 1 - 2 - -julia> Diagonal(V) -2×2 Diagonal{Int64, Vector{Int64}}: - 1 ⋅ - ⋅ 2 +julia> A = permutedims(reshape(1:15, 5, 3)) +3×5 Matrix{Int64}: + 1 2 3 4 5 + 6 7 8 9 10 + 11 12 13 14 15 + +julia> Diagonal(A) +3×3 Diagonal{$Int, Vector{$Int}}: + 1 ⋅ ⋅ + ⋅ 7 ⋅ + ⋅ ⋅ 13 + +julia> diag(A, 2) +3-element Vector{$Int}: + 3 + 9 + 15 ``` """ -Diagonal(V::AbstractVector) +Diagonal(A::AbstractMatrix) = Diagonal(diag(A)) Diagonal(D::Diagonal) = D Diagonal{T}(D::Diagonal{T}) where {T} = D @@ -63,6 +72,13 @@ AbstractMatrix{T}(D::Diagonal) where {T} = Diagonal{T}(D) Matrix(D::Diagonal) = diagm(0 => D.diag) Array(D::Diagonal) = Matrix(D) +""" + Diagonal{T}(undef, n) + +Construct an uninitialized `Diagonal{T}` of length `n`. See `undef`. +""" +Diagonal{T}(::UndefInitializer, n::Integer) where T = Diagonal(Vector{T}(undef, n)) + # For D<:Diagonal, similar(D[, neweltype]) should yield a Diagonal matrix. # On the other hand, similar(D, [neweltype,] shape...) should yield a sparse matrix. # The first method below effects the former, and the second the latter. @@ -204,12 +220,20 @@ end function rmul!(A::AbstractMatrix, D::Diagonal) require_one_based_indexing(A) + nA, nD = size(A, 2), length(D.diag) + if nA != nD + throw(DimensionMismatch("second dimension of A, $nA, does not match the first of D, $nD")) + end A .= A .* permutedims(D.diag) return A end function lmul!(D::Diagonal, B::AbstractVecOrMat) require_one_based_indexing(B) + nB, nD = size(B, 1), length(D.diag) + if nB != nD + throw(DimensionMismatch("second dimension of D, $nD, does not match the first of B, $nB")) + end B .= D.diag .* B return B end @@ -420,35 +444,6 @@ mul!(C::AbstractMatrix, A::Transpose{<:Any,<:Diagonal}, B::Transpose{<:Any,<:Rea (/)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag ./ Db.diag) -function ldiv!(D::Diagonal{T}, v::AbstractVector{T}) where {T} - if length(v) != length(D.diag) - throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(length(v)) rows")) - end - for i = 1:length(D.diag) - d = D.diag[i] - if iszero(d) - throw(SingularException(i)) - end - v[i] = d\v[i] - end - v -end -function ldiv!(D::Diagonal{T}, V::AbstractMatrix{T}) where {T} - require_one_based_indexing(V) - if size(V,1) != length(D.diag) - throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $(size(V,1)) rows")) - end - for i = 1:length(D.diag) - d = D.diag[i] - if iszero(d) - throw(SingularException(i)) - end - for j = 1:size(V,2) - @inbounds V[i,j] = d\V[i,j] - end - end - V -end ldiv!(x::AbstractArray, A::Diagonal, b::AbstractArray) = (x .= A.diag .\ b) ldiv!(adjD::Adjoint{<:Any,<:Diagonal{T}}, B::AbstractVecOrMat{T}) where {T} = @@ -493,22 +488,13 @@ rdiv!(A::AbstractMatrix{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = (/)(A::Union{StridedMatrix, AbstractTriangular}, D::Diagonal) = rdiv!((typeof(oneunit(eltype(D))/oneunit(eltype(A)))).(A), D) -(\)(F::Factorization, D::Diagonal) = - ldiv!(F, Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D)) -\(adjF::Adjoint{<:Any,<:Factorization}, D::Diagonal) = - (F = adjF.parent; ldiv!(adjoint(F), Matrix{typeof(oneunit(eltype(D))/oneunit(eltype(F)))}(D))) -(\)(A::Union{QR,QRCompactWY,QRPivoted}, B::Diagonal) = - invoke(\, Tuple{Union{QR,QRCompactWY,QRPivoted}, AbstractVecOrMat}, A, B) - - -@inline function kron!(C::AbstractMatrix{T}, A::Diagonal, B::Diagonal) where T - fill!(C, zero(T)) +@inline function kron!(C::AbstractMatrix, A::Diagonal, B::Diagonal) valA = A.diag; nA = length(valA) valB = B.diag; nB = length(valB) nC = checksquare(C) @boundscheck nC == nA*nB || throw(DimensionMismatch("expect C to be a $(nA*nB)x$(nA*nB) matrix, got size $(nC)x$(nC)")) - + isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) @inbounds for i = 1:nA, j = 1:nB idx = (i-1)*nB+j C[idx, idx] = valA[i] * valB[j] @@ -516,19 +502,16 @@ rdiv!(A::AbstractMatrix{T}, transD::Transpose{<:Any,<:Diagonal{T}}) where {T} = return C end -function kron(A::Diagonal{T1}, B::Diagonal{T2}) where {T1<:Number, T2<:Number} - valA = A.diag; nA = length(valA) - valB = B.diag; nB = length(valB) - valC = Vector{typeof(zero(T1)*zero(T2))}(undef,nA*nB) - C = Diagonal(valC) - return @inbounds kron!(C, A, B) -end +kron(A::Diagonal{<:Number}, B::Diagonal{<:Number}) = Diagonal(kron(A.diag, B.diag)) @inline function kron!(C::AbstractMatrix, A::Diagonal, B::AbstractMatrix) Base.require_one_based_indexing(B) - (mA, nA) = size(A); (mB, nB) = size(B); (mC, nC) = size(C); + (mA, nA) = size(A) + (mB, nB) = size(B) + (mC, nC) = size(C) @boundscheck (mC, nC) == (mA * mB, nA * nB) || throw(DimensionMismatch("expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) + isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) m = 1 @inbounds for j = 1:nA A_jj = A[j,j] @@ -546,9 +529,12 @@ end @inline function kron!(C::AbstractMatrix, A::AbstractMatrix, B::Diagonal) require_one_based_indexing(A) - (mA, nA) = size(A); (mB, nB) = size(B); (mC, nC) = size(C); + (mA, nA) = size(A) + (mB, nB) = size(B) + (mC, nC) = size(C) @boundscheck (mC, nC) == (mA * mB, nA * nB) || throw(DimensionMismatch("expect C to be a $(mA * mB)x$(nA * nB) matrix, got size $(mC)x$(nC)")) + isempty(A) || isempty(B) || fill!(C, zero(A[1,1] * B[1,1])) m = 1 @inbounds for j = 1:nA for l = 1:mB @@ -564,23 +550,13 @@ end return C end -function kron(A::Diagonal{T}, B::AbstractMatrix{S}) where {T<:Number, S<:Number} - (mA, nA) = size(A); (mB, nB) = size(B) - R = zeros(Base.promote_op(*, T, S), mA * mB, nA * nB) - return @inbounds kron!(R, A, B) -end - -function kron(A::AbstractMatrix{T}, B::Diagonal{S}) where {T<:Number, S<:Number} - (mA, nA) = size(A); (mB, nB) = size(B) - R = zeros(promote_op(*, T, S), mA * mB, nA * nB) - return @inbounds kron!(R, A, B) -end - conj(D::Diagonal) = Diagonal(conj(D.diag)) transpose(D::Diagonal{<:Number}) = D transpose(D::Diagonal) = Diagonal(transpose.(D.diag)) adjoint(D::Diagonal{<:Number}) = conj(D) adjoint(D::Diagonal) = Diagonal(adjoint.(D.diag)) +Base.permutedims(D::Diagonal) = D +Base.permutedims(D::Diagonal, perm) = (Base.checkdims_perm(D, D, perm); D) function diag(D::Diagonal, k::Integer=0) # every branch call similar(..., ::Int) to make sure the @@ -602,7 +578,7 @@ function logdet(D::Diagonal{<:Complex}) # make sure branch cut is correct end # Matrix functions -for f in (:exp, :log, :sqrt, +for f in (:exp, :cis, :log, :sqrt, :cos, :sin, :tan, :csc, :sec, :cot, :cosh, :sinh, :tanh, :csch, :sech, :coth, :acos, :asin, :atan, :acsc, :asec, :acot, @@ -610,8 +586,13 @@ for f in (:exp, :log, :sqrt, @eval $f(D::Diagonal) = Diagonal($f.(D.diag)) end -#Linear solver -function ldiv!(D::Diagonal, B::StridedVecOrMat) +(\)(D::Diagonal, A::AbstractMatrix) = + ldiv!(D, (typeof(oneunit(eltype(D))/oneunit(eltype(A)))).(A)) + +(\)(D::Diagonal, b::AbstractVector) = D.diag .\ b +(\)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag .\ Db.diag) + +function ldiv!(D::Diagonal, B::AbstractVecOrMat) m, n = size(B, 1), size(B, 2) if m != length(D.diag) throw(DimensionMismatch("diagonal matrix is $(length(D.diag)) by $(length(D.diag)) but right hand side has $m rows")) @@ -628,11 +609,6 @@ function ldiv!(D::Diagonal, B::StridedVecOrMat) end return B end -(\)(D::Diagonal, A::AbstractMatrix) = - ldiv!(D, (typeof(oneunit(eltype(D))/oneunit(eltype(A)))).(A)) - -(\)(D::Diagonal, b::AbstractVector) = D.diag .\ b -(\)(Da::Diagonal, Db::Diagonal) = Diagonal(Da.diag .\ Db.diag) function inv(D::Diagonal{T}) where T Di = similar(D.diag, typeof(inv(zero(T)))) diff --git a/stdlib/LinearAlgebra/src/eigen.jl b/stdlib/LinearAlgebra/src/eigen.jl index 3a423a87295f3..9cd1c9bc20f4b 100644 --- a/stdlib/LinearAlgebra/src/eigen.jl +++ b/stdlib/LinearAlgebra/src/eigen.jl @@ -17,7 +17,7 @@ Iterating the decomposition produces the components `F.values` and `F.vectors`. # Examples ```jldoctest julia> F = eigen([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0]) -Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}} +Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}, Vector{Float64}} values: 3-element Vector{Float64}: 1.0 @@ -47,14 +47,18 @@ julia> vals == F.values && vecs == F.vectors true ``` """ -struct Eigen{T,V,S<:AbstractMatrix,U<:AbstractVector} <: Factorization{T} +struct Eigen{T,V,S<:AbstractMatrix,U<:AbstractVector,R<:AbstractVector} <: Factorization{T} values::U vectors::S - Eigen{T,V,S,U}(values::AbstractVector{V}, vectors::AbstractMatrix{T}) where {T,V,S,U} = - new(values, vectors) + vectorsl::S + unitary::Bool + rconde::R + rcondv::R + Eigen{T,V,S,U,R}(values::AbstractVector{V}, vectors::AbstractMatrix{T}, vectorsl::AbstractMatrix{T}, unitary::Bool, rconde::R, rcondv::R) where {T,V,S,U,R} = + new(values, vectors, vectorsl, unitary, rconde, rcondv) end -Eigen(values::AbstractVector{V}, vectors::AbstractMatrix{T}) where {T,V} = - Eigen{T,V,typeof(vectors),typeof(values)}(values, vectors) +Eigen(values::AbstractVector{V}, vectors::AbstractMatrix{T}, vectorsl=vectors, uni=true, rce=zeros(real(T),0), rcv=zeros(real(T), 0)) where {T,V} = + Eigen{T,V,typeof(vectors),typeof(values),typeof(rce)}(values, vectors, vectorsl, uni, rce, rcv) # Generalized eigenvalue problem. """ @@ -133,24 +137,55 @@ function sorteig!(λ::AbstractVector, X::AbstractMatrix, sortby::Union{Function, if sortby !== nothing && !issorted(λ, by=sortby) p = sortperm(λ; alg=QuickSort, by=sortby) permute!(λ, p) - Base.permutecols!!(X, p) + !isempty(X) && Base.permutecols!!(X, copy(p)) end return λ, X end +function sorteig!(λ::AbstractVector, X::AbstractMatrix, sortby::Union{Function,Nothing}, Y::AbstractMatrix, rconde::AbstractVector, rcondv::AbstractVector) + if sortby !== nothing && !issorted(λ, by=sortby) + p = sortperm(λ; alg=QuickSort, by=sortby) + permute!(λ, p) + !isempty(rconde) && permute!(rconde, p) + !isempty(rcondv) && permute!(rcondv, p) + !isempty(X) && Base.permutecols!!(X, copy(p)) + !isempty(Y) && X !== Y && Base.permutecols!!(Y, p) + end + return λ, X, Y, false, rconde, rcondv +end sorteig!(λ::AbstractVector, sortby::Union{Function,Nothing}=eigsortby) = sortby === nothing ? λ : sort!(λ, by=sortby) """ eigen!(A, [B]; permute, scale, sortby) -Same as [`eigen`](@ref), but saves space by overwriting the input `A` (and +came as [`eigen`](@ref), but saves space by overwriting the input `A` (and `B`), instead of creating a copy. """ -function eigen!(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby) where T<:BlasReal +function eigen!(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby, jvl::Bool=false, jvr::Bool=true, jce::Bool=false, jcv::Bool=false) where T<:BlasReal n = size(A, 2) n == 0 && return Eigen(zeros(T, 0), zeros(T, 0, 0)) issymmetric(A) && return eigen!(Symmetric(A), sortby=sortby) - A, WR, WI, VL, VR, _ = LAPACK.geevx!(permute ? (scale ? 'B' : 'P') : (scale ? 'S' : 'N'), 'N', 'V', 'N', A) - iszero(WI) && return Eigen(sorteig!(WR, VR, sortby)...) + + balance = permute ? (scale ? 'B' : 'P') : (scale ? 'S' : 'N') + jobvl = jvl || jce ? 'V' : 'N' + jobvr = jvr || jce ? 'V' : 'N' + sense = jce && jcv ? 'B' : jce ? 'E' : jcv ? 'V' : 'N' + A, WR, WI, VL, VR, _, _, scale, abnrm, rconde, rcondv = LAPACK.geevx!(balance, jobvl, jobvr, sense, A) + if iszero(WI) + evecr = VR + evecl = VL + evals = WR + else + evecr = complexeig(WI, VR) + evecl = complexeig(WI, VL) + evals = complex.(WR, WI) + end + rconde = jce ? inv.(rconde) : zeros(T, 0) + rcondv = jcv ? inv.(rcondv) : zeros(T, 0) + return Eigen(sorteig!(evals, evecr, sortby, evecl, rconde, rcondv)...) +end + +function complexeig(WI::Vector{T}, VR::Matrix{T}) where T + n = min(size(VR)...) evec = zeros(Complex{T}, n, n) j = 1 while j <= n @@ -165,15 +200,19 @@ function eigen!(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true, sortb end j += 1 end - return Eigen(sorteig!(complex.(WR, WI), evec, sortby)...) + evec end -function eigen!(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby) where T<:BlasComplex +function eigen!(A::StridedMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby, jvl::Bool=false, jvr::Bool=true, jce::Bool=false, jcv::Bool=false) where T<:BlasComplex n = size(A, 2) n == 0 && return Eigen(zeros(T, 0), zeros(T, 0, 0)) ishermitian(A) && return eigen!(Hermitian(A), sortby=sortby) - eval, evec = LAPACK.geevx!(permute ? (scale ? 'B' : 'P') : (scale ? 'S' : 'N'), 'N', 'V', 'N', A)[[2,4]] - return Eigen(sorteig!(eval, evec, sortby)...) + balance = permute ? (scale ? 'B' : 'P') : (scale ? 'S' : 'N') + jobvl = jvl || jce ? 'V' : 'N' + jobvr = jvr || jce ? 'V' : 'N' + sense = jce && jcv ? 'B' : jce ? 'E' : jcv ? 'V' : 'N' + A, W, VL, VR, _, _, scale, abnrm, rconde, rcondv = LAPACK.geevx!(balance, jobvl, jobvr, sense, A) + return Eigen(sorteig!(W, VR, sortby, VL, rconde, rcondv)...) end """ @@ -201,7 +240,7 @@ accept a `sortby` keyword. # Examples ```jldoctest julia> F = eigen([1.0 0.0 0.0; 0.0 3.0 0.0; 0.0 0.0 18.0]) -Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}} +Eigen{Float64, Float64, Matrix{Float64}, Vector{Float64}, Vector{Float64}} values: 3-element Vector{Float64}: 1.0 @@ -231,10 +270,10 @@ julia> vals == F.values && vecs == F.vectors true ``` """ -function eigen(A::AbstractMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby) where T +function eigen(A::AbstractMatrix{T}; permute::Bool=true, scale::Bool=true, sortby::Union{Function,Nothing}=eigsortby, jvl::Bool=false, jvr::Bool=true, jce::Bool=false, jcv::Bool=false) where T AA = copy_oftype(A, eigtype(T)) isdiag(AA) && return eigen(Diagonal(AA); permute=permute, scale=scale, sortby=sortby) - return eigen!(AA; permute=permute, scale=scale, sortby=sortby) + return eigen!(AA; permute=permute, scale=scale, sortby=sortby, jvl=jvl, jvr=jvr, jce=jce, jcv=jcv) end eigen(x::Number) = Eigen([x], fill(one(x), 1, 1)) @@ -420,7 +459,19 @@ function eigmin(A::Union{Number, AbstractMatrix}; minimum(v) end -inv(A::Eigen) = A.vectors * inv(Diagonal(A.values)) / A.vectors +""" + spectral(f, F::Eigen) + +Construct a matrix from an eigen-decomposition `F` by applying the function to +the spectrum (diagonal) of `F`. +""" +function spectral(f, A::Eigen) + d = Diagonal(f.(A.values)) + v = A.vectors + vd = v * d + A.unitary ? vd * v' : vd / v +end +inv(A::Eigen) = spectral(inv, A) det(A::Eigen) = prod(A.values) # Generalized eigenproblem @@ -610,14 +661,34 @@ function show(io::IO, mime::MIME{Symbol("text/plain")}, F::Union{Eigen,Generaliz summary(io, F); println(io) println(io, "values:") show(io, mime, F.values) - println(io, "\nvectors:") - show(io, mime, F.vectors) + if !isdefined(F, :vectorsl) || (!isempty(F.vectors) && (F.vectors === F.vectorsl || isempty(F.vectorsl))) + println(io, "\nvectors:") + show(io, mime, F.vectors) + else + if !isempty(F.vectors) + println(io, "\nright vectors:") + show(io, mime, F.vectors) + end + if !isempty(F.vectorsl) + println(io, "\nleft vectors:") + show(io, mime, F.vectorsl) + end + end + if isdefined(F, :rconde) && !isempty(F.rconde) + println(io, "\ncondition values:") + show(io, mime, F.rconde) + end + if isdefined(F, :rcondv) && !isempty(F.rcondv) + println(io, "\ncondition vectors:") + show(io, mime, F.rcondv) + end + nothing end # Conversion methods ## Can we determine the source/result is Real? This is not stored in the type Eigen -AbstractMatrix(F::Eigen) = F.vectors * Diagonal(F.values) / F.vectors +AbstractMatrix(F::Eigen) = spectral(identity, F) AbstractArray(F::Eigen) = AbstractMatrix(F) Matrix(F::Eigen) = Array(AbstractArray(F)) Array(F::Eigen) = Matrix(F) diff --git a/stdlib/LinearAlgebra/src/factorization.jl b/stdlib/LinearAlgebra/src/factorization.jl index 3e335ed391ad6..b651e85512f6d 100644 --- a/stdlib/LinearAlgebra/src/factorization.jl +++ b/stdlib/LinearAlgebra/src/factorization.jl @@ -16,9 +16,9 @@ size(F::Adjoint{<:Any,<:Factorization}) = reverse(size(parent(F))) size(F::Transpose{<:Any,<:Factorization}) = reverse(size(parent(F))) checkpositivedefinite(info) = info == 0 || throw(PosDefException(info)) -checknonsingular(info, pivoted::Val{true}) = info == 0 || throw(SingularException(info)) -checknonsingular(info, pivoted::Val{false}) = info == 0 || throw(ZeroPivotException(info)) -checknonsingular(info) = checknonsingular(info, Val{true}()) +checknonsingular(info, ::RowMaximum) = info == 0 || throw(SingularException(info)) +checknonsingular(info, ::NoPivot) = info == 0 || throw(ZeroPivotException(info)) +checknonsingular(info) = checknonsingular(info, RowMaximum()) """ issuccess(F::Factorization) @@ -59,6 +59,9 @@ convert(::Type{T}, f::Factorization) where {T<:AbstractArray} = T(f) ### General promotion rules Factorization{T}(F::Factorization{T}) where {T} = F +# This is a bit odd since the return is not a Factorization but it works well in generic code +Factorization{T}(A::Adjoint{<:Any,<:Factorization}) where {T} = + adjoint(Factorization{T}(parent(A))) inv(F::Factorization{T}) where {T} = (n = size(F, 1); ldiv!(F, Matrix{T}(I, n, n))) Base.hash(F::Factorization, h::UInt) = mapreduce(f -> hash(getfield(F, f)), hash, 1:nfields(F); init=h) @@ -96,40 +99,25 @@ function (/)(B::VecOrMat{Complex{T}}, F::Factorization{T}) where T<:BlasReal return copy(reinterpret(Complex{T}, x)) end -function \(F::Factorization, B::AbstractVecOrMat) +function \(F::Union{Factorization, Adjoint{<:Any,<:Factorization}}, B::AbstractVecOrMat) require_one_based_indexing(B) TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) BB = similar(B, TFB, size(B)) copyto!(BB, B) ldiv!(F, BB) end -function \(adjF::Adjoint{<:Any,<:Factorization}, B::AbstractVecOrMat) - require_one_based_indexing(B) - F = adjF.parent - TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) - BB = similar(B, TFB, size(B)) - copyto!(BB, B) - ldiv!(adjoint(F), BB) -end -function /(B::AbstractMatrix, F::Factorization) +function /(B::AbstractMatrix, F::Union{Factorization, Adjoint{<:Any,<:Factorization}}) require_one_based_indexing(B) TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) BB = similar(B, TFB, size(B)) copyto!(BB, B) rdiv!(BB, F) end -function /(B::AbstractMatrix, adjF::Adjoint{<:Any,<:Factorization}) - require_one_based_indexing(B) - F = adjF.parent - TFB = typeof(oneunit(eltype(B)) / oneunit(eltype(F))) - BB = similar(B, TFB, size(B)) - copyto!(BB, B) - rdiv!(BB, adjoint(F)) -end /(adjB::AdjointAbsVec, adjF::Adjoint{<:Any,<:Factorization}) = adjoint(adjF.parent \ adjB.parent) /(B::TransposeAbsVec, adjF::Adjoint{<:Any,<:Factorization}) = adjoint(adjF.parent \ adjoint(B)) + # support the same 3-arg idiom as in our other in-place A_*_B functions: function ldiv!(Y::AbstractVecOrMat, A::Factorization, B::AbstractVecOrMat) require_one_based_indexing(Y, B) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 8e0ca4fb72ad5..c9c624500e928 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -702,9 +702,10 @@ end function opnorm2(A::AbstractMatrix{T}) where T require_one_based_indexing(A) m,n = size(A) - if m == 1 || n == 1 return norm2(A) end Tnorm = typeof(float(real(zero(T)))) - (m == 0 || n == 0) ? zero(Tnorm) : convert(Tnorm, svdvals(A)[1]) + if m == 0 || n == 0 return zero(Tnorm) end + if m == 1 || n == 1 return norm2(A) end + return svdvals(A)[1] end function opnormInf(A::AbstractMatrix{T}) where T @@ -1109,6 +1110,8 @@ When `A` is sparse, a similar polyalgorithm is used. For indefinite matrices, th factorization does not use pivoting during the numerical factorization and therefore the procedure can fail even for invertible matrices. +See also: [`factorize`](@ref), [`pinv`](@ref). + # Examples ```jldoctest julia> A = [1 0; 1 -2]; B = [32; -4]; @@ -1138,7 +1141,7 @@ function (\)(A::AbstractMatrix, B::AbstractVecOrMat) end return lu(A) \ B end - return qr(A,Val(true)) \ B + return qr(A, ColumnNorm()) \ B end (\)(a::AbstractVector, b::AbstractArray) = pinv(a) * b @@ -1289,15 +1292,17 @@ false """ function istriu(A::AbstractMatrix, k::Integer = 0) require_one_based_indexing(A) + return _istriu(A, k) +end +istriu(x::Number) = true + +@inline function _istriu(A::AbstractMatrix, k) m, n = size(A) for j in 1:min(n, m + k - 1) - for i in max(1, j - k + 1):m - iszero(A[i, j]) || return false - end + all(iszero, view(A, max(1, j - k + 1):m, j)) || return false end return true end -istriu(x::Number) = true """ istril(A::AbstractMatrix, k::Integer = 0) -> Bool @@ -1331,15 +1336,17 @@ false """ function istril(A::AbstractMatrix, k::Integer = 0) require_one_based_indexing(A) + return _istril(A, k) +end +istril(x::Number) = true + +@inline function _istril(A::AbstractMatrix, k) m, n = size(A) for j in max(1, k + 2):n - for i in 1:min(j - k - 1, m) - iszero(A[i, j]) || return false - end + all(iszero, view(A, 1:min(j - k - 1, m), j)) || return false end return true end -istril(x::Number) = true """ isbanded(A::AbstractMatrix, kl::Integer, ku::Integer) -> Bool @@ -1487,21 +1494,17 @@ end # Elementary reflection similar to LAPACK. The reflector is not Hermitian but # ensures that tridiagonalization of Hermitian matrices become real. See lawn72 -@inline function reflector!(x::AbstractVector) +@inline function reflector!(x::AbstractVector{T}) where {T} require_one_based_indexing(x) n = length(x) n == 0 && return zero(eltype(x)) @inbounds begin ξ1 = x[1] - normu = abs2(ξ1) - for i = 2:n - normu += abs2(x[i]) - end + normu = norm(x) if iszero(normu) return zero(ξ1/normu) end - normu = sqrt(normu) - ν = copysign(normu, real(ξ1)) + ν = T(copysign(normu, real(ξ1))) ξ1 += ν x[1] = -ν for i = 2:n @@ -1512,29 +1515,18 @@ end end # apply reflector from left -@inline function reflectorApply!(x::AbstractVector, τ::Number, A::StridedMatrix) +@inline function reflectorApply!(x::AbstractVector, τ::Number, A::AbstractMatrix) require_one_based_indexing(x) m, n = size(A) if length(x) != m throw(DimensionMismatch("reflector has length $(length(x)), which must match the first dimension of matrix A, $m")) end m == 0 && return A - @inbounds begin - for j = 1:n - # dot - vAj = A[1, j] - for i = 2:m - vAj += x[i]'*A[i, j] - end - - vAj = conj(τ)*vAj - - # ger - A[1, j] -= vAj - for i = 2:m - A[i, j] -= x[i]*vAj - end - end + @inbounds for j = 1:n + Aj, xj = view(A, 2:m, j), view(x, 2:m) + vAj = conj(τ)*(A[1, j] + dot(xj, Aj)) + A[1, j] -= vAj + axpy!(-vAj, xj, Aj) end return A end @@ -1544,6 +1536,8 @@ end Matrix determinant. +See also: [`logdet`](@ref) and [`logabsdet`](@ref). + # Examples ```jldoctest julia> M = [1 0; 2 2] @@ -1564,6 +1558,9 @@ function det(A::AbstractMatrix{T}) where T end det(x::Number) = x +# Resolve Issue #40128 +det(A::AbstractMatrix{BigInt}) = det_bareiss(A) + """ logabsdet(M) @@ -1626,6 +1623,55 @@ logdet(A) = log(det(A)) const NumberArray{T<:Number} = AbstractArray{T} +exactdiv(a, b) = a/b +exactdiv(a::Integer, b::Integer) = div(a, b) + +""" + det_bareiss!(M) + +Calculates the determinant of a matrix using the +[Bareiss Algorithm](https://en.wikipedia.org/wiki/Bareiss_algorithm) using +inplace operations. + +# Examples +```jldoctest +julia> M = [1 0; 2 2] +2×2 Matrix{Int64}: + 1 0 + 2 2 + +julia> LinearAlgebra.det_bareiss!(M) +2 +``` +""" +function det_bareiss!(M) + n = checksquare(M) + sign, prev = Int8(1), one(eltype(M)) + for i in 1:n-1 + if iszero(M[i,i]) # swap with another col to make nonzero + swapto = findfirst(!iszero, @view M[i,i+1:end]) + isnothing(swapto) && return zero(prev) + sign = -sign + Base.swapcols!(M, i, i + swapto) + end + for k in i+1:n, j in i+1:n + M[j,k] = exactdiv(M[j,k]*M[i,i] - M[j,i]*M[i,k], prev) + end + prev = M[i,i] + end + return sign * M[end,end] +end +""" + LinearAlgebra.det_bareiss(M) + +Calculates the determinant of a matrix using the +[Bareiss Algorithm](https://en.wikipedia.org/wiki/Bareiss_algorithm). +Also refer to [`det_bareiss!`](@ref). +""" +det_bareiss(M) = det_bareiss!(copy(M)) + + + """ promote_leaf_eltypes(itr) diff --git a/stdlib/LinearAlgebra/src/givens.jl b/stdlib/LinearAlgebra/src/givens.jl index 4270994018811..d892720a7a1f3 100644 --- a/stdlib/LinearAlgebra/src/givens.jl +++ b/stdlib/LinearAlgebra/src/givens.jl @@ -31,7 +31,7 @@ conjugated transpose right multiplication `A*G'`. The type doesn't have a `size` therefore be multiplied with matrices of arbitrary size as long as `i2<=size(A,2)` for `G*A` or `i2<=size(A,1)` for `A*G'`. -See also: [`givens`](@ref) +See also [`givens`](@ref). """ struct Givens{T} <: AbstractRotation{T} i1::Int @@ -282,7 +282,7 @@ y[i1] = r y[i2] = 0 ``` -See also: [`LinearAlgebra.Givens`](@ref) +See also [`LinearAlgebra.Givens`](@ref). """ function givens(f::T, g::T, i1::Integer, i2::Integer) where T if i1 == i2 @@ -308,7 +308,7 @@ B[i1,j] = r B[i2,j] = 0 ``` -See also: [`LinearAlgebra.Givens`](@ref) +See also [`LinearAlgebra.Givens`](@ref). """ givens(A::AbstractMatrix, i1::Integer, i2::Integer, j::Integer) = givens(A[i1,j], A[i2,j],i1,i2) @@ -327,7 +327,7 @@ B[i1] = r B[i2] = 0 ``` -See also: [`LinearAlgebra.Givens`](@ref) +See also [`LinearAlgebra.Givens`](@ref). """ givens(x::AbstractVector, i1::Integer, i2::Integer) = givens(x[i1], x[i2], i1, i2) diff --git a/stdlib/LinearAlgebra/src/hessenberg.jl b/stdlib/LinearAlgebra/src/hessenberg.jl index b284b4f940085..e3b5d4983b30d 100644 --- a/stdlib/LinearAlgebra/src/hessenberg.jl +++ b/stdlib/LinearAlgebra/src/hessenberg.jl @@ -94,17 +94,96 @@ Base.copy(A::Transpose{<:Any,<:UpperHessenberg}) = tril!(transpose!(similar(A.pa rmul!(H::UpperHessenberg, x::Number) = (rmul!(H.data, x); H) lmul!(x::Number, H::UpperHessenberg) = (lmul!(x, H.data); H) -# (future: we could also have specialized routines for UpperHessenberg * UpperTriangular) - fillstored!(H::UpperHessenberg, x) = (fillband!(H.data, x, -1, size(H,2)-1); H) +(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data+B.data) -(A::UpperHessenberg, B::UpperHessenberg) = UpperHessenberg(A.data-B.data) -# (future: we could also have specialized routines for UpperHessenberg ± UpperTriangular) -# shift Hessenberg by λI -+(H::UpperHessenberg, J::UniformScaling) = UpperHessenberg(H.data + J) --(J::UniformScaling, H::UpperHessenberg) = UpperHessenberg(J - H.data) +for T = (:UniformScaling, :Diagonal, :Bidiagonal, :Tridiagonal, :SymTridiagonal, + :UpperTriangular, :UnitUpperTriangular) + for op = (:+, :-) + @eval begin + $op(H::UpperHessenberg, x::$T) = UpperHessenberg($op(H.data, x)) + $op(x::$T, H::UpperHessenberg) = UpperHessenberg($op(x, H.data)) + end + end +end + +for T = (:Number, :UniformScaling, :Diagonal) + @eval begin + *(H::UpperHessenberg, x::$T) = UpperHessenberg(H.data * x) + *(x::$T, H::UpperHessenberg) = UpperHessenberg(x * H.data) + /(H::UpperHessenberg, x::$T) = UpperHessenberg(H.data / x) + \(x::$T, H::UpperHessenberg) = UpperHessenberg(x \ H.data) + end +end + +function *(H::UpperHessenberg, U::UpperOrUnitUpperTriangular) + T = typeof(oneunit(eltype(H))*oneunit(eltype(U))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + rmul!(HH, U) + UpperHessenberg(HH) +end +function *(U::UpperOrUnitUpperTriangular, H::UpperHessenberg) + T = typeof(oneunit(eltype(H))*oneunit(eltype(U))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + lmul!(U, HH) + UpperHessenberg(HH) +end + +function /(H::UpperHessenberg, U::UpperTriangular) + T = typeof(oneunit(eltype(H))/oneunit(eltype(U))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + rdiv!(HH, U) + UpperHessenberg(HH) +end +function /(H::UpperHessenberg, U::UnitUpperTriangular) + T = typeof(oneunit(eltype(H))/oneunit(eltype(U))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + rdiv!(HH, U) + UpperHessenberg(HH) +end + +function \(U::UpperTriangular, H::UpperHessenberg) + T = typeof(oneunit(eltype(U))\oneunit(eltype(H))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + ldiv!(U, HH) + UpperHessenberg(HH) +end +function \(U::UnitUpperTriangular, H::UpperHessenberg) + T = typeof(oneunit(eltype(U))\oneunit(eltype(H))) + HH = similar(H.data, T, size(H)) + copyto!(HH, H) + ldiv!(U, HH) + UpperHessenberg(HH) +end + +function *(H::UpperHessenberg, B::Bidiagonal) + TS = promote_op(matprod, eltype(H), eltype(B)) + if B.uplo == 'U' + A_mul_B_td!(UpperHessenberg(zeros(TS, size(H)...)), H, B) + else + A_mul_B_td!(zeros(TS, size(H)...), H, B) + end +end +function *(B::Bidiagonal, H::UpperHessenberg) + TS = promote_op(matprod, eltype(B), eltype(H)) + if B.uplo == 'U' + A_mul_B_td!(UpperHessenberg(zeros(TS, size(B)...)), B, H) + else + A_mul_B_td!(zeros(TS, size(B)...), B, H) + end +end + +function /(H::UpperHessenberg, B::Bidiagonal) + A = Base.@invoke /(H::AbstractMatrix, B::Bidiagonal) + B.uplo == 'U' ? UpperHessenberg(A) : A +end # Solving (H+µI)x = b: we can do this in O(m²) time and O(m) memory # (in-place in x) by the RQ algorithm from: @@ -485,28 +564,30 @@ function AbstractMatrix(F::Hessenberg) end end +# adjoint(Q::HessenbergQ{<:Real}) + lmul!(Q::BlasHessenbergQ{T,false}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormhr!('L', 'N', 1, size(Q.factors, 1), Q.factors, Q.τ, X) -rmul!(X::StridedMatrix{T}, Q::BlasHessenbergQ{T,false}) where {T<:BlasFloat} = +rmul!(X::StridedVecOrMat{T}, Q::BlasHessenbergQ{T,false}) where {T<:BlasFloat} = LAPACK.ormhr!('R', 'N', 1, size(Q.factors, 1), Q.factors, Q.τ, X) lmul!(adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,false}}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = (Q = adjQ.parent; LAPACK.ormhr!('L', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X)) -rmul!(X::StridedMatrix{T}, adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,false}}) where {T<:BlasFloat} = +rmul!(X::StridedVecOrMat{T}, adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,false}}) where {T<:BlasFloat} = (Q = adjQ.parent; LAPACK.ormhr!('R', ifelse(T<:Real, 'T', 'C'), 1, size(Q.factors, 1), Q.factors, Q.τ, X)) lmul!(Q::BlasHessenbergQ{T,true}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = LAPACK.ormtr!('L', Q.uplo, 'N', Q.factors, Q.τ, X) -rmul!(X::StridedMatrix{T}, Q::BlasHessenbergQ{T,true}) where {T<:BlasFloat} = +rmul!(X::StridedVecOrMat{T}, Q::BlasHessenbergQ{T,true}) where {T<:BlasFloat} = LAPACK.ormtr!('R', Q.uplo, 'N', Q.factors, Q.τ, X) lmul!(adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,true}}, X::StridedVecOrMat{T}) where {T<:BlasFloat} = (Q = adjQ.parent; LAPACK.ormtr!('L', Q.uplo, ifelse(T<:Real, 'T', 'C'), Q.factors, Q.τ, X)) -rmul!(X::StridedMatrix{T}, adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,true}}) where {T<:BlasFloat} = +rmul!(X::StridedVecOrMat{T}, adjQ::Adjoint{<:Any,<:BlasHessenbergQ{T,true}}) where {T<:BlasFloat} = (Q = adjQ.parent; LAPACK.ormtr!('R', Q.uplo, ifelse(T<:Real, 'T', 'C'), Q.factors, Q.τ, X)) lmul!(Q::HessenbergQ{T}, X::Adjoint{T,<:StridedVecOrMat{T}}) where {T} = rmul!(X', Q')' -rmul!(X::Adjoint{T,<:StridedMatrix{T}}, Q::HessenbergQ{T}) where {T} = lmul!(Q', X')' +rmul!(X::Adjoint{T,<:StridedVecOrMat{T}}, Q::HessenbergQ{T}) where {T} = lmul!(Q', X')' lmul!(adjQ::Adjoint{<:Any,<:HessenbergQ{T}}, X::Adjoint{T,<:StridedVecOrMat{T}}) where {T} = rmul!(X', adjQ')' -rmul!(X::Adjoint{T,<:StridedMatrix{T}}, adjQ::Adjoint{<:Any,<:HessenbergQ{T}}) where {T} = lmul!(adjQ', X')' +rmul!(X::Adjoint{T,<:StridedVecOrMat{T}}, adjQ::Adjoint{<:Any,<:HessenbergQ{T}}) where {T} = lmul!(adjQ', X')' # multiply x by the entries of M in the upper-k triangle, which contains # the entries of the upper-Hessenberg matrix H for k=-1 diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 3d02f3b058884..05e080e00450d 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -7,6 +7,11 @@ Interfaces to LAPACK subroutines. const libblastrampoline = "libblastrampoline" +# Legacy binding maintained for backwards-compatibility but new packages +# should not look at this, instead preferring to parse the output +# of BLAS.get_config() +const liblapack = libblastrampoline + import ..LinearAlgebra.BLAS.@blasfunc import ..LinearAlgebra: BlasFloat, BlasInt, LAPACKException, @@ -3770,8 +3775,8 @@ for (stev, stebz, stegr, stein, elty) in require_one_based_indexing(dv, ev) chkstride1(dv, ev) n = length(dv) - if length(ev) != n - 1 - throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than dv's length, $n)")) + if length(ev) != n - 1 && length(ev) != n + throw(DimensionMismatch("ev has length $(length(ev)) but needs one less than or equal to dv's length, $n)")) end Zmat = similar(dv, $elty, (n, job != 'N' ? n : 0)) work = Vector{$elty}(undef, max(1, 2n-2)) @@ -3830,7 +3835,7 @@ for (stev, stebz, stegr, stein, elty) in eev = copy(ev) eev[n] = zero($elty) else - throw(DimensionMismatch("ev has length $(length(ev)) but should be either $(length(dv) - 1) or $(length(dv))")) + throw(DimensionMismatch("ev has length $ne but needs one less than or equal to dv's length, $n)")) end abstol = Vector{$elty}(undef, 1) @@ -3873,10 +3878,15 @@ for (stev, stebz, stegr, stein, elty) in require_one_based_indexing(dv, ev_in, w_in, iblock_in, isplit_in) chkstride1(dv, ev_in, w_in, iblock_in, isplit_in) n = length(dv) - if length(ev_in) != n - 1 - throw(DimensionMismatch("ev_in has length $(length(ev_in)) but needs one less than dv's length, $n)")) + ne = length(ev_in) + if ne == n - 1 + ev = [ev_in; zero($elty)] + elseif ne == n + ev = copy(ev_in) + ev[n] = zero($elty) + else + throw(DimensionMismatch("ev_in has length $ne but needs one less than or equal to dv's length, $n)")) end - ev = [ev_in; zeros($elty,1)] ldz = n #Leading dimension #Number of eigenvalues to find if !(1 <= length(w_in) <= n) @@ -5953,9 +5963,9 @@ for (gees, gges, elty) in alphar = similar(A, $elty, n) alphai = similar(A, $elty, n) beta = similar(A, $elty, n) - ldvsl = jobvsl == 'V' ? n : 1 + ldvsl = jobvsl == 'V' ? max(1, n) : 1 vsl = similar(A, $elty, ldvsl, n) - ldvsr = jobvsr == 'V' ? n : 1 + ldvsr = jobvsr == 'V' ? max(1, n) : 1 vsr = similar(A, $elty, ldvsr, n) work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) @@ -6048,9 +6058,9 @@ for (gees, gges, elty, relty) in sdim = BlasInt(0) alpha = similar(A, $elty, n) beta = similar(A, $elty, n) - ldvsl = jobvsl == 'V' ? n : 1 + ldvsl = jobvsl == 'V' ? max(1, n) : 1 vsl = similar(A, $elty, ldvsl, n) - ldvsr = jobvsr == 'V' ? n : 1 + ldvsr = jobvsr == 'V' ? max(1, n) : 1 vsr = similar(A, $elty, ldvsr, n) work = Vector{$elty}(undef, 1) lwork = BlasInt(-1) diff --git a/stdlib/LinearAlgebra/src/lbt.jl b/stdlib/LinearAlgebra/src/lbt.jl index 4ed93188d1f61..67ce521a9aa7e 100644 --- a/stdlib/LinearAlgebra/src/lbt.jl +++ b/stdlib/LinearAlgebra/src/lbt.jl @@ -103,6 +103,42 @@ struct LBTConfig end end +Base.show(io::IO, lbt::LBTLibraryInfo) = print(io, "LBTLibraryInfo(", basename(lbt.libname), ", ", lbt.interface, ")") +function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, lbt::LBTLibraryInfo) + summary(io, lbt); println(io) + println(io, "├ Library: ", basename(lbt.libname)) + println(io, "├ Interface: ", lbt.interface) + print(io, "└ F2C: ", lbt.f2c) +end + +function Base.show(io::IO, lbt::LBTConfig) + if length(lbt.loaded_libs) <= 3 + print(io, "LBTConfig(") + gen = (string("[", uppercase(string(l.interface)), "] ", + basename(l.libname)) for l in lbt.loaded_libs) + print(io, join(gen, ", ")) + print(io, ")") + else + print(io, "LBTConfig(...)") + end +end +function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, lbt::LBTConfig) + summary(io, lbt); println(io) + println(io, "Libraries: ") + for (i,l) in enumerate(lbt.loaded_libs) + char = i == length(lbt.loaded_libs) ? "└" : "├" + interface_str = if l.interface == :ilp64 + "ILP64" + elseif l.interface == :lp64 + " LP64" + else + "UNKWN" + end + print(io, char, " [", interface_str,"] ", basename(l.libname)) + i !== length(lbt.loaded_libs) && println() + end +end + function lbt_get_config() config_ptr = ccall((:lbt_get_config, libblastrampoline), Ptr{lbt_config_t}, ()) return LBTConfig(unsafe_load(config_ptr)) diff --git a/stdlib/LinearAlgebra/src/ldlt.jl b/stdlib/LinearAlgebra/src/ldlt.jl index d0f59ebb9ff1b..f1ea10aa0f614 100644 --- a/stdlib/LinearAlgebra/src/ldlt.jl +++ b/stdlib/LinearAlgebra/src/ldlt.jl @@ -77,6 +77,9 @@ function getproperty(F::LDLt, d::Symbol) end end +adjoint(F::LDLt{<:Real,<:SymTridiagonal}) = F +adjoint(F::LDLt) = LDLt(copy(adjoint(F.data))) + function show(io::IO, mime::MIME{Symbol("text/plain")}, F::LDLt) summary(io, F); println(io) println(io, "L factor:") diff --git a/stdlib/LinearAlgebra/src/lq.jl b/stdlib/LinearAlgebra/src/lq.jl index 21ba6a27ac580..d9e49f3a9c1c6 100644 --- a/stdlib/LinearAlgebra/src/lq.jl +++ b/stdlib/LinearAlgebra/src/lq.jl @@ -22,9 +22,15 @@ julia> A = [5. 7.; -2. -4.] -2.0 -4.0 julia> S = lq(A) -LQ{Float64, Matrix{Float64}} with factors L and Q: -[-8.60233 0.0; 4.41741 -0.697486] -[-0.581238 -0.813733; -0.813733 0.581238] +LQ{Float64, Matrix{Float64}} +L factor: +2×2 Matrix{Float64}: + -8.60233 0.0 + 4.41741 -0.697486 +Q factor: +2×2 LinearAlgebra.LQPackedQ{Float64, Matrix{Float64}}: + -0.581238 -0.813733 + -0.813733 0.581238 julia> S.L * S.Q 2×2 Matrix{Float64}: @@ -56,12 +62,10 @@ Base.iterate(S::LQ) = (S.L, Val(:Q)) Base.iterate(S::LQ, ::Val{:Q}) = (S.Q, Val(:done)) Base.iterate(S::LQ, ::Val{:done}) = nothing -struct LQPackedQ{T,S<:AbstractMatrix} <: AbstractMatrix{T} - factors::Matrix{T} +struct LQPackedQ{T,S<:AbstractMatrix{T}} <: AbstractMatrix{T} + factors::S τ::Vector{T} - LQPackedQ{T,S}(factors::AbstractMatrix{T}, τ::Vector{T}) where {T,S<:AbstractMatrix} = new(factors, τ) end -LQPackedQ(factors::AbstractMatrix{T}, τ::Vector{T}) where {T} = LQPackedQ{T,typeof(factors)}(factors, τ) """ @@ -92,9 +96,15 @@ julia> A = [5. 7.; -2. -4.] -2.0 -4.0 julia> S = lq(A) -LQ{Float64, Matrix{Float64}} with factors L and Q: -[-8.60233 0.0; 4.41741 -0.697486] -[-0.581238 -0.813733; -0.813733 0.581238] +LQ{Float64, Matrix{Float64}} +L factor: +2×2 Matrix{Float64}: + -8.60233 0.0 + 4.41741 -0.697486 +Q factor: +2×2 LinearAlgebra.LQPackedQ{Float64, Matrix{Float64}}: + -0.581238 -0.813733 + -0.813733 0.581238 julia> S.L * S.Q 2×2 Matrix{Float64}: @@ -107,14 +117,16 @@ julia> l == S.L && q == S.Q true ``` """ -lq(A::StridedMatrix{<:BlasFloat}) = lq!(copy(A)) -lq(x::Number) = lq(fill(x,1,1)) +lq(A::AbstractMatrix{T}) where {T} = lq!(copy_oftype(A, lq_eltype(T))) +lq(x::Number) = lq!(fill(convert(lq_eltype(typeof(x)), x), 1, 1)) + +lq_eltype(::Type{T}) where {T} = typeof(zero(T) / sqrt(abs2(one(T)))) copy(A::LQ) = LQ(copy(A.factors), copy(A.τ)) LQ{T}(A::LQ) where {T} = LQ(convert(AbstractMatrix{T}, A.factors), convert(Vector{T}, A.τ)) -Factorization{T}(A::LQ{T}) where {T} = A Factorization{T}(A::LQ) where {T} = LQ{T}(A) + AbstractMatrix(A::LQ) = A.L*A.Q AbstractArray(A::LQ) = AbstractMatrix(A) Matrix(A::LQ) = Array(AbstractArray(A)) @@ -141,12 +153,12 @@ Base.propertynames(F::LQ, private::Bool=false) = getindex(A::LQPackedQ, i::Integer, j::Integer) = lmul!(A, setindex!(zeros(eltype(A), size(A, 2)), 1, j))[i] -function show(io::IO, ::MIME"text/plain", C::LQ) - println(io, typeof(C), " with factors L and Q:") - io = IOContext(io, :compact => true) - show(io, C.L) - println(io) - show(io, C.Q) +function show(io::IO, mime::MIME{Symbol("text/plain")}, F::LQ) + summary(io, F); println(io) + println(io, "L factor:") + show(io, mime, F.L) + println(io, "\nQ factor:") + show(io, mime, F.Q) end LQPackedQ{T}(Q::LQPackedQ) where {T} = LQPackedQ(convert(AbstractMatrix{T}, Q.factors), convert(Vector{T}, Q.τ)) @@ -182,7 +194,7 @@ function lmul!(A::LQ, B::StridedVecOrMat) end function *(A::LQ{TA}, B::StridedVecOrMat{TB}) where {TA,TB} TAB = promote_type(TA, TB) - _cut_B(lmul!(Factorization{TAB}(A), copy_oftype(B, TAB)), 1:size(A,1)) + _cut_B(lmul!(convert(Factorization{TAB}, A), copy_oftype(B, TAB)), 1:size(A,1)) end ## Multiplication by Q @@ -306,17 +318,6 @@ _rightappdimmismatch(rowsorcols) = "or (2) the number of rows of that (LQPackedQ) matrix's internal representation ", "(the factorization's originating matrix's number of rows)"))) - -function (\)(A::LQ{TA},B::StridedVecOrMat{TB}) where {TA,TB} - S = promote_type(TA,TB) - m, n = size(A) - m ≤ n || throw(DimensionMismatch("LQ solver does not support overdetermined systems (more rows than columns)")) - m == size(B,1) || throw(DimensionMismatch("Both inputs should have the same number of rows")) - AA = Factorization{S}(A) - X = _zeros(S, B, n) - X[1:size(B, 1), :] = B - return ldiv!(AA, X) -end # With a real lhs and complex rhs with the same precision, we can reinterpret # the complex rhs as a real rhs with twice the number of columns function (\)(F::LQ{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal @@ -330,12 +331,25 @@ function (\)(F::LQ{T}, B::VecOrMat{Complex{T}}) where T<:BlasReal end -function ldiv!(A::LQ{T}, B::StridedVecOrMat{T}) where T +function ldiv!(A::LQ, B::StridedVecOrMat) require_one_based_indexing(B) + m, n = size(A) + m ≤ n || throw(DimensionMismatch("LQ solver does not support overdetermined systems (more rows than columns)")) + ldiv!(LowerTriangular(A.L), view(B, 1:size(A,1), axes(B,2))) return lmul!(adjoint(A.Q), B) end +function ldiv!(Fadj::Adjoint{<:Any,<:LQ}, B::StridedVecOrMat) + require_one_based_indexing(B) + m, n = size(Fadj) + m >= n || throw(DimensionMismatch("solver does not support underdetermined systems (more columns than rows)")) + + F = parent(Fadj) + lmul!(F.Q, B) + ldiv!(UpperTriangular(adjoint(F.L)), view(B, 1:size(F,1), axes(B,2))) + return B +end # In LQ factorization, `Q` is expressed as the product of the adjoint of the # reflectors. Thus, `det` has to be conjugated. diff --git a/stdlib/LinearAlgebra/src/lu.jl b/stdlib/LinearAlgebra/src/lu.jl index 2d915680d5381..e55508db6b397 100644 --- a/stdlib/LinearAlgebra/src/lu.jl +++ b/stdlib/LinearAlgebra/src/lu.jl @@ -76,22 +76,26 @@ adjoint(F::LU) = Adjoint(F) transpose(F::LU) = Transpose(F) # StridedMatrix -function lu!(A::StridedMatrix{T}, pivot::Union{Val{false}, Val{true}} = Val(true); - check::Bool = true) where T<:BlasFloat - if pivot === Val(false) - return generic_lufact!(A, pivot; check = check) - end +lu!(A::StridedMatrix{<:BlasFloat}; check::Bool = true) = lu!(A, RowMaximum(); check=check) +function lu!(A::StridedMatrix{T}, ::RowMaximum; check::Bool = true) where {T<:BlasFloat} lpt = LAPACK.getrf!(A) check && checknonsingular(lpt[3]) return LU{T,typeof(A)}(lpt[1], lpt[2], lpt[3]) end -function lu!(A::HermOrSym, pivot::Union{Val{false}, Val{true}} = Val(true); check::Bool = true) +function lu!(A::StridedMatrix{<:BlasFloat}, pivot::NoPivot; check::Bool = true) + return generic_lufact!(A, pivot; check = check) +end +function lu!(A::HermOrSym, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) copytri!(A.data, A.uplo, isa(A, Hermitian)) lu!(A.data, pivot; check = check) end +# for backward compatibility +# TODO: remove towards Julia v2 +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{true}; check::Bool = true) lu!(A, RowMaximum(); check=check) +@deprecate lu!(A::Union{StridedMatrix,HermOrSym,Tridiagonal}, ::Val{false}; check::Bool = true) lu!(A, NoPivot(); check=check) """ - lu!(A, pivot=Val(true); check = true) -> LU + lu!(A, pivot = RowMaximum(); check = true) -> LU `lu!` is the same as [`lu`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) @@ -127,19 +131,22 @@ Stacktrace: [...] ``` """ -lu!(A::StridedMatrix, pivot::Union{Val{false}, Val{true}} = Val(true); check::Bool = true) = +lu!(A::StridedMatrix, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) = generic_lufact!(A, pivot; check = check) -function generic_lufact!(A::StridedMatrix{T}, ::Val{Pivot} = Val(true); - check::Bool = true) where {T,Pivot} +function generic_lufact!(A::StridedMatrix{T}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); + check::Bool = true) where {T} + # Extract values m, n = size(A) minmn = min(m,n) + + # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, minmn) @inbounds begin for k = 1:minmn # find index max kp = k - if Pivot && k < m + if pivot === RowMaximum() && k < m amax = abs(A[k, k]) for i = k+1:m absi = abs(A[i,k]) @@ -175,7 +182,7 @@ function generic_lufact!(A::StridedMatrix{T}, ::Val{Pivot} = Val(true); end end end - check && checknonsingular(info, Val{Pivot}()) + check && checknonsingular(info, pivot) return LU{T,typeof(A)}(A, ipiv, convert(BlasInt, info)) end @@ -200,7 +207,7 @@ end # for all other types we must promote to a type which is stable under division """ - lu(A, pivot=Val(true); check = true) -> F::LU + lu(A, pivot = RowMaximum(); check = true) -> F::LU Compute the LU factorization of `A`. @@ -211,7 +218,7 @@ validity (via [`issuccess`](@ref)) lies with the user. In most cases, if `A` is a subtype `S` of `AbstractMatrix{T}` with an element type `T` supporting `+`, `-`, `*` and `/`, the return type is `LU{T,S{T}}`. If pivoting is chosen (default) the element type should also support [`abs`](@ref) and -[`<`](@ref). +[`<`](@ref). Pivoting can be turned off by passing `pivot = NoPivot()`. The individual components of the factorization `F` can be accessed via [`getproperty`](@ref): @@ -267,11 +274,14 @@ julia> l == F.L && u == F.U && p == F.p true ``` """ -function lu(A::AbstractMatrix{T}, pivot::Union{Val{false}, Val{true}}=Val(true); - check::Bool = true) where T +function lu(A::AbstractMatrix{T}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) where {T} S = lutype(T) lu!(copy_oftype(A, S), pivot; check = check) end +# TODO: remove for Julia v2.0 +@deprecate lu(A::AbstractMatrix, ::Val{true}; check::Bool = true) lu(A, RowMaximum(); check=check) +@deprecate lu(A::AbstractMatrix, ::Val{false}; check::Bool = true) lu(A, NoPivot(); check=check) + lu(S::LU) = S function lu(x::Number; check::Bool=true) @@ -481,9 +491,11 @@ inv(A::LU{<:BlasFloat,<:StridedMatrix}) = inv!(copy(A)) # Tridiagonal # See dgttrf.f -function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true); - check::Bool = true) where {T,V} +function lu!(A::Tridiagonal{T,V}, pivot::Union{RowMaximum,NoPivot} = RowMaximum(); check::Bool = true) where {T,V} + # Extract values n = size(A, 1) + + # Initialize variables info = 0 ipiv = Vector{BlasInt}(undef, n) dl = A.dl @@ -500,7 +512,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true end for i = 1:n-2 # pivot or not? - if pivot === Val(false) || abs(d[i]) >= abs(dl[i]) + if pivot === NoPivot() || abs(d[i]) >= abs(dl[i]) # No interchange if d[i] != 0 fact = dl[i]/d[i] @@ -523,7 +535,7 @@ function lu!(A::Tridiagonal{T,V}, pivot::Union{Val{false}, Val{true}} = Val(true end if n > 1 i = n-1 - if pivot === Val(false) || abs(d[i]) >= abs(dl[i]) + if pivot === NoPivot() || abs(d[i]) >= abs(dl[i]) if d[i] != 0 fact = dl[i]/d[i] dl[i] = fact diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index 27bd9c2f23b15..e755cc88c6572 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -683,7 +683,7 @@ function copyto!(B::AbstractVecOrMat, ir_dest::UnitRange{Int}, jr_dest::UnitRang copyto!(B, ir_dest, jr_dest, M, ir_src, jr_src) else LinearAlgebra.copy_transpose!(B, ir_dest, jr_dest, M, jr_src, ir_src) - tM == 'C' && conj!(B) + tM == 'C' && conj!(@view B[ir_dest, jr_dest]) end B end @@ -693,7 +693,7 @@ function copy_transpose!(B::AbstractMatrix, ir_dest::UnitRange{Int}, jr_dest::Un LinearAlgebra.copy_transpose!(B, ir_dest, jr_dest, M, ir_src, jr_src) else copyto!(B, ir_dest, jr_dest, M, jr_src, ir_src) - tM == 'C' && conj!(B) + tM == 'C' && conj!(@view B[ir_dest, jr_dest]) end B end diff --git a/stdlib/LinearAlgebra/src/qr.jl b/stdlib/LinearAlgebra/src/qr.jl index c9ba49d2cd1ad..d0ec430347193 100644 --- a/stdlib/LinearAlgebra/src/qr.jl +++ b/stdlib/LinearAlgebra/src/qr.jl @@ -198,7 +198,7 @@ function qrfactUnblocked!(A::AbstractMatrix{T}) where {T} end # Find index for columns with largest two norm -function indmaxcolumn(A::StridedMatrix) +function indmaxcolumn(A::AbstractMatrix) mm = norm(view(A, :, 1)) ii = 1 for i = 2:size(A, 2) @@ -211,7 +211,7 @@ function indmaxcolumn(A::StridedMatrix) return ii end -function qrfactPivotedUnblocked!(A::StridedMatrix) +function qrfactPivotedUnblocked!(A::AbstractMatrix) m, n = size(A) piv = Vector(UnitRange{BlasInt}(1,n)) τ = Vector{eltype(A)}(undef, min(m,n)) @@ -246,17 +246,17 @@ function qrfactPivotedUnblocked!(A::StridedMatrix) end # LAPACK version -qr!(A::StridedMatrix{<:BlasFloat}, ::Val{false} = Val(false); blocksize=36) = +qr!(A::StridedMatrix{<:BlasFloat}, ::NoPivot; blocksize=36) = QRCompactWY(LAPACK.geqrt!(A, min(min(size(A)...), blocksize))...) -qr!(A::StridedMatrix{<:BlasFloat}, ::Val{true}) = QRPivoted(LAPACK.geqp3!(A)...) +qr!(A::StridedMatrix{<:BlasFloat}, ::ColumnNorm) = QRPivoted(LAPACK.geqp3!(A)...) # Generic fallbacks """ - qr!(A, pivot=Val(false); blocksize) + qr!(A, pivot = NoPivot(); blocksize) -`qr!` is the same as [`qr`](@ref) when `A` is a subtype of -[`StridedMatrix`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. +`qr!` is the same as [`qr`](@ref) when `A` is a subtype of [`StridedMatrix`](@ref), +but saves space by overwriting the input `A`, instead of creating a copy. An [`InexactError`](@ref) exception is thrown if the factorization produces a number not representable by the element type of `A`, e.g. for integer types. @@ -287,19 +287,22 @@ julia> a = [1 2; 3 4] 3 4 julia> qr!(a) -ERROR: InexactError: Int64(-3.1622776601683795) +ERROR: InexactError: Int64(3.1622776601683795) Stacktrace: [...] ``` """ -qr!(A::StridedMatrix, ::Val{false}) = qrfactUnblocked!(A) -qr!(A::StridedMatrix, ::Val{true}) = qrfactPivotedUnblocked!(A) -qr!(A::StridedMatrix) = qr!(A, Val(false)) +qr!(A::AbstractMatrix, ::NoPivot) = qrfactUnblocked!(A) +qr!(A::AbstractMatrix, ::ColumnNorm) = qrfactPivotedUnblocked!(A) +qr!(A::AbstractMatrix) = qr!(A, NoPivot()) +# TODO: Remove in Julia v2.0 +@deprecate qr!(A::AbstractMatrix, ::Val{true}) qr!(A, ColumnNorm()) +@deprecate qr!(A::AbstractMatrix, ::Val{false}) qr!(A, NoPivot()) _qreltype(::Type{T}) where T = typeof(zero(T)/sqrt(abs2(one(T)))) """ - qr(A, pivot=Val(false); blocksize) -> F + qr(A, pivot = NoPivot(); blocksize) -> F Compute the QR factorization of the matrix `A`: an orthogonal (or unitary if `A` is complex-valued) matrix `Q`, and an upper triangular matrix `R` such that @@ -310,7 +313,7 @@ A = Q R The returned object `F` stores the factorization in a packed format: - - if `pivot == Val(true)` then `F` is a [`QRPivoted`](@ref) object, + - if `pivot == ColumnNorm()` then `F` is a [`QRPivoted`](@ref) object, - otherwise if the element type of `A` is a BLAS type ([`Float32`](@ref), [`Float64`](@ref), `ComplexF32` or `ComplexF64`), then `F` is a [`QRCompactWY`](@ref) object, @@ -340,7 +343,7 @@ and `F.Q*A` are supported. A `Q` matrix can be converted into a regular matrix w orthogonal matrix. The block size for QR decomposition can be specified by keyword argument -`blocksize :: Integer` when `pivot == Val(false)` and `A isa StridedMatrix{<:BlasFloat}`. +`blocksize :: Integer` when `pivot == NoPivot()` and `A isa StridedMatrix{<:BlasFloat}`. It is ignored when `blocksize > minimum(size(A))`. See [`QRCompactWY`](@ref). !!! compat "Julia 1.4" @@ -382,6 +385,10 @@ function qr(A::AbstractMatrix{T}, arg...; kwargs...) where T copyto!(AA, A) return qr!(AA, arg...; kwargs...) end +# TODO: remove in Julia v2.0 +@deprecate qr(A::AbstractMatrix, ::Val{false}; kwargs...) qr(A, NoPivot(); kwargs...) +@deprecate qr(A::AbstractMatrix, ::Val{true}; kwargs...) qr(A, ColumnNorm(); kwargs...) + qr(x::Number) = qr(fill(x,1,1)) function qr(v::AbstractVector) require_one_based_indexing(v) @@ -465,6 +472,8 @@ end Base.propertynames(F::QRPivoted, private::Bool=false) = (:R, :Q, :p, :P, (private ? fieldnames(typeof(F)) : ())...) +adjoint(F::Union{QR,QRPivoted,QRCompactWY}) = Adjoint(F) + abstract type AbstractQ{T} <: AbstractMatrix{T} end inv(Q::AbstractQ) = Q' @@ -932,28 +941,35 @@ function ldiv!(A::QRPivoted, B::StridedMatrix) B end -# convenience methods -## return only the solution of a least squares problem while avoiding promoting -## vectors to matrices. -_cut_B(x::AbstractVector, r::UnitRange) = length(x) > length(r) ? x[r] : x -_cut_B(X::AbstractMatrix, r::UnitRange) = size(X, 1) > length(r) ? X[r,:] : X - -## append right hand side with zeros if necessary -_zeros(::Type{T}, b::AbstractVector, n::Integer) where {T} = zeros(T, max(length(b), n)) -_zeros(::Type{T}, B::AbstractMatrix, n::Integer) where {T} = zeros(T, max(size(B, 1), n), size(B, 2)) +function _apply_permutation!(F::QRPivoted, B::AbstractVecOrMat) + # Apply permutation but only to the top part of the solution vector since + # it's padded with zeros for underdetermined problems + B[1:length(F.p), :] = B[F.p, :] + return B +end +_apply_permutation!(F::Factorization, B::AbstractVecOrMat) = B -function (\)(A::Union{QR{TA},QRCompactWY{TA},QRPivoted{TA}}, B::AbstractVecOrMat{TB}) where {TA,TB} +function ldiv!(Fadj::Adjoint{<:Any,<:Union{QR,QRCompactWY,QRPivoted}}, B::AbstractVecOrMat) require_one_based_indexing(B) - S = promote_type(TA,TB) - m, n = size(A) - m == size(B,1) || throw(DimensionMismatch("Both inputs should have the same number of rows")) + m, n = size(Fadj) - AA = Factorization{S}(A) + # We don't allow solutions overdetermined systems + if m > n + throw(DimensionMismatch("overdetermined systems are not supported")) + end + if n != size(B, 1) + throw(DimensionMismatch("inputs should have the same number of rows")) + end + F = parent(Fadj) - X = _zeros(S, B, n) - X[1:size(B, 1), :] = B - ldiv!(AA, X) - return _cut_B(X, 1:n) + B = _apply_permutation!(F, B) + + # For underdetermined system, the triangular solve should only be applied to the top + # part of B that contains the rhs. For square problems, the view corresponds to B itself + ldiv!(LowerTriangular(adjoint(F.R)), view(B, 1:size(F.R, 2), :)) + lmul!(F.Q, B) + + return B end # With a real lhs and complex rhs with the same precision, we can reinterpret the complex diff --git a/stdlib/LinearAlgebra/src/structuredbroadcast.jl b/stdlib/LinearAlgebra/src/structuredbroadcast.jl index f9416b4cf3557..95a1842702291 100644 --- a/stdlib/LinearAlgebra/src/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/src/structuredbroadcast.jl @@ -105,9 +105,29 @@ function isstructurepreserving(::typeof(Base.literal_pow), ::Ref{typeof(^)}, ::S end isstructurepreserving(f, args...) = false -_iszero(n::Number) = iszero(n) -_iszero(x) = x == 0 -fzeropreserving(bc) = (v = fzero(bc); !ismissing(v) && _iszero(v)) +""" + iszerodefined(T::Type) + +Return a `Bool` indicating whether `iszero` is well-defined for objects of type +`T`. By default, this function returns `false` unless `T <: Number`. Note that +this function may return `true` even if `zero(::T)` is not defined as long as +`iszero(::T)` has a method that does not requires `zero(::T)`. + +This function is used to determine if mapping the elements of an array with +a specific structure of nonzero elements preserve this structure. +For instance, it is used to determine whether the output of +`tuple.(Diagonal([1, 2]))` is `Diagonal([(1,), (2,)])` or +`[(1,) (0,); (0,) (2,)]`. For this, we need to determine whether `(0,)` is +considered to be zero. `iszero((0,))` falls back to `(0,) == zero((0,))` which +fails as `zero(::Tuple{Int})` is not defined. However, +`iszerodefined(::Tuple{Int})` is `false` hence we falls back to the comparison +`(0,) == 0` which returns `false` and decides that the correct output is +`[(1,) (0,); (0,) (2,)]`. +""" +iszerodefined(::Type) = false +iszerodefined(::Type{<:Number}) = true + +fzeropreserving(bc) = (v = fzero(bc); !ismissing(v) && (iszerodefined(typeof(v)) ? iszero(v) : v == 0)) # Like sparse matrices, we assume that the zero-preservation property of a broadcasted # expression is stable. We can test the zero-preservability by applying the function # in cases where all other arguments are known scalars against a zero from the structured diff --git a/stdlib/LinearAlgebra/src/svd.jl b/stdlib/LinearAlgebra/src/svd.jl index 68bce4793661f..3290b4529be37 100644 --- a/stdlib/LinearAlgebra/src/svd.jl +++ b/stdlib/LinearAlgebra/src/svd.jl @@ -72,6 +72,11 @@ function SVD{T}(U::AbstractArray, S::AbstractVector{Tr}, Vt::AbstractArray) wher convert(AbstractArray{T}, Vt)) end +SVD{T}(F::SVD) where {T} = SVD( + convert(AbstractMatrix{T}, F.U), + convert(AbstractVector{real(T)}, F.S), + convert(AbstractMatrix{T}, F.Vt)) +Factorization{T}(F::SVD) where {T} = SVD{T}(F) # iteration for destructuring into components Base.iterate(S::SVD) = (S.U, Val(:S)) @@ -235,10 +240,11 @@ svdvals(A::AbstractVector{<:BlasFloat}) = [norm(A)] svdvals(x::Number) = abs(x) svdvals(S::SVD{<:Any,T}) where {T} = (S.S)::Vector{T} -# SVD least squares +### SVD least squares ### function ldiv!(A::SVD{T}, B::StridedVecOrMat) where T + m, n = size(A) k = searchsortedlast(A.S, eps(real(T))*A.S[1], rev=true) - view(A.Vt,1:k,:)' * (view(A.S,1:k) .\ (view(A.U,:,1:k)' * B)) + return mul!(view(B, 1:n, :), view(A.Vt, 1:k, :)', view(A.S, 1:k) .\ (view(A.U, :, 1:k)' * _cut_B(B, 1:m))) end function inv(F::SVD{T}) where T @@ -252,6 +258,10 @@ end size(A::SVD, dim::Integer) = dim == 1 ? size(A.U, dim) : size(A.Vt, dim) size(A::SVD) = (size(A, 1), size(A, 2)) +function adjoint(F::SVD) + return SVD(F.Vt', F.S, F.U') +end + function show(io::IO, mime::MIME{Symbol("text/plain")}, F::SVD{<:Any,<:Any,<:AbstractArray}) summary(io, F); println(io) println(io, "U factor:") diff --git a/stdlib/LinearAlgebra/src/symmetric.jl b/stdlib/LinearAlgebra/src/symmetric.jl index 8f1073817b71d..f048425be31e2 100644 --- a/stdlib/LinearAlgebra/src/symmetric.jl +++ b/stdlib/LinearAlgebra/src/symmetric.jl @@ -482,6 +482,10 @@ for f in (:+, :-) @eval begin $f(A::Hermitian, B::Symmetric{<:Real}) = $f(A, Hermitian(parent(B), sym_uplo(B.uplo))) $f(A::Symmetric{<:Real}, B::Hermitian) = $f(Hermitian(parent(A), sym_uplo(A.uplo)), B) + $f(A::SymTridiagonal, B::Symmetric) = Symmetric($f(A, B.data), sym_uplo(B.uplo)) + $f(A::Symmetric, B::SymTridiagonal) = Symmetric($f(A.data, B), sym_uplo(A.uplo)) + $f(A::SymTridiagonal{<:Real}, B::Hermitian) = Hermitian($f(A, B.data), sym_uplo(B.uplo)) + $f(A::Hermitian, B::SymTridiagonal{<:Real}) = Hermitian($f(A.data, B), sym_uplo(A.uplo)) end end @@ -672,174 +676,6 @@ end inv(A::Hermitian{<:Any,<:StridedMatrix}) = Hermitian(_inv(A), sym_uplo(A.uplo)) inv(A::Symmetric{<:Any,<:StridedMatrix}) = Symmetric(_inv(A), sym_uplo(A.uplo)) -eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}; sortby::Union{Function,Nothing}=nothing) = Eigen(sorteig!(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)..., sortby)...) - -function eigen(A::RealHermSymComplexHerm; sortby::Union{Function,Nothing}=nothing) - T = eltype(A) - S = eigtype(T) - eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), sortby=sortby) -end - -eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = Eigen(LAPACK.syevr!('V', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)...) - -""" - eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> Eigen - -Computes the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` -which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the -matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) - -Iterating the decomposition produces the components `F.values` and `F.vectors`. - -The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). - -The [`UnitRange`](@ref) `irange` specifies indices of the sorted eigenvalues to search for. - -!!! note - If `irange` is not `1:n`, where `n` is the dimension of `A`, then the returned factorization - will be a *truncated* factorization. -""" -function eigen(A::RealHermSymComplexHerm, irange::UnitRange) - T = eltype(A) - S = eigtype(T) - eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), irange) -end - -eigen!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = - Eigen(LAPACK.syevr!('V', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)...) - -""" - eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> Eigen - -Computes the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` -which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the -matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) - -Iterating the decomposition produces the components `F.values` and `F.vectors`. - -The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). - -`vl` is the lower bound of the window of eigenvalues to search for, and `vu` is the upper bound. - -!!! note - If [`vl`, `vu`] does not contain all eigenvalues of `A`, then the returned factorization - will be a *truncated* factorization. -""" -function eigen(A::RealHermSymComplexHerm, vl::Real, vh::Real) - T = eltype(A) - S = eigtype(T) - eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), vl, vh) -end - -eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}) = - LAPACK.syevr!('N', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)[1] - -function eigvals(A::RealHermSymComplexHerm) - T = eltype(A) - S = eigtype(T) - eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A)) -end - -""" - eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values - -Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. -`irange` is a range of eigenvalue *indices* to search for - for instance, the 2nd to 8th eigenvalues. -""" -eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = - LAPACK.syevr!('N', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)[1] - -""" - eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values - -Returns the eigenvalues of `A`. It is possible to calculate only a subset of the -eigenvalues by specifying a [`UnitRange`](@ref) `irange` covering indices of the sorted eigenvalues, -e.g. the 2nd to 8th eigenvalues. - -# Examples -```jldoctest -julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) -3×3 SymTridiagonal{Float64, Vector{Float64}}: - 1.0 2.0 ⋅ - 2.0 2.0 3.0 - ⋅ 3.0 1.0 - -julia> eigvals(A, 2:2) -1-element Vector{Float64}: - 0.9999999999999996 - -julia> eigvals(A) -3-element Vector{Float64}: - -2.1400549446402604 - 1.0000000000000002 - 5.140054944640259 -``` -""" -function eigvals(A::RealHermSymComplexHerm, irange::UnitRange) - T = eltype(A) - S = eigtype(T) - eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), irange) -end - -""" - eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values - -Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. -`vl` is the lower bound of the interval to search for eigenvalues, and `vu` is the upper bound. -""" -eigvals!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = - LAPACK.syevr!('N', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)[1] - -""" - eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values - -Returns the eigenvalues of `A`. It is possible to calculate only a subset of the eigenvalues -by specifying a pair `vl` and `vu` for the lower and upper boundaries of the eigenvalues. - -# Examples -```jldoctest -julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) -3×3 SymTridiagonal{Float64, Vector{Float64}}: - 1.0 2.0 ⋅ - 2.0 2.0 3.0 - ⋅ 3.0 1.0 - -julia> eigvals(A, -1, 2) -1-element Vector{Float64}: - 1.0000000000000009 - -julia> eigvals(A) -3-element Vector{Float64}: - -2.1400549446402604 - 1.0000000000000002 - 5.140054944640259 -``` -""" -function eigvals(A::RealHermSymComplexHerm, vl::Real, vh::Real) - T = eltype(A) - S = eigtype(T) - eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), vl, vh) -end - -eigmax(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = eigvals(A, size(A, 1):size(A, 1))[1] -eigmin(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = eigvals(A, 1:1)[1] - -function eigen!(A::HermOrSym{T,S}, B::HermOrSym{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasReal,S<:StridedMatrix} - vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) - GeneralizedEigen(sorteig!(vals, vecs, sortby)...) -end -function eigen!(A::Hermitian{T,S}, B::Hermitian{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasComplex,S<:StridedMatrix} - vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) - GeneralizedEigen(sorteig!(vals, vecs, sortby)...) -end - -eigvals!(A::HermOrSym{T,S}, B::HermOrSym{T,S}) where {T<:BlasReal,S<:StridedMatrix} = - LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] -eigvals!(A::Hermitian{T,S}, B::Hermitian{T,S}) where {T<:BlasComplex,S<:StridedMatrix} = - LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] - -eigvecs(A::HermOrSym) = eigvecs(eigen(A)) - function svd(A::RealHermSymComplexHerm, full::Bool=false) vals, vecs = eigen(A) I = sortperm(vals; by=abs, rev=true) @@ -934,6 +770,12 @@ for func in (:exp, :cos, :sin, :tan, :cosh, :sinh, :tanh, :atan, :asinh, :atanh) end end +function cis(A::Union{RealHermSymComplexHerm,SymTridiagonal{<:Real}}) + F = eigen(A) + # The returned matrix is unitary, and is complex-symmetric for real A + return F.vectors .* cis.(F.values') * F.vectors' +end + for func in (:acos, :asin) @eval begin function ($func)(A::HermOrSym{<:Real}) diff --git a/stdlib/LinearAlgebra/src/symmetriceigen.jl b/stdlib/LinearAlgebra/src/symmetriceigen.jl new file mode 100644 index 0000000000000..0f18d290b4d62 --- /dev/null +++ b/stdlib/LinearAlgebra/src/symmetriceigen.jl @@ -0,0 +1,271 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +# Eigensolvers for symmetric and Hermitian matrices +eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}; sortby::Union{Function,Nothing}=nothing) = Eigen(sorteig!(LAPACK.syevr!('V', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)..., sortby)...) + +function eigen(A::RealHermSymComplexHerm; sortby::Union{Function,Nothing}=nothing) + T = eltype(A) + S = eigtype(T) + eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), sortby=sortby) +end + +eigen!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = Eigen(LAPACK.syevr!('V', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)...) + +""" + eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> Eigen + +Computes the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` +which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the +matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) + +Iterating the decomposition produces the components `F.values` and `F.vectors`. + +The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). + +The [`UnitRange`](@ref) `irange` specifies indices of the sorted eigenvalues to search for. + +!!! note + If `irange` is not `1:n`, where `n` is the dimension of `A`, then the returned factorization + will be a *truncated* factorization. +""" +function eigen(A::RealHermSymComplexHerm, irange::UnitRange) + T = eltype(A) + S = eigtype(T) + eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), irange) +end + +eigen!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = + Eigen(LAPACK.syevr!('V', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)...) + +""" + eigen(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> Eigen + +Computes the eigenvalue decomposition of `A`, returning an [`Eigen`](@ref) factorization object `F` +which contains the eigenvalues in `F.values` and the eigenvectors in the columns of the +matrix `F.vectors`. (The `k`th eigenvector can be obtained from the slice `F.vectors[:, k]`.) + +Iterating the decomposition produces the components `F.values` and `F.vectors`. + +The following functions are available for `Eigen` objects: [`inv`](@ref), [`det`](@ref), and [`isposdef`](@ref). + +`vl` is the lower bound of the window of eigenvalues to search for, and `vu` is the upper bound. + +!!! note + If [`vl`, `vu`] does not contain all eigenvalues of `A`, then the returned factorization + will be a *truncated* factorization. +""" +function eigen(A::RealHermSymComplexHerm, vl::Real, vh::Real) + T = eltype(A) + S = eigtype(T) + eigen!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), vl, vh) +end + +eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}) = + LAPACK.syevr!('N', 'A', A.uplo, A.data, 0.0, 0.0, 0, 0, -1.0)[1] + +function eigvals(A::RealHermSymComplexHerm) + T = eltype(A) + S = eigtype(T) + eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A)) +end + +""" + eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values + +Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. +`irange` is a range of eigenvalue *indices* to search for - for instance, the 2nd to 8th eigenvalues. +""" +eigvals!(A::RealHermSymComplexHerm{<:BlasReal,<:StridedMatrix}, irange::UnitRange) = + LAPACK.syevr!('N', 'I', A.uplo, A.data, 0.0, 0.0, irange.start, irange.stop, -1.0)[1] + +""" + eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, irange::UnitRange) -> values + +Returns the eigenvalues of `A`. It is possible to calculate only a subset of the +eigenvalues by specifying a [`UnitRange`](@ref) `irange` covering indices of the sorted eigenvalues, +e.g. the 2nd to 8th eigenvalues. + +# Examples +```jldoctest +julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) +3×3 SymTridiagonal{Float64, Vector{Float64}}: + 1.0 2.0 ⋅ + 2.0 2.0 3.0 + ⋅ 3.0 1.0 + +julia> eigvals(A, 2:2) +1-element Vector{Float64}: + 0.9999999999999996 + +julia> eigvals(A) +3-element Vector{Float64}: + -2.1400549446402604 + 1.0000000000000002 + 5.140054944640259 +``` +""" +function eigvals(A::RealHermSymComplexHerm, irange::UnitRange) + T = eltype(A) + S = eigtype(T) + eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), irange) +end + +""" + eigvals!(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values + +Same as [`eigvals`](@ref), but saves space by overwriting the input `A`, instead of creating a copy. +`vl` is the lower bound of the interval to search for eigenvalues, and `vu` is the upper bound. +""" +eigvals!(A::RealHermSymComplexHerm{T,<:StridedMatrix}, vl::Real, vh::Real) where {T<:BlasReal} = + LAPACK.syevr!('N', 'V', A.uplo, A.data, convert(T, vl), convert(T, vh), 0, 0, -1.0)[1] + +""" + eigvals(A::Union{SymTridiagonal, Hermitian, Symmetric}, vl::Real, vu::Real) -> values + +Returns the eigenvalues of `A`. It is possible to calculate only a subset of the eigenvalues +by specifying a pair `vl` and `vu` for the lower and upper boundaries of the eigenvalues. + +# Examples +```jldoctest +julia> A = SymTridiagonal([1.; 2.; 1.], [2.; 3.]) +3×3 SymTridiagonal{Float64, Vector{Float64}}: + 1.0 2.0 ⋅ + 2.0 2.0 3.0 + ⋅ 3.0 1.0 + +julia> eigvals(A, -1, 2) +1-element Vector{Float64}: + 1.0000000000000009 + +julia> eigvals(A) +3-element Vector{Float64}: + -2.1400549446402604 + 1.0000000000000002 + 5.140054944640259 +``` +""" +function eigvals(A::RealHermSymComplexHerm, vl::Real, vh::Real) + T = eltype(A) + S = eigtype(T) + eigvals!(S != T ? convert(AbstractMatrix{S}, A) : copy(A), vl, vh) +end + +eigmax(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = eigvals(A, size(A, 1):size(A, 1))[1] +eigmin(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = eigvals(A, 1:1)[1] + +function eigen!(A::HermOrSym{T,S}, B::HermOrSym{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasReal,S<:StridedMatrix} + vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) + GeneralizedEigen(sorteig!(vals, vecs, sortby)...) +end +function eigen!(A::Hermitian{T,S}, B::Hermitian{T,S}; sortby::Union{Function,Nothing}=nothing) where {T<:BlasComplex,S<:StridedMatrix} + vals, vecs, _ = LAPACK.sygvd!(1, 'V', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data')) + GeneralizedEigen(sorteig!(vals, vecs, sortby)...) +end + +function eigen!(A::RealHermSymComplexHerm{T,S}, B::AbstractMatrix{T}; sortby::Union{Function,Nothing}=nothing) where {T<:Number,S<:StridedMatrix} + U = cholesky(B).U + vals, w = eigen!(UtiAUi!(A, U)) + vecs = U \ w + GeneralizedEigen(sorteig!(vals, vecs, sortby)...) +end + +# Perform U' \ A / U in-place. +UtiAUi!(As::Symmetric, Utr::UpperTriangular) = Symmetric(_UtiAsymUi!(As.uplo, parent(As), parent(Utr)), sym_uplo(As.uplo)) +UtiAUi!(As::Hermitian, Utr::UpperTriangular) = Hermitian(_UtiAsymUi!(As.uplo, parent(As), parent(Utr)), sym_uplo(As.uplo)) +UtiAUi!(As::Symmetric, Udi::Diagonal) = Symmetric(_UtiAsymUi_diag!(As.uplo, parent(As), Udi), sym_uplo(As.uplo)) +UtiAUi!(As::Hermitian, Udi::Diagonal) = Hermitian(_UtiAsymUi_diag!(As.uplo, parent(As), Udi), sym_uplo(As.uplo)) + +# U is upper triangular +function _UtiAsymUi!(uplo, A, U) + n = size(A, 1) + μ⁻¹ = 1 / U[1, 1] + αμ⁻² = A[1, 1] * μ⁻¹' * μ⁻¹ + + # Update (1, 1) element + A[1, 1] = αμ⁻² + if n > 1 + Unext = view(U, 2:n, 2:n) + + if uplo === 'U' + # Update submatrix + for j in 2:n, i in 2:j + A[i, j] = ( + A[i, j] + - μ⁻¹' * U[1, j] * A[1, i]' + - μ⁻¹ * A[1, j] * U[1, i]' + + αμ⁻² * U[1, j] * U[1, i]' + ) + end + + # Update vector + for j in 2:n + A[1, j] = A[1, j] * μ⁻¹' - U[1, j] * αμ⁻² + end + ldiv!(view(A', 2:n, 1), UpperTriangular(Unext)', view(A', 2:n, 1)) + else + # Update submatrix + for j in 2:n, i in 2:j + A[j, i] = ( + A[j, i] + - μ⁻¹ * A[i, 1]' * U[1, j]' + - μ⁻¹' * U[1, i] * A[j, 1] + + αμ⁻² * U[1, i] * U[1, j]' + ) + end + + # Update vector + for j in 2:n + A[j, 1] = A[j, 1] * μ⁻¹ - U[1, j]' * αμ⁻² + end + ldiv!(view(A, 2:n, 1), UpperTriangular(Unext)', view(A, 2:n, 1)) + end + + # Recurse + _UtiAsymUi!(uplo, view(A, 2:n, 2:n), Unext) + end + + return A +end + +# U is diagonal +function _UtiAsymUi_diag!(uplo, A, U) + n = size(A, 1) + μ⁻¹ = 1 / U[1, 1] + αμ⁻² = A[1, 1] * μ⁻¹' * μ⁻¹ + + # Update (1, 1) element + A[1, 1] = αμ⁻² + if n > 1 + Unext = view(U, 2:n, 2:n) + + if uplo === 'U' + # No need to update any submatrix when U is diagonal + + # Update vector + for j in 2:n + A[1, j] = A[1, j] * μ⁻¹' + end + ldiv!(view(A', 2:n, 1), Diagonal(Unext)', view(A', 2:n, 1)) + else + # No need to update any submatrix when U is diagonal + + # Update vector + for j in 2:n + A[j, 1] = A[j, 1] * μ⁻¹ + end + ldiv!(view(A, 2:n, 1), Diagonal(Unext)', view(A, 2:n, 1)) + end + + # Recurse + _UtiAsymUi!(uplo, view(A, 2:n, 2:n), Unext) + end + + return A +end + +eigvals!(A::HermOrSym{T,S}, B::HermOrSym{T,S}) where {T<:BlasReal,S<:StridedMatrix} = + LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] +eigvals!(A::Hermitian{T,S}, B::Hermitian{T,S}) where {T<:BlasComplex,S<:StridedMatrix} = + LAPACK.sygvd!(1, 'N', A.uplo, A.data, B.uplo == A.uplo ? B.data : copy(B.data'))[1] + +eigvecs(A::HermOrSym) = eigvecs(eigen(A)) diff --git a/stdlib/LinearAlgebra/src/triangular.jl b/stdlib/LinearAlgebra/src/triangular.jl index cfc4e948d8d3d..c141f6469e359 100644 --- a/stdlib/LinearAlgebra/src/triangular.jl +++ b/stdlib/LinearAlgebra/src/triangular.jl @@ -285,23 +285,11 @@ end function istril(A::Union{LowerTriangular,UnitLowerTriangular}, k::Integer=0) k >= 0 && return true - m, n = size(A) - for j in max(1, k + 2):n - for i in 1:min(j - k - 1, m) - iszero(A[i, j]) || return false - end - end - return true + return _istril(A, k) end function istriu(A::Union{UpperTriangular,UnitUpperTriangular}, k::Integer=0) k <= 0 && return true - m, n = size(A) - for j in 1:min(n, m + k - 1) - for i in max(1, j - k + 1):m - iszero(A[i, j]) || return false - end - end - return true + return _istriu(A, k) end istril(A::Adjoint) = istriu(A.parent) istril(A::Transpose) = istriu(A.parent) @@ -2156,12 +2144,17 @@ end # 35(4), (2013), C394–C410. # Eq. 6.1 Base.@propagate_inbounds function _log_diag_block_2x2!(A, A0) - a, b, c, d = A0[1,1], A0[1,2], A0[2,1], A0[2,2] - bc = b * c - s = sqrt(-bc) + a, b, c = A0[1,1], A0[1,2], A0[2,1] + # avoid underflow/overflow for large/small b and c + s = sqrt(abs(b)) * sqrt(abs(c)) θ = atan(s, a) t = θ / s - a1 = log(a^2 - bc) / 2 + au = abs(a) + if au > s + a1 = log1p((s / au)^2) / 2 + log(au) + else + a1 = log1p((au / s)^2) / 2 + log(s) + end A[1,1] = a1 A[2,1] = c*t A[1,2] = b*t @@ -2435,25 +2428,30 @@ function _sqrt_quasitriu_offdiag_block!(R, A) return R end +# real square root of 2x2 diagonal block of quasi-triangular matrix from real Schur +# decomposition. Eqs 6.8-6.9 and Algorithm 6.5 of +# Higham, 2008, "Functions of Matrices: Theory and Computation", SIAM. Base.@propagate_inbounds function _sqrt_real_2x2!(R, A) - a11, a21, a12, a22 = A[1, 1], A[2, 1], A[1, 2], A[2, 2] - θ = (a11 + a22) / 2 - μ² = -(a11 - a22)^2 / 4 - a21 * a12 - μ = sqrt(μ²) - if θ > 0 - α = sqrt((sqrt(θ^2 + μ²) + θ) / 2) - else - α = μ / sqrt(2 * (sqrt(θ^2 + μ²) - θ)) - end + # in the real Schur form, A[1, 1] == A[2, 2], and A[2, 1] * A[1, 2] < 0 + θ, a21, a12 = A[1, 1], A[2, 1], A[1, 2] + # avoid overflow/underflow of μ + # for real sqrt, |d| ≤ 2 max(|a12|,|a21|) + μ = sqrt(abs(a12)) * sqrt(abs(a21)) + α = _real_sqrt(θ, μ) c = 2α - d = α - θ / c - R[1, 1] = a11 / c + d + R[1, 1] = α R[2, 1] = a21 / c R[1, 2] = a12 / c - R[2, 2] = a22 / c + d + R[2, 2] = α return R end +# real part of square root of θ+im*μ +@inline function _real_sqrt(θ, μ) + t = sqrt((abs(θ) + hypot(θ, μ)) / 2) + return θ ≥ 0 ? t : μ / 2t +end + Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_1x1!(R, A, i, j) Rii = R[i, i] Rjj = R[j, j] @@ -2522,7 +2520,9 @@ Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x2!(R, A, i, j) Rii = @view R[irange, irange] Rjj = @view R[jrange, jrange] Rij = @view R[irange, jrange] - _sylvester_2x2!(Rii, Rjj, Rij) + if !iszero(Rij) && !all(isnan, Rij) + _sylvester_2x2!(Rii, Rjj, Rij) + end return R end diff --git a/stdlib/LinearAlgebra/src/uniformscaling.jl b/stdlib/LinearAlgebra/src/uniformscaling.jl index c59871e0641ef..44ad5d98e99a4 100644 --- a/stdlib/LinearAlgebra/src/uniformscaling.jl +++ b/stdlib/LinearAlgebra/src/uniformscaling.jl @@ -215,8 +215,8 @@ end function (+)(A::AbstractMatrix, J::UniformScaling) checksquare(A) B = copy_oftype(A, Base._return_type(+, Tuple{eltype(A), typeof(J)})) - @inbounds for i in axes(A, 1) - B[i,i] += J + for i in intersect(axes(A,1), axes(A,2)) + @inbounds B[i,i] += J end return B end @@ -224,8 +224,8 @@ end function (-)(J::UniformScaling, A::AbstractMatrix) checksquare(A) B = convert(AbstractMatrix{Base._return_type(+, Tuple{eltype(A), typeof(J)})}, -A) - @inbounds for i in axes(A, 1) - B[i,i] += J + for i in intersect(axes(A,1), axes(A,2)) + @inbounds B[i,i] += J end return B end @@ -265,7 +265,8 @@ end *(J::UniformScaling, x::Number) = UniformScaling(J.λ*x) /(J1::UniformScaling, J2::UniformScaling) = J2.λ == 0 ? throw(SingularException(1)) : UniformScaling(J1.λ/J2.λ) -/(J::UniformScaling, A::AbstractMatrix) = lmul!(J.λ, inv(A)) +/(J::UniformScaling, A::AbstractMatrix) = + (invA = inv(A); lmul!(J.λ, convert(AbstractMatrix{promote_type(eltype(J),eltype(invA))}, invA))) /(A::AbstractMatrix, J::UniformScaling) = J.λ == 0 ? throw(SingularException(1)) : A/J.λ /(v::AbstractVector, J::UniformScaling) = reshape(v, length(v), 1) / J @@ -273,7 +274,8 @@ end \(J1::UniformScaling, J2::UniformScaling) = J1.λ == 0 ? throw(SingularException(1)) : UniformScaling(J1.λ\J2.λ) \(J::UniformScaling, A::AbstractVecOrMat) = J.λ == 0 ? throw(SingularException(1)) : J.λ\A -\(A::AbstractMatrix, J::UniformScaling) = rmul!(inv(A), J.λ) +\(A::AbstractMatrix, J::UniformScaling) = + (invA = inv(A); rmul!(convert(AbstractMatrix{promote_type(eltype(invA),eltype(J))}, invA), J.λ)) \(F::Factorization, J::UniformScaling) = F \ J(size(F,1)) \(x::Number, J::UniformScaling) = UniformScaling(x\J.λ) @@ -282,6 +284,24 @@ end mul!(C, A, J.λ, alpha, beta) @inline mul!(C::AbstractVecOrMat, J::UniformScaling, B::AbstractVecOrMat, alpha::Number, beta::Number) = mul!(C, J.λ, B, alpha, beta) + +function mul!(out::AbstractMatrix{T}, a::Number, B::UniformScaling, α::Number, β::Number) where {T} + checksquare(out) + if iszero(β) # zero contribution of the out matrix + fill!(out, zero(T)) + elseif !isone(β) + rmul!(out, β) + end + s = convert(T, a*B.λ*α) + if !iszero(s) + @inbounds for i in diagind(out) + out[i] += s + end + end + return out +end +@inline mul!(out::AbstractMatrix, A::UniformScaling, b::Number, α::Number, β::Number)= + mul!(out, A.λ, UniformScaling(b), α, β) rmul!(A::AbstractMatrix, J::UniformScaling) = rmul!(A, J.λ) lmul!(J::UniformScaling, B::AbstractVecOrMat) = lmul!(J.λ, B) rdiv!(A::AbstractMatrix, J::UniformScaling) = rdiv!(A, J.λ) @@ -480,6 +500,9 @@ Array(s::UniformScaling, dims::Dims{2}) = Matrix(s, dims) Diagonal{T}(s::UniformScaling, m::Integer) where {T} = Diagonal{T}(fill(T(s.λ), m)) Diagonal(s::UniformScaling, m::Integer) = Diagonal{eltype(s)}(s, m) +dot(A::AbstractMatrix, J::UniformScaling) = dot(tr(A), J.λ) +dot(J::UniformScaling, A::AbstractMatrix) = dot(J.λ, tr(A)) + dot(x::AbstractVector, J::UniformScaling, y::AbstractVector) = dot(x, J.λ, y) dot(x::AbstractVector, a::Number, y::AbstractVector) = sum(t -> dot(t[1], a, t[2]), zip(x, y)) dot(x::AbstractVector, a::Union{Real,Complex}, y::AbstractVector) = a*dot(x, y) diff --git a/stdlib/LinearAlgebra/test/adjtrans.jl b/stdlib/LinearAlgebra/test/adjtrans.jl index bb2e54d306224..f0f0461c23862 100644 --- a/stdlib/LinearAlgebra/test/adjtrans.jl +++ b/stdlib/LinearAlgebra/test/adjtrans.jl @@ -7,15 +7,15 @@ using Test, LinearAlgebra, SparseArrays @testset "Adjoint and Transpose inner constructor basics" begin intvec, intmat = [1, 2], [1 2; 3 4] # Adjoint/Transpose eltype must match the type of the Adjoint/Transpose of the input eltype - @test_throws ErrorException Adjoint{Float64,Vector{Int}}(intvec) - @test_throws ErrorException Adjoint{Float64,Matrix{Int}}(intmat) - @test_throws ErrorException Transpose{Float64,Vector{Int}}(intvec) - @test_throws ErrorException Transpose{Float64,Matrix{Int}}(intmat) + @test_throws TypeError Adjoint{Float64,Vector{Int}}(intvec)[1,1] + @test_throws TypeError Adjoint{Float64,Matrix{Int}}(intmat)[1,1] + @test_throws TypeError Transpose{Float64,Vector{Int}}(intvec)[1,1] + @test_throws TypeError Transpose{Float64,Matrix{Int}}(intmat)[1,1] # Adjoint/Transpose wrapped array type must match the input array type - @test_throws MethodError Adjoint{Int,Vector{Float64}}(intvec) - @test_throws MethodError Adjoint{Int,Matrix{Float64}}(intmat) - @test_throws MethodError Transpose{Int,Vector{Float64}}(intvec) - @test_throws MethodError Transpose{Int,Matrix{Float64}}(intmat) + @test_throws TypeError Adjoint{Int,Vector{Float64}}(intvec)[1,1] + @test_throws TypeError Adjoint{Int,Matrix{Float64}}(intmat)[1,1] + @test_throws TypeError Transpose{Int,Vector{Float64}}(intvec)[1,1] + @test_throws TypeError Transpose{Int,Matrix{Float64}}(intmat)[1,1] # Adjoint/Transpose inner constructor basic functionality, concrete scalar eltype @test (Adjoint{Int,Vector{Int}}(intvec)::Adjoint{Int,Vector{Int}}).parent === intvec @test (Adjoint{Int,Matrix{Int}}(intmat)::Adjoint{Int,Matrix{Int}}).parent === intmat @@ -275,6 +275,9 @@ end @test vec(Transpose(intvec)) === intvec cvec = [1 + 1im] @test vec(cvec')[1] == cvec[1]' + mvec = [[1 2; 3 4+5im]]; + @test vec(transpose(mvec))[1] == transpose(mvec[1]) + @test vec(adjoint(mvec))[1] == adjoint(mvec[1]) end @testset "horizontal concatenation of Adjoint/Transpose-wrapped vectors and Numbers" begin @@ -573,4 +576,24 @@ end @test transpose(Int[]) * Int[] == 0 end +@testset "reductions: $adjtrans" for adjtrans in [transpose, adjoint] + mat = rand(ComplexF64, 3,5) + @test sum(adjtrans(mat)) ≈ sum(collect(adjtrans(mat))) + @test sum(adjtrans(mat), dims=1) ≈ sum(collect(adjtrans(mat)), dims=1) + @test sum(adjtrans(mat), dims=(1,2)) ≈ sum(collect(adjtrans(mat)), dims=(1,2)) + + @test sum(imag, adjtrans(mat)) ≈ sum(imag, collect(adjtrans(mat))) + @test sum(imag, adjtrans(mat), dims=1) ≈ sum(imag, collect(adjtrans(mat)), dims=1) + + mat = [rand(ComplexF64,2,2) for _ in 1:3, _ in 1:5] + @test sum(adjtrans(mat)) ≈ sum(collect(adjtrans(mat))) + @test sum(adjtrans(mat), dims=1) ≈ sum(collect(adjtrans(mat)), dims=1) + @test sum(adjtrans(mat), dims=(1,2)) ≈ sum(collect(adjtrans(mat)), dims=(1,2)) + + @test sum(imag, adjtrans(mat)) ≈ sum(imag, collect(adjtrans(mat))) + @test sum(x -> x[1,2], adjtrans(mat)) ≈ sum(x -> x[1,2], collect(adjtrans(mat))) + @test sum(imag, adjtrans(mat), dims=1) ≈ sum(imag, collect(adjtrans(mat)), dims=1) + @test sum(x -> x[1,2], adjtrans(mat), dims=1) ≈ sum(x -> x[1,2], collect(adjtrans(mat)), dims=1) +end + end # module TestAdjointTranspose diff --git a/stdlib/LinearAlgebra/test/blas.jl b/stdlib/LinearAlgebra/test/blas.jl index 6c2b27f9a53a5..911b684b1793b 100644 --- a/stdlib/LinearAlgebra/test/blas.jl +++ b/stdlib/LinearAlgebra/test/blas.jl @@ -514,6 +514,11 @@ end BLAS.axpby!(elty(2), x, elty(3), y) @test y == WrappedArray(elty[19, 50, 30, 56]) @test BLAS.iamax(x) == 2 + + M = fill(elty(1.0), 3, 3) + BLAS.scal!(elty(2), view(M,:,2)) + BLAS.scal!(elty(3), view(M,3,:)) + @test M == elty[1. 2. 1.; 1. 2. 1.; 3. 6. 3.] # Level 2 A = WrappedArray(elty[1 2; 3 4]) x = WrappedArray(elty[1, 2]) @@ -600,4 +605,8 @@ end @test BLAS.get_num_threads() === default end +# https://github.com/JuliaLang/julia/pull/39845 +@test LinearAlgebra.BLAS.libblas == "libblastrampoline" +@test LinearAlgebra.BLAS.liblapack == "libblastrampoline" + end # module TestBLAS diff --git a/stdlib/LinearAlgebra/test/bunchkaufman.jl b/stdlib/LinearAlgebra/test/bunchkaufman.jl index 5098f818f1804..e05592cdc1c5c 100644 --- a/stdlib/LinearAlgebra/test/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/test/bunchkaufman.jl @@ -114,7 +114,8 @@ bimg = randn(n,2)/2 @test logabsdet(bc2)[2] == sign(det(bc2)) @test inv(bc2)*apd ≈ Matrix(I, n, n) @test apd*(bc2\b) ≈ b rtol=eps(cond(apd)) - @test ishermitian(bc2) == !issymmetric(bc2) + @test ishermitian(bc2) + @test !issymmetric(bc2) || eltya <: Real end end end @@ -171,4 +172,22 @@ end end end +@testset "adjoint of BunchKaufman" begin + Ar = randn(5, 5) + Ar = Ar + Ar' + Actmp = complex.(randn(5, 5), randn(5, 5)) + Ac1 = Actmp + Actmp' + Ac2 = Actmp + transpose(Actmp) + b = ones(size(Ar, 1)) + + F = bunchkaufman(Ar) + @test F\b == F'\b + + F = bunchkaufman(Ac1) + @test F\b == F'\b + + F = bunchkaufman(Ac2) + @test_throws ArgumentError("adjoint not implemented for complex symmetric matrices") F' +end + end # module TestBunchKaufman diff --git a/stdlib/LinearAlgebra/test/cholesky.jl b/stdlib/LinearAlgebra/test/cholesky.jl index a3f780c047a29..170af59eef8c3 100644 --- a/stdlib/LinearAlgebra/test/cholesky.jl +++ b/stdlib/LinearAlgebra/test/cholesky.jl @@ -475,4 +475,12 @@ end end end +@testset "adjoint of Cholesky" begin + A = randn(5, 5) + A = A'A + F = cholesky(A) + b = ones(size(A, 1)) + @test F\b == F'\b +end + end # module TestCholesky diff --git a/stdlib/LinearAlgebra/test/dense.jl b/stdlib/LinearAlgebra/test/dense.jl index 51edd334f1e0f..de5b25a868fcb 100644 --- a/stdlib/LinearAlgebra/test/dense.jl +++ b/stdlib/LinearAlgebra/test/dense.jl @@ -145,9 +145,13 @@ end @testset "Matrix square root" begin asq = sqrt(a) @test asq*asq ≈ a + @test sqrt(transpose(a))*sqrt(transpose(a)) ≈ transpose(a) + @test sqrt(adjoint(a))*sqrt(adjoint(a)) ≈ adjoint(a) asym = a + a' # symmetric indefinite asymsq = sqrt(asym) @test asymsq*asymsq ≈ asym + @test sqrt(transpose(asym))*sqrt(transpose(asym)) ≈ transpose(asym) + @test sqrt(adjoint(asym))*sqrt(adjoint(asym)) ≈ adjoint(asym) if eltype(a) <: Real # real square root apos = a * a @test sqrt(apos)^2 ≈ apos @@ -447,6 +451,11 @@ end 183.765138646367 183.765138646366 163.679601723179; 71.797032399996 91.8825693231832 111.968106246371]') @test exp(A1) ≈ eA1 + @test exp(adjoint(A1)) ≈ adjoint(eA1) + @test exp(transpose(A1)) ≈ transpose(eA1) + for f in (sin, cos, sinh, cosh, tanh, tan) + @test f(adjoint(A1)) ≈ f(copy(adjoint(A1))) + end A2 = convert(Matrix{elty}, [29.87942128909879 0.7815750847907159 -2.289519314033932; @@ -457,26 +466,45 @@ end -18231880972009252.0 60605228702221920.0 101291842930249760.0; -30475770808580480.0 101291842930249728.0 169294411240851968.0]) @test exp(A2) ≈ eA2 + @test exp(adjoint(A2)) ≈ adjoint(eA2) + @test exp(transpose(A2)) ≈ transpose(eA2) A3 = convert(Matrix{elty}, [-131 19 18;-390 56 54;-387 57 52]) eA3 = convert(Matrix{elty}, [-1.50964415879218 -5.6325707998812 -4.934938326092; 0.367879439109187 1.47151775849686 1.10363831732856; 0.135335281175235 0.406005843524598 0.541341126763207]') @test exp(A3) ≈ eA3 + @test exp(adjoint(A3)) ≈ adjoint(eA3) + @test exp(transpose(A3)) ≈ transpose(eA3) A4 = convert(Matrix{elty}, [0.25 0.25; 0 0]) eA4 = convert(Matrix{elty}, [1.2840254166877416 0.2840254166877415; 0 1]) @test exp(A4) ≈ eA4 + @test exp(adjoint(A4)) ≈ adjoint(eA4) + @test exp(transpose(A4)) ≈ transpose(eA4) A5 = convert(Matrix{elty}, [0 0.02; 0 0]) eA5 = convert(Matrix{elty}, [1 0.02; 0 1]) @test exp(A5) ≈ eA5 + @test exp(adjoint(A5)) ≈ adjoint(eA5) + @test exp(transpose(A5)) ≈ transpose(eA5) # Hessenberg @test hessenberg(A1).H ≈ convert(Matrix{elty}, [4.000000000000000 -1.414213562373094 -1.414213562373095 -1.414213562373095 4.999999999999996 -0.000000000000000 0 -0.000000000000002 3.000000000000000]) + + # cis always returns a complex matrix + if elty <: Real + eltyim = Complex{elty} + else + eltyim = elty + end + + @test cis(A1) ≈ convert(Matrix{eltyim}, [-0.339938 + 0.000941506im 0.772659 - 0.8469im 0.52745 + 0.566543im; + 0.650054 - 0.140179im -0.0762135 + 0.284213im 0.38633 - 0.42345im ; + 0.650054 - 0.140179im 0.913779 + 0.143093im -0.603663 - 0.28233im ]) rtol=7e-7 end @testset "Additional tests for $elty" for elty in (Float64, ComplexF64) @@ -485,15 +513,23 @@ end 1/4 1/5 1/6 1/7; 1/5 1/6 1/7 1/8]) @test exp(log(A4)) ≈ A4 + @test exp(log(transpose(A4))) ≈ transpose(A4) + @test exp(log(adjoint(A4))) ≈ adjoint(A4) A5 = convert(Matrix{elty}, [1 1 0 1; 0 1 1 0; 0 0 1 1; 1 0 0 1]) @test exp(log(A5)) ≈ A5 + @test exp(log(transpose(A5))) ≈ transpose(A5) + @test exp(log(adjoint(A5))) ≈ adjoint(A5) A6 = convert(Matrix{elty}, [-5 2 0 0 ; 1/2 -7 3 0; 0 1/3 -9 4; 0 0 1/4 -11]) @test exp(log(A6)) ≈ A6 + @test exp(log(transpose(A6))) ≈ transpose(A6) + @test exp(log(adjoint(A6))) ≈ adjoint(A6) A7 = convert(Matrix{elty}, [1 0 0 1e-8; 0 1 0 0; 0 0 1 0; 0 0 0 1]) @test exp(log(A7)) ≈ A7 + @test exp(log(transpose(A7))) ≈ transpose(A7) + @test exp(log(adjoint(A7))) ≈ adjoint(A7) end @testset "Integer promotion tests" begin @@ -560,8 +596,13 @@ end @test cos(A) ≈ cos(-A) @test sin(A) ≈ -sin(-A) @test tan(A) ≈ sin(A) / cos(A) + @test cos(A) ≈ real(exp(im*A)) @test sin(A) ≈ imag(exp(im*A)) + @test cos(A) ≈ real(cis(A)) + @test sin(A) ≈ imag(cis(A)) + @test cis(A) ≈ cos(A) + im * sin(A) + @test cosh(A) ≈ 0.5 * (exp(A) + exp(-A)) @test sinh(A) ≈ 0.5 * (exp(A) - exp(-A)) @test cosh(A) ≈ cosh(-A) @@ -605,6 +646,9 @@ end @test cos(A5) ≈ 0.5 * (exp(im*A5) + exp(-im*A5)) @test sin(A5) ≈ -0.5im * (exp(im*A5) - exp(-im*A5)) + @test cos(A5) ≈ 0.5 * (cis(A5) + cis(-A5)) + @test sin(A5) ≈ -0.5im * (cis(A5) - cis(-A5)) + @test cosh(A5) ≈ 0.5 * (exp(A5) + exp(-A5)) @test sinh(A5) ≈ 0.5 * (exp(A5) - exp(-A5)) end @@ -870,6 +914,38 @@ end end end +@testset "issue #40141" begin + x = [-1 -eps() 0 0; eps() -1 0 0; 0 0 -1 -eps(); 0 0 eps() -1] + @test sqrt(x)^2 ≈ x + + x2 = [-1 -eps() 0 0; 3eps() -1 0 0; 0 0 -1 -3eps(); 0 0 eps() -1] + @test sqrt(x2)^2 ≈ x2 + + x3 = [-1 -eps() 0 0; eps() -1 0 0; 0 0 -1 -eps(); 0 0 eps() Inf] + @test all(isnan, sqrt(x3)) + + # test overflow/underflow handled + x4 = [0 -1e200; 1e200 0] + @test sqrt(x4)^2 ≈ x4 + + x5 = [0 -1e-200; 1e-200 0] + @test sqrt(x5)^2 ≈ x5 + + x6 = [1.0 1e200; -1e-200 1.0] + @test sqrt(x6)^2 ≈ x6 +end + +@testset "matrix logarithm block diagonal underflow/overflow" begin + x1 = [0 -1e200; 1e200 0] + @test exp(log(x1)) ≈ x1 + + x2 = [0 -1e-200; 1e-200 0] + @test exp(log(x2)) ≈ x2 + + x3 = [1.0 1e200; -1e-200 1.0] + @test exp(log(x3)) ≈ x3 +end + @testset "issue #7181" begin A = [ 1 5 9 2 6 10 diff --git a/stdlib/LinearAlgebra/test/diagonal.jl b/stdlib/LinearAlgebra/test/diagonal.jl index 043b2181a7908..dcd82618c4968 100644 --- a/stdlib/LinearAlgebra/test/diagonal.jl +++ b/stdlib/LinearAlgebra/test/diagonal.jl @@ -88,7 +88,7 @@ Random.seed!(1) @test func(D) ≈ func(DM) atol=n^2*eps(relty)*(1+(elty<:Complex)) end if relty <: BlasFloat - for func in (exp, sinh, cosh, tanh, sech, csch, coth) + for func in (exp, cis, sinh, cosh, tanh, sech, csch, coth) @test func(D) ≈ func(DM) atol=n^3*eps(relty) end @test log(Diagonal(abs.(D.diag))) ≈ log(abs.(DM)) atol=n^3*eps(relty) @@ -102,6 +102,10 @@ Random.seed!(1) end end + @testset "Two-dimensional Euler formula for Diagonal" begin + @test cis(Diagonal([π, π])) ≈ -I + end + @testset "Linear solve" begin for (v, U) in ((vv, UU), (view(vv, 1:n), view(UU, 1:n, 1:2))) @test D*v ≈ DM*v atol=n*eps(relty)*(1+(elty<:Complex)) @@ -295,6 +299,10 @@ Random.seed!(1) M4 = rand(elty, n÷2, n÷2) @test kron(D3, M4) ≈ kron(DM3, M4) @test kron(M4, D3) ≈ kron(M4, DM3) + X = [ones(1,1) for i in 1:2, j in 1:2] + @test kron(I(2), X)[1,3] == zeros(1,1) + X = [ones(2,2) for i in 1:2, j in 1:2] + @test kron(I(2), X)[1,3] == zeros(2,2) end @testset "iszero, isone, triu, tril" begin Dzero = Diagonal(zeros(elty, 10)) @@ -395,6 +403,23 @@ Random.seed!(1) end +@testset "kron (issue #40595)" begin + # custom array type to test that kron on Diagonal matrices preserves types of the parents if possible + struct KronTestArray{T, N, AT} <: AbstractArray{T, N} + data::AT + end + KronTestArray(data::AbstractArray) = KronTestArray{eltype(data), ndims(data), typeof(data)}(data) + Base.size(A::KronTestArray) = size(A.data) + LinearAlgebra.kron(A::KronTestArray, B::KronTestArray) = KronTestArray(kron(A.data, B.data)) + Base.getindex(K::KronTestArray{<:Any,N}, i::Vararg{Int,N}) where {N} = K.data[i...] + + A = KronTestArray([1, 2, 3]); + @test kron(A, A) isa KronTestArray + Ad = Diagonal(A); + @test kron(Ad, Ad).diag isa KronTestArray + @test kron(Ad, Ad).diag == kron([1, 2, 3], [1, 2, 3]) +end + @testset "svdvals and eigvals (#11120/#11247)" begin D = Diagonal(Matrix{Float64}[randn(3,3), randn(2,2)]) @test sort([svdvals(D)...;], rev = true) ≈ svdvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]]) @@ -540,7 +565,7 @@ end D = Diagonal(randn(5)) Q = qr(randn(5, 5)).Q @test D * Q' == Array(D) * Q' - Q = qr(randn(5, 5), Val(true)).Q + Q = qr(randn(5, 5), ColumnNorm()).Q @test_throws ArgumentError lmul!(Q, D) end @@ -568,6 +593,7 @@ end @test ishermitian(Dsym) == false @test exp(D) == Diagonal([exp([1 2; 3 4]), exp([1 2; 3 4])]) + @test cis(D) == Diagonal([cis([1 2; 3 4]), cis([1 2; 3 4])]) @test log(D) == Diagonal([log([1 2; 3 4]), log([1 2; 3 4])]) @test sqrt(D) == Diagonal([sqrt([1 2; 3 4]), sqrt([1 2; 3 4])]) @@ -653,13 +679,15 @@ end @test yt*D*y == (yt*D)*y == (yt*A)*y end -@testset "Multiplication of single element Diagonal (#36746)" begin +@testset "Multiplication of single element Diagonal (#36746, #40726)" begin @test_throws DimensionMismatch Diagonal(randn(1)) * randn(5) @test_throws DimensionMismatch Diagonal(randn(1)) * Diagonal(randn(3, 3)) A = [1 0; 0 2] v = [3, 4] @test Diagonal(A) * v == A * v @test Diagonal(A) * Diagonal(A) == A * A + @test_throws DimensionMismatch [1 0;0 1] * Diagonal([2 3]) # Issue #40726 + @test_throws DimensionMismatch lmul!(Diagonal([1]), [1,2,3]) # nearby end @testset "Triangular division by Diagonal #27989" begin @@ -735,6 +763,18 @@ end @test dot(zeros(Int32, 0), Diagonal(zeros(Int, 0)), zeros(Int16, 0)) === 0 end +@testset "Diagonal(undef)" begin + d = Diagonal{Float32}(undef, 2) + @test length(d.diag) == 2 +end + +@testset "permutedims (#39447)" begin + for D in (Diagonal(zeros(5)), Diagonal(zeros(5) .+ 1im), Diagonal([[1,2],[3,4]])) + @test permutedims(D) === permutedims(D,(1,2)) === permutedims(D,(2,1)) === D + @test_throws ArgumentError permutedims(D,(1,3)) + end +end + @testset "Inner product" begin A = Diagonal(rand(10) .+ im) B = Diagonal(rand(10) .+ im) diff --git a/stdlib/LinearAlgebra/test/eigen.jl b/stdlib/LinearAlgebra/test/eigen.jl index 16b47221a8333..fd9f7dfba92ee 100644 --- a/stdlib/LinearAlgebra/test/eigen.jl +++ b/stdlib/LinearAlgebra/test/eigen.jl @@ -3,7 +3,7 @@ module TestEigen using Test, LinearAlgebra, Random -using LinearAlgebra: BlasComplex, BlasFloat, BlasReal, QRPivoted +using LinearAlgebra: BlasComplex, BlasFloat, BlasReal, QRPivoted, UtiAUi! n = 10 @@ -73,6 +73,31 @@ aimg = randn(n,n)/2 d,v = eigen(asym_sg, a_sg'a_sg) @test d == f.values @test v == f.vectors + + # solver for in-place U' \ A / U (#14896) + if !(eltya <: Integer) + for atyp in (eltya <: Real ? (Symmetric, Hermitian) : (Hermitian,)) + for utyp in (UpperTriangular, Diagonal) + A = atyp(asym_sg) + U = utyp(a_sg'a_sg) + @test UtiAUi!(copy(A), U) ≈ U' \ A / U + end + end + end + + # matrices of different types (#14896) + if eltya <: Real + fs = eigen(Symmetric(asym_sg), a_sg'a_sg) + @test fs.values ≈ f.values + @test abs.(fs.vectors) ≈ abs.(f.vectors) # may change sign + gs = eigen(Symmetric(asym_sg), Diagonal(a_sg'a_sg)) + @test Symmetric(asym_sg)*gs.vectors ≈ (Diagonal(a_sg'a_sg)*gs.vectors) * Diagonal(gs.values) + end + fh = eigen(Hermitian(asym_sg), a_sg'a_sg) + @test fh.values ≈ f.values + @test abs.(fh.vectors) ≈ abs.(f.vectors) # may change sign + gh = eigen(Hermitian(asym_sg), Diagonal(a_sg'a_sg)) + @test Hermitian(asym_sg)*gh.vectors ≈ (Diagonal(a_sg'a_sg)*gh.vectors) * Diagonal(gh.values) end @testset "Non-symmetric generalized eigenproblem" begin if isa(a, Array) diff --git a/stdlib/LinearAlgebra/test/generic.jl b/stdlib/LinearAlgebra/test/generic.jl index 0c1365b11679f..489b96be56019 100644 --- a/stdlib/LinearAlgebra/test/generic.jl +++ b/stdlib/LinearAlgebra/test/generic.jl @@ -142,6 +142,10 @@ end @testset "Scaling with 5-argument mul!" begin @test mul!(copy(a), 5., a, 10, 100) == a*150 @test mul!(copy(a), a, 5., 10, 100) == a*150 + @test mul!(vec(copy(a)), 5., a, 10, 100) == vec(a*150) + @test mul!(vec(copy(a)), a, 5., 10, 100) == vec(a*150) + @test_throws DimensionMismatch mul!([vec(copy(a)); 0], 5., a, 10, 100) + @test_throws DimensionMismatch mul!([vec(copy(a)); 0], a, 5., 10, 100) @test mul!(copy(a), Diagonal([1.; 2.]), a, 10, 100) == 10a.*[1; 2] .+ 100a @test mul!(copy(a), Diagonal([1; 2]), a, 10, 100) == 10a.*[1; 2] .+ 100a @test mul!(copy(a), a, Diagonal(1.:an), 10, 100) == 10a.*Vector(1:an)' .+ 100a @@ -189,6 +193,7 @@ end @test det(a) == a @test norm(a) == abs(a) @test norm(a, 0) == 1 + @test norm(0, 0) == 0 end @test !issymmetric(NaN16) @@ -209,6 +214,19 @@ end @test norm([2.4e-322, 4.4e-323], 3) ≈ 2.4e-322 @test_throws ArgumentError opnorm(Matrix{Float64}(undef,5,5),5) +# operator norm for zero-dimensional domain is zero (see #40370) +@testset "opnorm" begin + for m in (0, 1, 2) + @test @inferred(opnorm(fill(1,0,m))) == 0.0 + @test @inferred(opnorm(fill(1,m,0))) == 0.0 + end + for m in (1, 2) + @test @inferred(opnorm(fill(1im,1,m))) ≈ sqrt(m) + @test @inferred(opnorm(fill(1im,m,1))) ≈ sqrt(m) + end + @test @inferred(opnorm(fill(1,2,2))) ≈ 2 +end + @testset "generic norm for arrays of arrays" begin x = Vector{Int}[[1,2], [3,4]] @test @inferred(norm(x)) ≈ sqrt(30) @@ -228,12 +246,14 @@ end rotate!(x, y, c, s) @test x ≈ c*x2 + s*y2 @test y ≈ -conj(s)*x2 + c*y2 + @test_throws DimensionMismatch rotate!([x; x], y, c, s) x3 = copy(x) y3 = copy(y) reflect!(x, y, c, s) @test x ≈ c*x3 + s*y3 @test y ≈ conj(s)*x3 - c*y3 + @test_throws DimensionMismatch reflect!([x; x], y, c, s) end @testset "LinearAlgebra.axp(b)y! for element type without commutative multiplication" begin @@ -257,6 +277,7 @@ end ry = [2 8] @test LinearAlgebra.axpy!(α, x, rx, y, ry) == [1 1 1 1; 11 1 1 26] end + @testset "norm and normalize!" begin vr = [3.0, 4.0] for Tr in (Float32, Float64) @@ -334,6 +355,11 @@ end @test [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]] ≈ [[1,2, [3,4]], 5.0, [6im, [7.0, 8.0]]] end +@testset "Issue 40128" begin + @test det(BigInt[9 1 8 0; 0 0 8 7; 7 6 8 3; 2 9 7 7])::BigInt == -1 + @test det(BigInt[1 big(2)^65+1; 3 4])::BigInt == (4 - 3*(big(2)^65+1)) +end + # Minimal modulo number type - but not subtyping Number struct ModInt{n} k @@ -361,13 +387,13 @@ LinearAlgebra.Transpose(a::ModInt{n}) where {n} = transpose(a) A = [ModInt{2}(1) ModInt{2}(0); ModInt{2}(1) ModInt{2}(1)] b = [ModInt{2}(1), ModInt{2}(0)] - @test A*(lu(A, Val(false))\b) == b + @test A*(lu(A, NoPivot())\b) == b # Needed for pivoting: Base.abs(a::ModInt{n}) where {n} = a Base.:<(a::ModInt{n}, b::ModInt{n}) where {n} = a.k < b.k - @test A*(lu(A, Val(true))\b) == b + @test A*(lu(A, RowMaximum())\b) == b end @testset "Issue 18742" begin diff --git a/stdlib/LinearAlgebra/test/hessenberg.jl b/stdlib/LinearAlgebra/test/hessenberg.jl index 62cafecb57609..0f9246c722349 100644 --- a/stdlib/LinearAlgebra/test/hessenberg.jl +++ b/stdlib/LinearAlgebra/test/hessenberg.jl @@ -4,6 +4,10 @@ module TestHessenberg using Test, LinearAlgebra, Random +const BASE_TEST_PATH = joinpath(Sys.BINDIR, "..", "share", "julia", "test") +isdefined(Main, :Furlongs) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "Furlongs.jl")) +using .Main.Furlongs + # for tuple tests below ≅(x,y) = all(p -> p[1] ≈ p[2], zip(x,y)) @@ -55,6 +59,54 @@ let n = 10 H = UpperHessenberg(Areal) @test Array(Hc + H) == Array(Hc) + Array(H) @test Array(Hc - H) == Array(Hc) - Array(H) + @testset "Preserve UpperHessenberg shape (issue #39388)" begin + for H = (UpperHessenberg(Areal), UpperHessenberg(Furlong.(Areal))) + if eltype(H) <: Furlong + A = Furlong.(rand(n,n)) + d = Furlong.(rand(n)) + dl = Furlong.(rand(n-1)) + du = Furlong.(rand(n-1)) + us = Furlong(1)*I + else + A = rand(n,n) + d = rand(n) + dl = rand(n-1) + du = rand(n-1) + us = 1*I + end + @testset "$op" for op = (+,-) + for x = (us, Diagonal(d), Bidiagonal(d,dl,:U), Bidiagonal(d,dl,:L), + Tridiagonal(dl,d,du), SymTridiagonal(d,dl), + UpperTriangular(A), UnitUpperTriangular(A)) + @test op(H,x) == op(Array(H),x) + @test op(x,H) == op(x,Array(H)) + @test op(H,x) isa UpperHessenberg + @test op(x,H) isa UpperHessenberg + end + end + A = randn(n,n) + d = randn(n) + dl = randn(n-1) + @testset "Multiplication/division" begin + for x = (5, 5I, Diagonal(d), Bidiagonal(d,dl,:U), + UpperTriangular(A), UnitUpperTriangular(A)) + @test H*x == Array(H)*x broken = eltype(H) <: Furlong && x isa Bidiagonal + @test x*H == x*Array(H) broken = eltype(H) <: Furlong && x isa Bidiagonal + @test H/x == Array(H)/x broken = eltype(H) <: Furlong && x isa Union{Bidiagonal, Diagonal, UpperTriangular} + @test x\H == x\Array(H) broken = eltype(H) <: Furlong && x isa Union{Bidiagonal, Diagonal, UpperTriangular} + @test H*x isa UpperHessenberg broken = eltype(H) <: Furlong && x isa Bidiagonal + @test x*H isa UpperHessenberg broken = eltype(H) <: Furlong && x isa Bidiagonal + @test H/x isa UpperHessenberg broken = eltype(H) <: Furlong && x isa Union{Bidiagonal, Diagonal} + @test x\H isa UpperHessenberg broken = eltype(H) <: Furlong && x isa Union{Bidiagonal, Diagonal} + end + x = Bidiagonal(d, dl, :L) + @test H*x == Array(H)*x + @test x*H == x*Array(H) + @test H/x == Array(H)/x broken = eltype(H) <: Furlong + @test_broken x\H == x\Array(H) # issue 40037 + end + end + end end @testset for eltya in (Float32, Float64, ComplexF32, ComplexF64, Int), herm in (false, true) @@ -133,4 +185,15 @@ end @test Base.propertynames(F, true) == (:Q, :H, :μ, :τ, :factors, :uplo) end +@testset "adjoint of Hessenberg" begin + Ar = randn(5, 5) + Ac = complex.(randn(5, 5), randn(5, 5)) + b = ones(size(Ar, 1)) + + for A in (Ar, Ac) + F = hessenberg(A) + @test A'\b ≈ F'\b + end +end + end # module TestHessenberg diff --git a/stdlib/LinearAlgebra/test/lapack.jl b/stdlib/LinearAlgebra/test/lapack.jl index e335fdc30ee31..6453f0f521092 100644 --- a/stdlib/LinearAlgebra/test/lapack.jl +++ b/stdlib/LinearAlgebra/test/lapack.jl @@ -407,10 +407,10 @@ end @testset for elty in (Float32, Float64) d = rand(elty,10) e = rand(elty,9) - @test_throws DimensionMismatch LAPACK.stev!('U',d,rand(elty,10)) + @test_throws DimensionMismatch LAPACK.stev!('U',d,rand(elty,11)) @test_throws DimensionMismatch LAPACK.stebz!('A','B',zero(elty),zero(elty),0,0,-1.,d,rand(elty,10)) @test_throws DimensionMismatch LAPACK.stegr!('N','A',d,rand(elty,11),zero(elty),zero(elty),0,0) - @test_throws DimensionMismatch LAPACK.stein!(d,zeros(elty,10),zeros(elty,10),zeros(BlasInt,10),zeros(BlasInt,10)) + @test_throws DimensionMismatch LAPACK.stein!(d,zeros(elty,11),zeros(elty,10),zeros(BlasInt,10),zeros(BlasInt,10)) @test_throws DimensionMismatch LAPACK.stein!(d,e,zeros(elty,11),zeros(BlasInt,10),zeros(BlasInt,10)) end end @@ -702,4 +702,7 @@ let A = [NaN NaN; NaN NaN] @test_throws ArgumentError eigen(A) end +# # https://github.com/JuliaLang/julia/pull/39845 +@test LinearAlgebra.LAPACK.liblapack == "libblastrampoline" + end # module TestLAPACK diff --git a/stdlib/LinearAlgebra/test/lq.jl b/stdlib/LinearAlgebra/test/lq.jl index 6e21b9ac6c1cc..b054621e11313 100644 --- a/stdlib/LinearAlgebra/test/lq.jl +++ b/stdlib/LinearAlgebra/test/lq.jl @@ -40,7 +40,7 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) lqa = lq(a) x = lqa\b l,q = lqa.L, lqa.Q - qra = qr(a, Val(true)) + qra = qr(a, ColumnNorm()) @testset "Basic ops" begin @test size(lqa,1) == size(a,1) @test size(lqa,3) == 1 @@ -56,9 +56,6 @@ rectangularQ(Q::LinearAlgebra.LQPackedQ) = convert(Array, Q) @test l*q ≈ a @test Array(lqa) ≈ a @test Array(copy(lqa)) ≈ a - lstring = sprint(show, l, context = :compact=>true) - qstring = sprint(show, q, context = :compact=>true) - @test sprint(show,MIME"text/plain"(),lqa) == "$(typeof(lqa)) with factors L and Q:\n$lstring\n$qstring" @test LinearAlgebra.Factorization{eltya}(lqa) === lqa @test Matrix{eltya}(q) isa Matrix{eltya} # test Array{T}(LQPackedQ{T}) @@ -203,4 +200,42 @@ end end end +@testset "REPL printing" begin + bf = IOBuffer() + show(bf, "text/plain", lq(Matrix(I, 4, 4))) + seekstart(bf) + @test String(take!(bf)) == """ +LinearAlgebra.LQ{Float64, Matrix{Float64}} +L factor: +4×4 Matrix{Float64}: + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0 +Q factor: +4×4 LinearAlgebra.LQPackedQ{Float64, Matrix{Float64}}: + 1.0 0.0 0.0 0.0 + 0.0 1.0 0.0 0.0 + 0.0 0.0 1.0 0.0 + 0.0 0.0 0.0 1.0""" +end + +@testset "adjoint of LQ" begin + n = 5 + + for b in (ones(n), ones(n, 2), ones(Complex{Float64}, n, 2)) + for A in ( + randn(n, n), + # Tall problems become least squares problems similarly to QR + randn(n - 2, n), + complex.(randn(n, n), randn(n, n))) + + F = lq(A) + @test A'\b ≈ F'\b + end + @test_throws DimensionMismatch lq(randn(n, n + 2))'\b + end + +end + end # module TestLQ diff --git a/stdlib/LinearAlgebra/test/lu.jl b/stdlib/LinearAlgebra/test/lu.jl index 8e6c06cdbd12e..6a1c34e511c2e 100644 --- a/stdlib/LinearAlgebra/test/lu.jl +++ b/stdlib/LinearAlgebra/test/lu.jl @@ -61,7 +61,7 @@ dimg = randn(n)/2 lua = factorize(a) @test_throws ErrorException lua.Z l,u,p = lua.L, lua.U, lua.p - ll,ul,pl = lu(a) + ll,ul,pl = @inferred lu(a) @test ll * ul ≈ a[pl,:] @test l*u ≈ a[p,:] @test (l*u)[invperm(p),:] ≈ a @@ -85,9 +85,9 @@ dimg = randn(n)/2 end κd = cond(Array(d),1) @testset "Tridiagonal LU" begin - lud = lu(d) + lud = @inferred lu(d) @test LinearAlgebra.issuccess(lud) - @test lu(lud) == lud + @test @inferred(lu(lud)) == lud @test_throws ErrorException lud.Z @test lud.L*lud.U ≈ lud.P*Array(d) @test lud.L*lud.U ≈ Array(d)[lud.p,:] @@ -199,14 +199,14 @@ dimg = randn(n)/2 @test lua.L*lua.U ≈ lua.P*a[:,1:n1] end @testset "Fat LU" begin - lua = lu(a[1:n1,:]) + lua = @inferred lu(a[1:n1,:]) @test lua.L*lua.U ≈ lua.P*a[1:n1,:] end end @testset "LU of Symmetric/Hermitian" begin for HS in (Hermitian(a'a), Symmetric(a'a)) - luhs = lu(HS) + luhs = @inferred lu(HS) @test luhs.L*luhs.U ≈ luhs.P*Matrix(HS) end end @@ -229,12 +229,12 @@ end @test_throws SingularException lu!(copy(A); check = true) @test !issuccess(lu(A; check = false)) @test !issuccess(lu!(copy(A); check = false)) - @test_throws ZeroPivotException lu(A, Val(false)) - @test_throws ZeroPivotException lu!(copy(A), Val(false)) - @test_throws ZeroPivotException lu(A, Val(false); check = true) - @test_throws ZeroPivotException lu!(copy(A), Val(false); check = true) - @test !issuccess(lu(A, Val(false); check = false)) - @test !issuccess(lu!(copy(A), Val(false); check = false)) + @test_throws ZeroPivotException lu(A, NoPivot()) + @test_throws ZeroPivotException lu!(copy(A), NoPivot()) + @test_throws ZeroPivotException lu(A, NoPivot(); check = true) + @test_throws ZeroPivotException lu!(copy(A), NoPivot(); check = true) + @test !issuccess(lu(A, NoPivot(); check = false)) + @test !issuccess(lu!(copy(A), NoPivot(); check = false)) F = lu(A; check = false) @test sprint((io, x) -> show(io, "text/plain", x), F) == "Failed factorization of type $(typeof(F))" @@ -320,7 +320,7 @@ include("trickyarithmetic.jl") @testset "lu with type whose sum is another type" begin A = TrickyArithmetic.A[1 2; 3 4] ElT = TrickyArithmetic.D{TrickyArithmetic.C,TrickyArithmetic.C} - B = lu(A, Val(false)) + B = lu(A, NoPivot()) @test B isa LinearAlgebra.LU{ElT,Matrix{ElT}} end diff --git a/stdlib/LinearAlgebra/test/qr.jl b/stdlib/LinearAlgebra/test/qr.jl index 394b371e02eac..dd5a0db40dd95 100644 --- a/stdlib/LinearAlgebra/test/qr.jl +++ b/stdlib/LinearAlgebra/test/qr.jl @@ -49,7 +49,6 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) a_1 = size(a, 1) @testset "QR decomposition (without pivoting)" begin qra = @inferred qr(a) - @inferred qr(a) q, r = qra.Q, qra.R @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @@ -78,8 +77,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "Thin QR decomposition (without pivoting)" begin - qra = @inferred qr(a[:, 1:n1], Val(false)) - @inferred qr(a[:, 1:n1], Val(false)) + qra = @inferred qr(a[:, 1:n1], NoPivot()) q,r = qra.Q, qra.R @test_throws ErrorException qra.Z @test q'*squareQ(q) ≈ Matrix(I, a_1, a_1) @@ -104,7 +102,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test Base.propertynames(qra) == (:R, :Q) end @testset "(Automatic) Fat (pivoted) QR decomposition" begin - @inferred qr(a, Val(true)) + @inferred qr(a, ColumnNorm()) qrpa = factorize(a[1:n1,:]) q,r = qrpa.Q, qrpa.R @@ -190,7 +188,7 @@ rectangularQ(Q::LinearAlgebra.AbstractQ) = convert(Array, Q) @test mul!(c, b, q') ≈ b*q' @test_throws DimensionMismatch mul!(Matrix{eltya}(I, n+1, n), q, b) - qra = qr(a[:,1:n1], Val(false)) + qra = qr(a[:,1:n1], NoPivot()) q, r = qra.Q, qra.R @test rmul!(copy(squareQ(q)'), q) ≈ Matrix(I, n, n) @test_throws DimensionMismatch rmul!(Matrix{eltya}(I, n+1, n+1),q) @@ -214,11 +212,8 @@ end @testset "transpose errors" begin @test_throws MethodError transpose(qr(randn(3,3))) - @test_throws MethodError adjoint(qr(randn(3,3))) - @test_throws MethodError transpose(qr(randn(3,3), Val(false))) - @test_throws MethodError adjoint(qr(randn(3,3), Val(false))) + @test_throws MethodError transpose(qr(randn(3,3), NoPivot())) @test_throws MethodError transpose(qr(big.(randn(3,3)))) - @test_throws MethodError adjoint(qr(big.(randn(3,3)))) end @testset "Issue 7304" begin @@ -256,7 +251,7 @@ end A = zeros(1, 2) B = zeros(1, 1) @test A \ B == zeros(2, 1) - @test qr(A, Val(true)) \ B == zeros(2, 1) + @test qr(A, ColumnNorm()) \ B == zeros(2, 1) end @testset "Issue 24107" begin @@ -278,7 +273,7 @@ end @test A \b ≈ ldiv!(c, qr(A ), b) @test b == b0 c0 = copy(c) - @test Ac\c ≈ ldiv!(b, qr(Ac, Val(true)), c) + @test Ac\c ≈ ldiv!(b, qr(Ac, ColumnNorm()), c) @test c0 == c end @@ -295,11 +290,11 @@ end @testset "det(Q::Union{QRCompactWYQ, QRPackedQ})" begin # 40 is the number larger than the default block size 36 of QRCompactWY - @testset for n in [1:3; 40], m in [1:3; 40], pivot in [false, true] + @testset for n in [1:3; 40], m in [1:3; 40], pivot in (NoPivot(), ColumnNorm()) @testset "real" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(n - k, m - k); dims=(1, 2)) - Q, = qr(A, Val(pivot)) + Q, = qr(A, pivot) @test det(Q) ≈ det(collect(Q)) @test abs(det(Q)) ≈ 1 end @@ -307,7 +302,7 @@ end @testset "complex" begin @testset for k in 0:min(n, m, 5) A = cat(Array(I(k)), randn(ComplexF64, n - k, m - k); dims=(1, 2)) - Q, = qr(A, Val(pivot)) + Q, = qr(A, pivot) @test det(Q) ≈ det(collect(Q)) @test abs(det(Q)) ≈ 1 end @@ -371,4 +366,45 @@ end end end +@testset "adjoint of QR" begin + n = 5 + B = randn(5, 2) + + @testset "size(b)=$(size(b))" for b in (B[:, 1], B) + @testset "size(A)=$(size(A))" for A in ( + randn(n, n), + # Wide problems become minimum norm (in x) problems similarly to LQ + randn(n + 2, n), + complex.(randn(n, n), randn(n, n))) + + @testset "QRCompactWY" begin + F = qr(A) + x = F'\b + @test x ≈ A'\b + @test length(size(x)) == length(size(b)) + end + + @testset "QR" begin + F = LinearAlgebra.qrfactUnblocked!(copy(A)) + x = F'\b + @test x ≈ A'\b + @test length(size(x)) == length(size(b)) + end + + @testset "QRPivoted" begin + F = LinearAlgebra.qr(A, ColumnNorm()) + x = F'\b + @test x ≈ A'\b + @test length(size(x)) == length(size(b)) + end + end + @test_throws DimensionMismatch("overdetermined systems are not supported") qr(randn(n - 2, n))'\b + @test_throws DimensionMismatch("arguments must have the same number of rows") qr(randn(n, n + 1))'\b + @test_throws DimensionMismatch("overdetermined systems are not supported") LinearAlgebra.qrfactUnblocked!(randn(n - 2, n))'\b + @test_throws DimensionMismatch("arguments must have the same number of rows") LinearAlgebra.qrfactUnblocked!(randn(n, n + 1))'\b + @test_throws DimensionMismatch("overdetermined systems are not supported") qr(randn(n - 2, n), ColumnNorm())'\b + @test_throws DimensionMismatch("arguments must have the same number of rows") qr(randn(n, n + 1), ColumnNorm())'\b + end +end + end # module TestQR diff --git a/stdlib/LinearAlgebra/test/schur.jl b/stdlib/LinearAlgebra/test/schur.jl index feb0ef8513b89..e8a4a619ae2c6 100644 --- a/stdlib/LinearAlgebra/test/schur.jl +++ b/stdlib/LinearAlgebra/test/schur.jl @@ -132,6 +132,43 @@ aimg = randn(n,n)/2 @test Z == A @test λ == zeros(0) end + @testset "0x0 $eltya matrices" begin + A = zeros(eltya, 0, 0) + B = zeros(eltya, 0, 0) + S = LinearAlgebra.schur(A, B) + @test S.S == A + @test S.T == A + @test S.Q == A + @test S.Z == A + @test S.alpha == zeros(0) + @test S.beta == zeros(0) + end +end + +@testset "Generalized Schur convergence" begin + # Check for convergence issues, #40279 + problematic_pencils = [ + ( ComplexF64[0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 3.7796350217469814 -3.3125635598133054 0.0 0.0 0.0 0.0 0.0 0.0 6.418270043493963 -6.625127119626611 0.0 0.0 0.0 0.0 0.0 -1.0; -3.312563559813306 3.779635021746982 0.0 0.0 0.0 0.0 0.0 0.0 -6.625127119626612 6.418270043493964 -1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 3.7796350217469814 0.0 0.0 -3.3125635598133054 0.0 0.0 0.0 -1.0 6.418270043493963 0.0 0.0 -6.625127119626611 0.0 0.0; 0.0 0.0 0.0 3.779635021746982 -3.312563559813306 0.0 0.0 0.0 0.0 0.0 0.0 6.418270043493964 -6.625127119626612 0.0 -1.0 0.0; 0.0 0.0 0.0 -3.3125635598133054 3.7796350217469814 0.0 0.0 0.0 0.0 0.0 0.0 -6.625127119626611 6.418270043493963 -1.0 0.0 0.0; 0.0 0.0 -3.312563559813306 0.0 0.0 3.779635021746982 0.0 0.0 0.0 0.0 -6.625127119626612 0.0 -1.0 6.418270043493964 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 3.7796350217469814 -3.3125635598133054 0.0 0.0 0.0 -1.0 0.0 0.0 6.418270043493963 -6.625127119626611; 0.0 0.0 0.0 0.0 0.0 0.0 -3.312563559813306 3.779635021746982 -1.0 0.0 0.0 0.0 0.0 0.0 -6.625127119626612 6.418270043493964], + ComplexF64[1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -3.7796350217469814 3.312563559813306 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.3125635598133054 -3.779635021746982 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -3.7796350217469814 0.0 0.0 3.312563559813306 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -3.779635021746982 3.3125635598133054 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.312563559813306 -3.7796350217469814 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.3125635598133054 0.0 0.0 -3.779635021746982 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -3.7796350217469814 3.312563559813306; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.3125635598133054 -3.779635021746982] + ), + ( ComplexF64[0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.62 -1.0 0.0 0.0 0.0 0.0 -1.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 -1.0 -2.62 0.0 0.0 0.0 0.0 0.0; 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0 0.0; 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62 0.0; 0.0 0.0 0.0 0.0 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0 -1.0 0.0 0.0 0.0 0.0 0.0 -2.62], + ComplexF64[1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0] + ), + ( ComplexF64[0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 0.33748484079831426 -0.10323794456968927 0.0 0.0 0.0 0.0 0.0 0.0 -2.5940303184033713 -0.20647588913937853 0.0 0.0 0.0 0.0 0.0 -1.0; -0.10323794456968927 0.3374848407983142 0.0 0.0 0.0 0.0 0.0 0.0 -0.20647588913937853 -2.5940303184033713 -1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.33748484079831426 0.0 0.0 -0.10323794456968927 0.0 0.0 0.0 -1.0 -2.5940303184033713 0.0 0.0 -0.20647588913937853 0.0 0.0; 0.0 0.0 0.0 0.3374848407983142 -0.10323794456968927 0.0 0.0 0.0 0.0 0.0 0.0 -2.5940303184033713 -0.20647588913937853 0.0 -1.0 0.0; 0.0 0.0 0.0 -0.10323794456968927 0.33748484079831426 0.0 0.0 0.0 0.0 0.0 0.0 -0.20647588913937853 -2.5940303184033713 -1.0 0.0 0.0; 0.0 0.0 -0.10323794456968927 0.0 0.0 0.3374848407983142 0.0 0.0 0.0 0.0 -0.20647588913937853 0.0 -1.0 -2.5940303184033713 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.33748484079831426 -0.10323794456968927 0.0 0.0 0.0 -1.0 0.0 0.0 -2.5940303184033713 -0.20647588913937853; 0.0 0.0 0.0 0.0 0.0 0.0 -0.10323794456968927 0.3374848407983142 -1.0 0.0 0.0 0.0 0.0 0.0 -0.20647588913937853 -2.5940303184033713], + ComplexF64[1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -0.33748484079831426 0.10323794456968927 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.10323794456968927 -0.3374848407983142 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -0.33748484079831426 0.0 0.0 0.10323794456968927 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -0.3374848407983142 0.10323794456968927 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.10323794456968927 -0.33748484079831426 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.10323794456968927 0.0 0.0 -0.3374848407983142 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -0.33748484079831426 0.10323794456968927; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.10323794456968927 -0.3374848407983142] + ), + ( ComplexF64[0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 1.7391668762048442 -1.309613611600033 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.150333752409688 -2.619227223200066 0.0 -1.0 0.0 0.0 0.0 0.0 0.0 0.0; -1.3096136116000332 1.739166876204844 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.6192272232000664 2.150333752409688 -1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.739166876204844 0.0 0.0 -1.3096136116000332 0.0 0.0 0.0 0.0 0.0 -1.0 2.150333752409688 0.0 0.0 -2.6192272232000664 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.739166876204844 0.0 0.0 0.0 0.0 -1.3096136116000332 0.0 -1.0 0.0 0.0 2.150333752409688 0.0 0.0 0.0 0.0 -2.6192272232000664 0.0; 0.0 0.0 0.0 0.0 1.7391668762048442 0.0 0.0 0.0 0.0 -1.309613611600033 0.0 0.0 0.0 0.0 2.150333752409688 -1.0 0.0 0.0 0.0 -2.619227223200066; 0.0 0.0 -1.309613611600033 0.0 0.0 1.7391668762048442 0.0 0.0 0.0 0.0 0.0 0.0 -2.619227223200066 0.0 -1.0 2.150333752409688 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.739166876204844 -1.3096136116000332 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.150333752409688 -2.6192272232000664 0.0 -1.0; 0.0 0.0 0.0 0.0 0.0 0.0 -1.309613611600033 1.7391668762048442 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.619227223200066 2.150333752409688 -1.0 0.0; 0.0 0.0 0.0 -1.309613611600033 0.0 0.0 0.0 0.0 1.7391668762048442 0.0 0.0 0.0 0.0 -2.619227223200066 0.0 0.0 0.0 -1.0 2.150333752409688 0.0; 0.0 0.0 0.0 0.0 -1.3096136116000332 0.0 0.0 0.0 0.0 1.739166876204844 0.0 0.0 0.0 0.0 -2.6192272232000664 0.0 -1.0 0.0 0.0 2.150333752409688], + ComplexF64[1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.7391668762048442 1.3096136116000332 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.309613611600033 -1.739166876204844 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.739166876204844 0.0 0.0 1.309613611600033 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.739166876204844 0.0 0.0 0.0 0.0 1.309613611600033 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.7391668762048442 0.0 0.0 0.0 0.0 1.3096136116000332; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.3096136116000332 0.0 0.0 -1.7391668762048442 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.739166876204844 1.309613611600033 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.3096136116000332 -1.7391668762048442 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.3096136116000332 0.0 0.0 0.0 0.0 -1.7391668762048442 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.309613611600033 0.0 0.0 0.0 0.0 -1.739166876204844] + ), + ( ComplexF64[0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0; 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230788 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007; 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769246 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230784 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769246 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230784 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.90076923076925 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -1.0000000000000007 -12.019230769230788; -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 -6.009615384615393 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384622 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769244 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615393 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384622 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769244 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.490384615384624 -1.0000000000000007 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -12.019230769230784 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 11.900769230769248], + ComplexF64[1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615393 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615393 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384622 0.0 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615392 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384622 0.0 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624 0.0; 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 6.009615384615394 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -6.490384615384624] + )] + + for (A, B) in problematic_pencils + f = schur(A, B) + @test f.Q*f.S*f.Z' ≈ A + @test f.Q*f.T*f.Z' ≈ B + end end end # module TestSchur diff --git a/stdlib/LinearAlgebra/test/special.jl b/stdlib/LinearAlgebra/test/special.jl index c23371f3d072e..48cb65e33eb74 100644 --- a/stdlib/LinearAlgebra/test/special.jl +++ b/stdlib/LinearAlgebra/test/special.jl @@ -192,10 +192,10 @@ end a = rand(n,n) atri = typ(a) b = rand(n,n) - qrb = qr(b,Val(true)) + qrb = qr(b, ColumnNorm()) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' - qrb = qr(b,Val(false)) + qrb = qr(b, NoPivot()) @test *(atri, adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' @test rmul!(copy(atri), adjoint(qrb.Q)) ≈ Matrix(atri) * qrb.Q' end diff --git a/stdlib/LinearAlgebra/test/structuredbroadcast.jl b/stdlib/LinearAlgebra/test/structuredbroadcast.jl index fea7fa08f0534..4aeca31a79a03 100644 --- a/stdlib/LinearAlgebra/test/structuredbroadcast.jl +++ b/stdlib/LinearAlgebra/test/structuredbroadcast.jl @@ -206,6 +206,33 @@ end end +struct Zero36193 end +Base.iszero(::Zero36193) = true +LinearAlgebra.iszerodefined(::Type{Zero36193}) = true +@testset "PR #36193" begin + f(::Union{Int, Zero36193}) = Zero36193() + function test(el) + M = [el el + el el] + v = [el, el] + U = UpperTriangular(M) + L = LowerTriangular(M) + D = Diagonal(v) + for (T, A) in [(UpperTriangular, U), (LowerTriangular, L), (Diagonal, D)] + @test identity.(A) isa typeof(A) + @test map(identity, A) isa typeof(A) + @test f.(A) isa T{Zero36193} + @test map(f, A) isa T{Zero36193} + end + end + # This should not need `zero(::Type{Zero36193})` to be defined + test(1) + Base.zero(::Type{Zero36193}) = Zero36193() + # This should not need `==(::Zero36193, ::Int)` to be defined as `iszerodefined` + # returns true. + test(Zero36193()) +end + # structured broadcast with function returning non-number type @test tuple.(Diagonal([1, 2])) == [(1,) (0,); (0,) (2,)] diff --git a/stdlib/LinearAlgebra/test/svd.jl b/stdlib/LinearAlgebra/test/svd.jl index 30dd6db300eb9..f02b8def49e82 100644 --- a/stdlib/LinearAlgebra/test/svd.jl +++ b/stdlib/LinearAlgebra/test/svd.jl @@ -217,4 +217,24 @@ end @test Uc * diagm(0=>Sc) * transpose(V) ≈ complex.(A) rtol=1e-3 end +@testset "adjoint of SVD" begin + n = 5 + B = randn(5, 2) + + @testset "size(b)=$(size(b))" for b in (B[:, 1], B) + @testset "size(A)=$(size(A))" for A in ( + randn(n, n), + # Wide problems become minimum norm (in x) problems similarly to LQ + randn(n + 2, n), + randn(n - 2, n), + complex.(randn(n, n), randn(n, n))) + + F = svd(A) + x = F'\b + @test x ≈ A'\b + @test length(size(x)) == length(size(b)) + end + end +end + end # module TestSVD diff --git a/stdlib/LinearAlgebra/test/symmetric.jl b/stdlib/LinearAlgebra/test/symmetric.jl index 7d99dd32889fd..93b91294cfecb 100644 --- a/stdlib/LinearAlgebra/test/symmetric.jl +++ b/stdlib/LinearAlgebra/test/symmetric.jl @@ -11,13 +11,19 @@ Random.seed!(1010) @test ishermitian(σ) end +@testset "Two-dimensional Euler formula for Hermitian" begin + @test cis(Hermitian([π 0; 0 π])) ≈ -I +end + @testset "Hermitian matrix exponential/log" begin A1 = randn(4,4) + im*randn(4,4) A2 = A1 + A1' @test exp(A2) ≈ exp(Hermitian(A2)) + @test cis(A2) ≈ cis(Hermitian(A2)) @test log(A2) ≈ log(Hermitian(A2)) A3 = A1 * A1' # posdef @test exp(A3) ≈ exp(Hermitian(A3)) + @test cis(A3) ≈ cis(Hermitian(A3)) @test log(A3) ≈ log(Hermitian(A3)) A1 = randn(4,4) @@ -727,4 +733,29 @@ end end end +@testset "Addition/subtraction with SymTridiagonal" begin + TR = SymTridiagonal(randn(Float64,5), randn(Float64,4)) + TC = SymTridiagonal(randn(ComplexF64,5), randn(ComplexF64,4)) + SR = Symmetric(randn(Float64,5,5)) + SC = Symmetric(randn(ComplexF64,5,5)) + HR = Hermitian(randn(Float64,5,5)) + HC = Hermitian(randn(ComplexF64,5,5)) + for op = (+,-) + for T = (TR, TC), S = (SR, SC) + @test op(T, S) == op(Array(T), S) + @test op(S, T) == op(S, Array(T)) + @test op(T, S) isa Symmetric + @test op(S, T) isa Symmetric + end + for H = (HR, HC) + for T = (TR, TC) + @test op(T, H) == op(Array(T), H) + @test op(H, T) == op(H, Array(T)) + end + @test op(TR, H) isa Hermitian + @test op(H, TR) isa Hermitian + end + end +end + end # module TestSymmetric diff --git a/stdlib/LinearAlgebra/test/tridiag.jl b/stdlib/LinearAlgebra/test/tridiag.jl index ec777bcd46222..d4137e3738206 100644 --- a/stdlib/LinearAlgebra/test/tridiag.jl +++ b/stdlib/LinearAlgebra/test/tridiag.jl @@ -589,7 +589,9 @@ end A2 = SymTridiagonal(fill(1.0, 3), fill(-1.0, 2)) F2 = eigen(A2) test_approx_eq_modphase(F.vectors, F2.vectors) - @test F.values ≈ F2.values + @test F.values ≈ F2.values ≈ eigvals(A) ≈ eigvals(A2) + @test eigvecs(A) ≈ eigvecs(A2) + @test eigvecs(A, eigvals(A)[1:1]) ≈ eigvecs(A2, eigvals(A2)[1:1]) end @testset "non-commutative algebra (#39701)" begin @@ -603,4 +605,16 @@ end end end +@testset "adjoint of LDLt" begin + Sr = SymTridiagonal(randn(5), randn(4)) + Sc = SymTridiagonal(complex.(randn(5)) .+ 1im, complex.(randn(4), randn(4))) + b = ones(size(Sr, 1)) + + F = ldlt(Sr) + @test F\b == F'\b + + F = ldlt(Sc) + @test copy(Sc')\b == F'\b +end + end # module TestTridiagonal diff --git a/stdlib/LinearAlgebra/test/uniformscaling.jl b/stdlib/LinearAlgebra/test/uniformscaling.jl index 27f6641657e81..8c69308d06ce8 100644 --- a/stdlib/LinearAlgebra/test/uniformscaling.jl +++ b/stdlib/LinearAlgebra/test/uniformscaling.jl @@ -7,6 +7,8 @@ using Test, LinearAlgebra, Random, SparseArrays const BASE_TEST_PATH = joinpath(Sys.BINDIR, "..", "share", "julia", "test") isdefined(Main, :Quaternions) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "Quaternions.jl")) using .Main.Quaternions +isdefined(Main, :OffsetArrays) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "OffsetArrays.jl")) +using .Main.OffsetArrays Random.seed!(123) @@ -452,6 +454,17 @@ end target = J * A * alpha + C * beta @test mul!(copy(C), J, A, alpha, beta) ≈ target @test mul!(copy(C), A, J, alpha, beta) ≈ target + + a = randn() + C = randn(3, 3) + target_5mul = a*alpha*J + beta*C + @test mul!(copy(C), a, J, alpha, beta) ≈ target_5mul + @test mul!(copy(C), J, a, alpha, beta) ≈ target_5mul + target_5mul = beta*C # alpha = 0 + @test mul!(copy(C), a, J, 0, beta) ≈ target_5mul + target_5mul = a*alpha*Matrix(J, 3, 3) # beta = 0 + @test mul!(copy(C), a, J, alpha, 0) ≈ target_5mul + end @testset "Construct Diagonal from UniformScaling" begin @@ -460,6 +473,20 @@ end @test I(3) == [1 0 0; 0 1 0; 0 0 1] end +@testset "dot" begin + A = randn(3, 3) + λ = randn() + J = UniformScaling(λ) + @test dot(A, J) ≈ dot(J, A) + @test dot(A, J) ≈ tr(A' * J) + + A = rand(ComplexF64, 3, 3) + λ = randn() + im * randn() + J = UniformScaling(λ) + @test dot(A, J) ≈ conj(dot(J, A)) + @test dot(A, J) ≈ tr(A' * J) +end + @testset "generalized dot" begin x = rand(-10:10, 3) y = rand(-10:10, 3) @@ -473,7 +500,7 @@ end @testset "Factorization solutions" begin J = complex(randn(),randn()) * I - qrp = A -> qr(A, Val(true)) + qrp = A -> qr(A, ColumnNorm()) # thin matrices X = randn(3,2) @@ -504,4 +531,20 @@ end end end +@testset "offset arrays" begin + A = OffsetArray(zeros(4,4), -1:2, 0:3) + @test sum(I + A) ≈ 3.0 + @test sum(A + I) ≈ 3.0 + @test sum(I - A) ≈ 3.0 + @test sum(A - I) ≈ -3.0 +end + +@testset "type promotion when dividing UniformScaling by matrix" begin + A = randn(5,5) + cA = complex(A) + J = (5+2im)*I + @test J/A ≈ J/cA + @test A\J ≈ cA\J +end + end # module TestUniformscaling diff --git a/stdlib/Logging/src/ConsoleLogger.jl b/stdlib/Logging/src/ConsoleLogger.jl index 2a96b08eb5ed2..04c56c6dbfaae 100644 --- a/stdlib/Logging/src/ConsoleLogger.jl +++ b/stdlib/Logging/src/ConsoleLogger.jl @@ -1,7 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license """ - ConsoleLogger(stream=stderr, min_level=Info; meta_formatter=default_metafmt, + ConsoleLogger([stream,] min_level=Info; meta_formatter=default_metafmt, show_limited=true, right_justify=0) Logger with formatting optimized for readability in a text console, for example @@ -30,12 +30,19 @@ struct ConsoleLogger <: AbstractLogger right_justify::Int message_limits::Dict{Any,Int} end -function ConsoleLogger(stream::IO=stderr, min_level=Info; +function ConsoleLogger(stream::IO, min_level=Info; meta_formatter=default_metafmt, show_limited=true, right_justify=0) ConsoleLogger(stream, min_level, meta_formatter, show_limited, right_justify, Dict{Any,Int}()) end +function ConsoleLogger(min_level=Info; + meta_formatter=default_metafmt, show_limited=true, + right_justify=0) + ConsoleLogger(closed_stream, min_level, meta_formatter, + show_limited, right_justify, Dict{Any,Int}()) +end + shouldlog(logger::ConsoleLogger, level, _module, group, id) = get(logger.message_limits, id, 1) > 0 @@ -110,12 +117,16 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module # Generate a text representation of the message and all key value pairs, # split into lines. msglines = [(indent=0, msg=l) for l in split(chomp(string(message)::String), '\n')] - dsize = displaysize(logger.stream)::Tuple{Int,Int} + stream = logger.stream + if !isopen(stream) + stream = level < Warn ? stdout : stderr + end + dsize = displaysize(stream)::Tuple{Int,Int} nkwargs = length(kwargs)::Int if nkwargs > hasmaxlog valbuf = IOBuffer() rows_per_value = max(1, dsize[1] ÷ (nkwargs + 1 - hasmaxlog)) - valio = IOContext(IOContext(valbuf, logger.stream), + valio = IOContext(IOContext(valbuf, stream), :displaysize => (rows_per_value, dsize[2] - 5), :limit => logger.show_limited) for (key, val) in kwargs @@ -136,7 +147,7 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module color, prefix, suffix = logger.meta_formatter(level, _module, group, id, filepath, line)::Tuple{Union{Symbol,Int},String,String} minsuffixpad = 2 buf = IOBuffer() - iob = IOContext(buf, logger.stream) + iob = IOContext(buf, stream) nonpadwidth = 2 + (isempty(prefix) || length(msglines) > 1 ? 0 : length(prefix)+1) + msglines[end].indent + termlength(msglines[end].msg) + (isempty(suffix) ? 0 : length(suffix)+minsuffixpad) @@ -164,6 +175,6 @@ function handle_message(logger::ConsoleLogger, level::LogLevel, message, _module println(iob) end - write(logger.stream, take!(buf)) + write(stream, take!(buf)) nothing end diff --git a/stdlib/Logging/src/Logging.jl b/stdlib/Logging/src/Logging.jl index b44b8ae67473c..a9d86d9bd4418 100644 --- a/stdlib/Logging/src/Logging.jl +++ b/stdlib/Logging/src/Logging.jl @@ -29,6 +29,9 @@ for sym in [ @eval const $sym = Base.CoreLogging.$sym end +using Base.CoreLogging: + closed_stream + export AbstractLogger, LogLevel, @@ -56,7 +59,7 @@ include("ConsoleLogger.jl") # handle_message, shouldlog, min_enabled_level, catch_exceptions, function __init__() - global_logger(ConsoleLogger(stderr)) + global_logger(ConsoleLogger()) end end diff --git a/stdlib/Makefile b/stdlib/Makefile index 718c18842f086..38c8c45ac8975 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -16,7 +16,7 @@ $(build_datarootdir)/julia/stdlib/$(VERSDIR): mkdir -p $@ JLLS = DSFMT GMP CURL LIBGIT2 LLVM LIBSSH2 LIBUV MBEDTLS MPFR NGHTTP2 \ - BLASTRAMPOLINE OPENBLAS OPENLIBM P7ZIP PCRE SUITESPARSE ZLIB \ + BLASTRAMPOLINE OPENBLAS OPENLIBM P7ZIP PCRE LIBSUITESPARSE ZLIB \ LLVMUNWIND CSL UNWIND # Initialize this with JLLs that aren't in deps/Versions.make @@ -44,7 +44,7 @@ STDLIBS = Artifacts Base64 CRC32c Dates DelimitedFiles Distributed FileWatching SharedArrays Sockets SparseArrays SuiteSparse Test TOML Unicode UUIDs \ $(JLL_NAMES) -STDLIBS_EXT = Pkg Statistics LibCURL Downloads ArgTools Tar NetworkOptions +STDLIBS_EXT = Pkg Statistics LibCURL Downloads ArgTools Tar NetworkOptions SuiteSparse PKG_GIT_URL := git://github.com/JuliaLang/Pkg.jl.git PKG_TAR_URL = https://api.github.com/repos/JuliaLang/Pkg.jl/tarball/$1 STATISTICS_GIT_URL := git://github.com/JuliaLang/Statistics.jl.git @@ -59,6 +59,8 @@ TAR_GIT_URL := git://github.com/JuliaIO/Tar.jl.git TAR_TAR_URL = https://api.github.com/repos/JuliaIO/Tar.jl/tarball/$1 NETWORKOPTIONS_GIT_URL := git://github.com/JuliaLang/NetworkOptions.jl.git NETWORKOPTIONS_TAR_URL = https://api.github.com/repos/JuliaLang/NetworkOptions.jl/tarball/$1 +SUITESPARSE_GIT_URL := git://github.com/JuliaLang/SuiteSparse.jl.git +SUITESPARSE_TAR_URL = https://api.github.com/repos/JuliaLang/SuiteSparse.jl/tarball/$1 $(foreach module, $(STDLIBS_EXT), $(eval $(call stdlib-external,$(module),$(shell echo $(module) | tr a-z A-Z)))) @@ -68,10 +70,12 @@ $(foreach module, $(STDLIBS), $(eval $(call symlink_target,$$(JULIAHOME)/stdlib/ STDLIBS_LINK_TARGETS := $(addprefix $(build_datarootdir)/julia/stdlib/$(VERSDIR)/,$(STDLIBS)) getall get: $(addprefix get-, $(STDLIBS_EXT) $(JLL_NAMES)) -install: $(addprefix install-, $(STDLIBS_EXT) $(JLL_NAMES)) $(STDLIBS_LINK_TARGETS) +install: version-check $(addprefix install-, $(STDLIBS_EXT) $(JLL_NAMES)) $(STDLIBS_LINK_TARGETS) +version-check: $(addprefix version-check-, $(STDLIBS_EXT)) +uninstall: $(addprefix uninstall-, $(STDLIBS_EXT)) clean: $(addprefix clean-, $(STDLIBS_EXT)) $(CLEAN_TARGETS) distclean: $(addprefix distclean-, $(STDLIBS_EXT)) clean checksumall: $(addprefix checksum-, $(STDLIBS_EXT)) -DEP_LIBS_STAGED := $(STDLIBS_EXT) +DEP_LIBS_STAGED_ALL := $(STDLIBS_EXT) include $(JULIAHOME)/deps/tools/uninstallers.mk diff --git a/stdlib/Markdown/src/render/terminal/formatting.jl b/stdlib/Markdown/src/render/terminal/formatting.jl index 4fd1cccedf7fb..87022124b9c8a 100644 --- a/stdlib/Markdown/src/render/terminal/formatting.jl +++ b/stdlib/Markdown/src/render/terminal/formatting.jl @@ -9,8 +9,9 @@ end words(s) = split(s, " ") lines(s) = split(s, "\n") -function wrapped_lines!(lines, io::IO, s::AbstractString, width, i) +function wrapped_line(io::IO, s::AbstractString, width, i) ws = words(s) + lines = String[] for word in ws word_length = ansi_length(word) word_length == 0 && continue @@ -22,19 +23,16 @@ function wrapped_lines!(lines, io::IO, s::AbstractString, width, i) lines[end] *= " " * word # this could be more efficient end end - return i + return i, lines end function wrapped_lines(io::IO, s::AbstractString; width = 80, i = 0) - lines = AbstractString[] - if occursin(r"\n", s) - for ss in split(s, "\n") - i = wrapped_lines!(lines, io, ss, width, i) - end - else - wrapped_lines!(lines, io, s, width, i) + ls = String[] + for ss in lines(s) + i, line = wrapped_line(io, ss, width, i) + append!(ls, line) end - return lines + return ls end wrapped_lines(io::IO, f::Function, args...; width = 80, i = 0) = @@ -42,6 +40,7 @@ wrapped_lines(io::IO, f::Function, args...; width = 80, i = 0) = function print_wrapped(io::IO, s...; width = 80, pre = "", i = 0) lines = wrapped_lines(io, s..., width = width, i = i) + isempty(lines) && return 0, 0 print(io, lines[1]) for line in lines[2:end] print(io, '\n', pre, line) diff --git a/stdlib/Markdown/test/runtests.jl b/stdlib/Markdown/test/runtests.jl index 286004707b8bd..f90eefb85310e 100644 --- a/stdlib/Markdown/test/runtests.jl +++ b/stdlib/Markdown/test/runtests.jl @@ -1213,3 +1213,20 @@ end | $x | """) end + +@testset "issue 40080: empty list item breaks display()" begin + d = TextDisplay(devnull) + display(d, md""" + 1. hello + 2. + """) +end + +@testset "issue #37232: linebreaks" begin + s = @md_str """ + Misc:\\ + - line\\ + """ + @test sprint(show, MIME("text/plain"), s) == " Misc:\n - line" +end + diff --git a/stdlib/Mmap/src/Mmap.jl b/stdlib/Mmap/src/Mmap.jl index 9a9d795a5aa17..6919421b92277 100644 --- a/stdlib/Mmap/src/Mmap.jl +++ b/stdlib/Mmap/src/Mmap.jl @@ -13,7 +13,7 @@ const PAGESIZE = Int(Sys.isunix() ? ccall(:jl_getpagesize, Clong, ()) : ccall(:j # for mmaps not backed by files mutable struct Anonymous <: IO - name::AbstractString + name::String readonly::Bool create::Bool end diff --git a/stdlib/OpenBLAS_jll/Project.toml b/stdlib/OpenBLAS_jll/Project.toml index e732272c12e09..b236ed0809eec 100644 --- a/stdlib/OpenBLAS_jll/Project.toml +++ b/stdlib/OpenBLAS_jll/Project.toml @@ -1,6 +1,6 @@ name = "OpenBLAS_jll" uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" -version = "0.3.13+3" +version = "0.3.13+5" [deps] CompilerSupportLibraries_jll = "e66e0078-7015-5450-92f7-15fbd957f2ae" diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 5d9153eefe853..75362ccf79bd0 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,2 +1,2 @@ PKG_BRANCH = master -PKG_SHA1 = af7e41cd9d9529bfc8e8fecd7e24c7392c73cdbc +PKG_SHA1 = 6cf6b95e051d8ecde0424ff8bac022fee197c690 diff --git a/stdlib/Printf/docs/src/index.md b/stdlib/Printf/docs/src/index.md index 828e527ed0cad..48e38e2b2ce5b 100644 --- a/stdlib/Printf/docs/src/index.md +++ b/stdlib/Printf/docs/src/index.md @@ -1,4 +1,4 @@ -# Printf +# [Printf](@id man-printf) ```@docs Printf.@printf diff --git a/stdlib/Printf/src/Printf.jl b/stdlib/Printf/src/Printf.jl index ac57f95ec6bb9..5f42df50b80de 100644 --- a/stdlib/Printf/src/Printf.jl +++ b/stdlib/Printf/src/Printf.jl @@ -421,11 +421,30 @@ const __BIG_FLOAT_MAX__ = 8192 elseif T == Val{'f'} || T == Val{'F'} newpos = Ryu.writefixed(buf, pos, x, prec, plus, space, hash, UInt8('.')) elseif T == Val{'g'} || T == Val{'G'} + # C11-compliant general format prec = prec == 0 ? 1 : prec - x = round(x, sigdigits=prec) - newpos = Ryu.writeshortest(buf, pos, x, plus, space, hash, prec, T == Val{'g'} ? UInt8('e') : UInt8('E'), true, UInt8('.')) + # format the value in scientific notation and parse the exponent part + exp = let p = Ryu.writeexp(buf, pos, x, prec) + b1, b2, b3, b4 = buf[p-4], buf[p-3], buf[p-2], buf[p-1] + Z = UInt8('0') + if b1 == UInt8('e') + # two-digit exponent + sign = b2 == UInt8('+') ? 1 : -1 + exp = 10 * (b3 - Z) + (b4 - Z) + else + # three-digit exponent + sign = b1 == UInt8('+') ? 1 : -1 + exp = 100 * (b2 - Z) + 10 * (b3 - Z) + (b4 - Z) + end + flipsign(exp, sign) + end + if -4 ≤ exp < prec + newpos = Ryu.writefixed(buf, pos, x, prec - (exp + 1), plus, space, hash, UInt8('.'), !hash) + else + newpos = Ryu.writeexp(buf, pos, x, prec - 1, plus, space, hash, T == Val{'g'} ? UInt8('e') : UInt8('E'), UInt8('.'), !hash) + end elseif T == Val{'a'} || T == Val{'A'} - x, neg = x < 0 ? (-x, true) : (x, false) + x, neg = x < 0 || x === -Base.zero(x) ? (-x, true) : (x, false) newpos = pos if neg buf[newpos] = UInt8('-') @@ -456,6 +475,8 @@ const __BIG_FLOAT_MAX__ = 8192 buf[newpos] = UInt8('0') newpos += 1 if prec > 0 + buf[newpos] = UInt8('.') + newpos += 1 while prec > 0 buf[newpos] = UInt8('0') newpos += 1 @@ -465,6 +486,7 @@ const __BIG_FLOAT_MAX__ = 8192 buf[newpos] = T <: Val{'a'} ? UInt8('p') : UInt8('P') buf[newpos + 1] = UInt8('+') buf[newpos + 2] = UInt8('0') + newpos += 3 else if prec > -1 s, p = frexp(x) @@ -547,7 +569,7 @@ const __BIG_FLOAT_MAX__ = 8192 end # pointers -fmt(buf, pos, arg, spec::Spec{Pointer}) = fmt(buf, pos, Int(arg), ptrfmt(spec, arg)) +fmt(buf, pos, arg, spec::Spec{Pointer}) = fmt(buf, pos, UInt64(arg), ptrfmt(spec, arg)) # old Printf compat function fix_dec end @@ -821,7 +843,7 @@ Use shorter of decimal or scientific 1.23 1.23e+07 ``` For a systematic specification of the format, see [here](https://www.cplusplus.com/reference/cstdio/printf/). -See also: [`@sprintf`](@ref). +See also [`@sprintf`](@ref). # Caveats `Inf` and `NaN` are printed consistently as `Inf` and `NaN` for flags `%a`, `%A`, diff --git a/stdlib/Printf/test/runtests.jl b/stdlib/Printf/test/runtests.jl index d38c90734d4f1..212a74da2b4c6 100644 --- a/stdlib/Printf/test/runtests.jl +++ b/stdlib/Printf/test/runtests.jl @@ -19,11 +19,17 @@ using Test, Printf @test (@sprintf "%-20p" C_NULL) == "0x00000000 " end + #40318 + @test @sprintf("%p", 0xfffffffffffe0000) == "0xfffffffffffe0000" + end @testset "%a" begin # hex float + @test (Printf.@sprintf "%a" 0.0) == "0x0p+0" + @test (Printf.@sprintf "%a" -0.0) == "-0x0p+0" + @test (Printf.@sprintf "%.3a" 0.0) == "0x0.000p+0" @test (Printf.@sprintf "%a" 1.5) == "0x1.8p+0" @test (Printf.@sprintf "%a" 1.5f0) == "0x1.8p+0" @test (Printf.@sprintf "%a" big"1.5") == "0x1.8p+0" @@ -104,9 +110,9 @@ end @test (Printf.@sprintf "%f" -Inf) == "-Inf" @test (Printf.@sprintf "%+f" -Inf) == "-Inf" @test (Printf.@sprintf "%f" NaN) == "NaN" - @test (Printf.@sprintf "%+f" NaN) == "NaN" - @test (Printf.@sprintf "% f" NaN) == "NaN" - @test (Printf.@sprintf "% #f" NaN) == "NaN" + @test (Printf.@sprintf "%+f" NaN) == "+NaN" + @test (Printf.@sprintf "% f" NaN) == " NaN" + @test (Printf.@sprintf "% #f" NaN) == " NaN" @test (Printf.@sprintf "%e" big"Inf") == "Inf" @test (Printf.@sprintf "%e" big"NaN") == "NaN" @@ -141,6 +147,10 @@ end @test Printf.@sprintf("%+ 09.1f", 1.234) == "+000001.2" @test Printf.@sprintf("%+ 09.0f", 1.234) == "+00000001" @test Printf.@sprintf("%+ #09.0f", 1.234) == "+0000001." + + #40303 + @test Printf.@sprintf("%+7.1f", 9.96) == " +10.0" + @test Printf.@sprintf("% 7.1f", 9.96) == " 10.0" end @testset "%e" begin @@ -153,9 +163,9 @@ end @test (Printf.@sprintf "%e" -Inf) == "-Inf" @test (Printf.@sprintf "%+e" -Inf) == "-Inf" @test (Printf.@sprintf "%e" NaN) == "NaN" - @test (Printf.@sprintf "%+e" NaN) == "NaN" - @test (Printf.@sprintf "% e" NaN) == "NaN" - @test (Printf.@sprintf "% #e" NaN) == "NaN" + @test (Printf.@sprintf "%+e" NaN) == "+NaN" + @test (Printf.@sprintf "% e" NaN) == " NaN" + @test (Printf.@sprintf "% #e" NaN) == " NaN" @test (Printf.@sprintf "%e" big"Inf") == "Inf" @test (Printf.@sprintf "%e" big"NaN") == "NaN" @@ -202,6 +212,10 @@ end @test Printf.@sprintf("%+ 09.1e", 1.234) == "+01.2e+00" @test Printf.@sprintf("%+ 09.0e", 1.234) == "+0001e+00" @test Printf.@sprintf("%+ #09.0e", 1.234) == "+001.e+00" + + #40303 + @test Printf.@sprintf("%+9.1e", 9.96) == " +1.0e+01" + @test Printf.@sprintf("% 9.1e", 9.96) == " 1.0e+01" end @testset "strings" begin @@ -435,6 +449,14 @@ end @test Printf.@sprintf("%e", 1) == "1.000000e+00" @test Printf.@sprintf("%g", 1) == "1" + # issue #39748 + @test Printf.@sprintf("%.16g", 194.4778127560983) == "194.4778127560983" + @test Printf.@sprintf("%.17g", 194.4778127560983) == "194.4778127560983" + @test Printf.@sprintf("%.18g", 194.4778127560983) == "194.477812756098302" + @test Printf.@sprintf("%.1g", 1.7976931348623157e308) == "2e+308" + @test Printf.@sprintf("%.2g", 1.7976931348623157e308) == "1.8e+308" + @test Printf.@sprintf("%.3g", 1.7976931348623157e308) == "1.8e+308" + # escaped '%' @test_throws ArgumentError @sprintf("%s%%%s", "a") @test @sprintf("%s%%%s", "a", "b") == "a%b" diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 718cd02e6eb98..9a6160c960fe3 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -182,7 +182,7 @@ function beep(s::PromptState, duration::Real=options(s).beep_duration, isinteractive() || return # some tests fail on some platforms s.beeping = min(s.beeping + duration, maxduration) let colors = Base.copymutable(colors) - @async begin + errormonitor(@async begin trylock(s.refresh_lock) || return try orig_prefix = s.p.prompt_prefix @@ -198,12 +198,10 @@ function beep(s::PromptState, duration::Real=options(s).beep_duration, s.p.prompt_prefix = orig_prefix refresh_multi_line(s, beeping=true) s.beeping = 0.0 - catch e - Base.showerror(stdout, e, catch_backtrace()) finally unlock(s.refresh_lock) end - end + end) end nothing end @@ -788,23 +786,32 @@ function edit_insert(s::PromptState, c::StringLike) after = options(s).auto_refresh_time_delay termbuf = terminal(s) w = width(termbuf) - delayup = !eof(buf) || old_wait offset = s.ias.curs_row == 1 || s.indent < 0 ? sizeof(prompt_string(s.p.prompt)::String) : s.indent offset += position(buf) - beginofline(buf) # size of current line - if offset + textwidth(str) <= w + spinner = '\0' + delayup = !eof(buf) || old_wait + if offset + textwidth(str) <= w && !(after == 0 && delayup) # Avoid full update when appending characters to the end # and an update of curs_row isn't necessary (conservatively estimated) write(termbuf, str) + spinner = ' ' # temporarily clear under the cursor elseif after == 0 refresh_line(s) delayup = false - else + else # render a spinner for each key press + if old_wait || length(str) != 1 + spinner = spin_seq[mod1(position(buf) - w, length(spin_seq))] + else + spinner = str[end] + end delayup = true end if delayup - write(termbuf, spin_seq[mod1(position(buf) - w, length(spin_seq))]) - cmove_left(termbuf) + if spinner != '\0' + write(termbuf, spinner) + cmove_left(termbuf) + end s.refresh_wait = Timer(after) do t s.refresh_wait === t || return s.refresh_wait = nothing diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 68f157322facc..54053f2066c71 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -29,8 +29,7 @@ import Base: display, show, AnyDict, - ==, - catch_stack + == _displaysize(io::IO) = displaysize(io)::Tuple{Int,Int} @@ -76,6 +75,9 @@ end answer_color(::AbstractREPL) = "" const JULIA_PROMPT = "julia> " +const PKG_PROMPT = "pkg> " +const SHELL_PROMPT = "shell> " +const HELP_PROMPT = "help?> " mutable struct REPLBackend "channel for AST" @@ -123,6 +125,12 @@ const softscope! = softscope const repl_ast_transforms = Any[softscope] # defaults for new REPL backends +# Allows an external package to add hooks into the code loading. +# The hook should take a Vector{Symbol} of package names and +# return true if all packages could be installed, false if not +# to e.g. install packages on demand +const install_packages_hooks = Any[] + function eval_user_input(@nospecialize(ast), backend::REPLBackend) lasterr = nothing Base.sigatomic_begin() @@ -133,6 +141,9 @@ function eval_user_input(@nospecialize(ast), backend::REPLBackend) put!(backend.response_channel, Pair{Any, Bool}(lasterr, true)) else backend.in_eval = true + if !isempty(install_packages_hooks) + check_for_missing_packages_and_run_hooks(ast) + end for xf in backend.ast_transforms ast = Base.invokelatest(xf, ast) end @@ -148,13 +159,42 @@ function eval_user_input(@nospecialize(ast), backend::REPLBackend) println("SYSTEM ERROR: Failed to report error to REPL frontend") println(err) end - lasterr = catch_stack() + lasterr = current_exceptions() end end Base.sigatomic_end() nothing end +function check_for_missing_packages_and_run_hooks(ast) + mods = modules_to_be_loaded(ast) + filter!(mod -> isnothing(Base.identify_package(String(mod))), mods) # keep missing modules + if !isempty(mods) + for f in install_packages_hooks + Base.invokelatest(f, mods) && return + end + end +end + +function modules_to_be_loaded(ast, mods = Symbol[]) + if ast.head in [:using, :import] + for arg in ast.args + if first(arg.args) isa Symbol # i.e. `Foo` + if first(arg.args) != :. # don't include local imports + push!(mods, first(arg.args)) + end + else # i.e. `Foo: bar` + push!(mods, first(first(arg.args).args)) + end + end + end + for arg in ast.args + arg isa Expr && modules_to_be_loaded(arg, mods) + end + return mods +end +modules_to_be_loaded(::Nothing) = Symbol[] # comments are parsed as nothing + """ start_repl_backend(repl_channel::Channel, response_channel::Channel) @@ -260,7 +300,7 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool, println(errio) # an error during printing is likely to leave us mid-line println(errio, "SYSTEM (REPL): showing an error caused an error") try - Base.invokelatest(Base.display_error, errio, catch_stack()) + Base.invokelatest(Base.display_error, errio, current_exceptions()) catch e # at this point, only print the name of the type as a Symbol to # minimize the possibility of further errors. @@ -270,7 +310,7 @@ function print_response(errio::IO, response, show_value::Bool, have_color::Bool, end break end - val = catch_stack() + val = current_exceptions() iserr = true end end @@ -313,10 +353,12 @@ function run_repl(repl::AbstractREPL, @nospecialize(consumer = x -> nothing); ba end if backend_on_current_task t = @async run_frontend(repl, backend_ref) + errormonitor(t) Base._wait2(t, cleanup) start_repl_backend(backend, consumer) else t = @async start_repl_backend(backend, consumer) + errormonitor(t) Base._wait2(t, cleanup) run_frontend(repl, backend_ref) end @@ -792,7 +834,7 @@ function respond(f, repl, main; pass_empty::Bool = false, suppress_on_semicolon: ast = Base.invokelatest(f, line) response = eval_with_backend(ast, backend(repl)) catch - response = Pair{Any, Bool}(catch_stack(), true) + response = Pair{Any, Bool}(current_exceptions(), true) end hide_output = suppress_on_semicolon && ends_with_semicolon(line) print_response(repl, response, !hide_output, hascolor(repl)) @@ -895,7 +937,7 @@ function setup_interface( on_enter = return_callback) # Setup help mode - help_mode = Prompt("help?> ", + help_mode = Prompt(HELP_PROMPT, prompt_prefix = hascolor ? repl.help_color : "", prompt_suffix = hascolor ? (repl.envcolors ? Base.input_color : repl.input_color) : "", @@ -907,7 +949,7 @@ function setup_interface( # Set up shell mode - shell_mode = Prompt("shell> "; + shell_mode = Prompt(SHELL_PROMPT; prompt_prefix = hascolor ? repl.shell_color : "", prompt_suffix = hascolor ? (repl.envcolors ? Base.input_color : repl.input_color) : "", @@ -944,7 +986,7 @@ function setup_interface( hist_from_file(hp, hist_path) catch # use REPL.hascolor to avoid using the local variable with the same name - print_response(repl, Pair{Any, Bool}(catch_stack(), true), true, REPL.hascolor(repl)) + print_response(repl, Pair{Any, Bool}(current_exceptions(), true), true, REPL.hascolor(repl)) println(outstream(repl)) @info "Disabling history file for this session" repl.history_file = false @@ -961,6 +1003,12 @@ function setup_interface( search_prompt, skeymap = LineEdit.setup_search_keymap(hp) search_prompt.complete = LatexCompletions() + jl_prompt_len = length(JULIA_PROMPT) + pkg_prompt_len = length(PKG_PROMPT) + shell_prompt_len = length(SHELL_PROMPT) + help_prompt_len = length(HELP_PROMPT) + pkg_prompt_regex = r"^(?:\(.+\) )?pkg> " + # Canonicalize user keymap input if isa(extra_repl_keymap, Dict) extra_repl_keymap = AnyDict[extra_repl_keymap] @@ -1013,12 +1061,15 @@ function setup_interface( oldpos = firstindex(input) firstline = true isprompt_paste = false - jl_prompt_len = 7 # "julia> " + curr_prompt_len = 0 + pasting_help = false + while oldpos <= lastindex(input) # loop until all lines have been executed if JL_PROMPT_PASTE[] - # Check if the next statement starts with "julia> ", in that case - # skip it. But first skip whitespace - while input[oldpos] in ('\n', ' ', '\t') + # Check if the next statement starts with a prompt i.e. "julia> ", in that case + # skip it. But first skip whitespace unless pasting in a docstring which may have + # indented prompt examples that we don't want to execute + while input[oldpos] in (pasting_help ? ('\n') : ('\n', ' ', '\t')) oldpos = nextind(input, oldpos) oldpos >= sizeof(input) && return end @@ -1026,7 +1077,32 @@ function setup_interface( if (firstline || isprompt_paste) && startswith(SubString(input, oldpos), JULIA_PROMPT) isprompt_paste = true oldpos += jl_prompt_len - # If we are prompt pasting and current statement does not begin with julia> , skip to next line + curr_prompt_len = jl_prompt_len + transition(s, julia_prompt) + pasting_help = false + # Check if input line starts with "pkg> " or "(...) pkg> ", remove it if we are in prompt paste mode and switch mode + elseif (firstline || isprompt_paste) && startswith(SubString(input, oldpos), pkg_prompt_regex) + detected_pkg_prompt = match(pkg_prompt_regex, SubString(input, oldpos)).match + isprompt_paste = true + curr_prompt_len = sizeof(detected_pkg_prompt) + oldpos += curr_prompt_len + Base.active_repl.interface.modes[1].keymap_dict[']'](s, o...) + pasting_help = false + # Check if input line starts with "shell> ", remove it if we are in prompt paste mode and switch mode + elseif (firstline || isprompt_paste) && startswith(SubString(input, oldpos), SHELL_PROMPT) + isprompt_paste = true + oldpos += shell_prompt_len + curr_prompt_len = shell_prompt_len + transition(s, shell_mode) + pasting_help = false + # Check if input line starts with "help?> ", remove it if we are in prompt paste mode and switch mode + elseif (firstline || isprompt_paste) && startswith(SubString(input, oldpos), HELP_PROMPT) + isprompt_paste = true + oldpos += help_prompt_len + curr_prompt_len = help_prompt_len + transition(s, help_mode) + pasting_help = true + # If we are prompt pasting and current statement does not begin with a mode prefix, skip to next line elseif isprompt_paste while input[oldpos] != '\n' oldpos = nextind(input, oldpos) @@ -1035,11 +1111,35 @@ function setup_interface( continue end end - ast, pos = Meta.parse(input, oldpos, raise=false, depwarn=false) - if (isa(ast, Expr) && (ast.head === :error || ast.head === :incomplete)) || - (pos > ncodeunits(input) && !endswith(input, '\n')) - # remaining text is incomplete (an error, or parser ran to the end but didn't stop with a newline): - # Insert all the remaining text as one line (might be empty) + dump_tail = false + nl_pos = findfirst('\n', input[oldpos:end]) + if s.current_mode == julia_prompt + ast, pos = Meta.parse(input, oldpos, raise=false, depwarn=false) + if (isa(ast, Expr) && (ast.head === :error || ast.head === :incomplete)) || + (pos > ncodeunits(input) && !endswith(input, '\n')) + # remaining text is incomplete (an error, or parser ran to the end but didn't stop with a newline): + # Insert all the remaining text as one line (might be empty) + dump_tail = true + end + elseif isnothing(nl_pos) # no newline at end, so just dump the tail into the prompt and don't execute + dump_tail = true + elseif s.current_mode == shell_mode # handle multiline shell commands + lines = split(input[oldpos:end], '\n') + pos = oldpos + sizeof(lines[1]) + 1 + if length(lines) > 1 + for line in lines[2:end] + # to be recognized as a multiline shell command, the lines must be indented to the + # same prompt position + if !startswith(line, ' '^curr_prompt_len) + break + end + pos += sizeof(line) + 1 + end + end + else + pos = oldpos + nl_pos + end + if dump_tail tail = input[oldpos:end] if !firstline # strip leading whitespace, but only if it was the result of executing something @@ -1047,7 +1147,7 @@ function setup_interface( tail = lstrip(tail) end if isprompt_paste # remove indentation spaces corresponding to the prompt - tail = replace(tail, r"^"m * ' '^jl_prompt_len => "") + tail = replace(tail, r"^"m * ' '^curr_prompt_len => "") end LineEdit.replace_line(s, tail, true) LineEdit.refresh_line(s) @@ -1057,7 +1157,7 @@ function setup_interface( line = strip(input[oldpos:prevind(input, pos)]) if !isempty(line) if isprompt_paste # remove indentation spaces corresponding to the prompt - line = replace(line, r"^"m * ' '^jl_prompt_len => "") + line = replace(line, r"^"m * ' '^curr_prompt_len => "") end # put the line on the screen and history LineEdit.replace_line(s, line) diff --git a/stdlib/REPL/src/REPLCompletions.jl b/stdlib/REPL/src/REPLCompletions.jl index fa5fd8434bec7..44b3e6a3a4158 100644 --- a/stdlib/REPL/src/REPLCompletions.jl +++ b/stdlib/REPL/src/REPLCompletions.jl @@ -384,16 +384,27 @@ function get_value(sym::Expr, fn) end get_value(sym::Symbol, fn) = isdefined(fn, sym) ? (getfield(fn, sym), true) : (nothing, false) get_value(sym::QuoteNode, fn) = isdefined(fn, sym.value) ? (getfield(fn, sym.value), true) : (nothing, false) +get_value(sym::GlobalRef, fn) = get_value(sym.name, sym.mod) get_value(sym, fn) = (sym, true) -# Return the value of a getfield call expression -function get_value_getfield(ex::Expr, fn) - # Example :((top(getfield))(Base,:max)) - val, found = get_value_getfield(ex.args[2],fn) #Look up Base in Main and returns the module - (found && length(ex.args) >= 3) || return (nothing, false) - return get_value_getfield(ex.args[3], val) #Look up max in Base and returns the function if found. +# Return the type of a getfield call expression +function get_type_getfield(ex::Expr, fn::Module) + length(ex.args) == 3 || return Any, false # should never happen, but just for safety + obj, x = ex.args[2:3] + objt, found = get_type(obj, fn) + objt isa DataType || return Any, false + found || return Any, false + if x isa QuoteNode + fld = x.value + elseif isexpr(x, :quote) || isexpr(x, :inert) + fld = x.args[1] + else + fld = nothing # we don't know how to get the value of variable `x` here + end + fld isa Symbol || return Any, false + hasfield(objt, fld) || return Any, false + return fieldtype(objt, fld), true end -get_value_getfield(sym, fn) = get_value(sym, fn) # Determines the return type with Base.return_types of a function call using the type information of the arguments. function get_type_call(expr::Expr) @@ -423,7 +434,7 @@ function get_type_call(expr::Expr) return (return_type, true) end -# Returns the return type. example: get_type(:(Base.strip("", ' ')), Main) returns (String, true) +# Returns the return type. example: get_type(:(Base.strip("", ' ')), Main) returns (SubString{String}, true) function try_get_type(sym::Expr, fn::Module) val, found = get_value(sym, fn) found && return Core.Typeof(val), found @@ -431,10 +442,8 @@ function try_get_type(sym::Expr, fn::Module) # getfield call is special cased as the evaluation of getfield provides good type information, # is inexpensive and it is also performed in the complete_symbol function. a1 = sym.args[1] - if isa(a1,GlobalRef) && isconst(a1.mod,a1.name) && isdefined(a1.mod,a1.name) && - eval(a1) === Core.getfield - val, found = get_value_getfield(sym, Main) - return found ? Core.Typeof(val) : Any, found + if a1 === :getfield || a1 === GlobalRef(Core, :getfield) + return get_type_getfield(sym, fn) end return get_type_call(sym) elseif sym.head === :thunk @@ -456,6 +465,11 @@ function get_type(sym::Expr, fn::Module) # try to analyze nests of calls. if this fails, try using the expanded form. val, found = try_get_type(sym, fn) found && return val, found + # https://github.com/JuliaLang/julia/issues/27184 + if isexpr(sym, :macrocall) + _, found = get_type(first(sym.args), fn) + found || return Any, false + end return try_get_type(Meta.lower(fn, sym), fn) end @@ -811,4 +825,18 @@ function shell_completions(string, pos) return Completion[], 0:-1, false end +function UndefVarError_hint(io::IO, ex::UndefVarError) + var = ex.var + if var === :or + print("\nsuggestion: Use `||` for short-circuiting boolean OR.") + elseif var === :and + print("\nsuggestion: Use `&&` for short-circuiting boolean AND.") + end +end + +function __init__() + Base.Experimental.register_error_hint(UndefVarError_hint, UndefVarError) + nothing +end + end # module diff --git a/stdlib/REPL/src/TerminalMenus/AbstractMenu.jl b/stdlib/REPL/src/TerminalMenus/AbstractMenu.jl index f01df5c389324..ee5bd4d426795 100644 --- a/stdlib/REPL/src/TerminalMenus/AbstractMenu.jl +++ b/stdlib/REPL/src/TerminalMenus/AbstractMenu.jl @@ -203,9 +203,9 @@ function request(term::REPL.Terminals.TTYTerminal, m::AbstractMenu; cursor::Unio lastoption = numoptions(m) c = readkey(term.in_stream) - if c == Int(ARROW_UP) + if c == Int(ARROW_UP) || c == Int('k') cursor[] = move_up!(m, cursor[], lastoption) - elseif c == Int(ARROW_DOWN) + elseif c == Int(ARROW_DOWN) || c == Int('j') cursor[] = move_down!(m, cursor[], lastoption) elseif c == Int(PAGE_UP) cursor[] = page_up!(m, cursor[], lastoption) @@ -217,7 +217,7 @@ function request(term::REPL.Terminals.TTYTerminal, m::AbstractMenu; cursor::Unio elseif c == Int(END_KEY) cursor[] = lastoption m.pageoffset = lastoption - m.pagesize - elseif c == 13 # + elseif c == 13 || c == Int(' ') # or # will break if pick returns true pick(m, cursor[]) && break elseif c == UInt32('q') diff --git a/stdlib/REPL/src/TerminalMenus/Pager.jl b/stdlib/REPL/src/TerminalMenus/Pager.jl new file mode 100644 index 0000000000000..af49c3aa63440 --- /dev/null +++ b/stdlib/REPL/src/TerminalMenus/Pager.jl @@ -0,0 +1,40 @@ +mutable struct Pager{C} <: _ConfiguredMenu{C} + lines::Vector{String} + pagesize::Int + pageoffset::Int + selected::Nothing + config::C +end + +function Pager(text::AbstractString; pagesize::Int=10, kwargs...) + lines = readlines(IOBuffer(text)) + return Pager(lines, pagesize, 0, nothing, Config(; kwargs...)) +end + +function header(p::Pager) + total = length(p.lines) + current = min(p.pageoffset + p.pagesize, total) + percent = round(Int, (current / total) * 100) + return "($(lpad(current, ndigits(total))) / $total) $(lpad(percent, 3))%" +end + +options(p::Pager) = p.lines + +cancel(::Pager) = nothing + +pick(::Pager, ::Int) = true + +function writeline(buf::IOBuffer, pager::Pager{Config}, idx::Int, iscursor::Bool) + print(buf, pager.lines[idx]) +end + +function pager(terminal, object) + lines, columns = displaysize(terminal)::Tuple{Int,Int} + columns -= 3 + buffer = IOBuffer() + ctx = IOContext(buffer, :color => REPL.Terminals.hascolor(terminal), :displaysize => (lines, columns)) + show(ctx, "text/plain", object) + pager = Pager(String(take!(buffer)); pagesize = div(lines, 2)) + return request(terminal, pager) +end +pager(object) = pager(terminal, object) diff --git a/stdlib/REPL/src/TerminalMenus/TerminalMenus.jl b/stdlib/REPL/src/TerminalMenus/TerminalMenus.jl index d9d3dc8598f7d..87869e84d9838 100644 --- a/stdlib/REPL/src/TerminalMenus/TerminalMenus.jl +++ b/stdlib/REPL/src/TerminalMenus/TerminalMenus.jl @@ -17,10 +17,12 @@ include("config.jl") include("AbstractMenu.jl") include("RadioMenu.jl") include("MultiSelectMenu.jl") +include("Pager.jl") export RadioMenu, MultiSelectMenu, + Pager, request # TODO: remove in Julia 2.0 diff --git a/stdlib/REPL/src/docview.jl b/stdlib/REPL/src/docview.jl index 9f36cadd0b868..2ff223beff4b2 100644 --- a/stdlib/REPL/src/docview.jl +++ b/stdlib/REPL/src/docview.jl @@ -224,7 +224,7 @@ function lookup_doc(ex) op = str[1:end-1] eq = isdotted ? ".=" : "=" return Markdown.parse("`x $op= y` is a synonym for `x $eq x $op y`") - elseif isdotted + elseif isdotted && ex !== :(..) op = str[2:end] return Markdown.parse("`x $ex y` is akin to `broadcast($op, x, y)`. See [`broadcast`](@ref).") end @@ -243,10 +243,12 @@ end function summarize(binding::Binding, sig) io = IOBuffer() - println(io, "No documentation found.\n") if defined(binding) - summarize(io, resolve(binding), binding) + binding_res = resolve(binding) + !isa(binding_res, Module) && println(io, "No documentation found.\n") + summarize(io, binding_res, binding) else + println(io, "No documentation found.\n") quot = any(isspace, sprint(print, binding)) ? "'" : "" println(io, "Binding ", quot, "`", binding, "`", quot, " does not exist.") end @@ -270,14 +272,14 @@ function summarize(io::IO, TT::Type, binding::Binding) if T isa DataType println(io, "```") print(io, - T.abstract ? "abstract type " : - T.mutable ? "mutable struct " : + T.name.abstract ? "abstract type " : + T.name.mutable ? "mutable struct " : Base.isstructtype(T) ? "struct " : "primitive type ") supert = supertype(T) println(io, T) println(io, "```") - if !T.abstract && T.name !== Tuple.name && !isempty(fieldnames(T)) + if !T.name.abstract && T.name !== Tuple.name && !isempty(fieldnames(T)) println(io, "# Fields") println(io, "```") pad = maximum(length(string(f)) for f in fieldnames(T)) @@ -291,7 +293,7 @@ function summarize(io::IO, TT::Type, binding::Binding) println(io, "# Subtypes") println(io, "```") for t in subt - println(io, t) + println(io, Base.unwrap_unionall(t)) end println(io, "```") end @@ -313,16 +315,46 @@ function summarize(io::IO, TT::Type, binding::Binding) end end -function summarize(io::IO, m::Module, binding::Binding) - println(io, "No docstring found for module `", m, "`.\n") +function find_readme(m::Module)::Union{String, Nothing} + mpath = pathof(m) + isnothing(mpath) && return nothing + !isfile(mpath) && return nothing # modules in sysimage, where src files are omitted + path = dirname(mpath) + top_path = pkgdir(m) + while true + for file in readdir(path; join=true, sort=true) + isfile(file) && (basename(lowercase(file)) in ["readme.md", "readme"]) || continue + return file + end + path == top_path && break # go no further than pkgdir + path = dirname(path) # work up through nested modules + end + return nothing +end +function summarize(io::IO, m::Module, binding::Binding; nlines::Int = 200) + readme_path = find_readme(m) + if isnothing(readme_path) + println(io, "No docstring or readme file found for module `$m`.\n") + else + println(io, "No docstring found for module `$m`.") + end exports = filter!(!=(nameof(m)), names(m)) if isempty(exports) println(io, "Module does not export any names.") else - println(io, "# Exported names:") + println(io, "# Exported names") print(io, " `") join(io, exports, "`, `") - println(io, "`") + println(io, "`\n") + end + if !isnothing(readme_path) + readme_lines = readlines(readme_path) + isempty(readme_lines) && return # don't say we are going to print empty file + println(io, "# Displaying contents of readme found at `$(readme_path)`") + for line in first(readme_lines, nlines) + println(io, line) + end + length(readme_lines) > nlines && println(io, "\n[output truncated to first $nlines lines]") end end @@ -550,8 +582,10 @@ function matchinds(needle, haystack; acronym::Bool = false) is = Int[] lastc = '\0' for (i, char) in enumerate(haystack) + while !isempty(chars) && isspace(first(chars)) + popfirst!(chars) # skip spaces + end isempty(chars) && break - while chars[1] == ' ' popfirst!(chars) end # skip spaces if lowercase(char) == lowercase(chars[1]) && (!acronym || !isletter(lastc)) push!(is, i) diff --git a/stdlib/REPL/src/emoji_symbols.jl b/stdlib/REPL/src/emoji_symbols.jl index 40f943cf246dd..49a55c97f6564 100644 --- a/stdlib/REPL/src/emoji_symbols.jl +++ b/stdlib/REPL/src/emoji_symbols.jl @@ -1,21 +1,37 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -#= +#== +using Pkg: @pkg_str +pkg"activate --temp" +pkg"add JSON@0.21" + import JSON -emojis = JSON.parsefile(download("https://raw.githubusercontent.com/iamcal/emoji-data/0f0cf4ea8845eb52d26df2a48c3c31c3b8cad14e/emoji_pretty.json")) -result = Dict() -for emj in emojis - name = "\\:" * emj["short_name"] * ":" - unicode = emj["unified"] - if '-' in unicode - continue +function emoji_data(url) + emojis = JSON.parsefile(download(url)) + result = Dict() + for emj in emojis + name = "\\:" * emj["short_name"] * ":" + unicode = emj["unified"] + if '-' in unicode + continue + end + result[name] = "$(Char(parse(UInt32, unicode, base = 16)))" end - result[name] = "$(Char(parse(UInt32, unicode, base = 16)))" + return result end -skeys = sort(collect(keys(result))) +# We combine multiple versions as the data changes, and not only by growing. +result = mapfoldr(emoji_data, merge, [ + # Newer versions must be added to the bottom list as we want the newer versions to + # overwrite the old with names that changed but still keep old ones that were removed + "https://raw.githubusercontent.com/iamcal/emoji-data/0f0cf4ea8845eb52d26df2a48c3c31c3b8cad14e/emoji_pretty.json", + "https://raw.githubusercontent.com/iamcal/emoji-data/e512953312c012f6bd00e3f2ef6bf152ca3710f8/emoji_pretty.json", + ]; + init=Dict() +) +skeys = sort(collect(keys(result))) open("emoji_symbols.jl", "w") do fh println(fh, "const emoji_symbols = Dict(") for key in skeys @@ -34,14 +50,22 @@ const emoji_symbols = Dict( "\\:8ball:" => "🎱", "\\:a:" => "🅰", "\\:ab:" => "🆎", + "\\:abacus:" => "🧮", "\\:abc:" => "🔤", "\\:abcd:" => "🔡", "\\:accept:" => "🉑", + "\\:accordion:" => "🪗", + "\\:adhesive_bandage:" => "🩹", + "\\:adult:" => "🧑", "\\:aerial_tramway:" => "🚡", "\\:airplane:" => "✈", + "\\:airplane_arriving:" => "🛬", + "\\:airplane_departure:" => "🛫", "\\:alarm_clock:" => "⏰", "\\:alien:" => "👽", "\\:ambulance:" => "🚑", + "\\:amphora:" => "🏺", + "\\:anatomical_heart:" => "🫀", "\\:anchor:" => "⚓", "\\:angel:" => "👼", "\\:anger:" => "💢", @@ -76,40 +100,59 @@ const emoji_symbols = Dict( "\\:astonished:" => "😲", "\\:athletic_shoe:" => "👟", "\\:atm:" => "🏧", + "\\:auto_rickshaw:" => "🛺", + "\\:avocado:" => "🥑", + "\\:axe:" => "🪓", "\\:b:" => "🅱", "\\:baby:" => "👶", "\\:baby_bottle:" => "🍼", "\\:baby_chick:" => "🐤", "\\:baby_symbol:" => "🚼", "\\:back:" => "🔙", + "\\:bacon:" => "🥓", + "\\:badger:" => "🦡", + "\\:badminton_racquet_and_shuttlecock:" => "🏸", + "\\:bagel:" => "🥯", "\\:baggage_claim:" => "🛄", + "\\:baguette_bread:" => "🥖", + "\\:ballet_shoes:" => "🩰", "\\:balloon:" => "🎈", "\\:ballot_box_with_check:" => "☑", "\\:bamboo:" => "🎍", "\\:banana:" => "🍌", "\\:bangbang:" => "‼", + "\\:banjo:" => "🪕", "\\:bank:" => "🏦", "\\:bar_chart:" => "📊", "\\:barber:" => "💈", "\\:baseball:" => "⚾", + "\\:basket:" => "🧺", "\\:basketball:" => "🏀", + "\\:bat:" => "🦇", "\\:bath:" => "🛀", "\\:bathtub:" => "🛁", "\\:battery:" => "🔋", "\\:bear:" => "🐻", + "\\:bearded_person:" => "🧔", + "\\:beaver:" => "🦫", "\\:bee:" => "🐝", "\\:beer:" => "🍺", "\\:beers:" => "🍻", - "\\:beetle:" => "🐞", + "\\:beetle:" => "🪲", "\\:beginner:" => "🔰", "\\:bell:" => "🔔", + "\\:bell_pepper:" => "🫑", "\\:bento:" => "🍱", + "\\:beverage_box:" => "🧃", "\\:bicyclist:" => "🚴", "\\:bike:" => "🚲", "\\:bikini:" => "👙", + "\\:billed_cap:" => "🧢", "\\:bird:" => "🐦", "\\:birthday:" => "🎂", + "\\:bison:" => "🦬", "\\:black_circle:" => "⚫", + "\\:black_heart:" => "🖤", "\\:black_joker:" => "🃏", "\\:black_large_square:" => "⬛", "\\:black_medium_small_square:" => "◾", @@ -122,59 +165,88 @@ const emoji_symbols = Dict( "\\:blue_book:" => "📘", "\\:blue_car:" => "🚙", "\\:blue_heart:" => "💙", + "\\:blueberries:" => "🫐", "\\:blush:" => "😊", "\\:boar:" => "🐗", "\\:boat:" => "⛵", "\\:bomb:" => "💣", + "\\:bone:" => "🦴", "\\:book:" => "📖", "\\:bookmark:" => "🔖", "\\:bookmark_tabs:" => "📑", "\\:books:" => "📚", "\\:boom:" => "💥", + "\\:boomerang:" => "🪃", "\\:boot:" => "👢", "\\:bouquet:" => "💐", "\\:bow:" => "🙇", + "\\:bow_and_arrow:" => "🏹", + "\\:bowl_with_spoon:" => "🥣", "\\:bowling:" => "🎳", + "\\:boxing_glove:" => "🥊", "\\:boy:" => "👦", + "\\:brain:" => "🧠", "\\:bread:" => "🍞", + "\\:breast-feeding:" => "🤱", + "\\:bricks:" => "🧱", "\\:bride_with_veil:" => "👰", "\\:bridge_at_night:" => "🌉", "\\:briefcase:" => "💼", + "\\:briefs:" => "🩲", + "\\:broccoli:" => "🥦", "\\:broken_heart:" => "💔", + "\\:broom:" => "🧹", + "\\:brown_heart:" => "🤎", + "\\:bubble_tea:" => "🧋", + "\\:bucket:" => "🪣", "\\:bug:" => "🐛", "\\:bulb:" => "💡", "\\:bullettrain_front:" => "🚅", "\\:bullettrain_side:" => "🚄", + "\\:burrito:" => "🌯", "\\:bus:" => "🚌", "\\:busstop:" => "🚏", "\\:bust_in_silhouette:" => "👤", "\\:busts_in_silhouette:" => "👥", + "\\:butter:" => "🧈", + "\\:butterfly:" => "🦋", "\\:cactus:" => "🌵", "\\:cake:" => "🍰", "\\:calendar:" => "📆", + "\\:call_me_hand:" => "🤙", "\\:calling:" => "📲", "\\:camel:" => "🐫", "\\:camera:" => "📷", + "\\:camera_with_flash:" => "📸", "\\:cancer:" => "♋", "\\:candy:" => "🍬", + "\\:canned_food:" => "🥫", + "\\:canoe:" => "🛶", "\\:capital_abcd:" => "🔠", "\\:capricorn:" => "♑", "\\:car:" => "🚗", "\\:card_index:" => "📇", "\\:carousel_horse:" => "🎠", + "\\:carpentry_saw:" => "🪚", + "\\:carrot:" => "🥕", "\\:cat2:" => "🐈", "\\:cat:" => "🐱", "\\:cd:" => "💿", + "\\:chair:" => "🪑", + "\\:champagne:" => "🍾", "\\:chart:" => "💹", "\\:chart_with_downwards_trend:" => "📉", "\\:chart_with_upwards_trend:" => "📈", "\\:checkered_flag:" => "🏁", + "\\:cheese_wedge:" => "🧀", "\\:cherries:" => "🍒", "\\:cherry_blossom:" => "🌸", "\\:chestnut:" => "🌰", "\\:chicken:" => "🐔", + "\\:child:" => "🧒", "\\:children_crossing:" => "🚸", "\\:chocolate_bar:" => "🍫", + "\\:chopsticks:" => "🥢", "\\:christmas_tree:" => "🎄", "\\:church:" => "⛪", "\\:cinema:" => "🎦", @@ -184,6 +256,7 @@ const emoji_symbols = Dict( "\\:cl:" => "🆑", "\\:clap:" => "👏", "\\:clapper:" => "🎬", + "\\:clinking_glasses:" => "🥂", "\\:clipboard:" => "📋", "\\:clock1030:" => "🕥", "\\:clock10:" => "🕙", @@ -213,10 +286,17 @@ const emoji_symbols = Dict( "\\:closed_lock_with_key:" => "🔐", "\\:closed_umbrella:" => "🌂", "\\:cloud:" => "☁", + "\\:clown_face:" => "🤡", "\\:clubs:" => "♣", + "\\:coat:" => "🧥", + "\\:cockroach:" => "🪳", "\\:cocktail:" => "🍸", + "\\:coconut:" => "🥥", "\\:coffee:" => "☕", + "\\:coin:" => "🪙", + "\\:cold_face:" => "🥶", "\\:cold_sweat:" => "😰", + "\\:compass:" => "🧭", "\\:computer:" => "💻", "\\:confetti_ball:" => "🎊", "\\:confounded:" => "😖", @@ -235,20 +315,30 @@ const emoji_symbols = Dict( "\\:couplekiss:" => "💏", "\\:cow2:" => "🐄", "\\:cow:" => "🐮", + "\\:crab:" => "🦀", "\\:credit_card:" => "💳", "\\:crescent_moon:" => "🌙", + "\\:cricket:" => "🦗", + "\\:cricket_bat_and_ball:" => "🏏", "\\:crocodile:" => "🐊", + "\\:croissant:" => "🥐", + "\\:crossed_fingers:" => "🤞", "\\:crossed_flags:" => "🎌", "\\:crown:" => "👑", "\\:cry:" => "😢", "\\:crying_cat_face:" => "😿", "\\:crystal_ball:" => "🔮", + "\\:cucumber:" => "🥒", + "\\:cup_with_straw:" => "🥤", + "\\:cupcake:" => "🧁", "\\:cupid:" => "💘", + "\\:curling_stone:" => "🥌", "\\:curly_loop:" => "➰", "\\:currency_exchange:" => "💱", "\\:curry:" => "🍛", "\\:custard:" => "🍮", "\\:customs:" => "🛃", + "\\:cut_of_meat:" => "🥩", "\\:cyclone:" => "🌀", "\\:dancer:" => "💃", "\\:dancers:" => "👯", @@ -256,15 +346,22 @@ const emoji_symbols = Dict( "\\:dart:" => "🎯", "\\:dash:" => "💨", "\\:date:" => "📅", + "\\:deaf_person:" => "🧏", "\\:deciduous_tree:" => "🌳", + "\\:deer:" => "🦌", "\\:department_store:" => "🏬", "\\:diamond_shape_with_a_dot_inside:" => "💠", "\\:diamonds:" => "♦", "\\:disappointed:" => "😞", "\\:disappointed_relieved:" => "😥", + "\\:disguised_face:" => "🥸", + "\\:diving_mask:" => "🤿", + "\\:diya_lamp:" => "🪔", "\\:dizzy:" => "💫", "\\:dizzy_face:" => "😵", + "\\:dna:" => "🧬", "\\:do_not_litter:" => "🚯", + "\\:dodo:" => "🦤", "\\:dog2:" => "🐕", "\\:dog:" => "🐶", "\\:dollar:" => "💵", @@ -276,20 +373,29 @@ const emoji_symbols = Dict( "\\:dragon_face:" => "🐲", "\\:dress:" => "👗", "\\:dromedary_camel:" => "🐪", + "\\:drooling_face:" => "🤤", + "\\:drop_of_blood:" => "🩸", "\\:droplet:" => "💧", + "\\:drum_with_drumsticks:" => "🥁", + "\\:duck:" => "🦆", + "\\:dumpling:" => "🥟", "\\:dvd:" => "📀", "\\:e-mail:" => "📧", + "\\:eagle:" => "🦅", "\\:ear:" => "👂", "\\:ear_of_rice:" => "🌾", + "\\:ear_with_hearing_aid:" => "🦻", "\\:earth_africa:" => "🌍", "\\:earth_americas:" => "🌎", "\\:earth_asia:" => "🌏", - "\\:egg:" => "🍳", + "\\:egg:" => "🥚", "\\:eggplant:" => "🍆", "\\:eight_pointed_black_star:" => "✴", "\\:eight_spoked_asterisk:" => "✳", "\\:electric_plug:" => "🔌", "\\:elephant:" => "🐘", + "\\:elevator:" => "🛗", + "\\:elf:" => "🧝", "\\:email:" => "✉", "\\:end:" => "🔚", "\\:envelope_with_arrow:" => "📩", @@ -298,22 +404,41 @@ const emoji_symbols = Dict( "\\:european_post_office:" => "🏤", "\\:evergreen_tree:" => "🌲", "\\:exclamation:" => "❗", + "\\:exploding_head:" => "🤯", "\\:expressionless:" => "😑", "\\:eyeglasses:" => "👓", "\\:eyes:" => "👀", + "\\:face_palm:" => "🤦", + "\\:face_vomiting:" => "🤮", + "\\:face_with_cowboy_hat:" => "🤠", + "\\:face_with_hand_over_mouth:" => "🤭", + "\\:face_with_head_bandage:" => "🤕", + "\\:face_with_monocle:" => "🧐", + "\\:face_with_raised_eyebrow:" => "🤨", + "\\:face_with_rolling_eyes:" => "🙄", + "\\:face_with_symbols_on_mouth:" => "🤬", + "\\:face_with_thermometer:" => "🤒", "\\:facepunch:" => "👊", "\\:factory:" => "🏭", + "\\:fairy:" => "🧚", + "\\:falafel:" => "🧆", "\\:fallen_leaf:" => "🍂", "\\:family:" => "👪", "\\:fast_forward:" => "⏩", "\\:fax:" => "📠", "\\:fearful:" => "😨", + "\\:feather:" => "🪶", "\\:feet:" => "🐾", + "\\:fencer:" => "🤺", "\\:ferris_wheel:" => "🎡", + "\\:field_hockey_stick_and_ball:" => "🏑", "\\:file_folder:" => "📁", "\\:fire:" => "🔥", "\\:fire_engine:" => "🚒", + "\\:fire_extinguisher:" => "🧯", + "\\:firecracker:" => "🧨", "\\:fireworks:" => "🎆", + "\\:first_place_medal:" => "🥇", "\\:first_quarter_moon:" => "🌓", "\\:first_quarter_moon_with_face:" => "🌛", "\\:fish:" => "🐟", @@ -321,17 +446,27 @@ const emoji_symbols = Dict( "\\:fishing_pole_and_fish:" => "🎣", "\\:fist:" => "✊", "\\:flags:" => "🎏", + "\\:flamingo:" => "🦩", "\\:flashlight:" => "🔦", + "\\:flatbread:" => "🫓", "\\:floppy_disk:" => "💾", "\\:flower_playing_cards:" => "🎴", "\\:flushed:" => "😳", + "\\:fly:" => "🪰", + "\\:flying_disc:" => "🥏", + "\\:flying_saucer:" => "🛸", "\\:foggy:" => "🌁", + "\\:fondue:" => "🫕", + "\\:foot:" => "🦶", "\\:football:" => "🏈", "\\:footprints:" => "👣", "\\:fork_and_knife:" => "🍴", + "\\:fortune_cookie:" => "🥠", "\\:fountain:" => "⛲", "\\:four_leaf_clover:" => "🍀", + "\\:fox_face:" => "🦊", "\\:free:" => "🆓", + "\\:fried_egg:" => "🍳", "\\:fried_shrimp:" => "🍤", "\\:fries:" => "🍟", "\\:frog:" => "🐸", @@ -340,25 +475,35 @@ const emoji_symbols = Dict( "\\:full_moon:" => "🌕", "\\:full_moon_with_face:" => "🌝", "\\:game_die:" => "🎲", + "\\:garlic:" => "🧄", "\\:gem:" => "💎", "\\:gemini:" => "♊", + "\\:genie:" => "🧞", "\\:ghost:" => "👻", "\\:gift:" => "🎁", "\\:gift_heart:" => "💝", + "\\:giraffe_face:" => "🦒", "\\:girl:" => "👧", + "\\:glass_of_milk:" => "🥛", "\\:globe_with_meridians:" => "🌐", + "\\:gloves:" => "🧤", + "\\:goal_net:" => "🥅", "\\:goat:" => "🐐", + "\\:goggles:" => "🥽", "\\:golf:" => "⛳", + "\\:gorilla:" => "🦍", "\\:grapes:" => "🍇", "\\:green_apple:" => "🍏", "\\:green_book:" => "📗", "\\:green_heart:" => "💚", + "\\:green_salad:" => "🥗", "\\:grey_exclamation:" => "❕", "\\:grey_question:" => "❔", "\\:grimacing:" => "😬", "\\:grin:" => "😁", "\\:grinning:" => "😀", "\\:guardsman:" => "💂", + "\\:guide_dog:" => "🦮", "\\:guitar:" => "🎸", "\\:gun:" => "🔫", "\\:haircut:" => "💇", @@ -367,10 +512,13 @@ const emoji_symbols = Dict( "\\:hamster:" => "🐹", "\\:hand:" => "✋", "\\:handbag:" => "👜", + "\\:handball:" => "🤾", + "\\:handshake:" => "🤝", "\\:hankey:" => "💩", "\\:hatched_chick:" => "🐥", "\\:hatching_chick:" => "🐣", "\\:headphones:" => "🎧", + "\\:headstone:" => "🪦", "\\:hear_no_evil:" => "🙉", "\\:heart:" => "❤", "\\:heart_decoration:" => "💟", @@ -385,24 +533,36 @@ const emoji_symbols = Dict( "\\:heavy_minus_sign:" => "➖", "\\:heavy_multiplication_x:" => "✖", "\\:heavy_plus_sign:" => "➕", + "\\:hedgehog:" => "🦔", "\\:helicopter:" => "🚁", "\\:herb:" => "🌿", "\\:hibiscus:" => "🌺", "\\:high_brightness:" => "🔆", "\\:high_heel:" => "👠", + "\\:hiking_boot:" => "🥾", + "\\:hindu_temple:" => "🛕", + "\\:hippopotamus:" => "🦛", "\\:hocho:" => "🔪", "\\:honey_pot:" => "🍯", + "\\:hook:" => "🪝", "\\:horse:" => "🐴", "\\:horse_racing:" => "🏇", "\\:hospital:" => "🏥", + "\\:hot_face:" => "🥵", + "\\:hotdog:" => "🌭", "\\:hotel:" => "🏨", "\\:hotsprings:" => "♨", "\\:hourglass:" => "⌛", "\\:hourglass_flowing_sand:" => "⏳", "\\:house:" => "🏠", "\\:house_with_garden:" => "🏡", + "\\:hugging_face:" => "🤗", "\\:hushed:" => "😯", + "\\:hut:" => "🛖", + "\\:i_love_you_hand_sign:" => "🤟", "\\:ice_cream:" => "🍨", + "\\:ice_cube:" => "🧊", + "\\:ice_hockey_stick_and_puck:" => "🏒", "\\:icecream:" => "🍦", "\\:id:" => "🆔", "\\:ideograph_advantage:" => "🉐", @@ -421,8 +581,12 @@ const emoji_symbols = Dict( "\\:japanese_goblin:" => "👺", "\\:japanese_ogre:" => "👹", "\\:jeans:" => "👖", + "\\:jigsaw:" => "🧩", "\\:joy:" => "😂", "\\:joy_cat:" => "😹", + "\\:juggling:" => "🤹", + "\\:kaaba:" => "🕋", + "\\:kangaroo:" => "🦘", "\\:key:" => "🔑", "\\:keycap_ten:" => "🔟", "\\:kimono:" => "👘", @@ -432,78 +596,136 @@ const emoji_symbols = Dict( "\\:kissing_closed_eyes:" => "😚", "\\:kissing_heart:" => "😘", "\\:kissing_smiling_eyes:" => "😙", + "\\:kite:" => "🪁", + "\\:kiwifruit:" => "🥝", + "\\:kneeling_person:" => "🧎", + "\\:knot:" => "🪢", "\\:koala:" => "🐨", "\\:koko:" => "🈁", + "\\:lab_coat:" => "🥼", + "\\:lacrosse:" => "🥍", + "\\:ladder:" => "🪜", + "\\:ladybug:" => "🐞", "\\:large_blue_circle:" => "🔵", "\\:large_blue_diamond:" => "🔷", + "\\:large_blue_square:" => "🟦", + "\\:large_brown_circle:" => "🟤", + "\\:large_brown_square:" => "🟫", + "\\:large_green_circle:" => "🟢", + "\\:large_green_square:" => "🟩", + "\\:large_orange_circle:" => "🟠", "\\:large_orange_diamond:" => "🔶", + "\\:large_orange_square:" => "🟧", + "\\:large_purple_circle:" => "🟣", + "\\:large_purple_square:" => "🟪", + "\\:large_red_square:" => "🟥", + "\\:large_yellow_circle:" => "🟡", + "\\:large_yellow_square:" => "🟨", "\\:last_quarter_moon:" => "🌗", "\\:last_quarter_moon_with_face:" => "🌜", "\\:laughing:" => "😆", + "\\:leafy_green:" => "🥬", "\\:leaves:" => "🍃", "\\:ledger:" => "📒", + "\\:left-facing_fist:" => "🤛", "\\:left_luggage:" => "🛅", "\\:left_right_arrow:" => "↔", "\\:leftwards_arrow_with_hook:" => "↩", + "\\:leg:" => "🦵", "\\:lemon:" => "🍋", "\\:leo:" => "♌", "\\:leopard:" => "🐆", "\\:libra:" => "♎", "\\:light_rail:" => "🚈", "\\:link:" => "🔗", + "\\:lion_face:" => "🦁", "\\:lips:" => "👄", "\\:lipstick:" => "💄", + "\\:lizard:" => "🦎", + "\\:llama:" => "🦙", + "\\:lobster:" => "🦞", "\\:lock:" => "🔒", "\\:lock_with_ink_pen:" => "🔏", "\\:lollipop:" => "🍭", + "\\:long_drum:" => "🪘", "\\:loop:" => "➿", + "\\:lotion_bottle:" => "🧴", "\\:loud_sound:" => "🔊", "\\:loudspeaker:" => "📢", "\\:love_hotel:" => "🏩", "\\:love_letter:" => "💌", "\\:low_brightness:" => "🔅", + "\\:luggage:" => "🧳", + "\\:lungs:" => "🫁", + "\\:lying_face:" => "🤥", "\\:m:" => "Ⓜ", "\\:mag:" => "🔍", "\\:mag_right:" => "🔎", + "\\:mage:" => "🧙", + "\\:magic_wand:" => "🪄", + "\\:magnet:" => "🧲", "\\:mahjong:" => "🀄", "\\:mailbox:" => "📫", "\\:mailbox_closed:" => "📪", "\\:mailbox_with_mail:" => "📬", "\\:mailbox_with_no_mail:" => "📭", + "\\:mammoth:" => "🦣", "\\:man:" => "👨", + "\\:man_and_woman_holding_hands:" => "👫", + "\\:man_dancing:" => "🕺", "\\:man_with_gua_pi_mao:" => "👲", "\\:man_with_turban:" => "👳", + "\\:mango:" => "🥭", "\\:mans_shoe:" => "👞", + "\\:manual_wheelchair:" => "🦽", "\\:maple_leaf:" => "🍁", + "\\:martial_arts_uniform:" => "🥋", "\\:mask:" => "😷", "\\:massage:" => "💆", + "\\:mate_drink:" => "🧉", "\\:meat_on_bone:" => "🍖", + "\\:mechanical_arm:" => "🦾", + "\\:mechanical_leg:" => "🦿", "\\:mega:" => "📣", "\\:melon:" => "🍈", "\\:memo:" => "📝", + "\\:menorah_with_nine_branches:" => "🕎", "\\:mens:" => "🚹", + "\\:merperson:" => "🧜", "\\:metro:" => "🚇", + "\\:microbe:" => "🦠", "\\:microphone:" => "🎤", "\\:microscope:" => "🔬", + "\\:middle_finger:" => "🖕", + "\\:military_helmet:" => "🪖", "\\:milky_way:" => "🌌", "\\:minibus:" => "🚐", "\\:minidisc:" => "💽", + "\\:mirror:" => "🪞", "\\:mobile_phone_off:" => "📴", + "\\:money_mouth_face:" => "🤑", "\\:money_with_wings:" => "💸", "\\:moneybag:" => "💰", "\\:monkey:" => "🐒", "\\:monkey_face:" => "🐵", "\\:monorail:" => "🚝", "\\:moon:" => "🌔", + "\\:moon_cake:" => "🥮", "\\:mortar_board:" => "🎓", + "\\:mosque:" => "🕌", + "\\:mosquito:" => "🦟", + "\\:motor_scooter:" => "🛵", + "\\:motorized_wheelchair:" => "🦼", "\\:mount_fuji:" => "🗻", "\\:mountain_bicyclist:" => "🚵", "\\:mountain_cableway:" => "🚠", "\\:mountain_railway:" => "🚞", "\\:mouse2:" => "🐁", "\\:mouse:" => "🐭", + "\\:mouse_trap:" => "🪤", "\\:movie_camera:" => "🎥", "\\:moyai:" => "🗿", + "\\:mrs_claus:" => "🤶", "\\:muscle:" => "💪", "\\:mushroom:" => "🍄", "\\:musical_keyboard:" => "🎹", @@ -512,8 +734,12 @@ const emoji_symbols = Dict( "\\:mute:" => "🔇", "\\:nail_care:" => "💅", "\\:name_badge:" => "📛", + "\\:nauseated_face:" => "🤢", + "\\:nazar_amulet:" => "🧿", "\\:necktie:" => "👔", "\\:negative_squared_cross_mark:" => "❎", + "\\:nerd_face:" => "🤓", + "\\:nesting_dolls:" => "🪆", "\\:neutral_face:" => "😐", "\\:new:" => "🆕", "\\:new_moon:" => "🌑", @@ -521,6 +747,7 @@ const emoji_symbols = Dict( "\\:newspaper:" => "📰", "\\:ng:" => "🆖", "\\:night_with_stars:" => "🌃", + "\\:ninja:" => "🥷", "\\:no_bell:" => "🔕", "\\:no_bicycles:" => "🚳", "\\:no_entry:" => "⛔", @@ -539,55 +766,89 @@ const emoji_symbols = Dict( "\\:o2:" => "🅾", "\\:o:" => "⭕", "\\:ocean:" => "🌊", + "\\:octagonal_sign:" => "🛑", "\\:octopus:" => "🐙", "\\:oden:" => "🍢", "\\:office:" => "🏢", "\\:ok:" => "🆗", "\\:ok_hand:" => "👌", "\\:ok_woman:" => "🙆", + "\\:older_adult:" => "🧓", "\\:older_man:" => "👴", "\\:older_woman:" => "👵", + "\\:olive:" => "🫒", "\\:on:" => "🔛", "\\:oncoming_automobile:" => "🚘", "\\:oncoming_bus:" => "🚍", "\\:oncoming_police_car:" => "🚔", "\\:oncoming_taxi:" => "🚖", + "\\:one-piece_swimsuit:" => "🩱", + "\\:onion:" => "🧅", "\\:open_file_folder:" => "📂", "\\:open_hands:" => "👐", "\\:open_mouth:" => "😮", "\\:ophiuchus:" => "⛎", "\\:orange_book:" => "📙", + "\\:orange_heart:" => "🧡", + "\\:orangutan:" => "🦧", + "\\:otter:" => "🦦", "\\:outbox_tray:" => "📤", + "\\:owl:" => "🦉", "\\:ox:" => "🐂", + "\\:oyster:" => "🦪", "\\:package:" => "📦", "\\:page_facing_up:" => "📄", "\\:page_with_curl:" => "📃", "\\:pager:" => "📟", "\\:palm_tree:" => "🌴", + "\\:palms_up_together:" => "🤲", + "\\:pancakes:" => "🥞", "\\:panda_face:" => "🐼", "\\:paperclip:" => "📎", + "\\:parachute:" => "🪂", "\\:parking:" => "🅿", + "\\:parrot:" => "🦜", "\\:part_alternation_mark:" => "〽", "\\:partly_sunny:" => "⛅", + "\\:partying_face:" => "🥳", "\\:passport_control:" => "🛂", "\\:peach:" => "🍑", + "\\:peacock:" => "🦚", + "\\:peanuts:" => "🥜", "\\:pear:" => "🍐", "\\:pencil2:" => "✏", "\\:penguin:" => "🐧", "\\:pensive:" => "😔", + "\\:people_hugging:" => "🫂", "\\:performing_arts:" => "🎭", "\\:persevere:" => "😣", + "\\:person_climbing:" => "🧗", + "\\:person_doing_cartwheel:" => "🤸", "\\:person_frowning:" => "🙍", + "\\:person_in_lotus_position:" => "🧘", + "\\:person_in_steamy_room:" => "🧖", + "\\:person_in_tuxedo:" => "🤵", "\\:person_with_blond_hair:" => "👱", + "\\:person_with_headscarf:" => "🧕", "\\:person_with_pouting_face:" => "🙎", + "\\:petri_dish:" => "🧫", "\\:phone:" => "☎", + "\\:pickup_truck:" => "🛻", + "\\:pie:" => "🥧", "\\:pig2:" => "🐖", "\\:pig:" => "🐷", "\\:pig_nose:" => "🐽", "\\:pill:" => "💊", + "\\:pinata:" => "🪅", + "\\:pinched_fingers:" => "🤌", + "\\:pinching_hand:" => "🤏", "\\:pineapple:" => "🍍", "\\:pisces:" => "♓", "\\:pizza:" => "🍕", + "\\:placard:" => "🪧", + "\\:place_of_worship:" => "🛐", + "\\:pleading_face:" => "🥺", + "\\:plunger:" => "🪠", "\\:point_down:" => "👇", "\\:point_left:" => "👈", "\\:point_right:" => "👉", @@ -595,16 +856,24 @@ const emoji_symbols = Dict( "\\:point_up_2:" => "👆", "\\:police_car:" => "🚓", "\\:poodle:" => "🐩", + "\\:popcorn:" => "🍿", "\\:post_office:" => "🏣", "\\:postal_horn:" => "📯", "\\:postbox:" => "📮", "\\:potable_water:" => "🚰", + "\\:potato:" => "🥔", + "\\:potted_plant:" => "🪴", "\\:pouch:" => "👝", "\\:poultry_leg:" => "🍗", "\\:pound:" => "💷", "\\:pouting_cat:" => "😾", "\\:pray:" => "🙏", + "\\:prayer_beads:" => "📿", + "\\:pregnant_woman:" => "🤰", + "\\:pretzel:" => "🥨", + "\\:prince:" => "🤴", "\\:princess:" => "👸", + "\\:probing_cane:" => "🦯", "\\:purple_heart:" => "💜", "\\:purse:" => "👛", "\\:pushpin:" => "📌", @@ -612,19 +881,24 @@ const emoji_symbols = Dict( "\\:question:" => "❓", "\\:rabbit2:" => "🐇", "\\:rabbit:" => "🐰", + "\\:raccoon:" => "🦝", "\\:racehorse:" => "🐎", "\\:radio:" => "📻", "\\:radio_button:" => "🔘", "\\:rage:" => "😡", "\\:railway_car:" => "🚃", "\\:rainbow:" => "🌈", + "\\:raised_back_of_hand:" => "🤚", "\\:raised_hands:" => "🙌", "\\:raising_hand:" => "🙋", "\\:ram:" => "🐏", "\\:ramen:" => "🍜", "\\:rat:" => "🐀", + "\\:razor:" => "🪒", + "\\:receipt:" => "🧾", "\\:recycle:" => "♻", "\\:red_circle:" => "🔴", + "\\:red_envelope:" => "🧧", "\\:registered:" => "®", "\\:relaxed:" => "☺", "\\:relieved:" => "😌", @@ -633,14 +907,22 @@ const emoji_symbols = Dict( "\\:restroom:" => "🚻", "\\:revolving_hearts:" => "💞", "\\:rewind:" => "⏪", + "\\:rhinoceros:" => "🦏", "\\:ribbon:" => "🎀", "\\:rice:" => "🍚", "\\:rice_ball:" => "🍙", "\\:rice_cracker:" => "🍘", "\\:rice_scene:" => "🎑", + "\\:right-facing_fist:" => "🤜", "\\:ring:" => "💍", + "\\:ringed_planet:" => "🪐", + "\\:robot_face:" => "🤖", + "\\:rock:" => "🪨", "\\:rocket:" => "🚀", + "\\:roll_of_paper:" => "🧻", "\\:roller_coaster:" => "🎢", + "\\:roller_skate:" => "🛼", + "\\:rolling_on_the_floor_laughing:" => "🤣", "\\:rooster:" => "🐓", "\\:rose:" => "🌹", "\\:rotating_light:" => "🚨", @@ -650,41 +932,70 @@ const emoji_symbols = Dict( "\\:runner:" => "🏃", "\\:running_shirt_with_sash:" => "🎽", "\\:sa:" => "🈂", + "\\:safety_pin:" => "🧷", + "\\:safety_vest:" => "🦺", "\\:sagittarius:" => "♐", "\\:sake:" => "🍶", + "\\:salt:" => "🧂", "\\:sandal:" => "👡", + "\\:sandwich:" => "🥪", "\\:santa:" => "🎅", + "\\:sari:" => "🥻", "\\:satellite:" => "📡", + "\\:satellite_antenna:" => "📡", + "\\:sauropod:" => "🦕", "\\:saxophone:" => "🎷", + "\\:scarf:" => "🧣", "\\:school:" => "🏫", "\\:school_satchel:" => "🎒", "\\:scissors:" => "✂", + "\\:scooter:" => "🛴", + "\\:scorpion:" => "🦂", "\\:scorpius:" => "♏", "\\:scream:" => "😱", "\\:scream_cat:" => "🙀", + "\\:screwdriver:" => "🪛", "\\:scroll:" => "📜", + "\\:seal:" => "🦭", "\\:seat:" => "💺", + "\\:second_place_medal:" => "🥈", "\\:secret:" => "㊙", "\\:see_no_evil:" => "🙈", "\\:seedling:" => "🌱", + "\\:selfie:" => "🤳", + "\\:sewing_needle:" => "🪡", + "\\:shallow_pan_of_food:" => "🥘", + "\\:shark:" => "🦈", "\\:shaved_ice:" => "🍧", "\\:sheep:" => "🐑", "\\:shell:" => "🐚", "\\:ship:" => "🚢", "\\:shirt:" => "👕", + "\\:shopping_trolley:" => "🛒", + "\\:shorts:" => "🩳", "\\:shower:" => "🚿", + "\\:shrimp:" => "🦐", + "\\:shrug:" => "🤷", + "\\:shushing_face:" => "🤫", "\\:signal_strength:" => "📶", "\\:six_pointed_star:" => "🔯", + "\\:skateboard:" => "🛹", "\\:ski:" => "🎿", - "\\:skin-tone-2:" => "\U1f3fb", - "\\:skin-tone-3:" => "\U1f3fc", - "\\:skin-tone-4:" => "\U1f3fd", - "\\:skin-tone-5:" => "\U1f3fe", - "\\:skin-tone-6:" => "\U1f3ff", + "\\:skin-tone-2:" => "🏻", + "\\:skin-tone-3:" => "🏼", + "\\:skin-tone-4:" => "🏽", + "\\:skin-tone-5:" => "🏾", + "\\:skin-tone-6:" => "🏿", "\\:skull:" => "💀", + "\\:skunk:" => "🦨", + "\\:sled:" => "🛷", "\\:sleeping:" => "😴", + "\\:sleeping_accommodation:" => "🛌", "\\:sleepy:" => "😪", + "\\:slightly_frowning_face:" => "🙁", + "\\:slightly_smiling_face:" => "🙂", "\\:slot_machine:" => "🎰", + "\\:sloth:" => "🦥", "\\:small_blue_diamond:" => "🔹", "\\:small_orange_diamond:" => "🔸", "\\:small_red_triangle:" => "🔺", @@ -693,17 +1004,24 @@ const emoji_symbols = Dict( "\\:smile_cat:" => "😸", "\\:smiley:" => "😃", "\\:smiley_cat:" => "😺", + "\\:smiling_face_with_3_hearts:" => "🥰", + "\\:smiling_face_with_tear:" => "🥲", "\\:smiling_imp:" => "😈", "\\:smirk:" => "😏", "\\:smirk_cat:" => "😼", "\\:smoking:" => "🚬", "\\:snail:" => "🐌", "\\:snake:" => "🐍", + "\\:sneezing_face:" => "🤧", "\\:snowboarder:" => "🏂", "\\:snowflake:" => "❄", "\\:snowman:" => "⛄", + "\\:snowman_without_snow:" => "⛄", + "\\:soap:" => "🧼", "\\:sob:" => "😭", "\\:soccer:" => "⚽", + "\\:socks:" => "🧦", + "\\:softball:" => "🥎", "\\:soon:" => "🔜", "\\:sos:" => "🆘", "\\:sound:" => "🔉", @@ -718,45 +1036,71 @@ const emoji_symbols = Dict( "\\:speaker:" => "🔈", "\\:speech_balloon:" => "💬", "\\:speedboat:" => "🚤", + "\\:spock-hand:" => "🖖", + "\\:sponge:" => "🧽", + "\\:spoon:" => "🥄", + "\\:sports_medal:" => "🏅", + "\\:squid:" => "🦑", + "\\:standing_person:" => "🧍", + "\\:star-struck:" => "🤩", "\\:star2:" => "🌟", "\\:star:" => "⭐", "\\:stars:" => "🌠", "\\:station:" => "🚉", "\\:statue_of_liberty:" => "🗽", "\\:steam_locomotive:" => "🚂", + "\\:stethoscope:" => "🩺", "\\:stew:" => "🍲", "\\:straight_ruler:" => "📏", "\\:strawberry:" => "🍓", "\\:stuck_out_tongue:" => "😛", "\\:stuck_out_tongue_closed_eyes:" => "😝", "\\:stuck_out_tongue_winking_eye:" => "😜", + "\\:stuffed_flatbread:" => "🥙", "\\:sun_with_face:" => "🌞", "\\:sunflower:" => "🌻", "\\:sunglasses:" => "😎", "\\:sunny:" => "☀", "\\:sunrise:" => "🌅", "\\:sunrise_over_mountains:" => "🌄", + "\\:superhero:" => "🦸", + "\\:supervillain:" => "🦹", "\\:surfer:" => "🏄", "\\:sushi:" => "🍣", "\\:suspension_railway:" => "🚟", + "\\:swan:" => "🦢", "\\:sweat:" => "😓", "\\:sweat_drops:" => "💦", "\\:sweat_smile:" => "😅", "\\:sweet_potato:" => "🍠", "\\:swimmer:" => "🏊", "\\:symbols:" => "🔣", + "\\:synagogue:" => "🕍", "\\:syringe:" => "💉", + "\\:t-rex:" => "🦖", + "\\:table_tennis_paddle_and_ball:" => "🏓", + "\\:taco:" => "🌮", "\\:tada:" => "🎉", + "\\:takeout_box:" => "🥡", + "\\:tamale:" => "🫔", "\\:tanabata_tree:" => "🎋", "\\:tangerine:" => "🍊", "\\:taurus:" => "♉", "\\:taxi:" => "🚕", "\\:tea:" => "🍵", + "\\:teapot:" => "🫖", + "\\:teddy_bear:" => "🧸", "\\:telephone_receiver:" => "📞", "\\:telescope:" => "🔭", "\\:tennis:" => "🎾", "\\:tent:" => "⛺", + "\\:test_tube:" => "🧪", + "\\:the_horns:" => "🤘", + "\\:thinking_face:" => "🤔", + "\\:third_place_medal:" => "🥉", + "\\:thong_sandal:" => "🩴", "\\:thought_balloon:" => "💭", + "\\:thread:" => "🧵", "\\:ticket:" => "🎫", "\\:tiger2:" => "🐅", "\\:tiger:" => "🐯", @@ -766,6 +1110,9 @@ const emoji_symbols = Dict( "\\:tokyo_tower:" => "🗼", "\\:tomato:" => "🍅", "\\:tongue:" => "👅", + "\\:toolbox:" => "🧰", + "\\:tooth:" => "🦷", + "\\:toothbrush:" => "🪥", "\\:top:" => "🔝", "\\:tophat:" => "🎩", "\\:tractor:" => "🚜", @@ -784,6 +1131,8 @@ const emoji_symbols = Dict( "\\:truck:" => "🚚", "\\:trumpet:" => "🎺", "\\:tulip:" => "🌷", + "\\:tumbler_glass:" => "🥃", + "\\:turkey:" => "🦃", "\\:turtle:" => "🐢", "\\:tv:" => "📺", "\\:twisted_rightwards_arrows:" => "🔀", @@ -802,11 +1151,15 @@ const emoji_symbols = Dict( "\\:u7981:" => "🈲", "\\:u7a7a:" => "🈳", "\\:umbrella:" => "☔", + "\\:umbrella_with_rain_drops:" => "☔", "\\:unamused:" => "😒", "\\:underage:" => "🔞", + "\\:unicorn_face:" => "🦄", "\\:unlock:" => "🔓", "\\:up:" => "🆙", + "\\:upside_down_face:" => "🙃", "\\:v:" => "✌", + "\\:vampire:" => "🧛", "\\:vertical_traffic_light:" => "🚦", "\\:vhs:" => "📼", "\\:vibration_mode:" => "📳", @@ -815,15 +1168,19 @@ const emoji_symbols = Dict( "\\:violin:" => "🎻", "\\:virgo:" => "♍", "\\:volcano:" => "🌋", + "\\:volleyball:" => "🏐", "\\:vs:" => "🆚", + "\\:waffle:" => "🧇", "\\:walking:" => "🚶", "\\:waning_crescent_moon:" => "🌘", "\\:waning_gibbous_moon:" => "🌖", "\\:warning:" => "⚠", "\\:watch:" => "⌚", "\\:water_buffalo:" => "🐃", + "\\:water_polo:" => "🤽", "\\:watermelon:" => "🍉", "\\:wave:" => "👋", + "\\:waving_black_flag:" => "🏴", "\\:wavy_dash:" => "〰", "\\:waxing_crescent_moon:" => "🌒", "\\:wc:" => "🚾", @@ -835,25 +1192,40 @@ const emoji_symbols = Dict( "\\:white_check_mark:" => "✅", "\\:white_circle:" => "⚪", "\\:white_flower:" => "💮", + "\\:white_heart:" => "🤍", "\\:white_large_square:" => "⬜", "\\:white_medium_small_square:" => "◽", "\\:white_medium_square:" => "◻", "\\:white_small_square:" => "▫", "\\:white_square_button:" => "🔳", + "\\:wilted_flower:" => "🥀", "\\:wind_chime:" => "🎐", + "\\:window:" => "🪟", "\\:wine_glass:" => "🍷", "\\:wink:" => "😉", "\\:wolf:" => "🐺", "\\:woman:" => "👩", "\\:womans_clothes:" => "👚", + "\\:womans_flat_shoe:" => "🥿", "\\:womans_hat:" => "👒", "\\:womens:" => "🚺", + "\\:wood:" => "🪵", + "\\:woozy_face:" => "🥴", + "\\:worm:" => "🪱", "\\:worried:" => "😟", "\\:wrench:" => "🔧", + "\\:wrestlers:" => "🤼", "\\:x:" => "❌", + "\\:yarn:" => "🧶", + "\\:yawning_face:" => "🥱", "\\:yellow_heart:" => "💛", "\\:yen:" => "💴", + "\\:yo-yo:" => "🪀", "\\:yum:" => "😋", + "\\:zany_face:" => "🤪", "\\:zap:" => "⚡", + "\\:zebra_face:" => "🦓", + "\\:zipper_mouth_face:" => "🤐", + "\\:zombie:" => "🧟", "\\:zzz:" => "💤", ) diff --git a/stdlib/REPL/src/latex_symbols.jl b/stdlib/REPL/src/latex_symbols.jl index 57e41ed670538..237aba92c45c7 100644 --- a/stdlib/REPL/src/latex_symbols.jl +++ b/stdlib/REPL/src/latex_symbols.jl @@ -110,6 +110,8 @@ const latex_symbols = Dict( "\\backpprime" => "‶", "\\backppprime" => "‷", "\\xor" => "⊻", + "\\nand" => "⊼", + "\\nor" => "⊽", "\\iff" => "⟺", "\\implies" => "⟹", "\\impliedby" => "⟸", @@ -669,8 +671,13 @@ const latex_symbols = Dict( "\\dashv" => "⊣", "\\top" => "⊤", "\\bot" => "⊥", + "\\Top" => "⫪", + "\\Bot" => "⫫", + "\\indep" => "⫫", "\\models" => "⊧", "\\vDash" => "⊨", + "\\downvDash" => "⫪", + "\\upvDash" => "⫫", "\\Vdash" => "⊩", "\\Vvdash" => "⊪", "\\VDash" => "⊫", @@ -2622,13 +2629,14 @@ const latex_symbols = Dict( # Canonical reverse mapping for symbols that have several completions (#39148). # -# These duplicate mappings can be investigated with the folllowing commands: +# These duplicate mappings can be investigated with the following commands: #= ls = REPL.REPLCompletions.latex_symbols; symbols = values(ls) duplicates = [v for v in unique(symbols) if count(==(v), symbols) > 1] [(v, REPL.symbol_latex(v)) => findall(==(v), ls) for v in duplicates] =# const symbols_latex_canonical = Dict( + "⫫" => "\\Bot", "ð" => "\\dh", "…" => "\\ldots", "∅" => "\\emptyset", @@ -2649,6 +2657,9 @@ const symbols_latex_canonical = Dict( "√" => "\\sqrt", "̶" => "\\sout", "→" => "\\to", + "⫪" => "\\Top", "ε" => "\\varepsilon", "⊻" => "\\xor", + "⊼" => "\\nand", + "⊽" => "\\nor", ) diff --git a/stdlib/REPL/src/options.jl b/stdlib/REPL/src/options.jl index 09e3f4265fabe..3ce0ab6ff00dc 100644 --- a/stdlib/REPL/src/options.jl +++ b/stdlib/REPL/src/options.jl @@ -46,7 +46,7 @@ Options(; auto_indent_tmp_off = false, auto_indent_bracketed_paste = false, auto_indent_time_threshold = 0.005, - auto_refresh_time_delay = 0.05, + auto_refresh_time_delay = Sys.iswindows() ? 0.05 : 0.0, iocontext = Dict{Symbol,Any}()) = Options(hascolor, extra_keymap, tabwidth, kill_ring_max, region_animation_duration, diff --git a/stdlib/REPL/test/TerminalMenus/pager.jl b/stdlib/REPL/test/TerminalMenus/pager.jl new file mode 100644 index 0000000000000..1d6579b8f5fc9 --- /dev/null +++ b/stdlib/REPL/test/TerminalMenus/pager.jl @@ -0,0 +1,39 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +content = + """ + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor + incididunt ut labore et dolore magna aliqua. Arcu non sodales neque sodales. + Placerat orci nulla pellentesque dignissim enim sit amet venenatis. Mauris + augue neque gravida in fermentum et sollicitudin. Amet venenatis urna cursus + eget. Enim praesent elementum facilisis leo vel fringilla est. Vitae sapien + pellentesque habitant morbi tristique. Ornare lectus sit amet est placerat in. + Leo urna molestie at elementum eu facilisis. Aliquam vestibulum morbi blandit + cursus risus at ultrices. Id aliquet lectus proin nibh. Facilisi etiam + dignissim diam quis enim lobortis scelerisque fermentum. Pretium lectus quam id + leo in vitae turpis massa sed. Elementum facilisis leo vel fringilla est. + Vulputate ut pharetra sit amet aliquam. Quis enim lobortis scelerisque + fermentum dui faucibus in ornare. Cursus turpis massa tincidunt dui ut. + + A arcu cursus vitae congue mauris rhoncus. Tellus rutrum tellus pellentesque + eu. Fringilla phasellus faucibus scelerisque eleifend donec pretium. Aliquam + etiam erat velit scelerisque. Volutpat lacus laoreet non curabitur gravida. + Felis imperdiet proin fermentum leo vel orci. Viverra tellus in hac habitasse + platea dictumst vestibulum rhoncus est. Ullamcorper dignissim cras tincidunt + lobortis feugiat vivamus. Sit amet luctus venenatis lectus. Odio facilisis + mauris sit amet massa vitae tortor condimentum. Purus sit amet volutpat + consequat mauris nunc congue. Enim nunc faucibus a pellentesque sit amet. Purus + non enim praesent elementum facilisis leo vel fringilla est. + """ |> strip + +let p = Pager(content) + @test p.pagesize == 10 + @test length(p.lines) == 22 + @test startswith(content, p.lines[1]) + @test endswith(content, p.lines[end]) + buffer = IOBuffer() + TerminalMenus.printmenu(buffer, p, 1) + str = String(take!(buffer)) + @test contains(str, "(10 / 22) 45%") + @test endswith(str, "leo in vitae turpis massa sed. Elementum facilisis leo vel fringilla est.") +end diff --git a/stdlib/REPL/test/TerminalMenus/runtests.jl b/stdlib/REPL/test/TerminalMenus/runtests.jl index fab105244d0a1..ac577dfd9ab27 100644 --- a/stdlib/REPL/test/TerminalMenus/runtests.jl +++ b/stdlib/REPL/test/TerminalMenus/runtests.jl @@ -6,10 +6,22 @@ using Test function simulate_input(expected, menu::TerminalMenus.AbstractMenu, keys...; kwargs...) - keydict = Dict(:up => "\e[A", - :down => "\e[B", - :enter => "\r") + keydict = Dict(:up => "\e[A", + :down => "\e[B", + :enter => "\r") + vimdict = Dict(:up => "k", + :down => "j", + :enter => " ") + errs = [] + got = _simulate_input(keydict, deepcopy(menu), keys...; kwargs...) + got == expected || push!(errs, :arrows => got) + got = _simulate_input(vimdict, menu, keys...; kwargs...) + got == expected || push!(errs, :vim => got) + isempty(errs) || return errs +end +function _simulate_input(keydict, menu::TerminalMenus.AbstractMenu, keys...; + kwargs...) for key in keys if isa(key, Symbol) write(stdin.buffer, keydict[key]) @@ -18,13 +30,14 @@ function simulate_input(expected, menu::TerminalMenus.AbstractMenu, keys...; end end - request(menu; suppress_output=true, kwargs...) == expected + request(menu; suppress_output=true, kwargs...) end include("radio_menu.jl") include("multiselect_menu.jl") include("dynamic_menu.jl") include("multiselect_with_skip_menu.jl") +include("pager.jl") # Legacy tests include("legacytests/old_radio_menu.jl") diff --git a/stdlib/REPL/test/docview.jl b/stdlib/REPL/test/docview.jl index 5001a981a35f8..1cc5037c1c806 100644 --- a/stdlib/REPL/test/docview.jl +++ b/stdlib/REPL/test/docview.jl @@ -41,3 +41,9 @@ end # https://github.com/JuliaLang/julia/issues/37757 @test REPL.insert_hlines(IOBuffer(), nothing) === nothing end + +@testset "fuzzy score" begin + # https://github.com/JunoLab/FuzzyCompletions.jl/issues/7 + # shouldn't throw when there is a space in a middle of query + @test (REPL.matchinds("a ", "a file.txt"); true) +end diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 577dfda1a811b..d467c82eb4226 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -453,7 +453,8 @@ for prompt = ["TestΠ", () -> randstring(rand(1:10))] # In the future if we want we can add a test that the right object # gets displayed by intercepting the display repl.specialdisplay = REPL.REPLDisplay(repl) - @async write(devnull, stdout_read) # redirect stdout to devnull so we drain the output pipe + + errormonitor(@async write(devnull, stdout_read)) # redirect stdout to devnull so we drain the output pipe repl.interface = REPL.setup_interface(repl) repl_mode = repl.interface.modes[1] @@ -749,6 +750,32 @@ fake_repl() do stdin_write, stdout_read, repl readuntil(stdout_read, "begin") @test readuntil(stdout_read, "end", keep=true) == "\n\r\e[7C α=1\n\r\e[7C β=2\n\r\e[7Cend" + # Test switching repl modes + sendrepl2("""\e[200~ + julia> A = 1 + 1 + + shell> echo foo + foo + + shell> echo foo + foo + foo foo + + help?> Int + Dummy docstring + + Some text + + julia> error("If this error throws, the paste handler has failed to ignore this docstring example") + + julia> B = 2 + 2\e[201~ + """) + wait(c) + @test Main.A == 1 + @test Main.B == 2 + # Close repl write(stdin_write, '\x04') Base.wait(repltask) @@ -850,7 +877,7 @@ mutable struct Error19864 <: Exception; end function test19864() @eval Base.showerror(io::IO, e::Error19864) = print(io, "correct19864") buf = IOBuffer() - fake_response = (Any[(Error19864(), Ptr{Cvoid}[])], true) + fake_response = (Base.ExceptionStack([(exception=Error19864(),backtrace=Ptr{Cvoid}[])]),true) REPL.print_response(buf, fake_response, false, false, nothing) return String(take!(buf)) end @@ -1095,6 +1122,9 @@ end # Issue 39427 @test occursin("does not exist", sprint(show, help_result(":="))) +# Issue #40563 +@test occursin("does not exist", sprint(show, help_result(".."))) + # Issue #25930 # Brief and extended docs (issue #25930) @@ -1252,7 +1282,7 @@ end # AST transformations (softscope, Revise, OhMyREPL, etc.) @testset "AST Transformation" begin backend = REPL.REPLBackend() - @async REPL.start_repl_backend(backend) + errormonitor(@async REPL.start_repl_backend(backend)) put!(backend.repl_channel, (:(1+1), false)) reply = take!(backend.response_channel) @test reply == Pair{Any, Bool}(2, false) @@ -1291,3 +1321,35 @@ Base.wait(frontend_task) macro throw_with_linenumbernode(err) Expr(:block, LineNumberNode(42, Symbol("test.jl")), :(() -> throw($err))) end + +@testset "Install missing packages via hooks" begin + @testset "Parse AST for packages" begin + mods = REPL.modules_to_be_loaded(Base.parse_input_line("using Foo")) + @test mods == [:Foo] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("import Foo")) + @test mods == [:Foo] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("using Foo, Bar")) + @test mods == [:Foo, :Bar] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("import Foo, Bar")) + @test mods == [:Foo, :Bar] + + mods = REPL.modules_to_be_loaded(Base.parse_input_line("if false using Foo end")) + @test mods == [:Foo] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("if false if false using Foo end end")) + @test mods == [:Foo] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("if false using Foo, Bar end")) + @test mods == [:Foo, :Bar] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("if false using Foo: bar end")) + @test mods == [:Foo] + + mods = REPL.modules_to_be_loaded(Base.parse_input_line("import Foo.bar as baz")) + @test mods == [:Foo] + mods = REPL.modules_to_be_loaded(Base.parse_input_line("using .Foo")) + @test isempty(mods) + + mods = REPL.modules_to_be_loaded(Base.parse_input_line("# comment")) + @test isempty(mods) + mods = REPL.modules_to_be_loaded(Base.parse_input_line("Foo")) + @test isempty(mods) + end +end diff --git a/stdlib/REPL/test/replcompletions.jl b/stdlib/REPL/test/replcompletions.jl index 8a1d2f39a18f4..545e81a27968d 100644 --- a/stdlib/REPL/test/replcompletions.jl +++ b/stdlib/REPL/test/replcompletions.jl @@ -97,10 +97,11 @@ function map_completion_text(completions) return map(completion_text, c), r, res end -test_complete(s) = map_completion_text(@inferred(completions(s,lastindex(s)))) -test_scomplete(s) = map_completion_text(@inferred(shell_completions(s,lastindex(s)))) -test_bslashcomplete(s) = map_completion_text(@inferred(bslash_completions(s,lastindex(s)))[2]) -test_complete_context(s) = map_completion_text(@inferred(completions(s,lastindex(s),Main.CompletionFoo))) +test_complete(s) = map_completion_text(@inferred(completions(s, lastindex(s)))) +test_scomplete(s) = map_completion_text(@inferred(shell_completions(s, lastindex(s)))) +test_bslashcomplete(s) = map_completion_text(@inferred(bslash_completions(s, lastindex(s)))[2]) +test_complete_context(s, m) = map_completion_text(@inferred(completions(s,lastindex(s), m))) +test_complete_foo(s) = test_complete_context(s, Main.CompletionFoo) module M32377 end test_complete_32377(s) = map_completion_text(completions(s,lastindex(s), M32377)) @@ -117,6 +118,10 @@ let s = "using REP" @test count(isequal("REPL"), c) == 1 # issue #30234 @test !Base.isbindingresolved(M32377, :tanh) + # check what happens if REPL is already imported + M32377.eval(:(using REPL)) + c, r = test_complete_32377(s) + @test count(isequal("REPL"), c) == 1 end let s = "Comp" @@ -293,7 +298,7 @@ end # test latex symbol completion in getindex expressions (#24705) let s = "tuple[\\alpha" - c, r, res = test_complete_context(s) + c, r, res = test_complete_foo(s) @test c[1] == "α" @test r == 7:12 @test length(c) == 1 @@ -983,13 +988,13 @@ end # No CompletionFoo.CompletionFoo let s = "" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test !("CompletionFoo" in c) end # Can see `rand()` after `using Random` let s = "r" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "rand" in c @test r == 1:1 @test s[r] == "r" @@ -997,7 +1002,7 @@ end # Can see `Test.AbstractTestSet` after `import Test` let s = "Test.A" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "AbstractTestSet" in c @test r == 6:6 @test s[r] == "A" @@ -1005,21 +1010,21 @@ end # Can complete relative import let s = "import ..M" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test_broken "Main" in c @test r == 10:10 @test s[r] == "M" end let s = "" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "bar" in c @test r === 1:0 @test s[r] == "" end let s = "f" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "foo" in c @test r == 1:1 @test s[r] == "f" @@ -1027,7 +1032,7 @@ let s = "f" end let s = "@f" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "@foobar" in c @test r == 1:2 @test s[r] == "@f" @@ -1035,48 +1040,48 @@ let s = "@f" end let s = "type_test.x" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "xx" in c @test r == 11:11 @test s[r] == "x" end let s = "bar.no_val_available" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test length(c)==0 end let s = "type_test.xx.y" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "yy" in c @test r == 14:14 @test s[r] == "y" end let s = ":(function foo(::Int) end).args[1].args[2]." - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test c == Any[] end let s = "log(log.(x)," - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test !isempty(c) end let s = "Base.return_types(getin" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test "getindex" in c @test r == 19:23 @test s[r] == "getin" end let s = "using Test, Random" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test !("RandomDevice" in c) end let s = "test(1,1, " - c, r, res = test_complete_context(s) + c, r, res = test_complete_foo(s) @test !res @test c[1] == string(first(methods(Main.CompletionFoo.test, Tuple{Int, Int}))) @test length(c) == 3 @@ -1085,7 +1090,7 @@ let s = "test(1,1, " end let s = "test.(1,1, " - c, r, res = test_complete_context(s) + c, r, res = test_complete_foo(s) @test !res @test length(c) == 4 @test r == 1:4 @@ -1093,7 +1098,7 @@ let s = "test.(1,1, " end let s = "prevind(\"θ\",1," - c, r, res = test_complete_context(s) + c, r, res = test_complete_foo(s) @test c[1] == string(first(methods(prevind, Tuple{String, Int}))) @test r == 1:7 @test s[r] == "prevind" @@ -1101,11 +1106,59 @@ end # Issue #32840 let s = "typeof(+)." - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test length(c) == length(fieldnames(DataType)) end let s = "test_dict[\"ab" - c, r = test_complete_context(s) + c, r = test_complete_foo(s) @test c == Any["\"abc\"", "\"abcd\""] end + +# https://github.com/JuliaLang/julia/issues/27184 +let + (test_complete("@noexist."); @test true) + (test_complete("Main.@noexist."); @test true) + (test_complete("@Main.noexist."); @test true) +end + +@testset "https://github.com/JuliaLang/julia/issues/40247" begin + # getfield type completion can work for complicated expression + + let + m = Module() + @eval m begin + struct Rs + rs::Vector{Regex} + end + var = nothing + function foo() + global var = 1 + return Rs([r"foo"]) + end + end + + c, r = test_complete_context("foo().rs[1].", m) + @test m.var ≠ 1 # getfield type completion should never execute `foo()` + @test length(c) == fieldcount(Regex) + end + + let + m = Module() + @eval m begin + struct R + r::Regex + end + var = nothing + function foo() + global var = 1 + return R(r"foo") + end + end + + c, r = test_complete_context("foo().r.", m) + # the current implementation of `REPL.REPLCompletions.completions(::String, ::Int, ::Module)` + # cuts off "foo().r." to `.r.`, and the getfield type completion doesn't work for this simpler case + @test_broken length(c) == fieldcount(Regex) + end +end diff --git a/stdlib/Random/Project.toml b/stdlib/Random/Project.toml index 6aa9f65374539..6958e618d3ea8 100644 --- a/stdlib/Random/Project.toml +++ b/stdlib/Random/Project.toml @@ -9,6 +9,7 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Future = "9fa8497b-333b-5362-9e8d-4d0656e87820" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" [targets] -test = ["Test", "SparseArrays", "LinearAlgebra", "Future"] +test = ["Test", "SparseArrays", "LinearAlgebra", "Future", "Statistics"] diff --git a/stdlib/Random/docs/src/index.md b/stdlib/Random/docs/src/index.md index 4e8ace596543a..ca86de44ecce4 100644 --- a/stdlib/Random/docs/src/index.md +++ b/stdlib/Random/docs/src/index.md @@ -13,7 +13,9 @@ type, which is a wrapper over the OS provided entropy. Most functions related to random generation accept an optional `AbstractRNG` object as first argument, which defaults to the global one if not provided. Moreover, some of them accept optionally dimension specifications `dims...` (which can be given as a tuple) to generate arrays of random -values. +values. In a multi-threaded program, you should generally use different RNG objects from different threads +in order to be thread-safe. However, the default global RNG is thread-safe as of Julia 1.3 (because +it internally corresponds to a per-thread RNG). A `MersenneTwister` or `RandomDevice` RNG can generate uniformly random numbers of the following types: [`Float16`](@ref), [`Float32`](@ref), [`Float64`](@ref), [`BigFloat`](@ref), [`Bool`](@ref), diff --git a/stdlib/Random/src/RNGs.jl b/stdlib/Random/src/RNGs.jl index 5c29954f13132..2bdecd92e6a08 100644 --- a/stdlib/Random/src/RNGs.jl +++ b/stdlib/Random/src/RNGs.jl @@ -181,9 +181,9 @@ function show(io::IO, rng::MersenneTwister) seed = from_seed(rng.seed) seed_str = seed <= typemax(Int) ? string(seed) : "0x" * string(seed, base=16) # DWIM if rng.adv_jump == 0 && rng.adv == 0 - return print(io, "MersenneTwister($seed_str)") + return print(io, MersenneTwister, "(", seed_str, ")") end - print(io, "MersenneTwister($seed_str, (") + print(io, MersenneTwister, "(", seed_str, ", (") # state adv = Integer[rng.adv_jump, rng.adv] if rng.adv_vals != -1 || rng.adv_ints != -1 diff --git a/stdlib/Random/src/misc.jl b/stdlib/Random/src/misc.jl index 3c09f5b30d257..7c26d36f0a0d4 100644 --- a/stdlib/Random/src/misc.jl +++ b/stdlib/Random/src/misc.jl @@ -71,7 +71,12 @@ function randstring end let b = UInt8['0':'9';'A':'Z';'a':'z'] global randstring - randstring(r::AbstractRNG, chars=b, n::Integer=8) = String(rand(r, chars, n)) + function randstring(r::AbstractRNG, chars=b, n::Integer=8) + T = eltype(chars) + v = T === UInt8 ? Base.StringVector(n) : Vector{T}(undef, n) + rand!(r, v, chars) + return String(v) + end randstring(r::AbstractRNG, n::Integer) = randstring(r, b, n) randstring(chars=b, n::Integer=8) = randstring(default_rng(), chars, n) randstring(n::Integer) = randstring(default_rng(), b, n) diff --git a/stdlib/Random/test/runtests.jl b/stdlib/Random/test/runtests.jl index c502b14bc3a7f..639a2bbed60c2 100644 --- a/stdlib/Random/test/runtests.jl +++ b/stdlib/Random/test/runtests.jl @@ -2,6 +2,7 @@ using Test, SparseArrays using Test: guardseed +using Statistics: mean const BASE_TEST_PATH = joinpath(Sys.BINDIR, "..", "share", "julia", "test") isdefined(Main, :OffsetArrays) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "OffsetArrays.jl")) @@ -898,3 +899,15 @@ end x = BigFloat() @test_throws ArgumentError rand!(rng, x, s) # incompatible precision end + +@testset "shuffle! for BitArray" begin + # Test that shuffle! is uniformly random on BitArrays + rng = MersenneTwister(123) + a = (reshape(1:(4*5), 4, 5) .<= 2) # 4x5 BitMatrix whose first two elements are true, rest are false + m = mean(1:50_000) do _ + shuffle!(rng, a) + end # mean result of shuffle!-ing a 50_000 times. If the shuffle! is uniform, then each index has a + # 10% chance of having a true in it, so each value should converge to 0.1. + @test minimum(m) >= 0.094 + @test maximum(m) <= 0.106 +end diff --git a/stdlib/Serialization/src/Serialization.jl b/stdlib/Serialization/src/Serialization.jl index bee52a72f7798..22782eff99816 100644 --- a/stdlib/Serialization/src/Serialization.jl +++ b/stdlib/Serialization/src/Serialization.jl @@ -425,7 +425,7 @@ function serialize(s::AbstractSerializer, meth::Method) serialize(s, nothing) end if isdefined(meth, :generator) - serialize(s, Base._uncompressed_ast(meth, meth.generator.inferred)) # XXX: what was this supposed to do? + serialize(s, meth.generator) else serialize(s, nothing) end @@ -439,9 +439,12 @@ end function serialize(s::AbstractSerializer, linfo::Core.MethodInstance) serialize_cycle(s, linfo) && return - isa(linfo.def, Module) || error("can only serialize toplevel MethodInstance objects") writetag(s.io, METHODINSTANCE_TAG) - serialize(s, linfo.uninferred) + if isdefined(linfo, :uninferred) + serialize(s, linfo.uninferred) + else + writetag(s.io, UNDEFREF_TAG) + end serialize(s, nothing) # for backwards compat serialize(s, linfo.sparam_vals) serialize(s, Any) # for backwards compat @@ -455,11 +458,19 @@ function serialize(s::AbstractSerializer, t::Task) if istaskstarted(t) && !istaskdone(t) error("cannot serialize a running Task") end - state = [t.code, t.storage, t.state, t.result, t._isexception] writetag(s.io, TASK_TAG) - for fld in state - serialize(s, fld) + serialize(s, t.code) + serialize(s, t.storage) + serialize(s, t.state) + if t._isexception && (stk = Base.current_exceptions(t); !isempty(stk)) + # the exception stack field is hidden inside the task, so if there + # is any information there make a CapturedException from it instead. + # TODO: Handle full exception chain, not just the first one. + serialize(s, CapturedException(stk[1].exception, stk[1].backtrace)) + else + serialize(s, t.result) end + serialize(s, t._isexception) end function serialize(s::AbstractSerializer, g::GlobalRef) @@ -496,8 +507,8 @@ function serialize_typename(s::AbstractSerializer, t::Core.TypeName) serialize(s, primary.parameters) serialize(s, primary.types) serialize(s, isdefined(primary, :instance)) - serialize(s, primary.abstract) - serialize(s, primary.mutable) + serialize(s, t.abstract) + serialize(s, t.mutable) serialize(s, primary.ninitialized) if isdefined(t, :mt) && t.mt !== Symbol.name.mt serialize(s, t.mt.name) @@ -649,7 +660,7 @@ function serialize_any(s::AbstractSerializer, @nospecialize(x)) serialize_type(s, t) write(s.io, x) else - if t.mutable + if t.name.mutable serialize_cycle(s, x) && return serialize_type(s, t, true) else @@ -926,7 +937,7 @@ function handle_deserialize(s::AbstractSerializer, b::Int32) return deserialize_dict(s, t) end t = desertag(b)::DataType - if t.mutable && length(t.types) > 0 # manual specialization of fieldcount + if t.name.mutable && length(t.types) > 0 # manual specialization of fieldcount slot = s.counter; s.counter += 1 push!(s.pending_refs, slot) end @@ -1036,11 +1047,7 @@ function deserialize(s::AbstractSerializer, ::Type{Method}) end meth.slot_syms = slot_syms if generator !== nothing - linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, ()) - linfo.specTypes = Tuple - linfo.inferred = generator - linfo.def = meth - meth.generator = linfo + meth.generator = generator end if recursion_relation !== nothing meth.recursion_relation = recursion_relation @@ -1059,7 +1066,10 @@ end function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance}) linfo = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, (Ptr{Cvoid},), C_NULL) deserialize_cycle(s, linfo) - linfo.uninferred = deserialize(s)::CodeInfo + tag = Int32(read(s.io, UInt8)::UInt8) + if tag != UNDEFREF_TAG + linfo.uninferred = handle_deserialize(s, tag)::CodeInfo + end tag = Int32(read(s.io, UInt8)::UInt8) if tag != UNDEFREF_TAG # for reading files prior to v1.2 @@ -1068,7 +1078,7 @@ function deserialize(s::AbstractSerializer, ::Type{Core.MethodInstance}) linfo.sparam_vals = deserialize(s)::SimpleVector _rettype = deserialize(s) # for backwards compat linfo.specTypes = deserialize(s) - linfo.def = deserialize(s)::Module + linfo.def = deserialize(s) return linfo end @@ -1243,8 +1253,8 @@ function deserialize_typename(s::AbstractSerializer, number) else # reuse the same name for the type, if possible, for nicer debugging tn_name = isdefined(__deserialized_types__, name) ? gensym() : name - tn = ccall(:jl_new_typename_in, Ref{Core.TypeName}, (Any, Any), - tn_name, __deserialized_types__) + tn = ccall(:jl_new_typename_in, Ref{Core.TypeName}, (Any, Any, Cint, Cint), + tn_name, __deserialized_types__, false, false) makenew = true end remember_object(s, tn, number) @@ -1260,7 +1270,7 @@ function deserialize_typename(s::AbstractSerializer, number) ninitialized = deserialize(s)::Int32 if makenew - tn.names = names + Core.setfield!(tn, :names, names) # TODO: there's an unhanded cycle in the dependency graph at this point: # while deserializing super and/or types, we may have encountered # tn.wrapper and throw UndefRefException before we get to this point @@ -1412,7 +1422,7 @@ function deserialize(s::AbstractSerializer, t::DataType) if nf == 0 && t.size > 0 # bits type return read(s.io, t) - elseif t.mutable + elseif t.name.mutable x = ccall(:jl_new_struct_uninit, Any, (Any,), t) deserialize_cycle(s, x) for i in 1:nf diff --git a/stdlib/SharedArrays/src/SharedArrays.jl b/stdlib/SharedArrays/src/SharedArrays.jl index 347d22180f7b5..85f1eb4fff150 100644 --- a/stdlib/SharedArrays/src/SharedArrays.jl +++ b/stdlib/SharedArrays/src/SharedArrays.jl @@ -295,14 +295,21 @@ size(S::SharedArray) = S.dims elsize(::Type{SharedArray{T,N}}) where {T,N} = elsize(Array{T,N}) # aka fieldtype(T, :s) IndexStyle(::Type{<:SharedArray}) = IndexLinear() +function local_array_by_id(refid) + if isa(refid, Future) + refid = remoteref_id(refid) + end + fetch(channel_from_id(refid)) +end + function reshape(a::SharedArray{T}, dims::NTuple{N,Int}) where {T,N} if length(a) != prod(dims) throw(DimensionMismatch("dimensions must be consistent with array size")) end refs = Vector{Future}(undef, length(a.pids)) for (i, p) in enumerate(a.pids) - refs[i] = remotecall(p, a.refs[i], dims) do r,d - reshape(fetch(r),d) + refs[i] = remotecall(p, a.refs[i], dims) do r, d + reshape(local_array_by_id(r), d) end end @@ -382,7 +389,7 @@ function shared_pids(pids) # only use workers on the current host pids = procs(myid()) if length(pids) > 1 - pids = filter(x -> x != 1, pids) + pids = filter(!=(1), pids) end onlocalhost = true @@ -419,13 +426,7 @@ sub_1dim(S::SharedArray, pidx) = view(S.s, range_1dim(S, pidx)) function init_loc_flds(S::SharedArray{T,N}, empty_local=false) where T where N if myid() in S.pids S.pidx = findfirst(isequal(myid()), S.pids) - if isa(S.refs[1], Future) - refid = remoteref_id(S.refs[S.pidx]) - else - refid = S.refs[S.pidx] - end - c = channel_from_id(refid) - S.s = fetch(c) + S.s = local_array_by_id(S.refs[S.pidx]) S.loc_subarr_1d = sub_1dim(S, S.pidx) else S.pidx = 0 diff --git a/stdlib/SharedArrays/test/runtests.jl b/stdlib/SharedArrays/test/runtests.jl index 7a4d46d4777b3..7f1bbb6891ce0 100644 --- a/stdlib/SharedArrays/test/runtests.jl +++ b/stdlib/SharedArrays/test/runtests.jl @@ -176,6 +176,12 @@ d = SharedArrays.shmem_fill(1.0, (10,10,10)) @test fill(1., 100, 10) == reshape(d,(100,10)) d = SharedArrays.shmem_fill(1.0, (10,10,10)) @test_throws DimensionMismatch reshape(d,(50,)) +# issue #40249, reshaping on another process +let m = SharedArray{ComplexF64}(10, 20, 30) + m2 = remotecall_fetch(() -> reshape(m, (100, :)), id_other) + @test size(m2) == (100, 60) + @test m2 isa SharedArray +end # rand, randn d = SharedArrays.shmem_rand(dims) diff --git a/stdlib/Sockets/src/addrinfo.jl b/stdlib/Sockets/src/addrinfo.jl index a4eed4d16d6fa..586463ba0fa21 100644 --- a/stdlib/Sockets/src/addrinfo.jl +++ b/stdlib/Sockets/src/addrinfo.jl @@ -260,7 +260,7 @@ julia> getipaddr(IPv6) ip"fe80::9731:35af:e1c5:6e49" ``` -See also: [`getipaddrs`](@ref) +See also [`getipaddrs`](@ref). """ function getipaddr(addr_type::Type{T}) where T<:IPAddr addrs = getipaddrs(addr_type) @@ -305,7 +305,7 @@ julia> getipaddrs(IPv6) ip"fe80::445e:5fff:fe5d:5500" ``` -See also: [`islinklocaladdr`](@ref), `split(ENV["SSH_CONNECTION"], ' ')[3]` +See also [`islinklocaladdr`](@ref). """ function getipaddrs(addr_type::Type{T}=IPAddr; loopback::Bool=false) where T<:IPAddr addresses = T[] diff --git a/stdlib/SparseArrays/Project.toml b/stdlib/SparseArrays/Project.toml index 53d4a9f064ad3..bc8a968cfb4ff 100644 --- a/stdlib/SparseArrays/Project.toml +++ b/stdlib/SparseArrays/Project.toml @@ -8,7 +8,8 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [extras] Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Dates", "Test", "InteractiveUtils"] +test = ["Dates", "Test", "Printf", "InteractiveUtils"] diff --git a/stdlib/SparseArrays/src/abstractsparse.jl b/stdlib/SparseArrays/src/abstractsparse.jl index 3ea70f48b4a7e..86d6c4b3da56d 100644 --- a/stdlib/SparseArrays/src/abstractsparse.jl +++ b/stdlib/SparseArrays/src/abstractsparse.jl @@ -50,17 +50,19 @@ julia> issparse(Array(sv)) false ``` """ -issparse(A::AbstractArray) = false +function issparse(A::AbstractArray) + # Handle wrapper arrays: sparse if it is wrapping a sparse array. + # This gets compiled away during specialization. + p = parent(A) + if p === A + # have reached top of wrapping without finding a sparse array, assume it is not. + return false + else + return issparse(p) + end +end +issparse(A::DenseArray) = false issparse(S::AbstractSparseArray) = true -issparse(S::LinearAlgebra.Adjoint{<:Any,<:AbstractSparseArray}) = true -issparse(S::LinearAlgebra.Transpose{<:Any,<:AbstractSparseArray}) = true - -issparse(S::LinearAlgebra.Symmetric{<:Any,<:AbstractSparseMatrix}) = true -issparse(S::LinearAlgebra.Hermitian{<:Any,<:AbstractSparseMatrix}) = true -issparse(S::LinearAlgebra.LowerTriangular{<:Any,<:AbstractSparseMatrix}) = true -issparse(S::LinearAlgebra.UnitLowerTriangular{<:Any,<:AbstractSparseMatrix}) = true -issparse(S::LinearAlgebra.UpperTriangular{<:Any,<:AbstractSparseMatrix}) = true -issparse(S::LinearAlgebra.UnitUpperTriangular{<:Any,<:AbstractSparseMatrix}) = true indtype(S::AbstractSparseArray{<:Any,Ti}) where {Ti} = Ti diff --git a/stdlib/SparseArrays/src/higherorderfns.jl b/stdlib/SparseArrays/src/higherorderfns.jl index 383211267ee3b..a5941da764883 100644 --- a/stdlib/SparseArrays/src/higherorderfns.jl +++ b/stdlib/SparseArrays/src/higherorderfns.jl @@ -8,7 +8,7 @@ import Base: map, map!, broadcast, copy, copyto!, _extrema_dims, _extrema_itr using Base: front, tail, to_shape using ..SparseArrays: SparseVector, SparseMatrixCSC, AbstractSparseVector, AbstractSparseMatrixCSC, - AbstractSparseMatrix, AbstractSparseArray, indtype, nnz, nzrange, + AbstractSparseMatrix, AbstractSparseArray, indtype, nnz, nzrange, spzeros, SparseVectorUnion, AdjOrTransSparseVectorUnion, nonzeroinds, nonzeros, rowvals, getcolptr, widelength using Base.Broadcast: BroadcastStyle, Broadcasted, flatten using LinearAlgebra @@ -132,12 +132,17 @@ function trimstorage!(A::SparseVecOrMat, maxstored) resize!(storedvals(A), maxstored) return maxstored end + function expandstorage!(A::SparseVecOrMat, maxstored) - length(storedinds(A)) < maxstored && resize!(storedinds(A), maxstored) - length(storedvals(A)) < maxstored && resize!(storedvals(A), maxstored) + if length(storedinds(A)) < maxstored + resize!(storedinds(A), maxstored) + resize!(storedvals(A), maxstored) + end return maxstored end +_checkbuffers(S::SparseMatrixCSC) = (@assert length(getcolptr(S)) == size(S, 2) + 1 && getcolptr(S)[end] - 1 == length(rowvals(S)) == length(nonzeros(S)); S) +_checkbuffers(S::SparseVector) = (@assert length(storedvals(S)) == length(storedinds(S)); S) # (2) map[!] entry points map(f::Tf, A::SparseVector) where {Tf} = _noshapecheck_map(f, A) @@ -181,7 +186,7 @@ copy(bc::SpBroadcasted1) = _noshapecheck_map(bc.f, bc.args[1]) storedvals(C)[1] = fofnoargs broadcast!(f, view(storedvals(C), 2:length(storedvals(C)))) end - return C + return _checkbuffers(C) end function _diffshape_broadcast(f::Tf, A::SparseVecOrMat, Bs::Vararg{SparseVecOrMat,N}) where {Tf,N} @@ -224,22 +229,17 @@ _maxnnzfrom(shape::NTuple{2}, A::AbstractSparseMatrixCSC) = nnz(A) * div(shape[1 @inline _unchecked_maxnnzbcres(shape, As...) = _unchecked_maxnnzbcres(shape, As) @inline _checked_maxnnzbcres(shape::NTuple{1}, As...) = shape[1] != 0 ? _unchecked_maxnnzbcres(shape, As) : 0 @inline _checked_maxnnzbcres(shape::NTuple{2}, As...) = shape[1] != 0 && shape[2] != 0 ? _unchecked_maxnnzbcres(shape, As) : 0 -@inline function _allocres(shape::NTuple{1}, indextype, entrytype, maxnnz) - storedinds = Vector{indextype}(undef, maxnnz) - storedvals = Vector{entrytype}(undef, maxnnz) - return SparseVector(shape..., storedinds, storedvals) -end -@inline function _allocres(shape::NTuple{2}, indextype, entrytype, maxnnz) - pointers = ones(indextype, shape[2] + 1) - storedinds = Vector{indextype}(undef, maxnnz) - storedvals = Vector{entrytype}(undef, maxnnz) - return SparseMatrixCSC(shape..., pointers, storedinds, storedvals) +@inline function _allocres(shape::Union{NTuple{1},NTuple{2}}, indextype, entrytype, maxnnz) + X = spzeros(entrytype, indextype, shape) + resize!(storedinds(X), maxnnz) + resize!(storedvals(X), maxnnz) + return X end # (4) _map_zeropres!/_map_notzeropres! specialized for a single sparse vector/matrix "Stores only the nonzero entries of `map(f, Array(A))` in `C`." function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where Tf - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) Ck = 1 @inbounds for j in columns(C) setcolptr!(C, j, Ck) @@ -255,7 +255,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where Tf end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end """ Densifies `C`, storing `fillvalue` in place of each unstored entry in `A` and @@ -274,7 +274,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMa end # NOTE: Combining the fill! above into the loop above to avoid multiple sweeps over / # nonsequential access of storedvals(C) does not appear to improve performance. - return C + return _checkbuffers(C) end # helper functions for these methods and some of those below @inline _densecoloffsets(A::SparseVector) = 0 @@ -297,7 +297,7 @@ end # (5) _map_zeropres!/_map_notzeropres! specialized for a pair of sparse vectors/matrices function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVecOrMat) where Tf - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) rowsentinelA = convert(indtype(A), numrows(C) + 1) rowsentinelB = convert(indtype(B), numrows(C) + 1) Ck = 1 @@ -336,7 +336,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVe end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVecOrMat) where Tf # Build dense matrix structure in C, expanding storage if necessary @@ -368,13 +368,13 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMa Cx != fillvalue && (storedvals(C)[jo + Ci] = Cx) end end - return C + return _checkbuffers(C) end # (6) _map_zeropres!/_map_notzeropres! for more than two sparse matrices / vectors function _map_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) where {Tf,N} - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) rowsentinel = numrows(C) + 1 Ck = 1 stopks = _colstartind_all(1, As) @@ -398,7 +398,7 @@ function _map_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) where {Tf,N} # Build dense matrix structure in C, expanding storage if necessary @@ -421,7 +421,7 @@ function _map_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{Spars activerow = min(rows...) end end - return C + return _checkbuffers(C) end # helper methods for map/map! methods just above @@ -462,7 +462,7 @@ end # (7) _broadcast_zeropres!/_broadcast_notzeropres! specialized for a single (input) sparse vector/matrix function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where Tf isempty(C) && return _finishempty!(C) - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) # C and A cannot have the same shape, as we directed that case to map in broadcast's # entry point; here we need efficiently handle only heterogeneous C-A combinations where # one or both of C and A has at least one singleton dimension. @@ -509,7 +509,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat) where end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMat) where Tf # For information on this code, see comments in similar code in _broadcast_zeropres! above @@ -540,14 +540,14 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV end end end - return C + return _checkbuffers(C) end # (8) _broadcast_zeropres!/_broadcast_notzeropres! specialized for a pair of (input) sparse vectors/matrices function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVecOrMat) where Tf isempty(C) && return _finishempty!(C) - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) rowsentinelA = convert(indtype(A), numrows(C) + 1) rowsentinelB = convert(indtype(B), numrows(C) + 1) # C, A, and B cannot all have the same shape, as we directed that case to map in broadcast's @@ -711,7 +711,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, A::SparseVecOrMat, B::Sp end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseVecOrMat, B::SparseVecOrMat) where Tf # For information on this code, see comments in similar code in _broadcast_zeropres! above @@ -810,7 +810,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, A::SparseV end end end - return C + return _checkbuffers(C) end _finishempty!(C::SparseVector) = C _finishempty!(C::AbstractSparseMatrixCSC) = (fill!(getcolptr(C), 1); C) @@ -861,7 +861,7 @@ end # (9) _broadcast_zeropres!/_broadcast_notzeropres! for more than two (input) sparse vectors/matrices function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) where {Tf,N} isempty(C) && return _finishempty!(C) - spaceC::Int = min(length(storedinds(C)), length(storedvals(C))) + spaceC::Int = length(nonzeros(C)) expandsverts = _expandsvert_all(C, As) expandshorzs = _expandshorz_all(C, As) rowsentinel = numrows(C) + 1 @@ -909,7 +909,7 @@ function _broadcast_zeropres!(f::Tf, C::SparseVecOrMat, As::Vararg{SparseVecOrMa end @inbounds setcolptr!(C, numcols(C) + 1, Ck) trimstorage!(C, Ck - 1) - return C + return _checkbuffers(C) end function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg{SparseVecOrMat,N}) where {Tf,N} isempty(C) && return _finishempty!(C) @@ -950,7 +950,7 @@ function _broadcast_notzeropres!(f::Tf, fillvalue, C::SparseVecOrMat, As::Vararg end end end - return C + return _checkbuffers(C) end # helper method for broadcast/broadcast! methods just above diff --git a/stdlib/SparseArrays/src/linalg.jl b/stdlib/SparseArrays/src/linalg.jl index c6852382b5406..73fc0c7dee03a 100644 --- a/stdlib/SparseArrays/src/linalg.jl +++ b/stdlib/SparseArrays/src/linalg.jl @@ -646,7 +646,7 @@ function _ldiv!(L::LowerTriangularPlain, B::StridedVecOrMat) for k = 1:ncolB for j = 1:nrowB i1 = ia[j] - i2 = ia[j + 1] - 1 + i2 = ia[j + 1] - one(eltype(ia)) # find diagonal element ii = searchsortedfirst(ja, j, i1, i2, Base.Order.Forward) @@ -688,7 +688,7 @@ function _ldiv!(U::UpperTriangularPlain, B::StridedVecOrMat) for k = 1:ncolB for j = nrowB:-1:1 i1 = ia[j] - i2 = ia[j + 1] - 1 + i2 = ia[j + 1] - one(eltype(ia)) # find diagonal element ii = searchsortedlast(ja, j, i1, i2, Base.Order.Forward) @@ -935,16 +935,15 @@ function triu(S::AbstractSparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} end rowval = Vector{Ti}(undef, nnz) nzval = Vector{Tv}(undef, nnz) - A = SparseMatrixCSC(m, n, colptr, rowval, nzval) for col = max(k+1,1) : n c1 = getcolptr(S)[col] - for c2 in nzrange(A, col) - rowvals(A)[c2] = rowvals(S)[c1] - nonzeros(A)[c2] = nonzeros(S)[c1] + for c2 in colptr[col]:colptr[col+1]-1 + rowval[c2] = rowvals(S)[c1] + nzval[c2] = nonzeros(S)[c1] c1 += 1 end end - A + SparseMatrixCSC(m, n, colptr, rowval, nzval) end function tril(S::AbstractSparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} @@ -965,17 +964,16 @@ function tril(S::AbstractSparseMatrixCSC{Tv,Ti}, k::Integer=0) where {Tv,Ti} end rowval = Vector{Ti}(undef, nnz) nzval = Vector{Tv}(undef, nnz) - A = SparseMatrixCSC(m, n, colptr, rowval, nzval) for col = 1 : min(n, m+k) c1 = getcolptr(S)[col+1]-1 - l2 = getcolptr(A)[col+1]-1 - for c2 = 0 : l2 - getcolptr(A)[col] - rowvals(A)[l2 - c2] = rowvals(S)[c1] - nonzeros(A)[l2 - c2] = nonzeros(S)[c1] + l2 = colptr[col+1]-1 + for c2 = 0 : l2 - colptr[col] + rowval[l2 - c2] = rowvals(S)[c1] + nzval[l2 - c2] = nonzeros(S)[c1] c1 -= 1 end end - A + SparseMatrixCSC(m, n, colptr, rowval, nzval) end ## diff @@ -1340,7 +1338,6 @@ end ## kron @inline function kron!(C::SparseMatrixCSC, A::AbstractSparseMatrixCSC, B::AbstractSparseMatrixCSC) - nnzC = nnz(A)*nnz(B) mA, nA = size(A); mB, nB = size(B) mC, nC = mA*mB, nA*nB @@ -1348,11 +1345,9 @@ end nzvalC = nonzeros(C) colptrC = getcolptr(C) - @boundscheck begin - length(colptrC) == nC+1 || throw(DimensionMismatch("expect C to be preallocated with $(nC+1) colptrs ")) - length(rowvalC) == nnzC || throw(DimensionMismatch("expect C to be preallocated with $(nnzC) rowvals")) - length(nzvalC) == nnzC || throw(DimensionMismatch("expect C to be preallocated with $(nnzC) nzvals")) - end + nnzC = nnz(A)*nnz(B) + resize!(nzvalC, nnzC) + resize!(rowvalC, nnzC) col = 1 @inbounds for j = 1:nA @@ -1381,16 +1376,13 @@ end end @inline function kron!(z::SparseVector, x::SparseVector, y::SparseVector) - nnzx = nnz(x); nnzy = nnz(y); nnzz = nnz(z); + nnzx = nnz(x); nnzy = nnz(y); nzind = nonzeroinds(z) nzval = nonzeros(z) - @boundscheck begin - nnzval = length(nzval); nnzind = length(nzind) - nnzz = nnzx*nnzy - nnzval == nnzz || throw(DimensionMismatch("expect z to be preallocated with $nnzz nonzeros")) - nnzind == nnzz || throw(DimensionMismatch("expect z to be preallocated with $nnzz nonzeros")) - end + nnzz = nnzx*nnzy + resize!(nzind, nnzz) + resize!(nzval, nnzz) @inbounds for i = 1:nnzx, j = 1:nnzy this_ind = (i-1)*nnzy+j @@ -1402,17 +1394,12 @@ end # sparse matrix ⊗ sparse matrix function kron(A::AbstractSparseMatrixCSC{T1,S1}, B::AbstractSparseMatrixCSC{T2,S2}) where {T1,S1,T2,S2} - nnzC = nnz(A)*nnz(B) mA, nA = size(A); mB, nB = size(B) mC, nC = mA*mB, nA*nB Tv = typeof(one(T1)*one(T2)) Ti = promote_type(S1,S2) - colptrC = Vector{Ti}(undef, nC+1) - rowvalC = Vector{Ti}(undef, nnzC) - nzvalC = Vector{Tv}(undef, nnzC) - colptrC[1] = 1 - # skip sparse_check - C = SparseMatrixCSC{Tv, Ti}(mC, nC, colptrC, rowvalC, nzvalC) + C = spzeros(Tv, Ti, mC, nC) + sizehint!(C, nnz(A)*nnz(B)) return @inbounds kron!(C, A, B) end diff --git a/stdlib/SparseArrays/src/sparsematrix.jl b/stdlib/SparseArrays/src/sparsematrix.jl index 7bd988d881152..4065b783de8b4 100644 --- a/stdlib/SparseArrays/src/sparsematrix.jl +++ b/stdlib/SparseArrays/src/sparsematrix.jl @@ -25,10 +25,9 @@ struct SparseMatrixCSC{Tv,Ti<:Integer} <: AbstractSparseMatrixCSC{Tv,Ti} function SparseMatrixCSC{Tv,Ti}(m::Integer, n::Integer, colptr::Vector{Ti}, rowval::Vector{Ti}, nzval::Vector{Tv}) where {Tv,Ti<:Integer} - @noinline throwsz(str, lbl, k) = - throw(ArgumentError("number of $str ($lbl) must be ≥ 0, got $k")) - m < 0 && throwsz("rows", 'm', m) - n < 0 && throwsz("columns", 'n', n) + sparse_check_Ti(m, n, Ti) + _goodbuffers(Int(m), Int(n), colptr, rowval, nzval) || + throw(ArgumentError("Illegal buffers for SparseMatrixCSC construction $n $colptr $rowval $nzval")) new(Int(m), Int(n), colptr, rowval, nzval) end end @@ -80,6 +79,15 @@ end size(S::SparseMatrixCSC) = (getfield(S, :m), getfield(S, :n)) +_goodbuffers(S::SparseMatrixCSC) = _goodbuffers(size(S)..., getcolptr(S), getrowval(S), nonzeros(S)) +_checkbuffers(S::SparseMatrixCSC) = (@assert _goodbuffers(S); S) + +function _goodbuffers(m, n, colptr, rowval, nzval) + (length(colptr) == n + 1 && colptr[end] - 1 == length(rowval) == length(nzval)) + # stronger check for debugging purposes + # && all(issorted(@view rowval[colptr[i]:colptr[i+1]-1]) for i=1:n) +end + # Define an alias for views of a SparseMatrixCSC which include all rows and a unit range of the columns. # Also define a union of SparseMatrixCSC and this view since many methods can be defined efficiently for # this union by extracting the fields via the get function: getcolptr, getrowval, and getnzval. The key @@ -220,6 +228,7 @@ Base.replace_in_print_matrix(A::AbstractSparseMatrix, i::Integer, j::Integer, s: Base.isstored(A, i, j) ? s : Base.replace_with_centered_mark(s) function Base.show(io::IO, ::MIME"text/plain", S::AbstractSparseMatrixCSC) + _checkbuffers(S) xnnz = nnz(S) m, n = size(S) print(io, m, "×", n, " ", typeof(S), " with ", xnnz, " stored ", @@ -295,6 +304,7 @@ function _show_with_braille_patterns(io::IOContext, S::AbstractSparseMatrixCSC) end function Base.show(io::IOContext, S::AbstractSparseMatrixCSC) + _checkbuffers(S) if max(size(S)...) < 16 && !(get(io, :compact, false)::Bool) ioc = IOContext(io, :compact => true) println(ioc) @@ -307,7 +317,7 @@ end ## Reshape -function sparse_compute_reshaped_colptr_and_rowval(colptrS::Vector{Ti}, rowvalS::Vector{Ti}, +function sparse_compute_reshaped_colptr_and_rowval!(colptrS::Vector{Ti}, rowvalS::Vector{Ti}, mS::Int, nS::Int, colptrA::Vector{Ti}, rowvalA::Vector{Ti}, mA::Int, nA::Int) where Ti lrowvalA = length(rowvalA) @@ -350,7 +360,7 @@ function copy(ra::ReshapedArray{<:Any,2,<:AbstractSparseMatrixCSC}) rowval = similar(rowvals(a)) nzval = copy(nonzeros(a)) - sparse_compute_reshaped_colptr_and_rowval(colptr, rowval, mS, nS, getcolptr(a), rowvals(a), mA, nA) + sparse_compute_reshaped_colptr_and_rowval!(colptr, rowval, mS, nS, getcolptr(a), rowvals(a), mA, nA) return SparseMatrixCSC(mS, nS, colptr, rowval, nzval) end @@ -377,7 +387,7 @@ function copyto!(A::AbstractSparseMatrixCSC, B::AbstractSparseMatrixCSC) copyto!(rowvals(A), rowvals(B)) else # This is like a "reshape B into A". - sparse_compute_reshaped_colptr_and_rowval(getcolptr(A), rowvals(A), size(A, 1), size(A, 2), getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) + sparse_compute_reshaped_colptr_and_rowval!(getcolptr(A), rowvals(A), size(A, 1), size(A, 2), getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) end else widelength(A) >= widelength(B) || throw(BoundsError()) @@ -407,10 +417,10 @@ function copyto!(A::AbstractSparseMatrixCSC, B::AbstractSparseMatrixCSC) @inbounds for i in 2:length(getcolptr(A)) getcolptr(A)[i] += nnzB - lastmodptrA end - sparse_compute_reshaped_colptr_and_rowval(getcolptr(A), rowvals(A), size(A, 1), lastmodcolA-1, getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) + sparse_compute_reshaped_colptr_and_rowval!(getcolptr(A), rowvals(A), size(A, 1), lastmodcolA-1, getcolptr(B), rowvals(B), size(B, 1), size(B, 2)) end copyto!(nonzeros(A), nonzeros(B)) - return A + return _checkbuffers(A) end copyto!(A::AbstractMatrix, B::AbstractSparseMatrixCSC) = _sparse_copyto!(A, B) @@ -469,17 +479,17 @@ function _sparsesimilar(S::AbstractSparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew} newrowval = copyto!(similar(rowvals(S), TiNew), rowvals(S)) return SparseMatrixCSC(size(S, 1), size(S, 2), newcolptr, newrowval, similar(nonzeros(S), TvNew)) end -# parent methods for similar that preserves only storage space (for when new and old dims differ) +# parent methods for similar that preserves only storage space (for when new dims are 2-d) _sparsesimilar(S::AbstractSparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{2}) where {TvNew,TiNew} = - SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(rowvals(S), TiNew), similar(nonzeros(S), TvNew)) -# parent method for similar that allocates an empty sparse vector (when new dims are single) + sizehint!(spzeros(TvNew, TiNew, dims...), length(nonzeros(S))) +# parent method for similar that allocates an empty sparse vector (for when new dims are 1-d) _sparsesimilar(S::AbstractSparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{1}) where {TvNew,TiNew} = SparseVector(dims..., similar(rowvals(S), TiNew, 0), similar(nonzeros(S), TvNew, 0)) -# + # The following methods hook into the AbstractArray similar hierarchy. The first method # covers similar(A[, Tv]) calls, which preserve stored-entry structure, and the latter -# methods cover similar(A[, Tv], shape...) calls, which preserve storage space when the shape -# calls for a two-dimensional result. +# methods cover similar(A[, Tv], shape...) calls, which partially preserve +# storage space when the shape calls for a two-dimensional result. similar(S::AbstractSparseMatrixCSC{<:Any,Ti}, ::Type{TvNew}) where {Ti,TvNew} = _sparsesimilar(S, TvNew, Ti) similar(S::AbstractSparseMatrixCSC{<:Any,Ti}, ::Type{TvNew}, dims::Union{Dims{1},Dims{2}}) where {Ti,TvNew} = _sparsesimilar(S, TvNew, Ti, dims) @@ -496,6 +506,12 @@ similar(S::AbstractSparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, m::Integer) wh similar(S::AbstractSparseMatrixCSC, ::Type{TvNew}, ::Type{TiNew}, m::Integer, n::Integer) where {TvNew,TiNew} = _sparsesimilar(S, TvNew, TiNew, (m, n)) +function Base.sizehint!(S::SparseMatrixCSC, n::Integer) + nhint = min(n, widelength(S)) + sizehint!(getrowval(S), nhint) + sizehint!(nonzeros(S), nhint) + return S +end # converting between SparseMatrixCSC types SparseMatrixCSC(S::AbstractSparseMatrixCSC) = copy(S) @@ -658,6 +674,7 @@ SparseMatrixCSC{Tv,Ti}(M::Transpose{<:Any,<:AbstractSparseMatrixCSC}) where {Tv, # converting from SparseMatrixCSC to other matrix types function Matrix(S::AbstractSparseMatrixCSC{Tv}) where Tv + _checkbuffers(S) A = Matrix{Tv}(undef, size(S, 1), size(S, 2)) copyto!(A, S) return A @@ -689,7 +706,7 @@ julia> sparse(A) ⋅ ⋅ 1.0 ``` """ -sparse(A::AbstractMatrix{Tv}) where {Tv} = convert(SparseMatrixCSC{Tv,Int}, A) +sparse(A::AbstractMatrix{Tv}) where {Tv} = convert(SparseMatrixCSC{Tv}, A) sparse(S::AbstractSparseMatrixCSC) = copy(S) @@ -1016,6 +1033,8 @@ respectively. Simultaneously fixes the one-position-forward shift in `getcolptr( """ @noinline function _distributevals_halfperm!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{TvA,Ti}, q::AbstractVector{<:Integer}, f::Function) where {Tv,TvA,Ti} + resize!(nonzeros(X), nnz(A)) + resize!(rowvals(X), nnz(A)) @inbounds for Xi in 1:size(A, 2) Aj = q[Xi] for Ak in nzrange(A, Aj) @@ -1035,16 +1054,8 @@ function ftranspose!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixC throw(DimensionMismatch(string("destination argument `X`'s column count, ", "`size(X, 2) (= $(size(X, 2)))`, must match source argument `A`'s row count, `size(A, 1) (= $(size(A, 1)))`"))) elseif size(X, 1) != size(A, 2) - throw(DimensionMismatch(string("destination argument `X`'s row count, - `size(X, 1) (= $(size(X, 1)))`, must match source argument `A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) - elseif length(rowvals(X)) < nnz(A) - throw(ArgumentError(string("the length of destination argument `X`'s `rowval` ", - "array, `length(rowvals(X)) (= $(length(rowvals(X))))`, must be greater than or ", - "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) - elseif length(nonzeros(X)) < nnz(A) - throw(ArgumentError(string("the length of destination argument `X`'s `nzval` ", - "array, `length(nonzeros(X)) (= $(length(nonzeros(X))))`, must be greater than or ", - "equal to source argument `A`'s allocated entry count, `nnz(A) (= $(nnz(A)))`"))) + throw(DimensionMismatch(string("destination argument `X`'s row count, ", + "`size(X, 1) (= $(size(X, 1)))`, must match source argument `A`'s column count, `size(A, 2) (= $(size(A, 2)))`"))) end halfperm!(X, A, 1:size(A, 2), f) end @@ -1055,8 +1066,9 @@ adjoint!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{Tv,Ti}) w function ftranspose(A::AbstractSparseMatrixCSC{TvA,Ti}, f::Function, eltype::Type{Tv} = TvA) where {Tv,TvA,Ti} X = SparseMatrixCSC(size(A, 2), size(A, 1), ones(Ti, size(A, 1)+1), - Vector{Ti}(undef, nnz(A)), - Vector{Tv}(undef, nnz(A))) + Vector{Ti}(undef, 0), + Vector{Tv}(undef, 0)) + sizehint!(X, nnz(A)) halfperm!(X, A, 1:size(A, 2), f) end adjoint(A::AbstractSparseMatrixCSC) = Adjoint(A) @@ -1091,7 +1103,7 @@ avoids an unnecessary length-`nnz(A)` array-sweep and associated recomputation o pointers. See [`halfperm!`](:func:SparseArrays.halfperm!) for additional algorithmic information. -See also: `unchecked_aliasing_permute!` +See also `unchecked_aliasing_permute!`. """ function unchecked_noalias_permute!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, @@ -1268,16 +1280,17 @@ For additional (algorithmic) information, and for versions of these methods that argument checking, see (unexported) parent methods `unchecked_noalias_permute!` and `unchecked_aliasing_permute!`. -See also: [`permute`](@ref). +See also [`permute`](@ref). """ function permute!(X::AbstractSparseMatrixCSC{Tv,Ti}, A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatdest_permute!(A, X) _checkargs_sourcecompatperms_permute!(A, p, q) - C = SparseMatrixCSC(size(A, 2), size(A, 1), - ones(Ti, size(A, 1) + 1), - Vector{Ti}(undef, nnz(A)), - Vector{Tv}(undef, nnz(A))) + # bypass strict buffer checking + C = spzeros(Tv, Ti, size(A,2), size(A,1)) + resize!(getrowval(C), nnz(A)) + resize!(getnzval(C), nnz(A)) + _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, getcolptr(X)) unchecked_noalias_permute!(X, A, p, q, C) end @@ -1293,10 +1306,9 @@ end function permute!(A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) - C = SparseMatrixCSC(size(A, 2), size(A, 1), - ones(Ti, size(A, 1) + 1), - Vector{Ti}(undef, nnz(A)), - Vector{Tv}(undef, nnz(A))) + C = spzeros(Tv, Ti, size(A,2), size(A,1)) + resize!(getrowval(C), nnz(A)) + resize!(getnzval(C), nnz(A)) workcolptr = Vector{Ti}(undef, size(A, 2) + 1) _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, workcolptr) unchecked_aliasing_permute!(A, p, q, C, workcolptr) @@ -1355,14 +1367,14 @@ julia> permute(A, [1, 2, 3, 4], [4, 3, 2, 1]) function permute(A::AbstractSparseMatrixCSC{Tv,Ti}, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}) where {Tv,Ti} _checkargs_sourcecompatperms_permute!(A, p, q) - X = SparseMatrixCSC(size(A, 1), size(A, 2), - ones(Ti, size(A, 2) + 1), - Vector{Ti}(undef, nnz(A)), - Vector{Tv}(undef, nnz(A))) - C = SparseMatrixCSC(size(A, 2), size(A, 1), - ones(Ti, size(A, 1) + 1), - Vector{Ti}(undef, nnz(A)), - Vector{Tv}(undef, nnz(A))) + # bypass strict buffer checking + X = spzeros(Tv, Ti, size(A,1), size(A,2)) + resize!(getrowval(X), nnz(A)) + resize!(getnzval(X), nnz(A)) + # bypass strict buffer checking + C = spzeros(Tv, Ti, size(A,2), size(A,1)) + resize!(getrowval(C), nnz(A)) + resize!(getnzval(C), nnz(A)) _checkargs_permutationsvalid_permute!(p, getcolptr(C), q, getcolptr(X)) unchecked_noalias_permute!(X, A, p, q, C) end @@ -1455,6 +1467,7 @@ For an out-of-place version, see [`dropzeros`](@ref). For algorithmic information, see `fkeep!`. """ dropzeros!(A::AbstractSparseMatrixCSC) = fkeep!(A, (i, j, x) -> !iszero(x)) + """ dropzeros(A::AbstractSparseMatrixCSC;) @@ -2480,7 +2493,7 @@ function permute_rows!(S::AbstractSparseMatrixCSC{Tv,Ti}, pI::Vector{Int}) where k += 1 end end - S + return _checkbuffers(S) end function getindex_general(A::AbstractSparseMatrixCSC, I::AbstractVector, J::AbstractVector) @@ -2634,6 +2647,7 @@ function Base.fill!(V::SubArray{Tv, <:Any, <:AbstractSparseMatrixCSC{Tv}, <:Tupl else _spsetnz_setindex!(A, convert(Tv, x), I, J) end + return _checkbuffers(A) end """ Helper method for immediately preceding fill! method. For all (i,j) such that i in I and @@ -2917,7 +2931,7 @@ function setindex!(A::AbstractSparseMatrixCSC{Tv,Ti}, V::AbstractVecOrMat, Ix::U deleteat!(rowvalA, colptrA[end]:length(rowvalA)) deleteat!(nzvalA, colptrA[end]:length(nzvalA)) - return A + return _checkbuffers(A) end # Logical setindex! @@ -3026,7 +3040,7 @@ function setindex!(A::AbstractSparseMatrixCSC, x::AbstractArray, I::AbstractMatr deleteat!(rowvalB, bidx:n) end end - A + return _checkbuffers(A) end function setindex!(A::AbstractSparseMatrixCSC, x::AbstractArray, Ix::AbstractVector{<:Integer}) @@ -3137,7 +3151,7 @@ function setindex!(A::AbstractSparseMatrixCSC, x::AbstractArray, Ix::AbstractVec deleteat!(rowvalB, bidx:n) end end - A + return _checkbuffers(A) end ## dropstored! methods @@ -3173,7 +3187,7 @@ function dropstored!(A::AbstractSparseMatrixCSC, i::Integer, j::Integer) @inbounds getcolptr(A)[m] -= 1 end end - return A + return _checkbuffers(A) end """ dropstored!(A::AbstractSparseMatrixCSC, I::AbstractVector{<:Integer}, J::AbstractVector{<:Integer}) @@ -3260,7 +3274,7 @@ function dropstored!(A::AbstractSparseMatrixCSC, deleteat!(rowvalA, rowidx:nnzA) deleteat!(nzvalA, rowidx:nnzA) end - return A + return _checkbuffers(A) end dropstored!(A::AbstractSparseMatrixCSC, i::Integer, J::AbstractVector{<:Integer}) = dropstored!(A, [i], J) dropstored!(A::AbstractSparseMatrixCSC, I::AbstractVector{<:Integer}, j::Integer) = dropstored!(A, I, [j]) @@ -3694,74 +3708,6 @@ function tr(A::AbstractSparseMatrixCSC{Tv}) where Tv return s end - -# Sort all the indices in each column of a CSC sparse matrix -# sortSparseMatrixCSC!(A, sortindices = :sortcols) # Sort each column with sort() -# sortSparseMatrixCSC!(A, sortindices = :doubletranspose) # Sort with a double transpose -function sortSparseMatrixCSC!(A::AbstractSparseMatrixCSC{Tv,Ti}; sortindices::Symbol = :sortcols) where {Tv,Ti} - if sortindices === :doubletranspose - nB, mB = size(A) - B = SparseMatrixCSC(mB, nB, Vector{Ti}(undef, nB+1), similar(rowvals(A)), similar(nonzeros(A))) - transpose!(B, A) - transpose!(A, B) - return A - end - - m, n = size(A) - colptr = getcolptr(A); rowval = rowvals(A); nzval = nonzeros(A) - - index = zeros(Ti, m) - row = zeros(Ti, m) - val = zeros(Tv, m) - - perm = Base.Perm(Base.ord(isless, identity, false, Base.Order.Forward), row) - - @inbounds for i = 1:n - nzr = nzrange(A, i) - numrows = length(nzr) - if numrows <= 1 - continue - elseif numrows == 2 - f = first(nzr) - s = f+1 - if rowval[f] > rowval[s] - rowval[f], rowval[s] = rowval[s], rowval[f] - nzval[f], nzval[s] = nzval[s], nzval[f] - end - continue - end - resize!(row, numrows) - resize!(index, numrows) - - jj = 1 - @simd for j = nzr - row[jj] = rowval[j] - val[jj] = nzval[j] - jj += 1 - end - - if numrows <= 16 - alg = Base.Sort.InsertionSort - else - alg = Base.Sort.QuickSort - end - - # Reset permutation - index .= 1:numrows - - sort!(index, alg, perm) - - jj = 1 - @simd for j = nzr - rowval[j] = row[index[jj]] - nzval[j] = val[index[jj]] - jj += 1 - end - end - - return A -end - ## rotations function rot180(A::AbstractSparseMatrixCSC) @@ -3837,7 +3783,7 @@ function circshift!(O::AbstractSparseMatrixCSC, X::AbstractSparseMatrixCSC, (r,c @inbounds for i=1:size(O, 2) subvector_shifter!(rowvals(O), nonzeros(O), getcolptr(O)[i], getcolptr(O)[i+1]-1, size(O, 1), r) end - return O + return _checkbuffers(O) end circshift!(O::AbstractSparseMatrixCSC, X::AbstractSparseMatrixCSC, (r,)::Base.DimsInteger{1}) = circshift!(O, X, (r,0)) diff --git a/stdlib/SparseArrays/src/sparsevector.jl b/stdlib/SparseArrays/src/sparsevector.jl index 777be897ea7df..eecda6d72add8 100644 --- a/stdlib/SparseArrays/src/sparsevector.jl +++ b/stdlib/SparseArrays/src/sparsevector.jl @@ -15,7 +15,7 @@ import LinearAlgebra: promote_to_array_type, promote_to_arrays_ Vector type for storing sparse vectors. """ struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} - n::Int # Length of the sparse vector + n::Ti # Length of the sparse vector nzind::Vector{Ti} # Indices of stored values nzval::Vector{Tv} # Stored values, typically nonzeros @@ -23,7 +23,7 @@ struct SparseVector{Tv,Ti<:Integer} <: AbstractSparseVector{Tv,Ti} n >= 0 || throw(ArgumentError("The number of elements must be non-negative.")) length(nzind) == length(nzval) || throw(ArgumentError("index and value vectors must be the same length")) - new(convert(Int, n), nzind, nzval) + new(convert(Ti, n), nzind, nzval) end end @@ -84,30 +84,37 @@ rowvals(x::SparseVectorUnion) = nonzeroinds(x) indtype(x::SparseColumnView) = indtype(parent(x)) indtype(x::SparseVectorView) = indtype(parent(x)) + +function Base.sizehint!(v::SparseVector, newlen::Integer) + sizehint!(nonzeroinds(v), newlen) + sizehint!(nonzeros(v), newlen) + return v +end + ## similar # # parent method for similar that preserves stored-entry structure (for when new and old dims match) _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}) where {TvNew,TiNew} = SparseVector(length(S), copyto!(similar(nonzeroinds(S), TiNew), nonzeroinds(S)), similar(nonzeros(S), TvNew)) -# parent method for similar that preserves nothing (for when old and new dims differ, and new is 1d) +# parent method for similar that preserves nothing (for when new dims are 1-d) _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{1}) where {TvNew,TiNew} = SparseVector(dims..., similar(nonzeroinds(S), TiNew, 0), similar(nonzeros(S), TvNew, 0)) # parent method for similar that preserves storage space (for old and new dims differ, and new is 2d) -_sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{2}) where {TvNew,TiNew} = - SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(nonzeroinds(S), TiNew), similar(nonzeros(S), TvNew)) +function _sparsesimilar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Dims{2}) where {TvNew,TiNew} + S1 = SparseMatrixCSC(dims..., fill(one(TiNew), last(dims)+1), similar(nonzeroinds(S), TiNew, 0), similar(nonzeros(S), TvNew, 0)) + return sizehint!(S1, min(widelength(S1), length(nonzeroinds(S)))) +end # The following methods hook into the AbstractArray similar hierarchy. The first method # covers similar(A[, Tv]) calls, which preserve stored-entry structure, and the latter # methods cover similar(A[, Tv], shape...) calls, which preserve nothing if the dims -# specify a SparseVector result and storage space if the dims specify a SparseMatrixCSC result. +# specify a SparseVector or a SparseMatrixCSC result. similar(S::SparseVector{<:Any,Ti}, ::Type{TvNew}) where {Ti,TvNew} = _sparsesimilar(S, TvNew, Ti) similar(S::SparseVector{<:Any,Ti}, ::Type{TvNew}, dims::Union{Dims{1},Dims{2}}) where {Ti,TvNew} = _sparsesimilar(S, TvNew, Ti, dims) # The following methods cover similar(A, Tv, Ti[, shape...]) calls, which specify the # result's index type in addition to its entry type, and aren't covered by the hooks above. -# The calls without shape again preserve stored-entry structure, whereas those with -# one-dimensional shape preserve nothing, and those with two-dimensional shape -# preserve storage space. +# The calls without shape again preserve stored-entry structure but no storage space. similar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}) where{TvNew,TiNew} = _sparsesimilar(S, TvNew, TiNew) similar(S::SparseVector, ::Type{TvNew}, ::Type{TiNew}, dims::Union{Dims{1},Dims{2}}) where {TvNew,TiNew} = @@ -125,8 +132,11 @@ Base.unaliascopy(S::SparseVector) = typeof(S)(length(S), unaliascopy(nonzeroinds ### Construct empty sparse vector spzeros(len::Integer) = spzeros(Float64, len) +spzeros(dims::Tuple{<:Integer}) = spzeros(Float64, dims[1]) spzeros(::Type{T}, len::Integer) where {T} = SparseVector(len, Int[], T[]) +spzeros(::Type{T}, dims::Tuple{<:Integer}) where {T} = spzeros(T, dims[1]) spzeros(::Type{Tv}, ::Type{Ti}, len::Integer) where {Tv,Ti<:Integer} = SparseVector(len, Ti[], Tv[]) +spzeros(::Type{Tv}, ::Type{Ti}, dims::Tuple{<:Integer}) where {Tv,Ti<:Integer} = spzeros(Tv, Ti, dims[1]) LinearAlgebra.fillstored!(x::SparseVector, y) = (fill!(nonzeros(x), y); x) @@ -1354,34 +1364,50 @@ end ### Reduction +function _sum(f, x::AbstractSparseVector) + n = length(x) + n > 0 || return sum(f, nonzeros(x)) # return zero() of proper type + m = nnz(x) + (m == 0 ? n * f(zero(eltype(x))) : + m == n ? sum(f, nonzeros(x)) : + Base.add_sum((n - m) * f(zero(eltype(x))), sum(f, nonzeros(x)))) +end + +sum(f::Union{Function, Type}, x::AbstractSparseVector) = _sum(f, x) # resolve ambiguity +sum(f, x::AbstractSparseVector) = _sum(f, x) sum(x::AbstractSparseVector) = sum(nonzeros(x)) -function maximum(x::AbstractSparseVector{T}) where T<:Real +function _maximum(f, x::AbstractSparseVector) n = length(x) - n > 0 || throw(ArgumentError("maximum over empty array is not allowed.")) + if n == 0 + if f === abs || f === abs2 + return zero(eltype(x)) # preserving maximum(abs/abs2, x) behaviour in 1.0.x + else + throw(ArgumentError("maximum over an empty array is not allowed.")) + end + end m = nnz(x) - (m == 0 ? zero(T) : - m == n ? maximum(nonzeros(x)) : - max(zero(T), maximum(nonzeros(x))))::T + (m == 0 ? f(zero(eltype(x))) : + m == n ? maximum(f, nonzeros(x)) : + max(f(zero(eltype(x))), maximum(f, nonzeros(x)))) end -function minimum(x::AbstractSparseVector{T}) where T<:Real +maximum(f::Union{Function, Type}, x::AbstractSparseVector) = _maximum(f, x) # resolve ambiguity +maximum(f, x::AbstractSparseVector) = _maximum(f, x) +maximum(x::AbstractSparseVector) = maximum(identity, x) + +function _minimum(f, x::AbstractSparseVector) n = length(x) - n > 0 || throw(ArgumentError("minimum over empty array is not allowed.")) + n > 0 || throw(ArgumentError("minimum over an empty array is not allowed.")) m = nnz(x) - (m == 0 ? zero(T) : - m == n ? minimum(nonzeros(x)) : - min(zero(T), minimum(nonzeros(x))))::T + (m == 0 ? f(zero(eltype(x))) : + m == n ? minimum(f, nonzeros(x)) : + min(f(zero(eltype(x))), minimum(f, nonzeros(x)))) end -for f in [:sum, :maximum, :minimum], op in [:abs, :abs2] - SV = :AbstractSparseVector - if f === :minimum - @eval ($f)(::typeof($op), x::$SV{T}) where {T<:Number} = nnz(x) < length(x) ? ($op)(zero(T)) : ($f)($op, nonzeros(x)) - else - @eval ($f)(::typeof($op), x::$SV) = ($f)($op, nonzeros(x)) - end -end +minimum(f::Union{Function, Type}, x::AbstractSparseVector) = _minimum(f, x) # resolve ambiguity +minimum(f, x::AbstractSparseVector) = _minimum(f, x) +minimum(x::AbstractSparseVector) = minimum(identity, x) norm(x::SparseVectorUnion, p::Real=2) = norm(nonzeros(x), p) diff --git a/stdlib/SparseArrays/test/sparse.jl b/stdlib/SparseArrays/test/sparse.jl index ef5159d41031d..85fb999cbe677 100644 --- a/stdlib/SparseArrays/test/sparse.jl +++ b/stdlib/SparseArrays/test/sparse.jl @@ -48,7 +48,7 @@ end S = sparse(I, 3, 3) fill!(S, 0) @test iszero(S) # test success with stored zeros via fill! - @test iszero(SparseMatrixCSC(2, 2, [1,2,3], [1,2], [0,0,1])) # test success with nonzeros beyond data range + @test_throws ArgumentError iszero(SparseMatrixCSC(2, 2, [1,2,3], [1,2], [0,0,1])) # test failure with nonzeros beyond data range end @testset "isone specialization for SparseMatrixCSC" begin @test isone(sparse(I, 3, 3)) # test success @@ -94,6 +94,7 @@ end # with combine @test sparse([1, 1, 2, 2, 2], [1, 2, 1, 2, 2], 1.0, 2, 2, +) == sparse([1, 1, 2, 2], [1, 2, 1, 2], [1.0, 1.0, 1.0, 2.0], 2, 2) @test sparse([1, 1, 2, 2, 2], [1, 2, 1, 2, 2], -1.0, 2, 2, *) == sparse([1, 1, 2, 2], [1, 2, 1, 2], [-1.0, -1.0, -1.0, 1.0], 2, 2) + @test sparse(sparse(Int32.(1:5), Int32.(1:5), trues(5))') isa SparseMatrixCSC{Bool,Int32} end @testset "SparseMatrixCSC construction from UniformScaling" begin @@ -673,8 +674,6 @@ end @testset "common error checking of [c]transpose! methods (ftranspose!)" begin @test_throws DimensionMismatch transpose!(A[:, 1:(smalldim - 1)], A) @test_throws DimensionMismatch transpose!(A[1:(smalldim - 1), 1], A) - @test_throws ArgumentError transpose!((B = similar(A); resize!(rowvals(B), nnz(A) - 1); B), A) - @test_throws ArgumentError transpose!((B = similar(A); resize!(nonzeros(B), nnz(A) - 1); B), A) end @testset "common error checking of permute[!] methods / source-perm compat" begin @test_throws DimensionMismatch permute(A, p[1:(end - 1)], q) @@ -2167,6 +2166,12 @@ end @test issparse(LinearAlgebra.UnitLowerTriangular(Array(m))) == false @test issparse(UpperTriangular(Array(m))) == false @test issparse(LinearAlgebra.UnitUpperTriangular(Array(m))) == false + @test issparse(Base.ReshapedArray(m, (20, 5), ())) + @test issparse(@view m[1:3, :]) + + # greater nesting + @test issparse(Symmetric(UpperTriangular(m))) + @test issparse(Symmetric(UpperTriangular(Array(m)))) == false end @testset "issparse for sparse vectors #34253" begin @@ -2416,19 +2421,6 @@ end @test String(take!(io)) == "⠛⠛" end -@testset "check buffers" for n in 1:3 - local A - rowval = [1,2,3] - nzval1 = Int[] - nzval2 = [1,1,1] - A = SparseMatrixCSC(n, n, [1:n+1;], rowval, nzval1) - @test nnz(A) == n - @test_throws BoundsError A[n,n] - A = SparseMatrixCSC(n, n, [1:n+1;], rowval, nzval2) - @test nnz(A) == n - @test A == Matrix(I, n, n) -end - @testset "reverse search direction if step < 0 #21986" begin local A, B A = guardseed(1234) do @@ -2487,22 +2479,22 @@ end @test typeof(simA) == typeof(A) @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(rowvals(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) - # test similar with entry type and Dims{2} specification (preserves storage space only) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 + # test similar with entry type and Dims{2} specification (empty storage space) simA = similar(A, Float32, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32,eltype(getcolptr(A))} @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(rowvals(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type, index type, and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, Int8, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32, Int8} @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(rowvals(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with Dims{1} specification (preserves nothing) simA = similar(A, (6,)) @test typeof(simA) == SparseVector{eltype(nonzeros(A)),eltype(getcolptr(A))} @@ -2530,8 +2522,6 @@ end # count should throw for sparse arrays for which zero(eltype) does not exist @test_throws MethodError count(SparseMatrixCSC(2, 2, Int[1, 2, 3], Int[1, 2], Any[true, true])) @test_throws MethodError count(SparseVector(2, Int[1], Any[true])) - # count should run only over nonzeros(S)[1:nnz(S)], not nonzeros(S) in full - @test count(SparseMatrixCSC(2, 2, Int[1, 2, 3], Int[1, 2], Bool[true, true, true])) == 2 end @testset "sparse findprev/findnext operations" begin @@ -2599,15 +2589,6 @@ end @test sum(s, dims=2) == reshape([1, 2, 3], 3, 1) end -@testset "mapreduce of sparse matrices with trailing elements in nzval #26534" begin - B = SparseMatrixCSC{Int,Int}(2, 3, - [1, 3, 4, 5], - [1, 2, 1, 2, 999, 999, 999, 999], - [1, 2, 3, 6, 999, 999, 999, 999] - ) - @test maximum(B) == 6 -end - _length_or_count_or_five(::Colon) = 5 _length_or_count_or_five(x::AbstractVector{Bool}) = count(x) _length_or_count_or_five(x) = length(x) @@ -2883,19 +2864,6 @@ end @test sparse(deepwrap(A)) == Matrix(deepwrap(B)) end -@testset "unary operations on matrices where length(nzval)>nnz" begin - # this should create a sparse matrix with length(nzval)>nnz - A = SparseMatrixCSC(Complex{BigInt}[1+im 2+2im]')'[1:1, 2:2] - # ...ensure it does! If necessary, the test needs to be updated to use - # another mechanism to create a suitable A. - resize!(nonzeros(A), 2) - @assert length(nonzeros(A)) > nnz(A) - @test -A == fill(-2-2im, 1, 1) - @test conj(A) == fill(2-2im, 1, 1) - conj!(A) - @test A == fill(2-2im, 1, 1) -end - @testset "issue #31453" for T in [UInt8, Int8, UInt16, Int16, UInt32, Int32] i = Int[1, 2] j = Int[2, 1] @@ -2945,14 +2913,8 @@ end @test_throws ArgumentError SparseMatrixCSC(10, 3, [1,2,1,2], Int[], Float64[]) # rowwal (and nzval) short @test_throws ArgumentError SparseMatrixCSC(10, 3, [1,2,2,4], [1,2], Float64[]) - # nzval short - @test SparseMatrixCSC(10, 3, [1,2,2,4], [1,2,3], Float64[]) !== nothing - # length(rowval) >= typemax - @test_throws ArgumentError SparseMatrixCSC(5, 1, Int8[1,2], fill(Int8(1),127), Int[1,2,3]) - @test SparseMatrixCSC{Int,Int8}(5, 1, Int8[1,2], fill(Int8(1),127), Int[1,2,3]) != 0 # length(nzval) >= typemax - @test_throws ArgumentError SparseMatrixCSC(5, 1, Int8[1,2], Int8[1], fill(7, 127)) - @test SparseMatrixCSC{Int,Int8}(5, 1, Int8[1,2], Int8[1], fill(7, 127)) != 0 + @test_throws ArgumentError SparseMatrixCSC(5, 1, Int8[1,2], fill(Int8(1), 127), fill(7, 127)) # length(I) >= typemax @test_throws ArgumentError sparse(UInt8.(1:255), fill(UInt8(1), 255), fill(1, 255)) diff --git a/stdlib/SparseArrays/test/sparsevector.jl b/stdlib/SparseArrays/test/sparsevector.jl index 602818678908b..2dc9738111a87 100644 --- a/stdlib/SparseArrays/test/sparsevector.jl +++ b/stdlib/SparseArrays/test/sparsevector.jl @@ -33,6 +33,9 @@ x1_full[SparseArrays.nonzeroinds(spv_x1)] = nonzeros(spv_x1) @test SparseArrays.nonzeroinds(x) == [2, 5, 6] @test nonzeros(x) == [1.25, -0.75, 3.5] @test count(SparseVector(8, [2, 5, 6], [true,false,true])) == 2 + y = SparseVector(typemax(Int128), Int128[4], [5]) + @test y isa SparseVector{Int,Int128} + @test @inferred size(y) == (@inferred(length(y)),) end @testset "isstored" begin @@ -75,7 +78,11 @@ end @testset "other constructors" begin # construct empty sparse vector - @test exact_equal(spzeros(Float64, 8), SparseVector(8, Int[], Float64[])) + for dims in (8, (8,)) + @test exact_equal(spzeros(dims), SparseVector(8, Int[], Float64[])) + @test exact_equal(spzeros(Float64, dims), SparseVector(8, Int[], Float64[])) + @test exact_equal(spzeros(Float64, Int16, dims), SparseVector(8, Int16[], Float64[])) + end @testset "from list of indices and values" begin @test exact_equal( @@ -789,6 +796,19 @@ end @test sum(x) == 4.0 @test sum(abs, x) == 5.5 @test sum(abs2, x) == 14.375 + @test @inferred(sum(t -> true, x)) === 8 + @test @inferred(sum(t -> abs(t) + one(t), x)) == 13.5 + + @test @inferred(sum(t -> true, spzeros(Float64, 8))) === 8 + @test @inferred(sum(t -> abs(t) + one(t), spzeros(Float64, 8))) === 8.0 + + # reducing over an empty collection + # FIXME sum(f, []) throws, should be fixed both for generic and sparse vectors + @test_broken sum(t -> true, zeros(Float64, 0)) === 0 + @test_broken sum(t -> true, spzeros(Float64, 0)) === 0 + @test @inferred(sum(abs2, spzeros(Float64, 0))) === 0.0 + @test_broken sum(t -> abs(t) + one(t), zeros(Float64, 0)) === 0.0 + @test_broken sum(t -> abs(t) + one(t), spzeros(Float64, 0)) === 0.0 @test norm(x) == sqrt(14.375) @test norm(x, 1) == 5.5 @@ -802,6 +822,12 @@ end @test minimum(x) == -0.75 @test maximum(abs, x) == 3.5 @test minimum(abs, x) == 0.0 + @test @inferred(minimum(t -> true, x)) === true + @test @inferred(maximum(t -> true, x)) === true + @test @inferred(minimum(t -> abs(t) + one(t), x)) == 1.0 + @test @inferred(maximum(t -> abs(t) + one(t), x)) == 4.5 + @test @inferred(minimum(t -> t + one(t), x)) == 0.25 + @test @inferred(maximum(t -> -abs(t) + one(t), x)) == 1.0 end let x = abs.(spv_x1) @@ -826,6 +852,15 @@ end @test minimum(x) == 0.0 @test maximum(abs, x) == 0.0 @test minimum(abs, x) == 0.0 + @test @inferred(minimum(t -> true, x)) === true + @test @inferred(maximum(t -> true, x)) === true + @test @inferred(minimum(t -> abs(t) + one(t), x)) === 1.0 + @test @inferred(maximum(t -> abs(t) + one(t), x)) === 1.0 + end + + let x = spzeros(Float64, 0) + @test_throws ArgumentError minimum(t -> true, x) + @test_throws ArgumentError maximum(t -> true, x) end end @@ -1050,6 +1085,10 @@ end @test y == Af'x2f end end + @testset "ldiv with different element types (#40171)" begin + sA = sparse(Int16.(1:4), Int16.(1:4), ones(4)) + @test all(ldiv!(LowerTriangular(sA), ones(4)) .≈ 1.) + end @testset "ldiv ops with triangular matrices and sparse vecs (#14005)" begin m = 10 sparsefloatvecs = SparseVector[sprand(m, 0.4) for k in 1:3] @@ -1383,27 +1422,27 @@ end # test entry points to similar with entry type, index type, and non-Dims shape specification @test similar(A, Float32, Int8, 6, 6) == similar(A, Float32, Int8, (6, 6)) @test similar(A, Float32, Int8, 6) == similar(A, Float32, Int8, (6,)) - # test similar with Dims{2} specification (preserves storage space only, not stored-entry structure) + # test similar with Dims{2} specification (preserves allocated storage space only, not stored-entry structure) simA = similar(A, (6,6)) @test typeof(simA) == SparseMatrixCSC{eltype(nonzeros(A)),eltype(nonzeroinds(A))} @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(nonzeroinds(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) - # test similar with entry type and Dims{2} specification (preserves storage space only) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 + # test similar with entry type and Dims{2} specification (preserves allocated storage space only) simA = similar(A, Float32, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32,eltype(nonzeroinds(A))} @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(nonzeroinds(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 # test similar with entry type, index type, and Dims{2} specification (preserves storage space only) simA = similar(A, Float32, Int8, (6,6)) @test typeof(simA) == SparseMatrixCSC{Float32, Int8} @test size(simA) == (6,6) @test getcolptr(simA) == fill(1, 6+1) - @test length(rowvals(simA)) == length(nonzeroinds(A)) - @test length(nonzeros(simA)) == length(nonzeros(A)) + @test length(rowvals(simA)) == 0 + @test length(nonzeros(simA)) == 0 end @testset "Fast operations on full column views" begin diff --git a/stdlib/SuiteSparse.version b/stdlib/SuiteSparse.version new file mode 100644 index 0000000000000..da54441dc4041 --- /dev/null +++ b/stdlib/SuiteSparse.version @@ -0,0 +1,2 @@ +SUITESPARSE_BRANCH = master +SUITESPARSE_SHA1 = ec4b40ad9c0490ebf0969a41d4f880620db3f6f9 diff --git a/stdlib/SuiteSparse/Project.toml b/stdlib/SuiteSparse/Project.toml deleted file mode 100644 index 0312b1625f7e3..0000000000000 --- a/stdlib/SuiteSparse/Project.toml +++ /dev/null @@ -1,19 +0,0 @@ -name = "SuiteSparse" -uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9" - -[deps] -Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" -LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" -SuiteSparse_jll = "bea87d4a-7f5b-5778-9afe-8cc45184846c" - -[extras] -DelimitedFiles = "8bb1440f-4735-579b-a4ab-409b98df4dab" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" -Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[targets] -test = ["Test", "Printf", "Random", "DelimitedFiles", "Serialization"] diff --git a/stdlib/SuiteSparse/docs/src/index.md b/stdlib/SuiteSparse/docs/src/index.md deleted file mode 100644 index e8654caf943b4..0000000000000 --- a/stdlib/SuiteSparse/docs/src/index.md +++ /dev/null @@ -1,34 +0,0 @@ -# Sparse Linear Algebra - -```@meta -DocTestSetup = :(using LinearAlgebra, SparseArrays, SuiteSparse) -``` - -Sparse matrix solvers call functions from [SuiteSparse](http://suitesparse.com). The following factorizations are available: - -| Type | Description | -|:--------------------------------- |:--------------------------------------------- | -| `SuiteSparse.CHOLMOD.Factor` | Cholesky factorization | -| `SuiteSparse.UMFPACK.UmfpackLU` | LU factorization | -| `SuiteSparse.SPQR.QRSparse` | QR factorization | - -Other solvers such as [Pardiso.jl](https://github.com/JuliaSparse/Pardiso.jl/) are as external packages. [Arpack.jl](https://julialinearalgebra.github.io/Arpack.jl/stable/) provides `eigs` and `svds` for iterative solution of eigensystems and singular value decompositions. - -These factorizations are described in the [`Linear Algebra`](@ref man-linalg) section of the manual: -1. [`cholesky`](@ref) -2. [`ldlt`](@ref) -3. [`lu`](@ref) -4. [`qr`](@ref) - -```@docs -SuiteSparse.CHOLMOD.lowrankupdate -SuiteSparse.CHOLMOD.lowrankupdate! -SuiteSparse.CHOLMOD.lowrankdowndate -SuiteSparse.CHOLMOD.lowrankdowndate! -SuiteSparse.CHOLMOD.lowrankupdowndate! -``` - - -```@meta -DocTestSetup = nothing -``` diff --git a/stdlib/SuiteSparse/src/SuiteSparse.jl b/stdlib/SuiteSparse/src/SuiteSparse.jl deleted file mode 100644 index e07e6aaea1c5a..0000000000000 --- a/stdlib/SuiteSparse/src/SuiteSparse.jl +++ /dev/null @@ -1,31 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -module SuiteSparse - -import Base: \ -import LinearAlgebra: ldiv!, rdiv! - -## Functions to switch to 0-based indexing to call external sparse solvers - -# Convert from 1-based to 0-based indices -function decrement!(A::AbstractArray{T}) where T<:Integer - for i in eachindex(A); A[i] -= oneunit(T) end - A -end -decrement(A::AbstractArray{<:Integer}) = decrement!(copy(A)) - -# Convert from 0-based to 1-based indices -function increment!(A::AbstractArray{T}) where T<:Integer - for i in eachindex(A); A[i] += oneunit(T) end - A -end -increment(A::AbstractArray{<:Integer}) = increment!(copy(A)) - -if Base.USE_GPL_LIBS - include("umfpack.jl") - include("cholmod.jl") - include("spqr.jl") - include("deprecated.jl") -end - -end # module SuiteSparse diff --git a/stdlib/SuiteSparse/src/cholmod.jl b/stdlib/SuiteSparse/src/cholmod.jl deleted file mode 100644 index cbfee4a30cb41..0000000000000 --- a/stdlib/SuiteSparse/src/cholmod.jl +++ /dev/null @@ -1,1875 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -# Theoretically CHOLMOD supports both Int32 and Int64 indices on 64-bit. -# However experience suggests that using both in the same session causes memory -# leaks, so we restrict indices to be SuiteSparse_long (see cholmod_h.jl). -# Ref: https://github.com/JuliaLang/julia/issues/12664 - -# Additionally, only Float64/ComplexF64 are supported in practice. -# Ref: https://github.com/JuliaLang/julia/issues/25986 - -module CHOLMOD - -import Base: (*), convert, copy, eltype, getindex, getproperty, show, size, - IndexStyle, IndexLinear, IndexCartesian, adjoint, axes -using Base: require_one_based_indexing - -using LinearAlgebra -import LinearAlgebra: (\), - cholesky, cholesky!, det, diag, ishermitian, isposdef, - issuccess, issymmetric, ldlt, ldlt!, logdet - -using SparseArrays -using SparseArrays: getcolptr -import Libdl - -export - Dense, - Factor, - Sparse - -import SparseArrays: AbstractSparseMatrix, SparseMatrixCSC, indtype, sparse, spzeros, nnz - -import ..increment, ..increment!, ..decrement, ..decrement! - -######### -# Setup # -######### - -include("cholmod_h.jl") - -const CHOLMOD_MIN_VERSION = v"2.1.1" - -const common_struct = Vector{Vector{UInt8}}() - -const common_supernodal = Vector{Ptr{Cint}}() -const common_final_ll = Vector{Ptr{Cint}}() -const common_print = Vector{Ptr{Cint}}() -const common_itype = Vector{Ptr{Cint}}() -const common_dtype = Vector{Ptr{Cint}}() -const common_nmethods = Vector{Ptr{Cint}}() -const common_postorder = Vector{Ptr{Cint}}() - -### These offsets are defined in SuiteSparse_wrapper.c -const common_size = ccall((:jl_cholmod_common_size,:libsuitesparse_wrapper),Int,()) - -const cholmod_com_offsets = Vector{Csize_t}(undef, 19) -ccall((:jl_cholmod_common_offsets, :libsuitesparse_wrapper), - Nothing, (Ptr{Csize_t},), cholmod_com_offsets) - -## macro to generate the name of the C function according to the integer type -macro cholmod_name(nm) - string("cholmod_l_", nm) -end - -function start(a::Vector{UInt8}) - @isok ccall((@cholmod_name("start"), :libcholmod), - Cint, (Ptr{UInt8},), a) - return a -end - -function finish(a::Vector{UInt8}) - @isok ccall((@cholmod_name("finish"), :libcholmod), - Cint, (Ptr{UInt8},), a) - return a -end - -function defaults(a::Vector{UInt8}) - @isok ccall((@cholmod_name("defaults"), :libcholmod), - Cint, (Ptr{UInt8},), a) - return a -end - -const build_version_array = Vector{Cint}(undef, 3) -ccall((:jl_cholmod_version, :libsuitesparse_wrapper), Cint, (Ptr{Cint},), build_version_array) -const build_version = VersionNumber(build_version_array...) - -function __init__() - try - ### Check if the linked library is compatible with the Julia code - if Libdl.dlsym_e(Libdl.dlopen("libcholmod"), :cholmod_version) != C_NULL - current_version_array = Vector{Cint}(undef, 3) - ccall((:cholmod_version, :libcholmod), Cint, (Ptr{Cint},), current_version_array) - current_version = VersionNumber(current_version_array...) - else # CHOLMOD < 2.1.1 does not include cholmod_version() - current_version = v"0.0.0" - end - - - if current_version < CHOLMOD_MIN_VERSION - @warn """ - CHOLMOD version incompatibility - - Julia was compiled with CHOLMOD version $build_version. It is - currently linked with a version older than - $(CHOLMOD_MIN_VERSION). This might cause Julia to - terminate when working with sparse matrix factorizations, - e.g. solving systems of equations with \\. - - It is recommended that you use Julia with a recent version - of CHOLMOD, or download the generic binaries - from www.julialang.org, which ship with the correct - versions of all dependencies. - """ - elseif build_version_array[1] != current_version_array[1] - @warn """ - CHOLMOD version incompatibility - - Julia was compiled with CHOLMOD version $build_version. It is - currently linked with version $current_version. - This might cause Julia to terminate when working with - sparse matrix factorizations, e.g. solving systems of - equations with \\. - - It is recommended that you use Julia with the same major - version of CHOLMOD as the one used during the build, or - download the generic binaries from www.julialang.org, - which ship with the correct versions of all dependencies. - """ - end - - intsize = Int(ccall((:jl_cholmod_sizeof_long,:libsuitesparse_wrapper),Csize_t,())) - if intsize != 4length(IndexTypes) - @error """ - CHOLMOD integer size incompatibility - - Julia was compiled with a version of CHOLMOD that - supported $(32length(IndexTypes)) bit integers. It is - currently linked with version that supports $(8intsize) - integers. This might cause Julia to terminate when - working with sparse matrix factorizations, e.g. solving - systems of equations with \\. - - This problem can be fixed by modifying the Julia build - configuration or by downloading the OS X or generic - Linux binary from www.julialang.org, which include - the correct versions of all dependencies. - """ - end - - ### Initiate CHOLMOD - ### common_struct controls the type of factorization and keeps pointers - ### to temporary memory. We need to manage a copy for each thread. - nt = Threads.nthreads() - resize!(common_struct , nt) - resize!(common_supernodal, nt) - resize!(common_final_ll , nt) - resize!(common_print , nt) - resize!(common_itype , nt) - resize!(common_dtype , nt) - resize!(common_nmethods , nt) - resize!(common_postorder , nt) - for i in 1:nt - common_struct[i] = fill(0xff, common_size) - - common_supernodal[i] = pointer(common_struct[i], cholmod_com_offsets[4] + 1) - common_final_ll[i] = pointer(common_struct[i], cholmod_com_offsets[7] + 1) - common_print[i] = pointer(common_struct[i], cholmod_com_offsets[13] + 1) - common_itype[i] = pointer(common_struct[i], cholmod_com_offsets[18] + 1) - common_dtype[i] = pointer(common_struct[i], cholmod_com_offsets[19] + 1) - common_nmethods[i] = pointer(common_struct[i], cholmod_com_offsets[15] + 1) - common_postorder[i] = pointer(common_struct[i], cholmod_com_offsets[17] + 1) - - start(common_struct[i]) # initializes CHOLMOD - set_print_level(common_struct[i], 0) # no printing from CHOLMOD by default - end - - # Register gc tracked allocator if CHOLMOD is new enough - if current_version >= v"3.0.0" - cnfg = cglobal((:SuiteSparse_config, :libsuitesparseconfig), Ptr{Cvoid}) - unsafe_store!(cnfg, cglobal(:jl_malloc, Ptr{Cvoid}), 1) - unsafe_store!(cnfg, cglobal(:jl_calloc, Ptr{Cvoid}), 2) - unsafe_store!(cnfg, cglobal(:jl_realloc, Ptr{Cvoid}), 3) - unsafe_store!(cnfg, cglobal(:jl_free, Ptr{Cvoid}), 4) - end - - catch ex - @error "Error during initialization of module CHOLMOD" exception=ex,catch_backtrace() - end -end - -function set_print_level(cm::Vector{UInt8}, lev::Integer) - unsafe_store!(common_print[Threads.threadid()], lev) -end - -#################### -# Type definitions # -#################### - -abstract type SuiteSparseStruct end - -# The three core data types for CHOLMOD: Dense, Sparse and Factor. -# CHOLMOD manages the memory, so the Julia versions only wrap a -# pointer to a struct. Therefore finalizers should be registered each -# time a pointer is returned from CHOLMOD. - -# Dense -struct C_Dense{T<:VTypes} <: SuiteSparseStruct - nrow::Csize_t - ncol::Csize_t - nzmax::Csize_t - d::Csize_t - x::Ptr{T} - z::Ptr{Cvoid} - xtype::Cint - dtype::Cint -end - -mutable struct Dense{Tv<:VTypes} <: DenseMatrix{Tv} - ptr::Ptr{C_Dense{Tv}} - function Dense{Tv}(ptr::Ptr{C_Dense{Tv}}) where Tv<:VTypes - if ptr == C_NULL - throw(ArgumentError("dense matrix construction failed for " * - "unknown reasons. Please submit a bug report.")) - end - s = unsafe_load(ptr) - if s.xtype != xtyp(Tv) - free!(ptr) - throw(CHOLMODException("xtype=$(s.xtype) not supported")) - elseif s.dtype != dtyp(Tv) - free!(ptr) - throw(CHOLMODException("dtype=$(s.dtype) not supported")) - end - A = new(ptr) - finalizer(free!, A) - return A - end -end -Dense(p::Ptr{C_Dense{Tv}}) where {Tv<:VTypes} = Dense{Tv}(p) - -# Sparse -# allow Cvoid pointer for reading matrices of unknown type from files as in -# cholmod_read_sparse -struct C_Sparse{Tv<:Union{Cvoid, VTypes}} <: SuiteSparseStruct - nrow::Csize_t - ncol::Csize_t - nzmax::Csize_t - p::Ptr{SuiteSparse_long} - i::Ptr{SuiteSparse_long} - nz::Ptr{SuiteSparse_long} - x::Ptr{Tv} - z::Ptr{Cvoid} - stype::Cint - itype::Cint - xtype::Cint - dtype::Cint - sorted::Cint - packed::Cint -end - -mutable struct Sparse{Tv<:VTypes} <: AbstractSparseMatrix{Tv,SuiteSparse_long} - ptr::Ptr{C_Sparse{Tv}} - function Sparse{Tv}(ptr::Ptr{C_Sparse{Tv}}) where Tv<:VTypes - if ptr == C_NULL - throw(ArgumentError("sparse matrix construction failed for " * - "unknown reasons. Please submit a bug report.")) - end - s = unsafe_load(ptr) - if s.itype != ityp(SuiteSparse_long) - free!(ptr) - throw(CHOLMODException("itype=$(s.itype) not supported")) - elseif s.xtype != xtyp(Tv) - free!(ptr) - throw(CHOLMODException("xtype=$(s.xtype) not supported")) - elseif s.dtype != dtyp(Tv) - free!(ptr) - throw(CHOLMODException("dtype=$(s.dtype) not supported")) - end - A = new(ptr) - finalizer(free!, A) - return A - end -end -Sparse(p::Ptr{C_Sparse{Tv}}) where {Tv<:VTypes} = Sparse{Tv}(p) - -# Useful when reading in files, but not type stable -function Sparse(p::Ptr{C_Sparse{Cvoid}}) - if p == C_NULL - throw(ArgumentError("sparse matrix construction failed for " * - "unknown reasons. Please submit a bug report.")) - end - s = unsafe_load(p) - Tv = s.xtype == REAL ? Float64 : ComplexF64 - Sparse(convert(Ptr{C_Sparse{Tv}}, p)) -end - -Base.unsafe_convert(::Type{Ptr{Tv}}, A::Sparse{Tv}) where {Tv} = getfield(A, :ptr) - -# Factor -# Cvoid is used for pattern-only factors -struct C_Factor{Tv<:VTypes} <: SuiteSparseStruct - n::Csize_t - minor::Csize_t - Perm::Ptr{SuiteSparse_long} - ColCount::Ptr{SuiteSparse_long} - @static if build_version >= v"2.1.0" - IPerm::Ptr{SuiteSparse_long} # this pointer was added in version 2.1.0 - end - nzmax::Csize_t - p::Ptr{SuiteSparse_long} - i::Ptr{SuiteSparse_long} - x::Ptr{Tv} - z::Ptr{Cvoid} - nz::Ptr{SuiteSparse_long} - next::Ptr{SuiteSparse_long} - prev::Ptr{SuiteSparse_long} - nsuper::Csize_t - ssize::Csize_t - xsize::Csize_t - maxcsize::Csize_t - maxesize::Csize_t - super::Ptr{SuiteSparse_long} - pi::Ptr{SuiteSparse_long} - px::Ptr{SuiteSparse_long} - s::Ptr{SuiteSparse_long} - ordering::Cint - is_ll::Cint - is_super::Cint - is_monotonic::Cint - itype::Cint - xtype::Cint - dtype::Cint -end - -mutable struct Factor{Tv<:VTypes} <: Factorization{Tv} - ptr::Ptr{C_Factor{Tv}} - function Factor{Tv}(ptr::Ptr{C_Factor{Tv}}, register_finalizer = true) where Tv - if ptr == C_NULL - throw(ArgumentError("factorization construction failed for " * - "unknown reasons. Please submit a bug report.")) - end - s = unsafe_load(ptr) - if s.itype != ityp(SuiteSparse_long) - free!(ptr) - throw(CHOLMODException("itype=$(s.itype) not supported")) - elseif s.xtype != xtyp(Tv) && s.xtype != PATTERN - free!(ptr) - throw(CHOLMODException("xtype=$(s.xtype) not supported")) - elseif s.dtype != dtyp(Tv) - free!(ptr) - throw(CHOLMODException("dtype=$(s.dtype) not supported")) - end - F = new(ptr) - if register_finalizer - finalizer(free!, F) - end - return F - end -end -Factor(ptr::Ptr{C_Factor{Tv}}) where {Tv<:VTypes} = Factor{Tv}(ptr) -Factor(x::Factor) = x - -Base.adjoint(F::Factor) = Adjoint(F) -Base.transpose(F::Factor) = Transpose(F) - -# All pointer loads should be checked to make sure that SuiteSparse is not called with -# a C_NULL pointer which could cause a segfault. Pointers are set to null -# when serialized so this can happen when multiple processes are in use. -function Base.unsafe_convert(::Type{Ptr{T}}, x::Union{Dense,Sparse,Factor}) where T<:SuiteSparseStruct - xp = getfield(x, :ptr) - if xp == C_NULL - throw(ArgumentError("pointer to the $T object is null. This can " * - "happen if the object has been serialized.")) - else - return xp - end -end -Base.pointer(x::Dense{Tv}) where {Tv} = Base.unsafe_convert(Ptr{C_Dense{Tv}}, x) -Base.pointer(x::Sparse{Tv}) where {Tv} = Base.unsafe_convert(Ptr{C_Sparse{Tv}}, x) -Base.pointer(x::Factor{Tv}) where {Tv} = Base.unsafe_convert(Ptr{C_Factor{Tv}}, x) - -# FactorComponent, for encoding particular factors from a factorization -mutable struct FactorComponent{Tv,S} <: AbstractMatrix{Tv} - F::Factor{Tv} - - function FactorComponent{Tv,S}(F::Factor{Tv}) where {Tv,S} - s = unsafe_load(pointer(F)) - if s.is_ll != 0 - if !(S === :L || S === :U || S === :PtL || S === :UP) - throw(CHOLMODException(string(S, " not supported for sparse ", - "LLt matrices; try :L, :U, :PtL, or :UP"))) - end - elseif !(S === :L || S === :U || S === :PtL || S === :UP || - S === :D || S === :LD || S === :DU || S === :PtLD || S === :DUP) - throw(CHOLMODException(string(S, " not supported for sparse LDLt ", - "matrices; try :L, :U, :PtL, :UP, :D, :LD, :DU, :PtLD, or :DUP"))) - end - new(F) - end -end -function FactorComponent(F::Factor{Tv}, sym::Symbol) where Tv - FactorComponent{Tv,sym}(F) -end - -Factor(FC::FactorComponent) = Factor(FC.F) - -################# -# Thin wrappers # -################# - -# Dense wrappers - -### cholmod_core_h ### -function allocate_dense(m::Integer, n::Integer, d::Integer, ::Type{Tv}) where {Tv<:VTypes} - Dense(ccall((@cholmod_name("allocate_dense"), :libcholmod), Ptr{C_Dense{Tv}}, - (Csize_t, Csize_t, Csize_t, Cint, Ptr{Cvoid}), - m, n, d, xtyp(Tv), common_struct[Threads.threadid()])) -end - -function free!(p::Ptr{C_Dense{Tv}}) where {Tv<:VTypes} - @isok ccall((@cholmod_name("free_dense"), :libcholmod), Cint, - (Ref{Ptr{C_Dense{Tv}}}, Ptr{Cvoid}), - p, common_struct[Threads.threadid()]) -end -function zeros(m::Integer, n::Integer, ::Type{Tv}) where Tv<:VTypes - Dense(ccall((@cholmod_name("zeros"), :libcholmod), Ptr{C_Dense{Tv}}, - (Csize_t, Csize_t, Cint, Ptr{UInt8}), - m, n, xtyp(Tv), common_struct[Threads.threadid()])) -end -zeros(m::Integer, n::Integer) = zeros(m, n, Float64) - -function ones(m::Integer, n::Integer, ::Type{Tv}) where Tv<:VTypes - Dense(ccall((@cholmod_name("ones"), :libcholmod), Ptr{C_Dense{Tv}}, - (Csize_t, Csize_t, Cint, Ptr{UInt8}), - m, n, xtyp(Tv), common_struct[Threads.threadid()])) -end -ones(m::Integer, n::Integer) = ones(m, n, Float64) - -function eye(m::Integer, n::Integer, ::Type{Tv}) where Tv<:VTypes - Dense(ccall((@cholmod_name("eye"), :libcholmod), Ptr{C_Dense{Tv}}, - (Csize_t, Csize_t, Cint, Ptr{UInt8}), - m, n, xtyp(Tv), common_struct[Threads.threadid()])) -end -eye(m::Integer, n::Integer) = eye(m, n, Float64) -eye(n::Integer) = eye(n, n, Float64) - -function copy(A::Dense{Tv}) where Tv<:VTypes - Dense(ccall((@cholmod_name("copy_dense"), :libcholmod), Ptr{C_Dense{Tv}}, - (Ptr{C_Dense{Tv}}, Ptr{UInt8}), - A, common_struct[Threads.threadid()])) -end - -function sort!(S::Sparse{Tv}) where Tv<:VTypes - @isok ccall((@cholmod_name("sort"), :libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - S, common_struct[Threads.threadid()]) - return S -end - -### cholmod_matrixops.h ### -function norm_dense(D::Dense{Tv}, p::Integer) where Tv<:VTypes - s = unsafe_load(pointer(D)) - if p == 2 - if s.ncol > 1 - throw(ArgumentError("2 norm only supported when matrix has one column")) - end - elseif p != 0 && p != 1 - throw(ArgumentError("second argument must be either 0 (Inf norm), 1, or 2")) - end - ccall((@cholmod_name("norm_dense"), :libcholmod), Cdouble, - (Ptr{C_Dense{Tv}}, Cint, Ptr{UInt8}), - D, p, common_struct[Threads.threadid()]) -end - -### cholmod_check.h ### -function check_dense(A::Dense{Tv}) where Tv<:VTypes - ccall((@cholmod_name("check_dense"), :libcholmod), Cint, - (Ptr{C_Dense{Tv}}, Ptr{UInt8}), - pointer(A), common_struct[Threads.threadid()]) != 0 -end - -# Non-Dense wrappers -### cholmod_core.h ### -function allocate_sparse(nrow::Integer, ncol::Integer, nzmax::Integer, - sorted::Bool, packed::Bool, stype::Integer, ::Type{Tv}) where {Tv<:VTypes} - Sparse(ccall((@cholmod_name("allocate_sparse"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Csize_t, Csize_t, Csize_t, Cint, - Cint, Cint, Cint, Ptr{Cvoid}), - nrow, ncol, nzmax, sorted, - packed, stype, xtyp(Tv), common_struct[Threads.threadid()])) -end - -function free!(ptr::Ptr{C_Sparse{Tv}}) where Tv<:VTypes - @isok ccall((@cholmod_name("free_sparse"), :libcholmod), Cint, - (Ref{Ptr{C_Sparse{Tv}}}, Ptr{UInt8}), - ptr, common_struct[Threads.threadid()]) -end - -function free!(ptr::Ptr{C_Factor{Tv}}) where Tv<:VTypes - # Warning! Important that finalizer doesn't modify the global Common struct. - @isok ccall((@cholmod_name("free_factor"), :libcholmod), Cint, - (Ref{Ptr{C_Factor{Tv}}}, Ptr{Cvoid}), - ptr, common_struct[Threads.threadid()]) -end - -function aat(A::Sparse{Tv}, fset::Vector{SuiteSparse_long}, mode::Integer) where Tv<:VRealTypes - Sparse(ccall((@cholmod_name("aat"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{SuiteSparse_long}, Csize_t, Cint, Ptr{UInt8}), - A, fset, length(fset), mode, common_struct[Threads.threadid()])) -end - -function sparse_to_dense(A::Sparse{Tv}) where Tv<:VTypes - Dense(ccall((@cholmod_name("sparse_to_dense"),:libcholmod), - Ptr{C_Dense{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - A, common_struct[Threads.threadid()])) -end -function dense_to_sparse(D::Dense{Tv}, ::Type{SuiteSparse_long}) where Tv<:VTypes - Sparse(ccall((@cholmod_name("dense_to_sparse"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Dense{Tv}}, Cint, Ptr{UInt8}), - D, true, common_struct[Threads.threadid()])) -end - -function factor_to_sparse!(F::Factor{Tv}) where Tv<:VTypes - ss = unsafe_load(pointer(F)) - ss.xtype == PATTERN && throw(CHOLMODException("only numeric factors are supported")) - Sparse(ccall((@cholmod_name("factor_to_sparse"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Factor{Tv}}, Ptr{UInt8}), - F, common_struct[Threads.threadid()])) -end - -function change_factor!(F::Factor{Tv}, to_ll::Bool, to_super::Bool, to_packed::Bool, - to_monotonic::Bool) where Tv<:VTypes - @isok ccall((@cholmod_name("change_factor"),:libcholmod), Cint, - (Cint, Cint, Cint, Cint, Cint, Ptr{C_Factor{Tv}}, Ptr{UInt8}), - xtyp(Tv), to_ll, to_super, to_packed, to_monotonic, F, common_struct[Threads.threadid()]) -end - -function check_sparse(A::Sparse{Tv}) where Tv<:VTypes - ccall((@cholmod_name("check_sparse"),:libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - A, common_struct[Threads.threadid()]) != 0 -end - -function check_factor(F::Factor{Tv}) where Tv<:VTypes - ccall((@cholmod_name("check_factor"),:libcholmod), Cint, - (Ptr{C_Factor{Tv}}, Ptr{UInt8}), - F, common_struct[Threads.threadid()]) != 0 -end - -function nnz(A::Sparse{Tv}) where Tv<:VTypes - ccall((@cholmod_name("nnz"),:libcholmod), Int, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - A, common_struct[Threads.threadid()]) -end - -function speye(m::Integer, n::Integer, ::Type{Tv}) where Tv<:VTypes - Sparse(ccall((@cholmod_name("speye"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Csize_t, Csize_t, Cint, Ptr{UInt8}), - m, n, xtyp(Tv), common_struct[Threads.threadid()])) -end - -function spzeros(m::Integer, n::Integer, nzmax::Integer, ::Type{Tv}) where Tv<:VTypes - Sparse(ccall((@cholmod_name("spzeros"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Csize_t, Csize_t, Csize_t, Cint, Ptr{UInt8}), - m, n, nzmax, xtyp(Tv), common_struct[Threads.threadid()])) -end - -function transpose_(A::Sparse{Tv}, values::Integer) where Tv<:VTypes - Sparse(ccall((@cholmod_name("transpose"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Cint, Ptr{UInt8}), - A, values, common_struct[Threads.threadid()])) -end - -function copy(F::Factor{Tv}) where Tv<:VTypes - Factor(ccall((@cholmod_name("copy_factor"),:libcholmod), - Ptr{C_Factor{Tv}}, - (Ptr{C_Factor{Tv}}, Ptr{UInt8}), - F, common_struct[Threads.threadid()])) -end -function copy(A::Sparse{Tv}) where Tv<:VTypes - Sparse(ccall((@cholmod_name("copy_sparse"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - A, common_struct[Threads.threadid()])) -end -function copy(A::Sparse{Tv}, stype::Integer, mode::Integer) where Tv<:VRealTypes - Sparse(ccall((@cholmod_name("copy"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Cint, Cint, Ptr{UInt8}), - A, stype, mode, common_struct[Threads.threadid()])) -end - -### cholmod_check.h ### -function print_sparse(A::Sparse{Tv}, name::String) where Tv<:VTypes - isascii(name) || error("non-ASCII name: $name") - set_print_level(common_struct[Threads.threadid()], 3) - @isok ccall((@cholmod_name("print_sparse"),:libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}, Ptr{UInt8}), - A, name, common_struct[Threads.threadid()]) - nothing -end -function print_factor(F::Factor{Tv}, name::String) where Tv<:VTypes - set_print_level(common_struct[Threads.threadid()], 3) - @isok ccall((@cholmod_name("print_factor"),:libcholmod), Cint, - (Ptr{C_Factor{Tv}}, Ptr{UInt8}, Ptr{UInt8}), - F, name, common_struct[Threads.threadid()]) - nothing -end - -### cholmod_matrixops.h ### -function ssmult(A::Sparse{Tv}, B::Sparse{Tv}, stype::Integer, - values::Bool, sorted::Bool) where Tv<:VRealTypes - lA = unsafe_load(pointer(A)) - lB = unsafe_load(pointer(B)) - if lA.ncol != lB.nrow - throw(DimensionMismatch("inner matrix dimensions do not fit")) - end - Sparse(ccall((@cholmod_name("ssmult"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{C_Sparse{Tv}}, Cint, Cint, - Cint, Ptr{UInt8}), - A, B, stype, values, - sorted, common_struct[Threads.threadid()])) -end - -function norm_sparse(A::Sparse{Tv}, norm::Integer) where Tv<:VTypes - if norm != 0 && norm != 1 - throw(ArgumentError("norm argument must be either 0 or 1")) - end - ccall((@cholmod_name("norm_sparse"), :libcholmod), Cdouble, - (Ptr{C_Sparse{Tv}}, Cint, Ptr{UInt8}), - A, norm, common_struct[Threads.threadid()]) -end - -function horzcat(A::Sparse{Tv}, B::Sparse{Tv}, values::Bool) where Tv<:VRealTypes - Sparse(ccall((@cholmod_name("horzcat"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{C_Sparse{Tv}}, Cint, Ptr{UInt8}), - A, B, values, common_struct[Threads.threadid()])) -end - -function scale!(S::Dense{Tv}, scale::Integer, A::Sparse{Tv}) where Tv<:VRealTypes - sS = unsafe_load(pointer(S)) - sA = unsafe_load(pointer(A)) - if sS.ncol != 1 && sS.nrow != 1 - throw(DimensionMismatch("first argument must be a vector")) - end - if scale == SCALAR && sS.nrow != 1 - throw(DimensionMismatch("scaling argument must have length one")) - elseif scale == ROW && sS.nrow*sS.ncol != sA.nrow - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * - "but matrix has $(sA.nrow) rows.")) - elseif scale == COL && sS.nrow*sS.ncol != sA.ncol - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * - "but matrix has $(sA.ncol) columns")) - elseif scale == SYM - if sA.nrow != sA.ncol - throw(DimensionMismatch("matrix must be square")) - elseif sS.nrow*sS.ncol != sA.nrow - throw(DimensionMismatch("scaling vector has length $(sS.nrow*sS.ncol), " * - "but matrix has $(sA.ncol) columns and rows")) - end - end - - sA = unsafe_load(pointer(A)) - @isok ccall((@cholmod_name("scale"),:libcholmod), Cint, - (Ptr{C_Dense{Tv}}, Cint, Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - S, scale, A, common_struct[Threads.threadid()]) - A -end - -function sdmult!(A::Sparse{Tv}, transpose::Bool, - α::Number, β::Number, X::Dense{Tv}, Y::Dense{Tv}) where Tv<:VTypes - m, n = size(A) - nc = transpose ? m : n - nr = transpose ? n : m - if nc != size(X, 1) - throw(DimensionMismatch("incompatible dimensions, $nc and $(size(X,1))")) - end - @isok ccall((@cholmod_name("sdmult"),:libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Cint, - Ref{ComplexF64}, Ref{ComplexF64}, - Ptr{C_Dense{Tv}}, Ptr{C_Dense{Tv}}, Ptr{UInt8}), - A, transpose, α, β, X, Y, common_struct[Threads.threadid()]) - Y -end - -function vertcat(A::Sparse{Tv}, B::Sparse{Tv}, values::Bool) where Tv<:VRealTypes - Sparse(ccall((@cholmod_name("vertcat"), :libcholmod), - Ptr{C_Sparse{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{C_Sparse{Tv}}, Cint, Ptr{UInt8}), - A, B, values, common_struct[Threads.threadid()])) -end - -function symmetry(A::Sparse{Tv}, option::Integer) where Tv<:VTypes - xmatched = Ref{SuiteSparse_long}() - pmatched = Ref{SuiteSparse_long}() - nzoffdiag = Ref{SuiteSparse_long}() - nzdiag = Ref{SuiteSparse_long}() - rv = ccall((@cholmod_name("symmetry"), :libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Cint, Ptr{SuiteSparse_long}, Ptr{SuiteSparse_long}, - Ptr{SuiteSparse_long}, Ptr{SuiteSparse_long}, Ptr{UInt8}), - A, option, xmatched, pmatched, - nzoffdiag, nzdiag, common_struct[Threads.threadid()]) - rv, xmatched[], pmatched[], nzoffdiag[], nzdiag[] -end - -# cholmod_cholesky.h -# For analyze, analyze_p, and factorize_p!, the Common argument must be -# supplied in order to control if the factorization is LLt or LDLt -function analyze(A::Sparse{Tv}, cmmn::Vector{UInt8}) where Tv<:VTypes - Factor(ccall((@cholmod_name("analyze"),:libcholmod), - Ptr{C_Factor{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - A, cmmn)) -end -function analyze_p(A::Sparse{Tv}, perm::Vector{SuiteSparse_long}, - cmmn::Vector{UInt8}) where Tv<:VTypes - length(perm) != size(A,1) && throw(BoundsError()) - Factor(ccall((@cholmod_name("analyze_p"),:libcholmod), - Ptr{C_Factor{Tv}}, - (Ptr{C_Sparse{Tv}}, Ptr{SuiteSparse_long}, Ptr{SuiteSparse_long}, - Csize_t, Ptr{UInt8}), - A, perm, C_NULL, 0, cmmn)) -end -function factorize!(A::Sparse{Tv}, F::Factor{Tv}, cmmn::Vector{UInt8}) where Tv<:VTypes - @isok ccall((@cholmod_name("factorize"),:libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Ptr{C_Factor{Tv}}, Ptr{UInt8}), - A, F, cmmn) - F -end -function factorize_p!(A::Sparse{Tv}, β::Real, F::Factor{Tv}, cmmn::Vector{UInt8}) where Tv<:VTypes - # note that β is passed as a complex number (double beta[2]), - # but the CHOLMOD manual says that only beta[0] (real part) is used - @isok ccall((@cholmod_name("factorize_p"),:libcholmod), Cint, - (Ptr{C_Sparse{Tv}}, Ref{ComplexF64}, Ptr{SuiteSparse_long}, Csize_t, - Ptr{C_Factor{Tv}}, Ptr{UInt8}), - A, β, C_NULL, 0, F, cmmn) - F -end - -function solve(sys::Integer, F::Factor{Tv}, B::Dense{Tv}) where Tv<:VTypes - if size(F,1) != size(B,1) - throw(DimensionMismatch("LHS and RHS should have the same number of rows. " * - "LHS has $(size(F,1)) rows, but RHS has $(size(B,1)) rows.")) - end - if !issuccess(F) - s = unsafe_load(pointer(F)) - if s.is_ll == 1 - throw(LinearAlgebra.PosDefException(s.minor)) - else - throw(LinearAlgebra.ZeroPivotException(s.minor)) - end - end - Dense(ccall((@cholmod_name("solve"),:libcholmod), Ptr{C_Dense{Tv}}, - (Cint, Ptr{C_Factor{Tv}}, Ptr{C_Dense{Tv}}, Ptr{UInt8}), - sys, F, B, common_struct[Threads.threadid()])) -end - -function spsolve(sys::Integer, F::Factor{Tv}, B::Sparse{Tv}) where Tv<:VTypes - if size(F,1) != size(B,1) - throw(DimensionMismatch("LHS and RHS should have the same number of rows. " * - "LHS has $(size(F,1)) rows, but RHS has $(size(B,1)) rows.")) - end - Sparse(ccall((@cholmod_name("spsolve"),:libcholmod), - Ptr{C_Sparse{Tv}}, - (Cint, Ptr{C_Factor{Tv}}, Ptr{C_Sparse{Tv}}, Ptr{UInt8}), - sys, F, B, common_struct[Threads.threadid()])) -end - -# Autodetects the types -function read_sparse(file::Libc.FILE, ::Type{SuiteSparse_long}) - ptr = ccall((@cholmod_name("read_sparse"), :libcholmod), - Ptr{C_Sparse{Cvoid}}, - (Ptr{Cvoid}, Ptr{UInt8}), - file.ptr, common_struct[Threads.threadid()]) - if ptr == C_NULL - throw(ArgumentError("sparse matrix construction failed. Check that input file is valid.")) - end - Sparse(ptr) -end - -function read_sparse(file::IO, T) - cfile = Libc.FILE(file) - try return read_sparse(cfile, T) - finally close(cfile) - end -end - -function get_perm(F::Factor) - s = unsafe_load(pointer(F)) - p = unsafe_wrap(Array, s.Perm, s.n, own = false) - p .+ 1 -end -get_perm(FC::FactorComponent) = get_perm(Factor(FC)) - -######################### -# High level interfaces # -######################### - -# Conversion/construction -function Dense{T}(A::StridedVecOrMat) where T<:VTypes - d = allocate_dense(size(A, 1), size(A, 2), stride(A, 2), T) - GC.@preserve d begin - s = unsafe_load(pointer(d)) - for (i, c) in enumerate(eachindex(A)) - unsafe_store!(s.x, A[c], i) - end - end - d -end -function Dense{T}(A::Union{Adjoint{<:Any, <:StridedVecOrMat}, Transpose{<:Any, <:StridedVecOrMat}}) where T<:VTypes - d = allocate_dense(size(A, 1), size(A, 2), size(A, 1), T) - GC.@preserve d begin - s = unsafe_load(pointer(d)) - for (i, c) in enumerate(eachindex(A)) - unsafe_store!(s.x, A[c], i) - end - end - d -end -function Dense(A::Union{StridedVecOrMat, Adjoint{<:Any, <:StridedVecOrMat}, Transpose{<:Any, <:StridedVecOrMat}}) - T = promote_type(eltype(A), Float64) - return Dense{T}(A) -end -Dense(A::Sparse) = sparse_to_dense(A) - -# This constructior assumes zero based colptr and rowval -function Sparse(m::Integer, n::Integer, - colptr0::Vector{SuiteSparse_long}, rowval0::Vector{SuiteSparse_long}, - nzval::Vector{Tv}, stype) where Tv<:VTypes - # checks - ## length of input - if length(colptr0) <= n - throw(ArgumentError("length of colptr0 must be at least n + 1 = $(n + 1) but was $(length(colptr0))")) - end - if colptr0[n + 1] > length(rowval0) - throw(ArgumentError("length of rowval0 is $(length(rowval0)) but value of colptr0 requires length to be at least $(colptr0[n + 1])")) - end - if colptr0[n + 1] > length(nzval) - throw(ArgumentError("length of nzval is $(length(nzval)) but value of colptr0 requires length to be at least $(colptr0[n + 1])")) - end - ## columns are sorted - iss = true - for i = 2:length(colptr0) - if !issorted(view(rowval0, colptr0[i - 1] + 1:colptr0[i])) - iss = false - break - end - end - - o = allocate_sparse(m, n, colptr0[n + 1], iss, true, stype, Tv) - s = unsafe_load(pointer(o)) - - unsafe_copyto!(s.p, pointer(colptr0), n + 1) - unsafe_copyto!(s.i, pointer(rowval0), colptr0[n + 1]) - unsafe_copyto!(s.x, pointer(nzval) , colptr0[n + 1]) - - @isok check_sparse(o) - - return o -end - -function Sparse(m::Integer, n::Integer, - colptr0::Vector{SuiteSparse_long}, - rowval0::Vector{SuiteSparse_long}, - nzval::Vector{<:VTypes}) - o = Sparse(m, n, colptr0, rowval0, nzval, 0) - - # sort indices - sort!(o) - - # check if array is symmetric and change stype if it is - if ishermitian(o) - change_stype!(o, -1) - end - o -end - -function Sparse{Tv}(A::SparseMatrixCSC, stype::Integer) where Tv<:VTypes - ## Check length of input. This should never fail but see #20024 - if length(getcolptr(A)) <= size(A, 2) - throw(ArgumentError("length of colptr must be at least size(A,2) + 1 = $(size(A, 2) + 1) but was $(length(getcolptr(A)))")) - end - if nnz(A) > length(rowvals(A)) - throw(ArgumentError("length of rowval is $(length(rowvals(A))) but value of colptr requires length to be at least $(nnz(A))")) - end - if nnz(A) > length(nonzeros(A)) - throw(ArgumentError("length of nzval is $(length(nonzeros(A))) but value of colptr requires length to be at least $(nnz(A))")) - end - - o = allocate_sparse(size(A, 1), size(A, 2), nnz(A), true, true, stype, Tv) - s = unsafe_load(pointer(o)) - for i = 1:(size(A, 2) + 1) - unsafe_store!(s.p, getcolptr(A)[i] - 1, i) - end - for i = 1:nnz(A) - unsafe_store!(s.i, rowvals(A)[i] - 1, i) - end - if Tv <: Complex && stype != 0 - # Need to remove any non real elements in the diagonal because, in contrast to - # BLAS/LAPACK these are not ignored by CHOLMOD. If even tiny imaginary parts are - # present CHOLMOD will fail with a non-positive definite/zero pivot error. - for j = 1:size(A, 2) - for ip = getcolptr(A)[j]:getcolptr(A)[j + 1] - 1 - v = nonzeros(A)[ip] - unsafe_store!(s.x, rowvals(A)[ip] == j ? Complex(real(v)) : v, ip) - end - end - elseif Tv == eltype(nonzeros(A)) - unsafe_copyto!(s.x, pointer(nonzeros(A)), nnz(A)) - else - for i = 1:nnz(A) - unsafe_store!(s.x, nonzeros(A)[i], i) - end - end - - @isok check_sparse(o) - - return o -end - -# handle promotion -function Sparse(A::SparseMatrixCSC{Tv,SuiteSparse_long}, stype::Integer) where {Tv} - T = promote_type(Tv, Float64) - return Sparse{T}(A, stype) -end - -# convert SparseVectors into CHOLMOD Sparse types through a mx1 CSC matrix -Sparse(A::SparseVector) = Sparse(SparseMatrixCSC(A)) -function Sparse(A::SparseMatrixCSC) - o = Sparse(A, 0) - # check if array is symmetric and change stype if it is - if ishermitian(o) - change_stype!(o, -1) - end - o -end - -Sparse(A::Symmetric{Tv, SparseMatrixCSC{Tv,Ti}}) where {Tv<:Real, Ti} = - Sparse(A.data, A.uplo == 'L' ? -1 : 1) -Sparse(A::Hermitian{Tv,SparseMatrixCSC{Tv,Ti}}) where {Tv, Ti} = - Sparse(A.data, A.uplo == 'L' ? -1 : 1) - -Sparse(A::Dense) = dense_to_sparse(A, SuiteSparse_long) -Sparse(L::Factor) = factor_to_sparse!(copy(L)) -function Sparse(filename::String) - open(filename) do f - return read_sparse(f, SuiteSparse_long) - end -end - -## conversion back to base Julia types -function Matrix{T}(D::Dense{T}) where T - s = unsafe_load(pointer(D)) - a = Matrix{T}(undef, s.nrow, s.ncol) - copyto!(a, D) -end - -Base.copyto!(dest::Base.PermutedDimsArrays.PermutedDimsArray, src::Dense) = _copy!(dest, src) # ambig -Base.copyto!(dest::Dense{T}, D::Dense{T}) where {T<:VTypes} = _copy!(dest, D) -Base.copyto!(dest::AbstractArray{T}, D::Dense{T}) where {T<:VTypes} = _copy!(dest, D) -Base.copyto!(dest::AbstractArray{T,2}, D::Dense{T}) where {T<:VTypes} = _copy!(dest, D) -Base.copyto!(dest::AbstractArray, D::Dense) = _copy!(dest, D) - -function _copy!(dest::AbstractArray, D::Dense) - require_one_based_indexing(dest) - s = unsafe_load(pointer(D)) - n = s.nrow*s.ncol - n <= length(dest) || throw(BoundsError(dest, n)) - if s.d == s.nrow && isa(dest, Array) - unsafe_copyto!(pointer(dest), s.x, s.d*s.ncol) - else - k = 0 - for j = 1:s.ncol - for i = 1:s.nrow - dest[k+=1] = unsafe_load(s.x, i + (j - 1)*s.d) - end - end - end - dest -end -Matrix(D::Dense{T}) where {T} = Matrix{T}(D) -function Vector{T}(D::Dense{T}) where T - if size(D, 2) > 1 - throw(DimensionMismatch("input must be a vector but had $(size(D, 2)) columns")) - end - copyto!(Vector{T}(undef, size(D, 1)), D) -end -Vector(D::Dense{T}) where {T} = Vector{T}(D) - -function SparseMatrixCSC{Tv,SuiteSparse_long}(A::Sparse{Tv}) where Tv - s = unsafe_load(pointer(A)) - if s.stype != 0 - throw(ArgumentError("matrix has stype != 0. Convert to matrix " * - "with stype == 0 before converting to SparseMatrixCSC")) - end - - B = SparseMatrixCSC(s.nrow, s.ncol, - increment(unsafe_wrap(Array, s.p, (s.ncol + 1,), own = false)), - increment(unsafe_wrap(Array, s.i, (s.nzmax,), own = false)), - copy(unsafe_wrap(Array, s.x, (s.nzmax,), own = false))) - - if s.sorted == 0 - return SparseArrays.sortSparseMatrixCSC!(B) - else - return B - end -end - -function Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}(A::Sparse{Float64}) - s = unsafe_load(pointer(A)) - if !issymmetric(A) - throw(ArgumentError("matrix is not symmetric")) - end - - B = Symmetric(SparseMatrixCSC(s.nrow, s.ncol, - increment(unsafe_wrap(Array, s.p, (s.ncol + 1,), own = false)), - increment(unsafe_wrap(Array, s.i, (s.nzmax,), own = false)), - copy(unsafe_wrap(Array, s.x, (s.nzmax,), own = false))), s.stype > 0 ? :U : :L) - - if s.sorted == 0 - return SparseArrays.sortSparseMatrixCSC!(B.data) - else - return B - end -end -convert(T::Type{Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}}, A::Sparse{Float64}) = T(A) - -function Hermitian{Tv,SparseMatrixCSC{Tv,SuiteSparse_long}}(A::Sparse{Tv}) where Tv<:VTypes - s = unsafe_load(pointer(A)) - if !ishermitian(A) - throw(ArgumentError("matrix is not Hermitian")) - end - - B = Hermitian(SparseMatrixCSC(s.nrow, s.ncol, - increment(unsafe_wrap(Array, s.p, (s.ncol + 1,), own = false)), - increment(unsafe_wrap(Array, s.i, (s.nzmax,), own = false)), - copy(unsafe_wrap(Array, s.x, (s.nzmax,), own = false))), s.stype > 0 ? :U : :L) - - if s.sorted == 0 - return SparseArrays.sortSparseMatrixCSC!(B.data) - else - return B - end -end -convert(T::Type{Hermitian{Tv,SparseMatrixCSC{Tv,SuiteSparse_long}}}, A::Sparse{Tv}) where {Tv<:VTypes} = T(A) - -function sparse(A::Sparse{Float64}) # Notice! Cannot be type stable because of stype - s = unsafe_load(pointer(A)) - if s.stype == 0 - return SparseMatrixCSC{Float64,SuiteSparse_long}(A) - end - return Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}(A) -end -function sparse(A::Sparse{ComplexF64}) # Notice! Cannot be type stable because of stype - s = unsafe_load(pointer(A)) - if s.stype == 0 - return SparseMatrixCSC{ComplexF64,SuiteSparse_long}(A) - end - return Hermitian{ComplexF64,SparseMatrixCSC{ComplexF64,SuiteSparse_long}}(A) -end -function sparse(F::Factor) - s = unsafe_load(pointer(F)) - if s.is_ll != 0 - L = Sparse(F) - A = sparse(L*L') - else - LD = sparse(F.LD) - L, d = getLd!(LD) - A = (L * Diagonal(d)) * L' - end - SparseArrays.sortSparseMatrixCSC!(A) - p = get_perm(F) - if p != [1:s.n;] - pinv = Vector{Int}(undef, length(p)) - for k = 1:length(p) - pinv[p[k]] = k - end - A = A[pinv,pinv] - end - A -end - -sparse(D::Dense) = sparse(Sparse(D)) - -function sparse(FC::FactorComponent{Tv,:L}) where Tv - F = Factor(FC) - s = unsafe_load(pointer(F)) - if s.is_ll == 0 - throw(CHOLMODException("sparse: supported only for :LD on LDLt factorizations")) - end - sparse(Sparse(F)) -end -sparse(FC::FactorComponent{Tv,:LD}) where {Tv} = sparse(Sparse(Factor(FC))) - -# Calculate the offset into the stype field of the cholmod_sparse_struct and -# change the value -let offset = fieldoffset(C_Sparse{Float64}, findfirst(name -> name === :stype, fieldnames(C_Sparse{Float64}))::Int) - global change_stype! - function change_stype!(A::Sparse, i::Integer) - unsafe_store!(convert(Ptr{Cint}, pointer(A)), i, div(offset, 4) + 1) - return A - end -end - -free!(A::Dense) = free!(pointer(A)) -free!(A::Sparse) = free!(pointer(A)) -free!(F::Factor) = free!(pointer(F)) - -eltype(::Type{Dense{T}}) where {T<:VTypes} = T -eltype(::Type{Factor{T}}) where {T<:VTypes} = T -eltype(::Type{Sparse{T}}) where {T<:VTypes} = T - -nnz(F::Factor) = nnz(Sparse(F)) - -function show(io::IO, F::Factor) - println(io, typeof(F)) - showfactor(io, F) -end - -function show(io::IO, FC::FactorComponent) - println(io, typeof(FC)) - showfactor(io, Factor(FC)) -end - -function showfactor(io::IO, F::Factor) - s = unsafe_load(pointer(F)) - print(io, """ - type: $(s.is_ll!=0 ? "LLt" : "LDLt") - method: $(s.is_super!=0 ? "supernodal" : "simplicial") - maxnnz: $(Int(s.nzmax)) - nnz: $(nnz(F)) - success: $(s.minor == size(F, 1)) - """) -end - -# getindex not defined for these, so don't use the normal array printer -show(io::IO, ::MIME"text/plain", FC::FactorComponent) = show(io, FC) -show(io::IO, ::MIME"text/plain", F::Factor) = show(io, F) - -isvalid(A::Dense) = check_dense(A) -isvalid(A::Sparse) = check_sparse(A) -isvalid(A::Factor) = check_factor(A) - -function size(A::Union{Dense,Sparse}) - s = unsafe_load(pointer(A)) - return (Int(s.nrow), Int(s.ncol)) -end -function size(F::Factor, i::Integer) - if i < 1 - throw(ArgumentError("dimension must be positive")) - end - s = unsafe_load(pointer(F)) - if i <= 2 - return Int(s.n) - end - return 1 -end -size(F::Factor) = (size(F, 1), size(F, 2)) -axes(A::Union{Dense,Sparse,Factor}) = map(Base.OneTo, size(A)) - -IndexStyle(::Dense) = IndexLinear() - -size(FC::FactorComponent, i::Integer) = size(FC.F, i) -size(FC::FactorComponent) = size(FC.F) - -adjoint(FC::FactorComponent{Tv,:L}) where {Tv} = FactorComponent{Tv,:U}(FC.F) -adjoint(FC::FactorComponent{Tv,:U}) where {Tv} = FactorComponent{Tv,:L}(FC.F) -adjoint(FC::FactorComponent{Tv,:PtL}) where {Tv} = FactorComponent{Tv,:UP}(FC.F) -adjoint(FC::FactorComponent{Tv,:UP}) where {Tv} = FactorComponent{Tv,:PtL}(FC.F) -adjoint(FC::FactorComponent{Tv,:D}) where {Tv} = FC -adjoint(FC::FactorComponent{Tv,:LD}) where {Tv} = FactorComponent{Tv,:DU}(FC.F) -adjoint(FC::FactorComponent{Tv,:DU}) where {Tv} = FactorComponent{Tv,:LD}(FC.F) -adjoint(FC::FactorComponent{Tv,:PtLD}) where {Tv} = FactorComponent{Tv,:DUP}(FC.F) -adjoint(FC::FactorComponent{Tv,:DUP}) where {Tv} = FactorComponent{Tv,:PtLD}(FC.F) - -function getindex(A::Dense, i::Integer) - s = unsafe_load(pointer(A)) - 0 < i <= s.nrow*s.ncol || throw(BoundsError()) - unsafe_load(s.x, i) -end - -IndexStyle(::Sparse) = IndexCartesian() -function getindex(A::Sparse{T}, i0::Integer, i1::Integer) where T - s = unsafe_load(pointer(A)) - !(1 <= i0 <= s.nrow && 1 <= i1 <= s.ncol) && throw(BoundsError()) - s.stype < 0 && i0 < i1 && return conj(A[i1,i0]) - s.stype > 0 && i0 > i1 && return conj(A[i1,i0]) - - r1 = Int(unsafe_load(s.p, i1) + 1) - r2 = Int(unsafe_load(s.p, i1 + 1)) - (r1 > r2) && return zero(T) - r1 = Int(searchsortedfirst(unsafe_wrap(Array, s.i, (s.nzmax,), own = false), - i0 - 1, r1, r2, Base.Order.Forward)) - ((r1 > r2) || (unsafe_load(s.i, r1) + 1 != i0)) ? zero(T) : unsafe_load(s.x, r1) -end - -@inline function getproperty(F::Factor, sym::Symbol) - if sym === :p - return get_perm(F) - elseif sym === :ptr - return getfield(F, :ptr) - else - return FactorComponent(F, sym) - end -end - -function getLd!(S::SparseMatrixCSC) - d = Vector{eltype(S)}(undef, size(S, 1)) - fill!(d, 0) - col = 1 - for k = 1:nnz(S) - while k >= getcolptr(S)[col+1] - col += 1 - end - if rowvals(S)[k] == col - d[col] = nonzeros(S)[k] - nonzeros(S)[k] = 1 - end - end - S, d -end - -## Multiplication -(*)(A::Sparse, B::Sparse) = ssmult(A, B, 0, true, true) -(*)(A::Sparse, B::Dense) = sdmult!(A, false, 1., 0., B, zeros(size(A, 1), size(B, 2))) -(*)(A::Sparse, B::VecOrMat) = (*)(A, Dense(B)) - -function *(A::Sparse{Tv}, adjB::Adjoint{Tv,Sparse{Tv}}) where Tv<:VRealTypes - B = adjB.parent - if A !== B - aa1 = transpose_(B, 2) - ## result of ssmult will have stype==0, contain numerical values and be sorted - return ssmult(A, aa1, 0, true, true) - end - - ## The A*A' case is handled by cholmod_aat. This routine requires - ## A->stype == 0 (storage of upper and lower parts). If necessary - ## the matrix A is first converted to stype == 0 - s = unsafe_load(pointer(A)) - fset = s.ncol == 0 ? SuiteSparse_long[] : SuiteSparse_long[0:s.ncol-1;] - if s.stype != 0 - aa1 = copy(A, 0, 1) - return aat(aa1, fset, 1) - else - return aat(A, fset, 1) - end -end - -function *(adjA::Adjoint{<:Any,<:Sparse}, B::Sparse) - A = adjA.parent - aa1 = transpose_(A, 2) - if A === B - return *(aa1, adjoint(aa1)) - end - ## result of ssmult will have stype==0, contain numerical values and be sorted - return ssmult(aa1, B, 0, true, true) -end - -*(adjA::Adjoint{<:Any,<:Sparse}, B::Dense) = - (A = adjA.parent; sdmult!(A, true, 1., 0., B, zeros(size(A, 2), size(B, 2)))) -*(adjA::Adjoint{<:Any,<:Sparse}, B::VecOrMat) = - (A = adjA.parent; *(adjoint(A), Dense(B))) - - -## Factorization methods - -## Compute that symbolic factorization only -function fact_(A::Sparse{<:VTypes}, cm::Array{UInt8}; - perm::Union{Nothing,AbstractVector{SuiteSparse_long}}=nothing, - postorder::Bool=true, userperm_only::Bool=true) - - sA = unsafe_load(pointer(A)) - sA.stype == 0 && throw(ArgumentError("sparse matrix is not symmetric/Hermitian")) - - if !postorder - unsafe_store!(common_postorder[Threads.threadid()], 0) - end - - if perm === nothing || isempty(perm) # TODO: deprecate empty perm - F = analyze(A, cm) - else # user permutation provided - if userperm_only # use perm even if it is worse than AMD - unsafe_store!(common_nmethods[Threads.threadid()], 1) - end - F = analyze_p(A, SuiteSparse_long[p-1 for p in perm], cm) - end - - return F -end - -function cholesky!(F::Factor{Tv}, A::Sparse{Tv}; - shift::Real=0.0, check::Bool = true) where Tv - # Makes it an LLt - unsafe_store!(common_final_ll[Threads.threadid()], 1) - - # Compute the numerical factorization - factorize_p!(A, shift, F, common_struct[Threads.threadid()]) - - check && (issuccess(F) || throw(LinearAlgebra.PosDefException(1))) - return F -end - -""" - cholesky!(F::CHOLMOD.Factor, A::SparseMatrixCSC; shift = 0.0, check = true) -> CHOLMOD.Factor - -Compute the Cholesky (``LL'``) factorization of `A`, reusing the symbolic -factorization `F`. `A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/ -[`Hermitian`](@ref) view of a `SparseMatrixCSC`. Note that even if `A` doesn't -have the type tag, it must still be symmetric or Hermitian. - -See also [`cholesky`](@ref). - -!!! note - This method uses the CHOLMOD library from SuiteSparse, which only supports - doubles or complex doubles. Input matrices not of those element types will - be converted to `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` - as appropriate. -""" -cholesky!(F::Factor, A::Union{SparseMatrixCSC{T}, - SparseMatrixCSC{Complex{T}}, - Symmetric{T,SparseMatrixCSC{T,SuiteSparse_long}}, - Hermitian{Complex{T},SparseMatrixCSC{Complex{T},SuiteSparse_long}}, - Hermitian{T,SparseMatrixCSC{T,SuiteSparse_long}}}; - shift = 0.0, check::Bool = true) where {T<:Real} = - cholesky!(F, Sparse(A); shift = shift, check = check) - -function cholesky(A::Sparse; shift::Real=0.0, check::Bool = true, - perm::Union{Nothing,AbstractVector{SuiteSparse_long}}=nothing) - - cm = defaults(common_struct[Threads.threadid()]) - set_print_level(cm, 0) - - # Compute the symbolic factorization - F = fact_(A, cm; perm = perm) - - # Compute the numerical factorization - cholesky!(F, A; shift = shift, check = check) - - return F -end - -""" - cholesky(A::SparseMatrixCSC; shift = 0.0, check = true, perm = nothing) -> CHOLMOD.Factor - -Compute the Cholesky factorization of a sparse positive definite matrix `A`. -`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) -view of a `SparseMatrixCSC`. Note that even if `A` doesn't -have the type tag, it must still be symmetric or Hermitian. -If `perm` is not given, a fill-reducing permutation is used. -`F = cholesky(A)` is most frequently used to solve systems of equations with `F\\b`, -but also the methods [`diag`](@ref), [`det`](@ref), and -[`logdet`](@ref) are defined for `F`. -You can also extract individual factors from `F`, using `F.L`. -However, since pivoting is on by default, the factorization is internally -represented as `A == P'*L*L'*P` with a permutation matrix `P`; -using just `L` without accounting for `P` will give incorrect answers. -To include the effects of permutation, -it's typically preferable to extract "combined" factors like `PtL = F.PtL` -(the equivalent of `P'*L`) and `LtP = F.UP` (the equivalent of `L'*P`). - -When `check = true`, an error is thrown if the decomposition fails. -When `check = false`, responsibility for checking the decomposition's -validity (via [`issuccess`](@ref)) lies with the user. - -Setting the optional `shift` keyword argument computes the factorization of -`A+shift*I` instead of `A`. If the `perm` argument is provided, -it should be a permutation of `1:size(A,1)` giving the ordering to use -(instead of CHOLMOD's default AMD ordering). - -# Examples - -In the following example, the fill-reducing permutation used is `[3, 2, 1]`. -If `perm` is set to `1:3` to enforce no permutation, the number of nonzero -elements in the factor is 6. -```jldoctest -julia> A = [2 1 1; 1 2 0; 1 0 2] -3×3 Matrix{Int64}: - 2 1 1 - 1 2 0 - 1 0 2 - -julia> C = cholesky(sparse(A)) -SuiteSparse.CHOLMOD.Factor{Float64} -type: LLt -method: simplicial -maxnnz: 5 -nnz: 5 -success: true - -julia> C.p -3-element Vector{Int64}: - 3 - 2 - 1 - -julia> L = sparse(C.L); - -julia> Matrix(L) -3×3 Matrix{Float64}: - 1.41421 0.0 0.0 - 0.0 1.41421 0.0 - 0.707107 0.707107 1.0 - -julia> L * L' ≈ A[C.p, C.p] -true - -julia> P = sparse(1:3, C.p, ones(3)) -3×3 SparseMatrixCSC{Float64, Int64} with 3 stored entries: - ⋅ ⋅ 1.0 - ⋅ 1.0 ⋅ - 1.0 ⋅ ⋅ - -julia> P' * L * L' * P ≈ A -true - -julia> C = cholesky(sparse(A), perm=1:3) -SuiteSparse.CHOLMOD.Factor{Float64} -type: LLt -method: simplicial -maxnnz: 6 -nnz: 6 -success: true - -julia> L = sparse(C.L); - -julia> Matrix(L) -3×3 Matrix{Float64}: - 1.41421 0.0 0.0 - 0.707107 1.22474 0.0 - 0.707107 -0.408248 1.1547 - -julia> L * L' ≈ A -true -``` - -!!! note - This method uses the CHOLMOD library from SuiteSparse, which only supports - doubles or complex doubles. Input matrices not of those element types will - be converted to `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` - as appropriate. - - Many other functions from CHOLMOD are wrapped but not exported from the - `Base.SparseArrays.CHOLMOD` module. -""" -cholesky(A::Union{SparseMatrixCSC{T}, SparseMatrixCSC{Complex{T}}, - Symmetric{T,SparseMatrixCSC{T,SuiteSparse_long}}, - Hermitian{Complex{T},SparseMatrixCSC{Complex{T},SuiteSparse_long}}, - Hermitian{T,SparseMatrixCSC{T,SuiteSparse_long}}}; - kws...) where {T<:Real} = cholesky(Sparse(A); kws...) - - -function ldlt!(F::Factor{Tv}, A::Sparse{Tv}; - shift::Real=0.0, check::Bool = true) where Tv - cm = defaults(common_struct[Threads.threadid()]) - set_print_level(cm, 0) - - # Makes it an LDLt - change_factor!(F, false, false, true, false) - - # Compute the numerical factorization - factorize_p!(A, shift, F, cm) - - check && (issuccess(F) || throw(LinearAlgebra.ZeroPivotException(1))) - return F -end - -""" - ldlt!(F::CHOLMOD.Factor, A::SparseMatrixCSC; shift = 0.0, check = true) -> CHOLMOD.Factor - -Compute the ``LDL'`` factorization of `A`, reusing the symbolic factorization `F`. -`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) -view of a `SparseMatrixCSC`. Note that even if `A` doesn't -have the type tag, it must still be symmetric or Hermitian. - -See also [`ldlt`](@ref). - -!!! note - This method uses the CHOLMOD library from SuiteSparse, which only supports - doubles or complex doubles. Input matrices not of those element types will - be converted to `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` - as appropriate. -""" -ldlt!(F::Factor, A::Union{SparseMatrixCSC{T}, - SparseMatrixCSC{Complex{T}}, - Symmetric{T,SparseMatrixCSC{T,SuiteSparse_long}}, - Hermitian{Complex{T},SparseMatrixCSC{Complex{T},SuiteSparse_long}}, - Hermitian{T,SparseMatrixCSC{T,SuiteSparse_long}}}; - shift = 0.0, check::Bool = true) where {T<:Real} = - ldlt!(F, Sparse(A), shift = shift, check = check) - -function ldlt(A::Sparse; shift::Real=0.0, check::Bool = true, - perm::Union{Nothing,AbstractVector{SuiteSparse_long}}=nothing) - - cm = defaults(common_struct[Threads.threadid()]) - set_print_level(cm, 0) - - # Makes it an LDLt - unsafe_store!(common_final_ll[Threads.threadid()], 0) - # Really make sure it's an LDLt by avoiding supernodal factorization - unsafe_store!(common_supernodal[Threads.threadid()], 0) - - # Compute the symbolic factorization - F = fact_(A, cm; perm = perm) - - # Compute the numerical factorization - ldlt!(F, A; shift = shift, check = check) - - return F -end - -""" - ldlt(A::SparseMatrixCSC; shift = 0.0, check = true, perm=nothing) -> CHOLMOD.Factor - -Compute the ``LDL'`` factorization of a sparse matrix `A`. -`A` must be a [`SparseMatrixCSC`](@ref) or a [`Symmetric`](@ref)/[`Hermitian`](@ref) -view of a `SparseMatrixCSC`. Note that even if `A` doesn't -have the type tag, it must still be symmetric or Hermitian. -A fill-reducing permutation is used. `F = ldlt(A)` is most frequently -used to solve systems of equations `A*x = b` with `F\\b`. The returned -factorization object `F` also supports the methods [`diag`](@ref), -[`det`](@ref), [`logdet`](@ref), and [`inv`](@ref). -You can extract individual factors from `F` using `F.L`. -However, since pivoting is on by default, the factorization is internally -represented as `A == P'*L*D*L'*P` with a permutation matrix `P`; -using just `L` without accounting for `P` will give incorrect answers. -To include the effects of permutation, it is typically preferable to extract -"combined" factors like `PtL = F.PtL` (the equivalent of -`P'*L`) and `LtP = F.UP` (the equivalent of `L'*P`). -The complete list of supported factors is `:L, :PtL, :D, :UP, :U, :LD, :DU, :PtLD, :DUP`. - -When `check = true`, an error is thrown if the decomposition fails. -When `check = false`, responsibility for checking the decomposition's -validity (via [`issuccess`](@ref)) lies with the user. - -Setting the optional `shift` keyword argument computes the factorization of -`A+shift*I` instead of `A`. If the `perm` argument is provided, -it should be a permutation of `1:size(A,1)` giving the ordering to use -(instead of CHOLMOD's default AMD ordering). - -!!! note - This method uses the CHOLMOD library from SuiteSparse, which only supports - doubles or complex doubles. Input matrices not of those element types will - be converted to `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` - as appropriate. - - Many other functions from CHOLMOD are wrapped but not exported from the - `Base.SparseArrays.CHOLMOD` module. -""" -ldlt(A::Union{SparseMatrixCSC{T},SparseMatrixCSC{Complex{T}}, - Symmetric{T,SparseMatrixCSC{T,SuiteSparse_long}}, - Hermitian{Complex{T},SparseMatrixCSC{Complex{T},SuiteSparse_long}}, - Hermitian{T,SparseMatrixCSC{T,SuiteSparse_long}}}; - kws...) where {T<:Real} = ldlt(Sparse(A); kws...) - -## Rank updates - -""" - lowrankupdowndate!(F::CHOLMOD.Factor, C::Sparse, update::Cint) - -Update an `LDLt` or `LLt` Factorization `F` of `A` to a factorization of `A ± C*C'`. - -If sparsity preserving factorization is used, i.e. `L*L' == P*A*P'` then the new -factor will be `L*L' == P*A*P' + C'*C` - -`update`: `Cint(1)` for `A + CC'`, `Cint(0)` for `A - CC'` -""" -function lowrankupdowndate!(F::Factor{Tv}, C::Sparse{Tv}, update::Cint) where Tv<:VTypes - lF = unsafe_load(pointer(F)) - lC = unsafe_load(pointer(C)) - if lF.n != lC.nrow - throw(DimensionMismatch("matrix dimensions do not fit")) - end - @isok ccall((@cholmod_name("updown"), :libcholmod), Cint, - (Cint, Ptr{C_Sparse{Tv}}, Ptr{C_Factor{Tv}}, Ptr{Cvoid}), - update, C, F, common_struct[Threads.threadid()]) - F -end - -#Helper functions for rank updates -lowrank_reorder(V::AbstractArray,p) = Sparse(sparse(V[p,:])) -lowrank_reorder(V::AbstractSparseArray,p) = Sparse(V[p,:]) - -""" - lowrankupdate!(F::CHOLMOD.Factor, C::AbstractArray) - -Update an `LDLt` or `LLt` Factorization `F` of `A` to a factorization of `A + C*C'`. - -`LLt` factorizations are converted to `LDLt`. - -See also [`lowrankupdate`](@ref), [`lowrankdowndate`](@ref), [`lowrankdowndate!`](@ref). -""" -function lowrankupdate!(F::Factor{Tv}, V::AbstractArray{Tv}) where Tv<:VTypes - #Reorder and copy V to account for permutation - C = lowrank_reorder(V, get_perm(F)) - lowrankupdowndate!(F, C, Cint(1)) -end - -""" - lowrankdowndate!(F::CHOLMOD.Factor, C::AbstractArray) - -Update an `LDLt` or `LLt` Factorization `F` of `A` to a factorization of `A - C*C'`. - -`LLt` factorizations are converted to `LDLt`. - -See also [`lowrankdowndate`](@ref), [`lowrankupdate`](@ref), [`lowrankupdate!`](@ref). -""" -function lowrankdowndate!(F::Factor{Tv}, V::AbstractArray{Tv}) where Tv<:VTypes - #Reorder and copy V to account for permutation - C = lowrank_reorder(V, get_perm(F)) - lowrankupdowndate!(F, C, Cint(0)) -end - -""" - lowrankupdate(F::CHOLMOD.Factor, C::AbstractArray) -> FF::CHOLMOD.Factor - -Get an `LDLt` Factorization of `A + C*C'` given an `LDLt` or `LLt` factorization `F` of `A`. - -The returned factor is always an `LDLt` factorization. - -See also [`lowrankupdate!`](@ref), [`lowrankdowndate`](@ref), [`lowrankdowndate!`](@ref). -""" -lowrankupdate(F::Factor{Tv}, V::AbstractArray{Tv}) where {Tv<:VTypes} = - lowrankupdate!(copy(F), V) - -""" - lowrankupdate(F::CHOLMOD.Factor, C::AbstractArray) -> FF::CHOLMOD.Factor - -Get an `LDLt` Factorization of `A + C*C'` given an `LDLt` or `LLt` factorization `F` of `A`. - -The returned factor is always an `LDLt` factorization. - -See also [`lowrankdowndate!`](@ref), [`lowrankupdate`](@ref), [`lowrankupdate!`](@ref). -""" -lowrankdowndate(F::Factor{Tv}, V::AbstractArray{Tv}) where {Tv<:VTypes} = - lowrankdowndate!(copy(F), V) - -## Solvers - -for (T, f) in ((:Dense, :solve), (:Sparse, :spsolve)) - @eval begin - # Solve Lx = b and L'x=b where A = L*L' - function (\)(L::FactorComponent{T,:L}, B::$T) where T - ($f)(CHOLMOD_L, Factor(L), B) - end - function (\)(L::FactorComponent{T,:U}, B::$T) where T - ($f)(CHOLMOD_Lt, Factor(L), B) - end - # Solve PLx = b and L'P'x=b where A = P*L*L'*P' - function (\)(L::FactorComponent{T,:PtL}, B::$T) where T - F = Factor(L) - ($f)(CHOLMOD_L, F, ($f)(CHOLMOD_P, F, B)) # Confusingly, CHOLMOD_P solves P'x = b - end - function (\)(L::FactorComponent{T,:UP}, B::$T) where T - F = Factor(L) - ($f)(CHOLMOD_Pt, F, ($f)(CHOLMOD_Lt, F, B)) - end - # Solve various equations for A = L*D*L' and A = P*L*D*L'*P' - function (\)(L::FactorComponent{T,:D}, B::$T) where T - ($f)(CHOLMOD_D, Factor(L), B) - end - function (\)(L::FactorComponent{T,:LD}, B::$T) where T - ($f)(CHOLMOD_LD, Factor(L), B) - end - function (\)(L::FactorComponent{T,:DU}, B::$T) where T - ($f)(CHOLMOD_DLt, Factor(L), B) - end - function (\)(L::FactorComponent{T,:PtLD}, B::$T) where T - F = Factor(L) - ($f)(CHOLMOD_LD, F, ($f)(CHOLMOD_P, F, B)) - end - function (\)(L::FactorComponent{T,:DUP}, B::$T) where T - F = Factor(L) - ($f)(CHOLMOD_Pt, F, ($f)(CHOLMOD_DLt, F, B)) - end - end -end - -SparseVecOrMat{Tv,Ti} = Union{SparseVector{Tv,Ti}, SparseMatrixCSC{Tv,Ti}} - -function (\)(L::FactorComponent, b::Vector) - reshape(Matrix(L\Dense(b)), length(b)) -end -function (\)(L::FactorComponent, B::Matrix) - Matrix(L\Dense(B)) -end -function (\)(L::FactorComponent, B::SparseVecOrMat) - sparse(L\Sparse(B,0)) -end -(\)(L::FactorComponent, B::Adjoint{<:Any,<:SparseMatrixCSC}) = L \ copy(B) -(\)(L::FactorComponent, B::Transpose{<:Any,<:SparseMatrixCSC}) = L \ copy(B) - -\(adjL::Adjoint{<:Any,<:FactorComponent}, B::Union{VecOrMat,SparseVecOrMat}) = (L = adjL.parent; adjoint(L)\B) - -(\)(L::Factor{T}, B::Dense{T}) where {T<:VTypes} = solve(CHOLMOD_A, L, B) -# Explicit typevars are necessary to avoid ambiguities with defs in linalg/factorizations.jl -# Likewise the two following explicit Vector and Matrix defs (rather than a single VecOrMat) -(\)(L::Factor{T}, B::Vector{Complex{T}}) where {T<:Float64} = complex.(L\real(B), L\imag(B)) -(\)(L::Factor{T}, B::Matrix{Complex{T}}) where {T<:Float64} = complex.(L\real(B), L\imag(B)) -(\)(L::Factor{T}, B::Adjoint{<:Any, <:Matrix{Complex{T}}}) where {T<:Float64} = complex.(L\real(B), L\imag(B)) -(\)(L::Factor{T}, B::Transpose{<:Any, <:Matrix{Complex{T}}}) where {T<:Float64} = complex.(L\real(B), L\imag(B)) - -(\)(L::Factor{T}, b::StridedVector) where {T<:VTypes} = Vector(L\Dense{T}(b)) -(\)(L::Factor{T}, B::StridedMatrix) where {T<:VTypes} = Matrix(L\Dense{T}(B)) -(\)(L::Factor{T}, B::Adjoint{<:Any, <:StridedMatrix}) where {T<:VTypes} = Matrix(L\Dense{T}(B)) -(\)(L::Factor{T}, B::Transpose{<:Any, <:StridedMatrix}) where {T<:VTypes} = Matrix(L\Dense{T}(B)) - -(\)(L::Factor, B::Sparse) = spsolve(CHOLMOD_A, L, B) -# When right hand side is sparse, we have to ensure that the rhs is not marked as symmetric. -(\)(L::Factor, B::SparseMatrixCSC) = sparse(spsolve(CHOLMOD_A, L, Sparse(B, 0))) -(\)(L::Factor, B::Adjoint{<:Any,<:SparseMatrixCSC}) = L \ copy(B) -(\)(L::Factor, B::Transpose{<:Any,<:SparseMatrixCSC}) = L \ copy(B) -(\)(L::Factor, B::SparseVector) = sparse(spsolve(CHOLMOD_A, L, Sparse(B))) - -\(adjL::Adjoint{<:Any,<:Factor}, B::Dense) = (L = adjL.parent; solve(CHOLMOD_A, L, B)) -\(adjL::Adjoint{<:Any,<:Factor}, B::Sparse) = (L = adjL.parent; spsolve(CHOLMOD_A, L, B)) -\(adjL::Adjoint{<:Any,<:Factor}, B::SparseVecOrMat) = (L = adjL.parent; \(adjoint(L), Sparse(B))) - -function \(adjL::Adjoint{<:Any,<:Factor}, b::StridedVector) - L = adjL.parent - return Vector(solve(CHOLMOD_A, L, Dense(b))) -end -function \(adjL::Adjoint{<:Any,<:Factor}, B::StridedMatrix) - L = adjL.parent - return Matrix(solve(CHOLMOD_A, L, Dense(B))) -end - -const RealHermSymComplexHermF64SSL = Union{ - Symmetric{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, - Hermitian{Float64,SparseMatrixCSC{Float64,SuiteSparse_long}}, - Hermitian{ComplexF64,SparseMatrixCSC{ComplexF64,SuiteSparse_long}}} -const StridedVecOrMatInclAdjAndTrans = Union{StridedVecOrMat, Adjoint{<:Any, <:StridedVecOrMat}, Transpose{<:Any, <:StridedVecOrMat}} -function \(A::RealHermSymComplexHermF64SSL, B::StridedVecOrMatInclAdjAndTrans) - F = cholesky(A; check = false) - if issuccess(F) - return \(F, B) - else - ldlt!(F, A; check = false) - if issuccess(F) - return \(F, B) - else - return \(lu(SparseMatrixCSC{eltype(A), SuiteSparse_long}(A)), B) - end - end -end -function \(adjA::Adjoint{<:Any,<:RealHermSymComplexHermF64SSL}, B::StridedVecOrMatInclAdjAndTrans) - A = adjA.parent - F = cholesky(A; check = false) - if issuccess(F) - return \(adjoint(F), B) - else - ldlt!(F, A; check = false) - if issuccess(F) - return \(adjoint(F), B) - else - return \(adjoint(lu(SparseMatrixCSC{eltype(A), SuiteSparse_long}(A))), B) - end - end -end - -## Other convenience methods -function diag(F::Factor{Tv}) where Tv - f = unsafe_load(pointer(F)) - fsuper = f.super - fpi = f.pi - res = Base.zeros(Tv, Int(f.n)) - xv = f.x - if f.is_super!=0 - px = f.px - pos = 1 - for i in 1:f.nsuper - base = unsafe_load(px, i) + 1 - res[pos] = unsafe_load(xv, base) - pos += 1 - for j in 1:unsafe_load(fsuper, i + 1) - unsafe_load(fsuper, i) - 1 - res[pos] = unsafe_load(xv, base + j*(unsafe_load(fpi, i + 1) - - unsafe_load(fpi, i) + 1)) - pos += 1 - end - end - else - c0 = f.p - r0 = f.i - xv = f.x - for j in 1:f.n - jj = unsafe_load(c0, j) + 1 - @assert(unsafe_load(r0, jj) == j - 1) - res[j] = unsafe_load(xv, jj) - end - end - res -end - -function logdet(F::Factor{Tv}) where Tv<:VTypes - f = unsafe_load(pointer(F)) - res = zero(Tv) - for d in diag(F); res += log(abs(d)) end - f.is_ll != 0 ? 2res : res -end - -det(L::Factor) = exp(logdet(L)) - -function issuccess(F::Factor) - s = unsafe_load(pointer(F)) - return s.minor == size(F, 1) -end - -function isposdef(F::Factor) - if issuccess(F) - s = unsafe_load(pointer(F)) - if s.is_ll == 1 - return true - else - # try conversion to LLt - change_factor!(F, true, s.is_super, true, s.is_monotonic) - b = issuccess(F) - # convert back - change_factor!(F, false, s.is_super, true, s.is_monotonic) - return b - end - else - return false - end -end - -function ishermitian(A::Sparse{Float64}) - s = unsafe_load(pointer(A)) - if s.stype != 0 - return true - else - i = symmetry(A, 1)[1] - if i < 0 - throw(CHOLMODException("negative value returned from CHOLMOD's symmetry function. This - is either because the indices are not sorted or because of a memory error")) - end - return i == MM_SYMMETRIC || i == MM_SYMMETRIC_POSDIAG - end -end -function ishermitian(A::Sparse{ComplexF64}) - s = unsafe_load(pointer(A)) - if s.stype != 0 - return true - else - i = symmetry(A, 1)[1] - if i < 0 - throw(CHOLMODException("negative value returned from CHOLMOD's symmetry function. This - is either because the indices are not sorted or because of a memory error")) - end - return i == MM_HERMITIAN || i == MM_HERMITIAN_POSDIAG - end -end - -(*)(A::Symmetric{Float64,SparseMatrixCSC{Float64,Ti}}, - B::SparseVecOrMat{Float64,Ti}) where {Ti} = sparse(Sparse(A)*Sparse(B)) -(*)(A::Hermitian{ComplexF64,SparseMatrixCSC{ComplexF64,Ti}}, - B::SparseVecOrMat{ComplexF64,Ti}) where {Ti} = sparse(Sparse(A)*Sparse(B)) -(*)(A::Hermitian{Float64,SparseMatrixCSC{Float64,Ti}}, - B::SparseVecOrMat{Float64,Ti}) where {Ti} = sparse(Sparse(A)*Sparse(B)) - -(*)(A::SparseVecOrMat{Float64,Ti}, - B::Symmetric{Float64,SparseMatrixCSC{Float64,Ti}}) where {Ti} = sparse(Sparse(A)*Sparse(B)) -(*)(A::SparseVecOrMat{ComplexF64,Ti}, - B::Hermitian{ComplexF64,SparseMatrixCSC{ComplexF64,Ti}}) where {Ti} = sparse(Sparse(A)*Sparse(B)) -(*)(A::SparseVecOrMat{Float64,Ti}, - B::Hermitian{Float64,SparseMatrixCSC{Float64,Ti}}) where {Ti} = sparse(Sparse(A)*Sparse(B)) - -end #module diff --git a/stdlib/SuiteSparse/src/cholmod_h.jl b/stdlib/SuiteSparse/src/cholmod_h.jl deleted file mode 100644 index 26bb046b45dfc..0000000000000 --- a/stdlib/SuiteSparse/src/cholmod_h.jl +++ /dev/null @@ -1,79 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -## CHOLMOD -const TRUE = Int32(1) -const FALSE = Int32(0) - -## itype defines the types of integer used: -const INT = Int32(0) # all integer arrays are int -const INTLONG = Int32(1) # most are int, some are SuiteSparse_long -const LONG = Int32(2) # all integer arrays are SuiteSparse_long - -## dtype defines what the numerical type is (double or float): -const DOUBLE = Int32(0) # all numerical values are double -const SINGLE = Int32(1) # all numerical values are float -dtyp(::Type{Float32}) = SINGLE -dtyp(::Type{Float64}) = DOUBLE -dtyp(::Type{ComplexF32}) = SINGLE -dtyp(::Type{ComplexF64}) = DOUBLE - -## xtype defines the kind of numerical values used: -const PATTERN = Int32(0) # pattern only, no numerical values -const REAL = Int32(1) # a real matrix -const COMPLEX = Int32(2) # a complex matrix (ANSI C99 compatible) -const ZOMPLEX = Int32(3) # a complex matrix (MATLAB compatible) -xtyp(::Type{Float32}) = REAL -xtyp(::Type{Float64}) = REAL -xtyp(::Type{ComplexF32}) = COMPLEX -xtyp(::Type{ComplexF64}) = COMPLEX - -## Scaling modes, selected by the scale input parameter: -const SCALAR = Int32(0) # A = s*A -const ROW = Int32(1) # A = diag(s)*A -const COL = Int32(2) # A = A*diag(s) -const SYM = Int32(3) # A = diag(s)*A*diag(s) - -## Types of systems to solve -const CHOLMOD_A = Int32(0) # solve Ax=b -const CHOLMOD_LDLt = Int32(1) # solve LDL'x=b -const CHOLMOD_LD = Int32(2) # solve LDx=b -const CHOLMOD_DLt = Int32(3) # solve DL'x=b -const CHOLMOD_L = Int32(4) # solve Lx=b -const CHOLMOD_Lt = Int32(5) # solve L'x=b -const CHOLMOD_D = Int32(6) # solve Dx=b -const CHOLMOD_P = Int32(7) # permute x=Px -const CHOLMOD_Pt = Int32(8) # permute x=P'x - -# Symmetry types -const EMPTY =-1 -const MM_RECTANGULAR = 1 -const MM_UNSYMMETRIC = 2 -const MM_SYMMETRIC = 3 -const MM_HERMITIAN = 4 -const MM_SKEW_SYMMETRIC = 5 -const MM_SYMMETRIC_POSDIAG = 6 -const MM_HERMITIAN_POSDIAG = 7 - -# check the size of SuiteSparse_long -if Int(ccall((:jl_cholmod_sizeof_long, :libsuitesparse_wrapper),Csize_t,())) == 4 - const SuiteSparse_long = Int32 - const IndexTypes = (:Int32,) - const ITypes = Union{Int32} -else - const SuiteSparse_long = Int64 - const IndexTypes = (:Int32, :Int64) - const ITypes = Union{Int32, Int64} -end -ityp(::Type{SuiteSparse_long}) = LONG - - -const VTypes = Union{ComplexF64, Float64} -const VRealTypes = Union{Float64} - -struct CHOLMODException <: Exception - msg::AbstractString -end - -macro isok(A) - :($(esc(A)) == TRUE || throw(CHOLMODException(""))) -end diff --git a/stdlib/SuiteSparse/src/deprecated.jl b/stdlib/SuiteSparse/src/deprecated.jl deleted file mode 100644 index ee28d60dc4406..0000000000000 --- a/stdlib/SuiteSparse/src/deprecated.jl +++ /dev/null @@ -1 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license diff --git a/stdlib/SuiteSparse/src/spqr.jl b/stdlib/SuiteSparse/src/spqr.jl deleted file mode 100644 index 79897b6c0de76..0000000000000 --- a/stdlib/SuiteSparse/src/spqr.jl +++ /dev/null @@ -1,458 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -module SPQR - -import Base: \ -using Base: require_one_based_indexing -using LinearAlgebra - -# ordering options */ -const ORDERING_FIXED = Int32(0) -const ORDERING_NATURAL = Int32(1) -const ORDERING_COLAMD = Int32(2) -const ORDERING_GIVEN = Int32(3) # only used for C/C++ interface -const ORDERING_CHOLMOD = Int32(4) # CHOLMOD best-effort (COLAMD, METIS,...) -const ORDERING_AMD = Int32(5) # AMD(A'*A) -const ORDERING_METIS = Int32(6) # metis(A'*A) -const ORDERING_DEFAULT = Int32(7) # SuiteSparseQR default ordering -const ORDERING_BEST = Int32(8) # try COLAMD, AMD, and METIS; pick best -const ORDERING_BESTAMD = Int32(9) # try COLAMD and AMD; pick best# -const ORDERINGS = [ORDERING_FIXED, ORDERING_NATURAL, ORDERING_COLAMD, ORDERING_CHOLMOD, - ORDERING_AMD, ORDERING_METIS, ORDERING_DEFAULT, ORDERING_BEST, - ORDERING_BESTAMD] - -# Let [m n] = size of the matrix after pruning singletons. The default -# ordering strategy is to use COLAMD if m <= 2*n. Otherwise, AMD(A'A) is -# tried. If there is a high fill-in with AMD then try METIS(A'A) and take -# the best of AMD and METIS. METIS is not tried if it isn't installed. - -using SparseArrays -using SparseArrays: getcolptr -using ..SuiteSparse.CHOLMOD -using ..SuiteSparse.CHOLMOD: change_stype!, free! - -function _qr!(ordering::Integer, tol::Real, econ::Integer, getCTX::Integer, - A::Sparse{Tv}, - Bsparse::Union{Sparse{Tv} , Ptr{Cvoid}} = C_NULL, - Bdense::Union{Dense{Tv} , Ptr{Cvoid}} = C_NULL, - Zsparse::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}} , Ptr{Cvoid}} = C_NULL, - Zdense::Union{Ref{Ptr{CHOLMOD.C_Dense{Tv}}} , Ptr{Cvoid}} = C_NULL, - R::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}} , Ptr{Cvoid}} = C_NULL, - E::Union{Ref{Ptr{CHOLMOD.SuiteSparse_long}} , Ptr{Cvoid}} = C_NULL, - H::Union{Ref{Ptr{CHOLMOD.C_Sparse{Tv}}} , Ptr{Cvoid}} = C_NULL, - HPinv::Union{Ref{Ptr{CHOLMOD.SuiteSparse_long}}, Ptr{Cvoid}} = C_NULL, - HTau::Union{Ref{Ptr{CHOLMOD.C_Dense{Tv}}} , Ptr{Cvoid}} = C_NULL) where {Tv<:CHOLMOD.VTypes} - - ordering ∈ ORDERINGS || error("unknown ordering $ordering") - - AA = unsafe_load(pointer(A)) - m, n = AA.nrow, AA.ncol - rnk = ccall((:SuiteSparseQR_C, :libspqr), CHOLMOD.SuiteSparse_long, - (Cint, Cdouble, CHOLMOD.SuiteSparse_long, Cint, - Ptr{CHOLMOD.C_Sparse{Tv}}, Ptr{CHOLMOD.C_Sparse{Tv}}, Ptr{CHOLMOD.C_Dense{Tv}}, - Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}}, Ptr{Ptr{CHOLMOD.C_Dense{Tv}}}, Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}}, - Ptr{Ptr{CHOLMOD.SuiteSparse_long}}, Ptr{Ptr{CHOLMOD.C_Sparse{Tv}}}, Ptr{Ptr{CHOLMOD.SuiteSparse_long}}, - Ptr{Ptr{CHOLMOD.C_Dense{Tv}}}, Ptr{Cvoid}), - ordering, # all, except 3:given treated as 0:fixed - tol, # columns with 2-norm <= tol treated as 0 - econ, # e = max(min(m,econ),rank(A)) - getCTX, # 0: Z=C (e-by-k), 1: Z=C', 2: Z=X (e-by-k) - A, # m-by-n sparse matrix to factorize - Bsparse, # sparse m-by-k B - Bdense, # dense m-by-k B - # /* outputs: */ - Zsparse, # sparse Z - Zdense, # dense Z - R, # e-by-n sparse matrix */ - E, # size n column perm, NULL if identity */ - H, # m-by-nh Householder vectors - HPinv, # size m row permutation - HTau, # 1-by-nh Householder coefficients - CHOLMOD.common_struct[Threads.threadid()]) # /* workspace and parameters */ - - if rnk < 0 - error("Sparse QR factorization failed") - end - - e = E[] - if e == C_NULL - _E = Vector{CHOLMOD.SuiteSparse_long}() - else - _E = Vector{CHOLMOD.SuiteSparse_long}(undef, n) - for i in 1:n - @inbounds _E[i] = unsafe_load(e, i) + 1 - end - # Free memory allocated by SPQR. This call will make sure that the - # correct deallocator function is called and that the memory count in - # the common struct is updated - ccall((:cholmod_l_free, :libcholmod), Cvoid, - (Csize_t, Cint, Ptr{CHOLMOD.SuiteSparse_long}, Ptr{Cvoid}), - n, sizeof(CHOLMOD.SuiteSparse_long), e, CHOLMOD.common_struct[Threads.threadid()]) - end - hpinv = HPinv[] - if hpinv == C_NULL - _HPinv = Vector{CHOLMOD.SuiteSparse_long}() - else - _HPinv = Vector{CHOLMOD.SuiteSparse_long}(undef, m) - for i in 1:m - @inbounds _HPinv[i] = unsafe_load(hpinv, i) + 1 - end - # Free memory allocated by SPQR. This call will make sure that the - # correct deallocator function is called and that the memory count in - # the common struct is updated - ccall((:cholmod_l_free, :libcholmod), Cvoid, - (Csize_t, Cint, Ptr{CHOLMOD.SuiteSparse_long}, Ptr{Cvoid}), - m, sizeof(CHOLMOD.SuiteSparse_long), hpinv, CHOLMOD.common_struct[Threads.threadid()]) - end - - return rnk, _E, _HPinv -end - -# Struct for storing sparse QR from SPQR such that -# A[invperm(rpivinv), cpiv] = (I - factors[:,1]*τ[1]*factors[:,1]')*...*(I - factors[:,k]*τ[k]*factors[:,k]')*R -# with k = size(factors, 2). -struct QRSparse{Tv,Ti} <: LinearAlgebra.Factorization{Tv} - factors::SparseMatrixCSC{Tv,Ti} - τ::Vector{Tv} - R::SparseMatrixCSC{Tv,Ti} - cpiv::Vector{Ti} - rpivinv::Vector{Ti} -end - -Base.size(F::QRSparse) = (size(F.factors, 1), size(F.R, 2)) -function Base.size(F::QRSparse, i::Integer) - if i == 1 - return size(F.factors, 1) - elseif i == 2 - return size(F.R, 2) - elseif i > 2 - return 1 - else - throw(ArgumentError("second argument must be positive")) - end -end -Base.axes(F::QRSparse) = map(Base.OneTo, size(F)) - -struct QRSparseQ{Tv<:CHOLMOD.VTypes,Ti<:Integer} <: LinearAlgebra.AbstractQ{Tv} - factors::SparseMatrixCSC{Tv,Ti} - τ::Vector{Tv} - n::Int # Number of columns in original matrix -end - -Base.size(Q::QRSparseQ) = (size(Q.factors, 1), size(Q.factors, 1)) -Base.axes(Q::QRSparseQ) = map(Base.OneTo, size(Q)) - -Matrix{T}(Q::QRSparseQ) where {T} = lmul!(Q, Matrix{T}(I, size(Q, 1), min(size(Q, 1), Q.n))) - -# From SPQR manual p. 6 -_default_tol(A::SparseMatrixCSC) = - 20*sum(size(A))*eps(real(eltype(A)))*maximum(norm(view(A, :, i)) for i in 1:size(A, 2)) - -""" - qr(A::SparseMatrixCSC; tol=_default_tol(A), ordering=ORDERING_DEFAULT) -> QRSparse - -Compute the `QR` factorization of a sparse matrix `A`. Fill-reducing row and column permutations -are used such that `F.R = F.Q'*A[F.prow,F.pcol]`. The main application of this type is to -solve least squares or underdetermined problems with [`\\`](@ref). The function calls the C library SPQR. - -!!! note - `qr(A::SparseMatrixCSC)` uses the SPQR library that is part of SuiteSparse. - As this library only supports sparse matrices with [`Float64`](@ref) or - `ComplexF64` elements, as of Julia v1.4 `qr` converts `A` into a copy that is - of type `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` as appropriate. - -# Examples -```jldoctest -julia> A = sparse([1,2,3,4], [1,1,2,2], [1.0,1.0,1.0,1.0]) -4×2 SparseMatrixCSC{Float64, Int64} with 4 stored entries: - 1.0 ⋅ - 1.0 ⋅ - ⋅ 1.0 - ⋅ 1.0 - -julia> qr(A) -SuiteSparse.SPQR.QRSparse{Float64, Int64} -Q factor: -4×4 SuiteSparse.SPQR.QRSparseQ{Float64, Int64}: - -0.707107 0.0 0.0 -0.707107 - 0.0 -0.707107 -0.707107 0.0 - 0.0 -0.707107 0.707107 0.0 - -0.707107 0.0 0.0 0.707107 -R factor: -2×2 SparseMatrixCSC{Float64, Int64} with 2 stored entries: - -1.41421 ⋅ - ⋅ -1.41421 -Row permutation: -4-element Vector{Int64}: - 1 - 3 - 4 - 2 -Column permutation: -2-element Vector{Int64}: - 1 - 2 -``` -""" -function LinearAlgebra.qr(A::SparseMatrixCSC{Tv}; tol=_default_tol(A), ordering=ORDERING_DEFAULT) where {Tv <: CHOLMOD.VTypes} - R = Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}() - E = Ref{Ptr{CHOLMOD.SuiteSparse_long}}() - H = Ref{Ptr{CHOLMOD.C_Sparse{Tv}}}() - HPinv = Ref{Ptr{CHOLMOD.SuiteSparse_long}}() - HTau = Ref{Ptr{CHOLMOD.C_Dense{Tv}}}(C_NULL) - - # SPQR doesn't accept symmetric matrices so we explicitly set the stype - r, p, hpinv = _qr!(ordering, tol, 0, 0, Sparse(A, 0), - C_NULL, C_NULL, C_NULL, C_NULL, - R, E, H, HPinv, HTau) - - R_ = SparseMatrixCSC(Sparse(R[])) - return QRSparse(SparseMatrixCSC(Sparse(H[])), - vec(Array(CHOLMOD.Dense(HTau[]))), - SparseMatrixCSC(min(size(A)...), - size(R_, 2), - getcolptr(R_), - rowvals(R_), - nonzeros(R_)), - p, hpinv) -end -LinearAlgebra.qr(A::SparseMatrixCSC{<:Union{Float16,Float32}}; tol=_default_tol(A)) = - qr(convert(SparseMatrixCSC{Float64}, A); tol=tol) -LinearAlgebra.qr(A::SparseMatrixCSC{<:Union{ComplexF16,ComplexF32}}; tol=_default_tol(A)) = - qr(convert(SparseMatrixCSC{ComplexF64}, A); tol=tol) -LinearAlgebra.qr(A::Union{SparseMatrixCSC{T},SparseMatrixCSC{Complex{T}}}; - tol=_default_tol(A)) where {T<:AbstractFloat} = - throw(ArgumentError(string("matrix type ", typeof(A), "not supported. ", - "Try qr(convert(SparseMatrixCSC{Float64/ComplexF64, Int}, A)) for ", - "sparse floating point QR using SPQR or qr(Array(A)) for generic ", - "dense QR."))) -LinearAlgebra.qr(A::SparseMatrixCSC; tol=_default_tol(A)) = qr(float(A); tol=tol) - -function LinearAlgebra.lmul!(Q::QRSparseQ, A::StridedVecOrMat) - if size(A, 1) != size(Q, 1) - throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) - end - for l in size(Q.factors, 2):-1:1 - τl = -Q.τ[l] - h = view(Q.factors, :, l) - for j in 1:size(A, 2) - a = view(A, :, j) - LinearAlgebra.axpy!(τl*dot(h, a), h, a) - end - end - return A -end - -function LinearAlgebra.rmul!(A::StridedMatrix, Q::QRSparseQ) - if size(A, 2) != size(Q, 1) - throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) - end - tmp = similar(A, size(A, 1)) - for l in 1:size(Q.factors, 2) - τl = -Q.τ[l] - h = view(Q.factors, :, l) - LinearAlgebra.mul!(tmp, A, h) - LinearAlgebra.lowrankupdate!(A, tmp, h, τl) - end - return A -end - -function LinearAlgebra.lmul!(adjQ::Adjoint{<:Any,<:QRSparseQ}, A::StridedVecOrMat) - Q = adjQ.parent - if size(A, 1) != size(Q, 1) - throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) - end - for l in 1:size(Q.factors, 2) - τl = -Q.τ[l] - h = view(Q.factors, :, l) - for j in 1:size(A, 2) - a = view(A, :, j) - LinearAlgebra.axpy!(τl'*dot(h, a), h, a) - end - end - return A -end - -function LinearAlgebra.rmul!(A::StridedMatrix, adjQ::Adjoint{<:Any,<:QRSparseQ}) - Q = adjQ.parent - if size(A, 2) != size(Q, 1) - throw(DimensionMismatch("size(Q) = $(size(Q)) but size(A) = $(size(A))")) - end - tmp = similar(A, size(A, 1)) - for l in size(Q.factors, 2):-1:1 - τl = -Q.τ[l] - h = view(Q.factors, :, l) - LinearAlgebra.mul!(tmp, A, h) - LinearAlgebra.lowrankupdate!(A, tmp, h, τl') - end - return A -end - -""" - getproperty(F::QRSparse, d::Symbol) - -Extract factors of a QRSparse factorization. Possible values of `d` are -- `Q` : `QRSparseQ` matrix of the ``Q`` factor in Householder form -- `R` : `UpperTriangular` ``R`` factor -- `prow` : Vector of the row permutations applied to the factorized matrix -- `pcol` : Vector of the column permutations applied to the factorized matrix - -# Examples -```jldoctest -julia> F = qr(sparse([1,3,2,3,4], [1,1,2,3,4], [1.0,2.0,3.0,4.0,5.0])); - -julia> F.Q -4×4 SuiteSparse.SPQR.QRSparseQ{Float64, Int64}: - 1.0 0.0 0.0 0.0 - 0.0 1.0 0.0 0.0 - 0.0 0.0 1.0 0.0 - 0.0 0.0 0.0 1.0 - -julia> F.R -4×4 SparseMatrixCSC{Float64, Int64} with 5 stored entries: - 3.0 ⋅ ⋅ ⋅ - ⋅ 4.0 ⋅ 2.0 - ⋅ ⋅ 5.0 ⋅ - ⋅ ⋅ ⋅ 1.0 - -julia> F.prow -4-element Vector{Int64}: - 2 - 3 - 4 - 1 - -julia> F.pcol -4-element Vector{Int64}: - 2 - 3 - 4 - 1 -``` -""" -@inline function Base.getproperty(F::QRSparse, d::Symbol) - if d === :Q - return QRSparseQ(F.factors, F.τ, size(F, 2)) - elseif d === :prow - return invperm(F.rpivinv) - elseif d === :pcol - return F.cpiv - else - getfield(F, d) - end -end - -function Base.propertynames(F::QRSparse, private::Bool=false) - public = (:R, :Q, :prow, :pcol) - private ? ((public ∪ fieldnames(typeof(F)))...,) : public -end - -function Base.show(io::IO, mime::MIME{Symbol("text/plain")}, F::QRSparse) - summary(io, F); println(io) - println(io, "Q factor:") - show(io, mime, F.Q) - println(io, "\nR factor:") - show(io, mime, F.R) - println(io, "\nRow permutation:") - show(io, mime, F.prow) - println(io, "\nColumn permutation:") - show(io, mime, F.pcol) -end - -# With a real lhs and complex rhs with the same precision, we can reinterpret -# the complex rhs as a real rhs with twice the number of columns -# -# This definition is similar to the definition in factorization.jl except that -# here we have to use \ instead of ldiv! because of limitations in SPQR - -## Two helper methods -_ret_size(F::QRSparse, b::AbstractVector) = (size(F, 2),) -_ret_size(F::QRSparse, B::AbstractMatrix) = (size(F, 2), size(B, 2)) - -LinearAlgebra.rank(F::QRSparse) = reduce(max, view(rowvals(F.R), 1:nnz(F.R)), init = eltype(rowvals(F.R))(0)) -LinearAlgebra.rank(S::SparseMatrixCSC) = rank(qr(S)) - -function (\)(F::QRSparse{T}, B::VecOrMat{Complex{T}}) where T<:LinearAlgebra.BlasReal -# |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3| -# |z2|z4| -> |y1|y2|y3|y4| -> |x2|y2| -> |x2|y2|x4|y4| -# |x3|y3| -# |x4|y4| - require_one_based_indexing(F, B) - c2r = reshape(copy(transpose(reinterpret(T, reshape(B, (1, length(B)))))), size(B, 1), 2*size(B, 2)) - x = F\c2r - -# |z1|z3| reinterpret |x1|x2|x3|x4| transpose |x1|y1| reshape |x1|y1|x3|y3| -# |z2|z4| <- |y1|y2|y3|y4| <- |x2|y2| <- |x2|y2|x4|y4| -# |x3|y3| -# |x4|y4| - return collect(reshape(reinterpret(Complex{T}, copy(transpose(reshape(x, (length(x) >> 1), 2)))), _ret_size(F, B))) -end - -function _ldiv_basic(F::QRSparse, B::StridedVecOrMat) - if size(F, 1) != size(B, 1) - throw(DimensionMismatch("size(F) = $(size(F)) but size(B) = $(size(B))")) - end - - # The rank of F equal might be reduced - rnk = rank(F) - - # allocate an array for the return value large enough to hold B and X - # For overdetermined problem, B is larger than X and vice versa - X = similar(B, ntuple(i -> i == 1 ? max(size(F, 2), size(B, 1)) : size(B, 2), Val(ndims(B)))) - - # Fill will zeros. These will eventually become the zeros in the basic solution - # fill!(X, 0) - # Apply left permutation to the solution and store in X - for j in 1:size(B, 2) - for i in 1:length(F.rpivinv) - @inbounds X[F.rpivinv[i], j] = B[i, j] - end - end - - # Make a view into X corresponding to the size of B - X0 = view(X, 1:size(B, 1), :) - - # Apply Q' to B - LinearAlgebra.lmul!(adjoint(F.Q), X0) - - # Zero out to get basic solution - X[rnk + 1:end, :] .= 0 - - # Solve R*X = B - LinearAlgebra.ldiv!(UpperTriangular(F.R[Base.OneTo(rnk), Base.OneTo(rnk)]), - view(X0, Base.OneTo(rnk), :)) - - # Apply right permutation and extract solution from X - # NB: cpiv == [] if SPQR was called with ORDERING_FIXED - if length(F.cpiv) == 0 - return getindex(X, ntuple(i -> i == 1 ? (1:size(F,2)) : :, Val(ndims(B)))...) - end - return getindex(X, ntuple(i -> i == 1 ? invperm(F.cpiv) : :, Val(ndims(B)))...) -end - -(\)(F::QRSparse{T}, B::StridedVecOrMat{T}) where {T} = _ldiv_basic(F, B) -""" - (\\)(F::QRSparse, B::StridedVecOrMat) - -Solve the least squares problem ``\\min\\|Ax - b\\|^2`` or the linear system of equations -``Ax=b`` when `F` is the sparse QR factorization of ``A``. A basic solution is returned -when the problem is underdetermined. - -# Examples -```jldoctest -julia> A = sparse([1,2,4], [1,1,1], [1.0,1.0,1.0], 4, 2) -4×2 SparseMatrixCSC{Float64, Int64} with 3 stored entries: - 1.0 ⋅ - 1.0 ⋅ - ⋅ ⋅ - 1.0 ⋅ - -julia> qr(A)\\fill(1.0, 4) -2-element Vector{Float64}: - 1.0 - 0.0 -``` -""" -(\)(F::QRSparse, B::StridedVecOrMat) = F\convert(AbstractArray{eltype(F)}, B) - -end # module diff --git a/stdlib/SuiteSparse/src/umfpack.jl b/stdlib/SuiteSparse/src/umfpack.jl deleted file mode 100644 index a6e0cf54d4b23..0000000000000 --- a/stdlib/SuiteSparse/src/umfpack.jl +++ /dev/null @@ -1,643 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -module UMFPACK - -export UmfpackLU - -import Base: (\), getproperty, show, size -using LinearAlgebra -import LinearAlgebra: Factorization, det, lu, lu!, ldiv! - -using SparseArrays -using SparseArrays: getcolptr -import SparseArrays: nnz - -import Serialization: AbstractSerializer, deserialize - -import ..increment, ..increment!, ..decrement, ..decrement! - -include("umfpack_h.jl") -struct MatrixIllConditionedException <: Exception - msg::AbstractString -end - -function umferror(status::Integer) - if status==UMFPACK_OK - return - elseif status==UMFPACK_WARNING_singular_matrix - throw(LinearAlgebra.SingularException(0)) - elseif status==UMFPACK_WARNING_determinant_underflow - throw(MatrixIllConditionedException("the determinant is nonzero but underflowed")) - elseif status==UMFPACK_WARNING_determinant_overflow - throw(MatrixIllConditionedException("the determinant overflowed")) - elseif status==UMFPACK_ERROR_out_of_memory - throw(OutOfMemoryError()) - elseif status==UMFPACK_ERROR_invalid_Numeric_object - throw(ArgumentError("invalid UMFPack numeric object")) - elseif status==UMFPACK_ERROR_invalid_Symbolic_object - throw(ArgumentError("invalid UMFPack symbolic object")) - elseif status==UMFPACK_ERROR_argument_missing - throw(ArgumentError("a required argument to UMFPack is missing")) - elseif status==UMFPACK_ERROR_n_nonpositive - throw(ArgumentError("the number of rows or columns of the matrix must be greater than zero")) - elseif status==UMFPACK_ERROR_invalid_matrix - throw(ArgumentError("invalid matrix")) - elseif status==UMFPACK_ERROR_different_pattern - throw(ArgumentError("pattern of the matrix changed")) - elseif status==UMFPACK_ERROR_invalid_system - throw(ArgumentError("invalid sys argument provided to UMFPack solver")) - elseif status==UMFPACK_ERROR_invalid_permutation - throw(ArgumentError("invalid permutation")) - elseif status==UMFPACK_ERROR_file_IO - throw(ErrorException("error saving / loading UMFPack decomposition")) - elseif status==UMFPACK_ERROR_ordering_failed - throw(ErrorException("the ordering method failed")) - elseif status==UMFPACK_ERROR_internal_error - throw(ErrorException("an internal error has occurred, of unknown cause")) - else - throw(ErrorException("unknown UMFPack error code: $status")) - end -end - -macro isok(A) - :(umferror($(esc(A)))) -end - -# check the size of SuiteSparse_long -if Int(ccall((:jl_cholmod_sizeof_long,:libsuitesparse_wrapper),Csize_t,())) == 4 - const UmfpackIndexTypes = (:Int32,) - const UMFITypes = Int32 -else - const UmfpackIndexTypes = (:Int32, :Int64) - const UMFITypes = Union{Int32, Int64} -end - -const UMFVTypes = Union{Float64,ComplexF64} - -## UMFPACK - -# the control and info arrays -const umf_ctrl = Vector{Float64}(undef, UMFPACK_CONTROL) -ccall((:umfpack_dl_defaults,:libumfpack), Cvoid, (Ptr{Float64},), umf_ctrl) -const umf_info = Vector{Float64}(undef, UMFPACK_INFO) - -function show_umf_ctrl(level::Real = 2.0) - old_prt::Float64 = umf_ctrl[1] - umf_ctrl[1] = Float64(level) - ccall((:umfpack_dl_report_control, :libumfpack), Cvoid, (Ptr{Float64},), umf_ctrl) - umf_ctrl[1] = old_prt -end - -function show_umf_info(level::Real = 2.0) - old_prt::Float64 = umf_ctrl[1] - umf_ctrl[1] = Float64(level) - ccall((:umfpack_dl_report_info, :libumfpack), Cvoid, - (Ptr{Float64}, Ptr{Float64}), umf_ctrl, umf_info) - umf_ctrl[1] = old_prt -end - -## Should this type be immutable? -mutable struct UmfpackLU{Tv<:UMFVTypes,Ti<:UMFITypes} <: Factorization{Tv} - symbolic::Ptr{Cvoid} - numeric::Ptr{Cvoid} - m::Int - n::Int - colptr::Vector{Ti} # 0-based column pointers - rowval::Vector{Ti} # 0-based row indices - nzval::Vector{Tv} - status::Int -end - -Base.adjoint(F::UmfpackLU) = Adjoint(F) -Base.transpose(F::UmfpackLU) = Transpose(F) - -""" - lu(A::SparseMatrixCSC; check = true) -> F::UmfpackLU - -Compute the LU factorization of a sparse matrix `A`. - -For sparse `A` with real or complex element type, the return type of `F` is -`UmfpackLU{Tv, Ti}`, with `Tv` = [`Float64`](@ref) or `ComplexF64` respectively and -`Ti` is an integer type ([`Int32`](@ref) or [`Int64`](@ref)). - -When `check = true`, an error is thrown if the decomposition fails. -When `check = false`, responsibility for checking the decomposition's -validity (via [`issuccess`](@ref)) lies with the user. - -The individual components of the factorization `F` can be accessed by indexing: - -| Component | Description | -|:----------|:------------------------------------| -| `L` | `L` (lower triangular) part of `LU` | -| `U` | `U` (upper triangular) part of `LU` | -| `p` | right permutation `Vector` | -| `q` | left permutation `Vector` | -| `Rs` | `Vector` of scaling factors | -| `:` | `(L,U,p,q,Rs)` components | - -The relation between `F` and `A` is - -`F.L*F.U == (F.Rs .* A)[F.p, F.q]` - -`F` further supports the following functions: - -- [`\\`](@ref) -- [`cond`](@ref) -- [`det`](@ref) - -!!! note - `lu(A::SparseMatrixCSC)` uses the UMFPACK library that is part of - SuiteSparse. As this library only supports sparse matrices with [`Float64`](@ref) or - `ComplexF64` elements, `lu` converts `A` into a copy that is of type - `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` as appropriate. -""" -function lu(S::SparseMatrixCSC{<:UMFVTypes,<:UMFITypes}; check::Bool = true) - zerobased = getcolptr(S)[1] == 0 - res = UmfpackLU(C_NULL, C_NULL, size(S, 1), size(S, 2), - zerobased ? copy(getcolptr(S)) : decrement(getcolptr(S)), - zerobased ? copy(rowvals(S)) : decrement(rowvals(S)), - copy(nonzeros(S)), 0) - finalizer(umfpack_free_symbolic, res) - umfpack_numeric!(res) - check && (issuccess(res) || throw(LinearAlgebra.SingularException(0))) - return res -end -lu(A::SparseMatrixCSC{<:Union{Float16,Float32},Ti}; - check::Bool = true) where {Ti<:UMFITypes} = - lu(convert(SparseMatrixCSC{Float64,Ti}, A); check = check) -lu(A::SparseMatrixCSC{<:Union{ComplexF16,ComplexF32},Ti}; - check::Bool = true) where {Ti<:UMFITypes} = - lu(convert(SparseMatrixCSC{ComplexF64,Ti}, A); check = check) -lu(A::Union{SparseMatrixCSC{T},SparseMatrixCSC{Complex{T}}}; - check::Bool = true) where {T<:AbstractFloat} = - throw(ArgumentError(string("matrix type ", typeof(A), "not supported. ", - "Try lu(convert(SparseMatrixCSC{Float64/ComplexF64,Int}, A)) for ", - "sparse floating point LU using UMFPACK or lu(Array(A)) for generic ", - "dense LU."))) -lu(A::SparseMatrixCSC; check::Bool = true) = lu(float(A); check = check) - -""" - lu!(F::UmfpackLU, A::SparseMatrixCSC; check=true) -> F::UmfpackLU - -Compute the LU factorization of a sparse matrix `A`, reusing the symbolic -factorization of an already existing LU factorization stored in `F`. The -sparse matrix `A` must have an identical nonzero pattern as the matrix used -to create the LU factorization `F`, otherwise an error is thrown. - -When `check = true`, an error is thrown if the decomposition fails. -When `check = false`, responsibility for checking the decomposition's -validity (via [`issuccess`](@ref)) lies with the user. - -!!! note - `lu!(F::UmfpackLU, A::SparseMatrixCSC)` uses the UMFPACK library that is part of - SuiteSparse. As this library only supports sparse matrices with [`Float64`](@ref) or - `ComplexF64` elements, `lu!` converts `A` into a copy that is of type - `SparseMatrixCSC{Float64}` or `SparseMatrixCSC{ComplexF64}` as appropriate. - -!!! compat "Julia 1.5" - `lu!` for `UmfpackLU` requires at least Julia 1.5. - -# Examples -```jldoctest -julia> A = sparse(Float64[1.0 2.0; 0.0 3.0]); - -julia> F = lu(A); - -julia> B = sparse(Float64[1.0 1.0; 0.0 1.0]); - -julia> lu!(F, B); - -julia> F \\ ones(2) -2-element Vector{Float64}: - 0.0 - 1.0 -``` -""" -function lu!(F::UmfpackLU, S::SparseMatrixCSC{<:UMFVTypes,<:UMFITypes}; check::Bool=true) - zerobased = getcolptr(S)[1] == 0 - F.m = size(S, 1) - F.n = size(S, 2) - F.colptr = zerobased ? copy(getcolptr(S)) : decrement(getcolptr(S)) - F.rowval = zerobased ? copy(rowvals(S)) : decrement(rowvals(S)) - F.nzval = copy(nonzeros(S)) - - umfpack_numeric!(F, reuse_numeric = false) - check && (issuccess(F) || throw(LinearAlgebra.SingularException(0))) - return F -end -lu!(F::UmfpackLU, A::SparseMatrixCSC{<:Union{Float16,Float32},Ti}; - check::Bool = true) where {Ti<:UMFITypes} = - lu!(F, convert(SparseMatrixCSC{Float64,Ti}, A); check = check) -lu!(F::UmfpackLU, A::SparseMatrixCSC{<:Union{ComplexF16,ComplexF32},Ti}; - check::Bool = true) where {Ti<:UMFITypes} = - lu!(F, convert(SparseMatrixCSC{ComplexF64,Ti}, A); check = check) -lu!(F::UmfpackLU, A::Union{SparseMatrixCSC{T},SparseMatrixCSC{Complex{T}}}; - check::Bool = true) where {T<:AbstractFloat} = - throw(ArgumentError(string("matrix type ", typeof(A), "not supported."))) -lu!(F::UmfpackLU, A::SparseMatrixCSC; check::Bool = true) = lu!(F, float(A); check = check) - -size(F::UmfpackLU) = (F.m, F.n) -function size(F::UmfpackLU, dim::Integer) - if dim < 1 - throw(ArgumentError("size: dimension $dim out of range")) - elseif dim == 1 - return Int(F.m) - elseif dim == 2 - return Int(F.n) - else - return 1 - end -end - -function show(io::IO, mime::MIME{Symbol("text/plain")}, F::UmfpackLU) - if F.numeric != C_NULL - if issuccess(F) - summary(io, F); println(io) - println(io, "L factor:") - show(io, mime, F.L) - println(io, "\nU factor:") - show(io, mime, F.U) - else - print(io, "Failed factorization of type $(typeof(F))") - end - end -end - -function deserialize(s::AbstractSerializer, t::Type{UmfpackLU{Tv,Ti}}) where {Tv,Ti} - symbolic = deserialize(s) - numeric = deserialize(s) - m = deserialize(s) - n = deserialize(s) - colptr = deserialize(s) - rowval = deserialize(s) - nzval = deserialize(s) - status = deserialize(s) - obj = UmfpackLU{Tv,Ti}(symbolic, numeric, m, n, colptr, rowval, nzval, status) - - finalizer(umfpack_free_symbolic, obj) - - return obj -end - -## Wrappers for UMFPACK functions - -# generate the name of the C function according to the value and integer types -umf_nm(nm,Tv,Ti) = "umfpack_" * (Tv === :Float64 ? "d" : "z") * (Ti === :Int64 ? "l_" : "i_") * nm - -for itype in UmfpackIndexTypes - sym_r = umf_nm("symbolic", :Float64, itype) - sym_c = umf_nm("symbolic", :ComplexF64, itype) - num_r = umf_nm("numeric", :Float64, itype) - num_c = umf_nm("numeric", :ComplexF64, itype) - sol_r = umf_nm("solve", :Float64, itype) - sol_c = umf_nm("solve", :ComplexF64, itype) - det_r = umf_nm("get_determinant", :Float64, itype) - det_z = umf_nm("get_determinant", :ComplexF64, itype) - lunz_r = umf_nm("get_lunz", :Float64, itype) - lunz_z = umf_nm("get_lunz", :ComplexF64, itype) - get_num_r = umf_nm("get_numeric", :Float64, itype) - get_num_z = umf_nm("get_numeric", :ComplexF64, itype) - @eval begin - function umfpack_symbolic!(U::UmfpackLU{Float64,$itype}) - if U.symbolic != C_NULL return U end - tmp = Vector{Ptr{Cvoid}}(undef, 1) - @isok ccall(($sym_r, :libumfpack), $itype, - ($itype, $itype, Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, Ptr{Cvoid}, - Ptr{Float64}, Ptr{Float64}), - U.m, U.n, U.colptr, U.rowval, U.nzval, tmp, - umf_ctrl, umf_info) - U.symbolic = tmp[1] - return U - end - function umfpack_symbolic!(U::UmfpackLU{ComplexF64,$itype}) - if U.symbolic != C_NULL return U end - tmp = Vector{Ptr{Cvoid}}(undef, 1) - @isok ccall(($sym_c, :libumfpack), $itype, - ($itype, $itype, Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, Ptr{Float64}, Ptr{Cvoid}, - Ptr{Float64}, Ptr{Float64}), - U.m, U.n, U.colptr, U.rowval, real(U.nzval), imag(U.nzval), tmp, - umf_ctrl, umf_info) - U.symbolic = tmp[1] - return U - end - function umfpack_numeric!(U::UmfpackLU{Float64,$itype}; reuse_numeric = true) - if (reuse_numeric && U.numeric != C_NULL) return U end - if U.symbolic == C_NULL umfpack_symbolic!(U) end - tmp = Vector{Ptr{Cvoid}}(undef, 1) - status = ccall(($num_r, :libumfpack), $itype, - (Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, Ptr{Cvoid}, Ptr{Cvoid}, - Ptr{Float64}, Ptr{Float64}), - U.colptr, U.rowval, U.nzval, U.symbolic, tmp, - umf_ctrl, umf_info) - U.status = status - if status != UMFPACK_WARNING_singular_matrix - umferror(status) - end - U.numeric != C_NULL && umfpack_free_numeric(U) - U.numeric = tmp[1] - return U - end - function umfpack_numeric!(U::UmfpackLU{ComplexF64,$itype}; reuse_numeric = true) - if (reuse_numeric && U.numeric != C_NULL) return U end - if U.symbolic == C_NULL umfpack_symbolic!(U) end - tmp = Vector{Ptr{Cvoid}}(undef, 1) - status = ccall(($num_c, :libumfpack), $itype, - (Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, Ptr{Float64}, Ptr{Cvoid}, Ptr{Cvoid}, - Ptr{Float64}, Ptr{Float64}), - U.colptr, U.rowval, real(U.nzval), imag(U.nzval), U.symbolic, tmp, - umf_ctrl, umf_info) - U.status = status - if status != UMFPACK_WARNING_singular_matrix - umferror(status) - end - U.numeric != C_NULL && umfpack_free_numeric(U) - U.numeric = tmp[1] - return U - end - function solve!(x::StridedVector{Float64}, lu::UmfpackLU{Float64,$itype}, b::StridedVector{Float64}, typ::Integer) - if x === b - throw(ArgumentError("output array must not be aliased with input array")) - end - if stride(x, 1) != 1 || stride(b, 1) != 1 - throw(ArgumentError("in and output vectors must have unit strides")) - end - umfpack_numeric!(lu) - (size(b,1) == lu.m) && (size(b) == size(x)) || throw(DimensionMismatch()) - @isok ccall(($sol_r, :libumfpack), $itype, - ($itype, Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, - Ptr{Float64}, Ptr{Float64}, Ptr{Cvoid}, Ptr{Float64}, - Ptr{Float64}), - typ, lu.colptr, lu.rowval, lu.nzval, - x, b, lu.numeric, umf_ctrl, - umf_info) - return x - end - function solve!(x::StridedVector{ComplexF64}, lu::UmfpackLU{ComplexF64,$itype}, b::StridedVector{ComplexF64}, typ::Integer) - if x === b - throw(ArgumentError("output array must not be aliased with input array")) - end - if stride(x, 1) != 1 || stride(b, 1) != 1 - throw(ArgumentError("in and output vectors must have unit strides")) - end - umfpack_numeric!(lu) - (size(b, 1) == lu.m) && (size(b) == size(x)) || throw(DimensionMismatch()) - n = size(b, 1) - @isok ccall(($sol_c, :libumfpack), $itype, - ($itype, Ptr{$itype}, Ptr{$itype}, Ptr{Float64}, - Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, - Ptr{Float64}, Ptr{Cvoid}, Ptr{Float64}, Ptr{Float64}), - typ, lu.colptr, lu.rowval, lu.nzval, - C_NULL, x, C_NULL, b, - C_NULL, lu.numeric, umf_ctrl, umf_info) - return x - end - function det(lu::UmfpackLU{Float64,$itype}) - mx = Ref{Float64}() - @isok ccall(($det_r,:libumfpack), $itype, - (Ptr{Float64},Ptr{Float64},Ptr{Cvoid},Ptr{Float64}), - mx, C_NULL, lu.numeric, umf_info) - mx[] - end - function det(lu::UmfpackLU{ComplexF64,$itype}) - mx = Ref{Float64}() - mz = Ref{Float64}() - @isok ccall(($det_z,:libumfpack), $itype, - (Ptr{Float64},Ptr{Float64},Ptr{Float64},Ptr{Cvoid},Ptr{Float64}), - mx, mz, C_NULL, lu.numeric, umf_info) - complex(mx[], mz[]) - end - function umf_lunz(lu::UmfpackLU{Float64,$itype}) - lnz = Ref{$itype}() - unz = Ref{$itype}() - n_row = Ref{$itype}() - n_col = Ref{$itype}() - nz_diag = Ref{$itype}() - @isok ccall(($lunz_r,:libumfpack), $itype, - (Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{Cvoid}), - lnz, unz, n_row, n_col, nz_diag, lu.numeric) - (lnz[], unz[], n_row[], n_col[], nz_diag[]) - end - function umf_lunz(lu::UmfpackLU{ComplexF64,$itype}) - lnz = Ref{$itype}() - unz = Ref{$itype}() - n_row = Ref{$itype}() - n_col = Ref{$itype}() - nz_diag = Ref{$itype}() - @isok ccall(($lunz_z,:libumfpack), $itype, - (Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{$itype},Ptr{Cvoid}), - lnz, unz, n_row, n_col, nz_diag, lu.numeric) - (lnz[], unz[], n_row[], n_col[], nz_diag[]) - end - function umf_extract(lu::UmfpackLU{Float64,$itype}) - umfpack_numeric!(lu) # ensure the numeric decomposition exists - (lnz, unz, n_row, n_col, nz_diag) = umf_lunz(lu) - Lp = Vector{$itype}(undef, n_row + 1) - Lj = Vector{$itype}(undef, lnz) # L is returned in CSR (compressed sparse row) format - Lx = Vector{Float64}(undef, lnz) - Up = Vector{$itype}(undef, n_col + 1) - Ui = Vector{$itype}(undef, unz) - Ux = Vector{Float64}(undef, unz) - P = Vector{$itype}(undef, n_row) - Q = Vector{$itype}(undef, n_col) - Rs = Vector{Float64}(undef, n_row) - @isok ccall(($get_num_r,:libumfpack), $itype, - (Ptr{$itype},Ptr{$itype},Ptr{Float64}, - Ptr{$itype},Ptr{$itype},Ptr{Float64}, - Ptr{$itype},Ptr{$itype},Ptr{Cvoid}, - Ref{$itype},Ptr{Float64},Ptr{Cvoid}), - Lp,Lj,Lx, - Up,Ui,Ux, - P, Q, C_NULL, - 0, Rs, lu.numeric) - (copy(transpose(SparseMatrixCSC(min(n_row, n_col), n_row, increment!(Lp), increment!(Lj), Lx))), - SparseMatrixCSC(min(n_row, n_col), n_col, increment!(Up), increment!(Ui), Ux), - increment!(P), increment!(Q), Rs) - end - function umf_extract(lu::UmfpackLU{ComplexF64,$itype}) - umfpack_numeric!(lu) # ensure the numeric decomposition exists - (lnz, unz, n_row, n_col, nz_diag) = umf_lunz(lu) - Lp = Vector{$itype}(undef, n_row + 1) - Lj = Vector{$itype}(undef, lnz) # L is returned in CSR (compressed sparse row) format - Lx = Vector{Float64}(undef, lnz) - Lz = Vector{Float64}(undef, lnz) - Up = Vector{$itype}(undef, n_col + 1) - Ui = Vector{$itype}(undef, unz) - Ux = Vector{Float64}(undef, unz) - Uz = Vector{Float64}(undef, unz) - P = Vector{$itype}(undef, n_row) - Q = Vector{$itype}(undef, n_col) - Rs = Vector{Float64}(undef, n_row) - @isok ccall(($get_num_z,:libumfpack), $itype, - (Ptr{$itype},Ptr{$itype},Ptr{Float64},Ptr{Float64}, - Ptr{$itype},Ptr{$itype},Ptr{Float64},Ptr{Float64}, - Ptr{$itype},Ptr{$itype},Ptr{Cvoid}, Ptr{Cvoid}, - Ref{$itype},Ptr{Float64},Ptr{Cvoid}), - Lp,Lj,Lx,Lz, - Up,Ui,Ux,Uz, - P, Q, C_NULL, C_NULL, - 0, Rs, lu.numeric) - (copy(transpose(SparseMatrixCSC(min(n_row, n_col), n_row, increment!(Lp), increment!(Lj), complex.(Lx, Lz)))), - SparseMatrixCSC(min(n_row, n_col), n_col, increment!(Up), increment!(Ui), complex.(Ux, Uz)), - increment!(P), increment!(Q), Rs) - end - end -end - -function nnz(lu::UmfpackLU) - lnz, unz, = umf_lunz(lu) - return Int(lnz + unz) -end - -LinearAlgebra.issuccess(lu::UmfpackLU) = lu.status == UMFPACK_OK - -### Solve with Factorization - -import LinearAlgebra.ldiv! - -ldiv!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - ldiv!(B, lu, copy(B)) -ldiv!(translu::Transpose{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - (lu = translu.parent; ldiv!(B, transpose(lu), copy(B))) -ldiv!(adjlu::Adjoint{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - (lu = adjlu.parent; ldiv!(B, adjoint(lu), copy(B))) -ldiv!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = - ldiv!(B, lu, copy(B)) -ldiv!(translu::Transpose{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{<:Complex}) = - (lu = translu.parent; ldiv!(B, transpose(lu), copy(B))) -ldiv!(adjlu::Adjoint{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{<:Complex}) = - (lu = adjlu.parent; ldiv!(B, adjoint(lu), copy(B))) - -ldiv!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_A) -ldiv!(X::StridedVecOrMat{T}, translu::Transpose{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - (lu = translu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat)) -ldiv!(X::StridedVecOrMat{T}, adjlu::Adjoint{T,<:UmfpackLU{T}}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = - (lu = adjlu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_At)) -ldiv!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = - _Aq_ldiv_B!(X, lu, B, UMFPACK_A) -ldiv!(X::StridedVecOrMat{Tb}, translu::Transpose{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = - (lu = translu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_Aat)) -ldiv!(X::StridedVecOrMat{Tb}, adjlu::Adjoint{Float64,<:UmfpackLU{Float64}}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} = - (lu = adjlu.parent; _Aq_ldiv_B!(X, lu, B, UMFPACK_At)) - -function _Aq_ldiv_B!(X::StridedVecOrMat, lu::UmfpackLU, B::StridedVecOrMat, transposeoptype) - if size(X, 2) != size(B, 2) - throw(DimensionMismatch("input and output arrays must have same number of columns")) - end - _AqldivB_kernel!(X, lu, B, transposeoptype) - return X -end -function _AqldivB_kernel!(x::StridedVector{T}, lu::UmfpackLU{T}, - b::StridedVector{T}, transposeoptype) where T<:UMFVTypes - solve!(x, lu, b, transposeoptype) -end -function _AqldivB_kernel!(X::StridedMatrix{T}, lu::UmfpackLU{T}, - B::StridedMatrix{T}, transposeoptype) where T<:UMFVTypes - for col in 1:size(X, 2) - solve!(view(X, :, col), lu, view(B, :, col), transposeoptype) - end -end -function _AqldivB_kernel!(x::StridedVector{Tb}, lu::UmfpackLU{Float64}, - b::StridedVector{Tb}, transposeoptype) where Tb<:Complex - r, i = similar(b, Float64), similar(b, Float64) - solve!(r, lu, Vector{Float64}(real(b)), transposeoptype) - solve!(i, lu, Vector{Float64}(imag(b)), transposeoptype) - map!(complex, x, r, i) -end -function _AqldivB_kernel!(X::StridedMatrix{Tb}, lu::UmfpackLU{Float64}, - B::StridedMatrix{Tb}, transposeoptype) where Tb<:Complex - r = similar(B, Float64, size(B, 1)) - i = similar(B, Float64, size(B, 1)) - for j in 1:size(B, 2) - solve!(r, lu, Vector{Float64}(real(view(B, :, j))), transposeoptype) - solve!(i, lu, Vector{Float64}(imag(view(B, :, j))), transposeoptype) - map!(complex, view(X, :, j), r, i) - end -end - - -@inline function getproperty(lu::UmfpackLU, d::Symbol) - if d === :L || d === :U || d === :p || d === :q || d === :Rs || d === :(:) - # Guard the call to umf_extract behaind a branch to avoid infinite recursion - L, U, p, q, Rs = umf_extract(lu) - if d === :L - return L - elseif d === :U - return U - elseif d === :p - return p - elseif d === :q - return q - elseif d === :Rs - return Rs - elseif d === :(:) - return (L, U, p, q, Rs) - end - else - getfield(lu, d) - end -end - -for Tv in (:Float64, :ComplexF64), Ti in UmfpackIndexTypes - f = Symbol(umf_nm("free_symbolic", Tv, Ti)) - @eval begin - function ($f)(symb::Ptr{Cvoid}) - tmp = [symb] - ccall(($(string(f)), :libumfpack), Cvoid, (Ptr{Cvoid},), tmp) - end - - function umfpack_free_symbolic(lu::UmfpackLU{$Tv,$Ti}) - if lu.symbolic == C_NULL return lu end - umfpack_free_numeric(lu) - ($f)(lu.symbolic) - lu.symbolic = C_NULL - return lu - end - end - - f = Symbol(umf_nm("free_numeric", Tv, Ti)) - @eval begin - function ($f)(num::Ptr{Cvoid}) - tmp = [num] - ccall(($(string(f)), :libumfpack), Cvoid, (Ptr{Cvoid},), tmp) - end - function umfpack_free_numeric(lu::UmfpackLU{$Tv,$Ti}) - if lu.numeric == C_NULL return lu end - ($f)(lu.numeric) - lu.numeric = C_NULL - return lu - end - end -end - -function umfpack_report_symbolic(symb::Ptr{Cvoid}, level::Real) - old_prl::Float64 = umf_ctrl[UMFPACK_PRL] - umf_ctrl[UMFPACK_PRL] = Float64(level) - @isok ccall((:umfpack_dl_report_symbolic, :libumfpack), Int, - (Ptr{Cvoid}, Ptr{Float64}), symb, umf_ctrl) - umf_ctrl[UMFPACK_PRL] = old_prl -end - -umfpack_report_symbolic(symb::Ptr{Cvoid}) = umfpack_report_symbolic(symb, 4.) - -function umfpack_report_symbolic(lu::UmfpackLU, level::Real) - umfpack_report_symbolic(umfpack_symbolic!(lu).symbolic, level) -end - -umfpack_report_symbolic(lu::UmfpackLU) = umfpack_report_symbolic(lu.symbolic,4.) -function umfpack_report_numeric(num::Ptr{Cvoid}, level::Real) - old_prl::Float64 = umf_ctrl[UMFPACK_PRL] - umf_ctrl[UMFPACK_PRL] = Float64(level) - @isok ccall((:umfpack_dl_report_numeric, :libumfpack), Int, - (Ptr{Cvoid}, Ptr{Float64}), num, umf_ctrl) - umf_ctrl[UMFPACK_PRL] = old_prl -end - -umfpack_report_numeric(num::Ptr{Cvoid}) = umfpack_report_numeric(num, 4.) -function umfpack_report_numeric(lu::UmfpackLU, level::Real) - umfpack_report_numeric(umfpack_numeric!(lu).numeric, level) -end - -umfpack_report_numeric(lu::UmfpackLU) = umfpack_report_numeric(lu,4.) - -end # UMFPACK module diff --git a/stdlib/SuiteSparse/src/umfpack_h.jl b/stdlib/SuiteSparse/src/umfpack_h.jl deleted file mode 100644 index 985f9387fcc75..0000000000000 --- a/stdlib/SuiteSparse/src/umfpack_h.jl +++ /dev/null @@ -1,43 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -## UMFPACK - -## Type of solve -const UMFPACK_A = 0 # Ax=b -const UMFPACK_At = 1 # adjoint(A)x=b -const UMFPACK_Aat = 2 # transpose(A)x=b -const UMFPACK_Pt_L = 3 # adjoint(P)Lx=b -const UMFPACK_L = 4 # Lx=b -const UMFPACK_Lt_P = 5 # adjoint(L)Px=b -const UMFPACK_Lat_P = 6 # transpose(L)Px=b -const UMFPACK_Lt = 7 # adjoint(L)x=b -const UMFPACK_Lat = 8 # transpose(L)x=b -const UMFPACK_U_Qt = 9 # U*adjoint(Q)x=b -const UMFPACK_U = 10 # Ux=b -const UMFPACK_Q_Ut = 11 # Q*adjoint(U)x=b -const UMFPACK_Q_Uat = 12 # Q*transpose(U)x=b -const UMFPACK_Ut = 13 # adjoint(U)x=b -const UMFPACK_Uat = 14 # transpose(U)x=b - -## Sizes of Control and Info arrays for returning information from solver -const UMFPACK_INFO = 90 -const UMFPACK_CONTROL = 20 -const UMFPACK_PRL = 1 - -## Status codes -const UMFPACK_OK = 0 -const UMFPACK_WARNING_singular_matrix = 1 -const UMFPACK_WARNING_determinant_underflow = 2 -const UMFPACK_WARNING_determinant_overflow = 3 -const UMFPACK_ERROR_out_of_memory = -1 -const UMFPACK_ERROR_invalid_Numeric_object = -3 -const UMFPACK_ERROR_invalid_Symbolic_object = -4 -const UMFPACK_ERROR_argument_missing = -5 -const UMFPACK_ERROR_n_nonpositive = -6 -const UMFPACK_ERROR_invalid_matrix = -8 -const UMFPACK_ERROR_different_pattern = -11 -const UMFPACK_ERROR_invalid_system = -13 -const UMFPACK_ERROR_invalid_permutation = -15 -const UMFPACK_ERROR_internal_error = -911 -const UMFPACK_ERROR_file_IO = -17 -const UMFPACK_ERROR_ordering_failed = -18 diff --git a/stdlib/SuiteSparse/test/cholmod.jl b/stdlib/SuiteSparse/test/cholmod.jl deleted file mode 100644 index 020c7129cc56f..0000000000000 --- a/stdlib/SuiteSparse/test/cholmod.jl +++ /dev/null @@ -1,896 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using SuiteSparse.CHOLMOD -using SuiteSparse -using DelimitedFiles -using Test -using Random -using Serialization -using LinearAlgebra: - I, cholesky, cholesky!, det, diag, eigmax, ishermitian, isposdef, issuccess, - issymmetric, ldlt, ldlt!, logdet, norm, opnorm, Diagonal, Hermitian, Symmetric, - PosDefException, ZeroPivotException -using SparseArrays -using SparseArrays: getcolptr - -# CHOLMOD tests -Random.seed!(123) - -@testset "based on deps/SuiteSparse-4.0.2/CHOLMOD/Demo/" begin - -# chm_rdsp(joinpath(Sys.BINDIR, "../../deps/SuiteSparse-4.0.2/CHOLMOD/Demo/Matrix/bcsstk01.tri")) -# because the file may not exist in binary distributions and when a system suitesparse library -# is used - -## Result from C program -## ---------------------------------- cholmod_demo: -## norm (A,inf) = 3.57095e+09 -## norm (A,1) = 3.57095e+09 -## CHOLMOD sparse: A: 48-by-48, nz 224, upper. OK -## CHOLMOD dense: B: 48-by-1, OK -## bnorm 1.97917 -## Analyze: flop 6009 lnz 489 -## Factorizing A -## CHOLMOD factor: L: 48-by-48 simplicial, LDL'. nzmax 489. nz 489 OK -## Ordering: AMD fl/lnz 12.3 lnz/anz 2.2 -## ints in L: 782, doubles in L: 489 -## factor flops 6009 nnz(L) 489 (w/no amalgamation) -## nnz(A*A'): 224 -## flops / nnz(L): 12.3 -## nnz(L) / nnz(A): 2.2 -## analyze cputime: 0.0000 -## factor cputime: 0.0000 mflop: 0.0 -## solve cputime: 0.0000 mflop: 0.0 -## overall cputime: 0.0000 mflop: 0.0 -## peak memory usage: 0 (MB) -## residual 2.5e-19 (|Ax-b|/(|A||x|+|b|)) -## residual 1.3e-19 (|Ax-b|/(|A||x|+|b|)) after iterative refinement -## rcond 9.5e-06 - - n = 48 - A = CHOLMOD.Sparse(n, n, - CHOLMOD.SuiteSparse_long[0,1,2,3,6,9,12,15,18,20,25,30,34,36,39,43,47,52,58, - 62,67,71,77,84,90,93,95,98,103,106,110,115,119,123,130,136,142,146,150,155, - 161,167,174,182,189,197,207,215,224], # zero-based column pointers - CHOLMOD.SuiteSparse_long[0,1,2,1,2,3,0,2,4,0,1,5,0,4,6,1,3,7,2,8,1,3,7,8,9, - 0,4,6,8,10,5,6,7,11,6,12,7,11,13,8,10,13,14,9,13,14,15,8,10,12,14,16,7,11, - 12,13,16,17,0,12,16,18,1,5,13,15,19,2,4,14,20,3,13,15,19,20,21,2,4,12,16,18, - 20,22,1,5,17,18,19,23,0,5,24,1,25,2,3,26,2,3,25,26,27,4,24,28,0,5,24,29,6, - 11,24,28,30,7,25,27,31,8,9,26,32,8,9,25,27,31,32,33,10,24,28,30,32,34,6,11, - 29,30,31,35,12,17,30,36,13,31,35,37,14,15,32,34,38,14,15,33,37,38,39,16,32, - 34,36,38,40,12,17,31,35,36,37,41,12,16,17,18,23,36,40,42,13,14,15,19,37,39, - 43,13,14,15,20,21,38,43,44,13,14,15,20,21,37,39,43,44,45,12,16,17,22,36,40, - 42,46,12,16,17,18,23,41,42,46,47], - [2.83226851852e6,1.63544753086e6,1.72436728395e6,-2.0e6,-2.08333333333e6, - 1.00333333333e9,1.0e6,-2.77777777778e6,1.0675e9,2.08333333333e6, - 5.55555555555e6,1.53533333333e9,-3333.33333333,-1.0e6,2.83226851852e6, - -6666.66666667,2.0e6,1.63544753086e6,-1.68e6,1.72436728395e6,-2.0e6,4.0e8, - 2.0e6,-2.08333333333e6,1.00333333333e9,1.0e6,2.0e8,-1.0e6,-2.77777777778e6, - 1.0675e9,-2.0e6,2.08333333333e6,5.55555555555e6,1.53533333333e9,-2.8e6, - 2.8360994695e6,-30864.1975309,-5.55555555555e6,1.76741074446e6, - -15432.0987654,2.77777777778e6,517922.131816,3.89003806848e6, - -3.33333333333e6,4.29857058902e6,-2.6349902747e6,1.97572063531e9, - -2.77777777778e6,3.33333333333e8,-2.14928529451e6,2.77777777778e6, - 1.52734651547e9,5.55555555555e6,6.66666666667e8,2.35916180402e6, - -5.55555555555e6,-1.09779731332e8,1.56411143711e9,-2.8e6,-3333.33333333, - 1.0e6,2.83226851852e6,-30864.1975309,-5.55555555555e6,-6666.66666667, - -2.0e6,1.63544753086e6,-15432.0987654,2.77777777778e6,-1.68e6, - 1.72436728395e6,-3.33333333333e6,2.0e6,4.0e8,-2.0e6,-2.08333333333e6, - 1.00333333333e9,-2.77777777778e6,3.33333333333e8,-1.0e6,2.0e8,1.0e6, - 2.77777777778e6,1.0675e9,5.55555555555e6,6.66666666667e8,-2.0e6, - 2.08333333333e6,-5.55555555555e6,1.53533333333e9,-28935.1851852, - -2.08333333333e6,60879.6296296,-1.59791666667e6,3.37291666667e6, - -28935.1851852,2.08333333333e6,2.41171296296e6,-2.08333333333e6, - 1.0e8,-2.5e6,-416666.666667,1.5e9,-833333.333333,1.25e6,5.01833333333e8, - 2.08333333333e6,1.0e8,416666.666667,5.025e8,-28935.1851852, - -2.08333333333e6,-4166.66666667,-1.25e6,3.98587962963e6,-1.59791666667e6, - -8333.33333333,2.5e6,3.41149691358e6,-28935.1851852,2.08333333333e6, - -2.355e6,2.43100308642e6,-2.08333333333e6,1.0e8,-2.5e6,5.0e8,2.5e6, - -416666.666667,1.50416666667e9,-833333.333333,1.25e6,2.5e8,-1.25e6, - -3.47222222222e6,1.33516666667e9,2.08333333333e6,1.0e8,-2.5e6, - 416666.666667,6.94444444444e6,2.16916666667e9,-28935.1851852, - -2.08333333333e6,-3.925e6,3.98587962963e6,-1.59791666667e6, - -38580.2469136,-6.94444444444e6,3.41149691358e6,-28935.1851852, - 2.08333333333e6,-19290.1234568,3.47222222222e6,2.43100308642e6, - -2.08333333333e6,1.0e8,-4.16666666667e6,2.5e6,-416666.666667, - 1.50416666667e9,-833333.333333,-3.47222222222e6,4.16666666667e8, - -1.25e6,3.47222222222e6,1.33516666667e9,2.08333333333e6,1.0e8, - 6.94444444445e6,8.33333333333e8,416666.666667,-6.94444444445e6, - 2.16916666667e9,-3830.95098171,1.14928529451e6,-275828.470683, - -28935.1851852,-2.08333333333e6,-4166.66666667,1.25e6,64710.5806113, - -131963.213599,-517922.131816,-2.29857058902e6,-1.59791666667e6, - -8333.33333333,-2.5e6,3.50487988027e6,-517922.131816,-2.16567078453e6, - 551656.941366,-28935.1851852,2.08333333333e6,-2.355e6,517922.131816, - 4.57738374749e6,2.29857058902e6,-551656.941367,4.8619365099e8, - -2.08333333333e6,1.0e8,2.5e6,5.0e8,-4.79857058902e6,134990.2747, - 2.47238730198e9,-1.14928529451e6,2.29724661236e8,-5.57173510779e7, - -833333.333333,-1.25e6,2.5e8,2.39928529451e6,9.61679848804e8,275828.470683, - -5.57173510779e7,1.09411960038e7,2.08333333333e6,1.0e8,-2.5e6, - 140838.195984,-1.09779731332e8,5.31278103775e8], 1) - @test CHOLMOD.norm_sparse(A, 0) ≈ 3.570948074697437e9 - @test CHOLMOD.norm_sparse(A, 1) ≈ 3.570948074697437e9 - @test_throws ArgumentError CHOLMOD.norm_sparse(A, 2) - @test CHOLMOD.isvalid(A) - - x = fill(1., n) - b = A*x - - chma = ldlt(A) # LDL' form - @test CHOLMOD.isvalid(chma) - @test unsafe_load(pointer(chma)).is_ll == 0 # check that it is in fact an LDLt - @test chma\b ≈ x - @test nnz(ldlt(A, perm=1:size(A,1))) > nnz(chma) - @test size(chma) == size(A) - chmal = CHOLMOD.FactorComponent(chma, :L) - @test size(chmal) == size(A) - @test size(chmal, 1) == size(A, 1) - - chma = cholesky(A) # LL' form - @test CHOLMOD.isvalid(chma) - @test unsafe_load(pointer(chma)).is_ll == 1 # check that it is in fact an LLt - @test chma\b ≈ x - @test nnz(chma) == 489 - @test nnz(cholesky(A, perm=1:size(A,1))) > nnz(chma) - @test size(chma) == size(A) - chmal = CHOLMOD.FactorComponent(chma, :L) - @test size(chmal) == size(A) - @test size(chmal, 1) == size(A, 1) - - @testset "eltype" begin - @test eltype(Dense(fill(1., 3))) == Float64 - @test eltype(A) == Float64 - @test eltype(chma) == Float64 - end -end - -@testset "lp_afiro example" begin - afiro = CHOLMOD.Sparse(27, 51, - CHOLMOD.SuiteSparse_long[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19, - 23,25,27,29,33,37,41,45,47,49,51,53,55,57,59,63,65,67,69,71,75,79,83,87,89, - 91,93,95,97,99,101,102], - CHOLMOD.SuiteSparse_long[2,3,6,7,8,9,12,13,16,17,18,19,20,21,22,23,24,25,26, - 0,1,2,23,0,3,0,21,1,25,4,5,6,24,4,5,7,24,4,5,8,24,4,5,9,24,6,20,7,20,8,20,9, - 20,3,4,4,22,5,26,10,11,12,21,10,13,10,23,10,20,11,25,14,15,16,22,14,15,17, - 22,14,15,18,22,14,15,19,22,16,20,17,20,18,20,19,20,13,15,15,24,14,26,15], - [1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, - 1.0,-1.0,-1.06,1.0,0.301,1.0,-1.0,1.0,-1.0,1.0,1.0,-1.0,-1.06,1.0,0.301, - -1.0,-1.06,1.0,0.313,-1.0,-0.96,1.0,0.313,-1.0,-0.86,1.0,0.326,-1.0,2.364, - -1.0,2.386,-1.0,2.408,-1.0,2.429,1.4,1.0,1.0,-1.0,1.0,1.0,-1.0,-0.43,1.0, - 0.109,1.0,-1.0,1.0,-1.0,1.0,-1.0,1.0,1.0,-0.43,1.0,1.0,0.109,-0.43,1.0,1.0, - 0.108,-0.39,1.0,1.0,0.108,-0.37,1.0,1.0,0.107,-1.0,2.191,-1.0,2.219,-1.0, - 2.249,-1.0,2.279,1.4,-1.0,1.0,-1.0,1.0,1.0,1.0], 0) - afiro2 = CHOLMOD.aat(afiro, CHOLMOD.SuiteSparse_long[0:50;], CHOLMOD.SuiteSparse_long(1)) - CHOLMOD.change_stype!(afiro2, -1) - chmaf = cholesky(afiro2) - y = afiro'*fill(1., size(afiro,1)) - sol = chmaf\(afiro*y) # least squares solution - @test CHOLMOD.isvalid(sol) - pred = afiro'*sol - @test norm(afiro * (convert(Matrix, y) - convert(Matrix, pred))) < 1e-8 -end - -@testset "Issue 9160" begin - local A, B - A = sprand(10, 10, 0.1) - A = convert(SparseMatrixCSC{Float64,CHOLMOD.SuiteSparse_long}, A) - cmA = CHOLMOD.Sparse(A) - - B = sprand(10, 10, 0.1) - B = convert(SparseMatrixCSC{Float64,CHOLMOD.SuiteSparse_long}, B) - cmB = CHOLMOD.Sparse(B) - - # Ac_mul_B - @test sparse(cmA'*cmB) ≈ A'*B - - # A_mul_Bc - @test sparse(cmA*cmB') ≈ A*B' - - # A_mul_Ac - @test sparse(cmA*cmA') ≈ A*A' - - # Ac_mul_A - @test sparse(cmA'*cmA) ≈ A'*A - - # A_mul_Ac for symmetric A - A = 0.5*(A + copy(A')) - cmA = CHOLMOD.Sparse(A) - @test sparse(cmA*cmA') ≈ A*A' -end - -@testset "Issue #9915" begin - sparseI = sparse(1.0I, 2, 2) - @test sparseI \ sparseI == sparseI -end - -@testset "test Sparse constructor Symmetric and Hermitian input (and issymmetric and ishermitian)" begin - ACSC = sprandn(10, 10, 0.3) + I - @test issymmetric(Sparse(Symmetric(ACSC, :L))) - @test issymmetric(Sparse(Symmetric(ACSC, :U))) - @test ishermitian(Sparse(Hermitian(complex(ACSC), :L))) - @test ishermitian(Sparse(Hermitian(complex(ACSC), :U))) -end - -@testset "test Sparse constructor for C_Sparse{Cvoid} (and read_sparse)" begin - mktempdir() do temp_dir - testfile = joinpath(temp_dir, "tmp.mtx") - - writedlm(testfile, ["%%MatrixMarket matrix coordinate real symmetric","3 3 4","1 1 1","2 2 1","3 2 0.5","3 3 1"]) - @test sparse(CHOLMOD.Sparse(testfile)) == [1 0 0;0 1 0.5;0 0.5 1] - rm(testfile) - - writedlm(testfile, ["%%MatrixMarket matrix coordinate complex Hermitian", - "3 3 4","1 1 1.0 0.0","2 2 1.0 0.0","3 2 0.5 0.5","3 3 1.0 0.0"]) - @test sparse(CHOLMOD.Sparse(testfile)) == [1 0 0;0 1 0.5-0.5im;0 0.5+0.5im 1] - rm(testfile) - - writedlm(testfile, ["%%MatrixMarket matrix coordinate real symmetric","%3 3 4","1 1 1","2 2 1","3 2 0.5","3 3 1"]) - @test_throws ArgumentError sparse(CHOLMOD.Sparse(testfile)) - rm(testfile) - end -end - -@testset "test that Sparse(Ptr) constructor throws the right places" begin - @test_throws ArgumentError CHOLMOD.Sparse(convert(Ptr{CHOLMOD.C_Sparse{Float64}}, C_NULL)) - @test_throws ArgumentError CHOLMOD.Sparse(convert(Ptr{CHOLMOD.C_Sparse{Cvoid}}, C_NULL)) -end - -## The struct pointer must be constructed by the library constructor and then modified afterwards to checks that the method throws -@testset "illegal dtype (for now but should be supported at some point)" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Cvoid}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - puint = convert(Ptr{UInt32}, p) - unsafe_store!(puint, CHOLMOD.SINGLE, 3*div(sizeof(Csize_t), 4) + 5*div(sizeof(Ptr{Cvoid}), 4) + 4) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.Sparse(p) -end - -@testset "illegal dtype" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Cvoid}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - puint = convert(Ptr{UInt32}, p) - unsafe_store!(puint, 5, 3*div(sizeof(Csize_t), 4) + 5*div(sizeof(Ptr{Cvoid}), 4) + 4) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.Sparse(p) -end - -@testset "illegal xtype" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Cvoid}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - puint = convert(Ptr{UInt32}, p) - unsafe_store!(puint, 3, 3*div(sizeof(Csize_t), 4) + 5*div(sizeof(Ptr{Cvoid}), 4) + 3) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.Sparse(p) -end - -@testset "illegal itype I" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Cvoid}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - puint = convert(Ptr{UInt32}, p) - unsafe_store!(puint, CHOLMOD.INTLONG, 3*div(sizeof(Csize_t), 4) + 5*div(sizeof(Ptr{Cvoid}), 4) + 2) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.Sparse(p) -end - -@testset "illegal itype II" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Cvoid}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - puint = convert(Ptr{UInt32}, p) - unsafe_store!(puint, 5, 3*div(sizeof(Csize_t), 4) + 5*div(sizeof(Ptr{Cvoid}), 4) + 2) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.Sparse(p) -end - -# Test Dense wrappers (only Float64 supported a present) - -@testset "High level interface" for elty in (Float64, ComplexF64) - local A, b - if elty == Float64 - A = randn(5, 5) - b = randn(5) - else - A = complex.(randn(5, 5), randn(5, 5)) - b = complex.(randn(5), randn(5)) - end - ADense = CHOLMOD.Dense(A) - bDense = CHOLMOD.Dense(b) - - @test_throws BoundsError ADense[6, 1] - @test_throws BoundsError ADense[1, 6] - @test copy(ADense) == ADense - @test CHOLMOD.norm_dense(ADense, 1) ≈ opnorm(A, 1) - @test CHOLMOD.norm_dense(ADense, 0) ≈ opnorm(A, Inf) - @test_throws ArgumentError CHOLMOD.norm_dense(ADense, 2) - @test_throws ArgumentError CHOLMOD.norm_dense(ADense, 3) - - @test CHOLMOD.norm_dense(bDense, 2) ≈ norm(b) - @test CHOLMOD.check_dense(bDense) - - AA = CHOLMOD.eye(3) - unsafe_store!(convert(Ptr{Csize_t}, pointer(AA)), 2, 1) # change size, but not stride, of Dense - @test convert(Matrix, AA) == Matrix(I, 2, 3) -end - -@testset "Low level interface" begin - @test isa(CHOLMOD.zeros(3, 3, Float64), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.zeros(3, 3), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.zeros(3, 3, Float64), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.ones(3, 3), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.eye(3, 4, Float64), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.eye(3, 4), CHOLMOD.Dense{Float64}) - @test isa(CHOLMOD.eye(3), CHOLMOD.Dense{Float64}) - @test isa(copy(CHOLMOD.eye(3)), CHOLMOD.Dense{Float64}) -end - -# Test Sparse and Factor -@testset "test free!" begin - p = ccall((:cholmod_l_allocate_sparse, :libcholmod), Ptr{CHOLMOD.C_Sparse{Float64}}, - (Csize_t, Csize_t, Csize_t, Cint, Cint, Cint, Cint, Ptr{Cvoid}), - 1, 1, 1, true, true, 0, CHOLMOD.REAL, CHOLMOD.common_struct[Threads.threadid()]) - @test CHOLMOD.free!(p) -end - -@testset "Core functionality" for elty in (Float64, ComplexF64) - A1 = sparse([1:5; 1], [1:5; 2], elty == Float64 ? randn(6) : complex.(randn(6), randn(6))) - A2 = sparse([1:5; 1], [1:5; 2], elty == Float64 ? randn(6) : complex.(randn(6), randn(6))) - A1pd = A1'A1 - A1Sparse = CHOLMOD.Sparse(A1) - A2Sparse = CHOLMOD.Sparse(A2) - A1pdSparse = CHOLMOD.Sparse( - size(A1pd, 1), - size(A1pd, 2), - SuiteSparse.decrement(getcolptr(A1pd)), - SuiteSparse.decrement(rowvals(A1pd)), - nonzeros(A1pd)) - - ## High level interface - @test isa(CHOLMOD.Sparse(3, 3, [0,1,3,4], [0,2,1,2], fill(1., 4)), CHOLMOD.Sparse) # Sparse doesn't require columns to be sorted - @test_throws BoundsError A1Sparse[6, 1] - @test_throws BoundsError A1Sparse[1, 6] - @test sparse(A1Sparse) == A1 - for i = 1:size(A1, 1) - A1[i, i] = real(A1[i, i]) - end #Construct Hermitian matrix properly - @test CHOLMOD.sparse(CHOLMOD.Sparse(Hermitian(A1, :L))) == Hermitian(A1, :L) - @test CHOLMOD.sparse(CHOLMOD.Sparse(Hermitian(A1, :U))) == Hermitian(A1, :U) - @test_throws ArgumentError convert(SparseMatrixCSC{elty,Int}, A1pdSparse) - if elty <: Real - @test_throws ArgumentError convert(Symmetric{Float64,SparseMatrixCSC{Float64,Int}}, A1Sparse) - else - @test_throws ArgumentError convert(Hermitian{ComplexF64,SparseMatrixCSC{ComplexF64,Int}}, A1Sparse) - end - @test copy(A1Sparse) == A1Sparse - @test size(A1Sparse, 3) == 1 - if elty <: Real # multiplication only defined for real matrices in CHOLMOD - @test A1Sparse*A2Sparse ≈ A1*A2 - @test_throws DimensionMismatch CHOLMOD.Sparse(A1[:,1:4])*A2Sparse - @test A1Sparse'A2Sparse ≈ A1'A2 - @test A1Sparse*A2Sparse' ≈ A1*A2' - - @test A1Sparse*A1Sparse ≈ A1*A1 - @test A1Sparse'A1Sparse ≈ A1'A1 - @test A1Sparse*A1Sparse' ≈ A1*A1' - - @test A1pdSparse*A1pdSparse ≈ A1pd*A1pd - @test A1pdSparse'A1pdSparse ≈ A1pd'A1pd - @test A1pdSparse*A1pdSparse' ≈ A1pd*A1pd' - - @test_throws DimensionMismatch A1Sparse*CHOLMOD.eye(4, 5, elty) - end - - # Factor - @test_throws ArgumentError cholesky(A1) - @test_throws ArgumentError cholesky(A1) - @test_throws ArgumentError cholesky(A1, shift=1.0) - @test_throws ArgumentError ldlt(A1) - @test_throws ArgumentError ldlt(A1, shift=1.0) - C = A1 + copy(adjoint(A1)) - λmaxC = eigmax(Array(C)) - b = fill(1., size(A1, 1)) - @test_throws PosDefException cholesky(C - 2λmaxC*I) - @test_throws PosDefException cholesky(C, shift=-2λmaxC) - @test_throws ZeroPivotException ldlt(C - C[1,1]*I) - @test_throws ZeroPivotException ldlt(C, shift=-real(C[1,1])) - @test !isposdef(cholesky(C - 2λmaxC*I; check = false)) - @test !isposdef(cholesky(C, shift=-2λmaxC; check = false)) - @test !issuccess(ldlt(C - C[1,1]*I; check = false)) - @test !issuccess(ldlt(C, shift=-real(C[1,1]); check = false)) - F = cholesky(A1pd) - tmp = IOBuffer() - show(tmp, F) - @test tmp.size > 0 - @test isa(CHOLMOD.Sparse(F), CHOLMOD.Sparse{elty}) - @test_throws DimensionMismatch F\CHOLMOD.Dense(fill(elty(1), 4)) - @test_throws DimensionMismatch F\CHOLMOD.Sparse(sparse(fill(elty(1), 4))) - b = fill(1., 5) - bT = fill(elty(1), 5) - @test F'\bT ≈ Array(A1pd)'\b - @test F'\sparse(bT) ≈ Array(A1pd)'\b - @test transpose(F)\bT ≈ conj(A1pd)'\bT - @test F\CHOLMOD.Sparse(sparse(bT)) ≈ A1pd\b - @test logdet(F) ≈ logdet(Array(A1pd)) - @test det(F) == exp(logdet(F)) - let # to test supernodal, we must use a larger matrix - Ftmp = sprandn(100, 100, 0.1) - Ftmp = Ftmp'Ftmp + I - @test logdet(cholesky(Ftmp)) ≈ logdet(Array(Ftmp)) - end - @test logdet(ldlt(A1pd)) ≈ logdet(Array(A1pd)) - @test isposdef(A1pd) - @test !isposdef(A1) - @test !isposdef(A1 + copy(A1') |> t -> t - 2eigmax(Array(t))*I) - - if elty <: Real - @test CHOLMOD.issymmetric(Sparse(A1pd, 0)) - @test CHOLMOD.Sparse(cholesky(Symmetric(A1pd, :L))) == CHOLMOD.Sparse(cholesky(A1pd)) - F1 = CHOLMOD.Sparse(cholesky(Symmetric(A1pd, :L), shift=2)) - F2 = CHOLMOD.Sparse(cholesky(A1pd, shift=2)) - @test F1 == F2 - @test CHOLMOD.Sparse(ldlt(Symmetric(A1pd, :L))) == CHOLMOD.Sparse(ldlt(A1pd)) - F1 = CHOLMOD.Sparse(ldlt(Symmetric(A1pd, :L), shift=2)) - F2 = CHOLMOD.Sparse(ldlt(A1pd, shift=2)) - @test F1 == F2 - else - @test !CHOLMOD.issymmetric(Sparse(A1pd, 0)) - @test CHOLMOD.ishermitian(Sparse(A1pd, 0)) - @test CHOLMOD.Sparse(cholesky(Hermitian(A1pd, :L))) == CHOLMOD.Sparse(cholesky(A1pd)) - F1 = CHOLMOD.Sparse(cholesky(Hermitian(A1pd, :L), shift=2)) - F2 = CHOLMOD.Sparse(cholesky(A1pd, shift=2)) - @test F1 == F2 - @test CHOLMOD.Sparse(ldlt(Hermitian(A1pd, :L))) == CHOLMOD.Sparse(ldlt(A1pd)) - F1 = CHOLMOD.Sparse(ldlt(Hermitian(A1pd, :L), shift=2)) - F2 = CHOLMOD.Sparse(ldlt(A1pd, shift=2)) - @test F1 == F2 - end - - ### cholesky!/ldlt! - F = cholesky(A1pd) - CHOLMOD.change_factor!(F, false, false, true, true) - @test unsafe_load(pointer(F)).is_ll == 0 - CHOLMOD.change_factor!(F, true, false, true, true) - @test CHOLMOD.Sparse(cholesky!(copy(F), A1pd)) ≈ CHOLMOD.Sparse(F) # surprisingly, this can cause small ulp size changes so we cannot test exact equality - @test size(F, 2) == 5 - @test size(F, 3) == 1 - @test_throws ArgumentError size(F, 0) - - F = cholesky(A1pdSparse, shift=2) - @test isa(CHOLMOD.Sparse(F), CHOLMOD.Sparse{elty}) - @test CHOLMOD.Sparse(cholesky!(copy(F), A1pd, shift=2.0)) ≈ CHOLMOD.Sparse(F) # surprisingly, this can cause small ulp size changes so we cannot test exact equality - - F = ldlt(A1pd) - @test isa(CHOLMOD.Sparse(F), CHOLMOD.Sparse{elty}) - @test CHOLMOD.Sparse(ldlt!(copy(F), A1pd)) ≈ CHOLMOD.Sparse(F) # surprisingly, this can cause small ulp size changes so we cannot test exact equality - - F = ldlt(A1pdSparse, shift=2) - @test isa(CHOLMOD.Sparse(F), CHOLMOD.Sparse{elty}) - @test CHOLMOD.Sparse(ldlt!(copy(F), A1pd, shift=2.0)) ≈ CHOLMOD.Sparse(F) # surprisingly, this can cause small ulp size changes so we cannot test exact equality - - @test isa(CHOLMOD.factor_to_sparse!(F), CHOLMOD.Sparse) - @test_throws CHOLMOD.CHOLMODException CHOLMOD.factor_to_sparse!(F) - - ## Low level interface - @test CHOLMOD.nnz(A1Sparse) == nnz(A1) - @test CHOLMOD.speye(5, 5, elty) == Matrix(I, 5, 5) - @test CHOLMOD.spzeros(5, 5, 5, elty) == zeros(elty, 5, 5) - if elty <: Real - @test CHOLMOD.copy(A1Sparse, 0, 1) == A1Sparse - @test CHOLMOD.horzcat(A1Sparse, A2Sparse, true) == [A1 A2] - @test CHOLMOD.vertcat(A1Sparse, A2Sparse, true) == [A1; A2] - svec = fill(elty(1), 1) - @test CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.SCALAR, A1Sparse) == A1Sparse - svec = fill(elty(1), 5) - @test_throws DimensionMismatch CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.SCALAR, A1Sparse) - @test CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.ROW, A1Sparse) == A1Sparse - @test_throws DimensionMismatch CHOLMOD.scale!(CHOLMOD.Dense([svec; 1]), CHOLMOD.ROW, A1Sparse) - @test CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.COL, A1Sparse) == A1Sparse - @test_throws DimensionMismatch CHOLMOD.scale!(CHOLMOD.Dense([svec; 1]), CHOLMOD.COL, A1Sparse) - @test CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.SYM, A1Sparse) == A1Sparse - @test_throws DimensionMismatch CHOLMOD.scale!(CHOLMOD.Dense([svec; 1]), CHOLMOD.SYM, A1Sparse) - @test_throws DimensionMismatch CHOLMOD.scale!(CHOLMOD.Dense(svec), CHOLMOD.SYM, CHOLMOD.Sparse(A1[:,1:4])) - else - @test_throws MethodError CHOLMOD.copy(A1Sparse, 0, 1) == A1Sparse - @test_throws MethodError CHOLMOD.horzcat(A1Sparse, A2Sparse, true) == [A1 A2] - @test_throws MethodError CHOLMOD.vertcat(A1Sparse, A2Sparse, true) == [A1; A2] - end - - if elty <: Real - @test CHOLMOD.ssmult(A1Sparse, A2Sparse, 0, true, true) ≈ A1*A2 - @test CHOLMOD.aat(A1Sparse, [0:size(A1,2)-1;], 1) ≈ A1*A1' - @test CHOLMOD.aat(A1Sparse, [0:1;], 1) ≈ A1[:,1:2]*A1[:,1:2]' - @test CHOLMOD.copy(A1Sparse, 0, 1) == A1Sparse - end - - @test CHOLMOD.Sparse(CHOLMOD.Dense(A1Sparse)) == A1Sparse -end - -@testset "extract factors" begin - Af = float([4 12 -16; 12 37 -43; -16 -43 98]) - As = sparse(Af) - Lf = float([2 0 0; 6 1 0; -8 5 3]) - LDf = float([4 0 0; 3 1 0; -4 5 9]) # D is stored along the diagonal - L_f = float([1 0 0; 3 1 0; -4 5 1]) # L by itself in LDLt of Af - D_f = float([4 0 0; 0 1 0; 0 0 9]) - p = [2,3,1] - p_inv = [3,1,2] - - @testset "cholesky, no permutation" begin - Fs = cholesky(As, perm=[1:3;]) - @test Fs.p == [1:3;] - @test sparse(Fs.L) ≈ Lf - @test sparse(Fs) ≈ As - b = rand(3) - @test Fs\b ≈ Af\b - @test Fs.UP\(Fs.PtL\b) ≈ Af\b - @test Fs.L\b ≈ Lf\b - @test Fs.U\b ≈ Lf'\b - @test Fs.L'\b ≈ Lf'\b - @test Fs.U'\b ≈ Lf\b - @test Fs.PtL\b ≈ Lf\b - @test Fs.UP\b ≈ Lf'\b - @test Fs.PtL'\b ≈ Lf'\b - @test Fs.UP'\b ≈ Lf\b - @test_throws CHOLMOD.CHOLMODException Fs.D - @test_throws CHOLMOD.CHOLMODException Fs.LD - @test_throws CHOLMOD.CHOLMODException Fs.DU - @test_throws CHOLMOD.CHOLMODException Fs.PLD - @test_throws CHOLMOD.CHOLMODException Fs.DUPt - end - - @testset "cholesky, with permutation" begin - Fs = cholesky(As, perm=p) - @test Fs.p == p - Afp = Af[p,p] - Lfp = cholesky(Afp).L - Ls = sparse(Fs.L) - @test Ls ≈ Lfp - @test Ls * Ls' ≈ Afp - P = sparse(1:3, Fs.p, ones(3)) - @test P' * Ls * Ls' * P ≈ As - @test sparse(Fs) ≈ As - b = rand(3) - @test Fs\b ≈ Af\b - @test Fs.UP\(Fs.PtL\b) ≈ Af\b - @test Fs.L\b ≈ Lfp\b - @test Fs.U'\b ≈ Lfp\b - @test Fs.U\b ≈ Lfp'\b - @test Fs.L'\b ≈ Lfp'\b - @test Fs.PtL\b ≈ Lfp\b[p] - @test Fs.UP\b ≈ (Lfp'\b)[p_inv] - @test Fs.PtL'\b ≈ (Lfp'\b)[p_inv] - @test Fs.UP'\b ≈ Lfp\b[p] - @test_throws CHOLMOD.CHOLMODException Fs.PL - @test_throws CHOLMOD.CHOLMODException Fs.UPt - @test_throws CHOLMOD.CHOLMODException Fs.D - @test_throws CHOLMOD.CHOLMODException Fs.LD - @test_throws CHOLMOD.CHOLMODException Fs.DU - @test_throws CHOLMOD.CHOLMODException Fs.PLD - @test_throws CHOLMOD.CHOLMODException Fs.DUPt - end - - @testset "ldlt, no permutation" begin - Fs = ldlt(As, perm=[1:3;]) - @test Fs.p == [1:3;] - @test sparse(Fs.LD) ≈ LDf - @test sparse(Fs) ≈ As - b = rand(3) - @test Fs\b ≈ Af\b - @test Fs.UP\(Fs.PtLD\b) ≈ Af\b - @test Fs.DUP\(Fs.PtL\b) ≈ Af\b - @test Fs.L\b ≈ L_f\b - @test Fs.U\b ≈ L_f'\b - @test Fs.L'\b ≈ L_f'\b - @test Fs.U'\b ≈ L_f\b - @test Fs.PtL\b ≈ L_f\b - @test Fs.UP\b ≈ L_f'\b - @test Fs.PtL'\b ≈ L_f'\b - @test Fs.UP'\b ≈ L_f\b - @test Fs.D\b ≈ D_f\b - @test Fs.D'\b ≈ D_f\b - @test Fs.LD\b ≈ D_f\(L_f\b) - @test Fs.DU'\b ≈ D_f\(L_f\b) - @test Fs.LD'\b ≈ L_f'\(D_f\b) - @test Fs.DU\b ≈ L_f'\(D_f\b) - @test Fs.PtLD\b ≈ D_f\(L_f\b) - @test Fs.DUP'\b ≈ D_f\(L_f\b) - @test Fs.PtLD'\b ≈ L_f'\(D_f\b) - @test Fs.DUP\b ≈ L_f'\(D_f\b) - end - - @testset "ldlt, with permutation" begin - Fs = ldlt(As, perm=p) - @test Fs.p == p - @test sparse(Fs) ≈ As - b = rand(3) - Asp = As[p,p] - LDp = sparse(ldlt(Asp, perm=[1,2,3]).LD) - # LDp = sparse(Fs.LD) - Lp, dp = SuiteSparse.CHOLMOD.getLd!(copy(LDp)) - Dp = sparse(Diagonal(dp)) - @test Fs\b ≈ Af\b - @test Fs.UP\(Fs.PtLD\b) ≈ Af\b - @test Fs.DUP\(Fs.PtL\b) ≈ Af\b - @test Fs.L\b ≈ Lp\b - @test Fs.U\b ≈ Lp'\b - @test Fs.L'\b ≈ Lp'\b - @test Fs.U'\b ≈ Lp\b - @test Fs.PtL\b ≈ Lp\b[p] - @test Fs.UP\b ≈ (Lp'\b)[p_inv] - @test Fs.PtL'\b ≈ (Lp'\b)[p_inv] - @test Fs.UP'\b ≈ Lp\b[p] - @test Fs.LD\b ≈ Dp\(Lp\b) - @test Fs.DU'\b ≈ Dp\(Lp\b) - @test Fs.LD'\b ≈ Lp'\(Dp\b) - @test Fs.DU\b ≈ Lp'\(Dp\b) - @test Fs.PtLD\b ≈ Dp\(Lp\b[p]) - @test Fs.DUP'\b ≈ Dp\(Lp\b[p]) - @test Fs.PtLD'\b ≈ (Lp'\(Dp\b))[p_inv] - @test Fs.DUP\b ≈ (Lp'\(Dp\b))[p_inv] - @test_throws CHOLMOD.CHOLMODException Fs.DUPt - @test_throws CHOLMOD.CHOLMODException Fs.PLD - end - - @testset "Element promotion and type inference" begin - @inferred cholesky(As)\fill(1, size(As, 1)) - @inferred ldlt(As)\fill(1, size(As, 1)) - end -end - -@testset "Issue 11745 - row and column pointers were not sorted in sparse(Factor)" begin - A = Float64[10 1 1 1; 1 10 0 0; 1 0 10 0; 1 0 0 10] - @test sparse(cholesky(sparse(A))) ≈ A -end -GC.gc() - -@testset "Issue 11747 - Wrong show method defined for FactorComponent" begin - v = cholesky(sparse(Float64[ 10 1 1 1; 1 10 0 0; 1 0 10 0; 1 0 0 10])).L - for s in (sprint(show, MIME("text/plain"), v), sprint(show, v)) - @test occursin("method: simplicial", s) - @test !occursin("#undef", s) - end -end - -@testset "Issue 14076" begin - @test cholesky(sparse([1,2,3,4], [1,2,3,4], Float32[1,4,16,64]))\[1,4,16,64] == fill(1, 4) -end - -@testset "Issue 29367" begin - if Int != Int32 - @test_throws MethodError cholesky(sparse(Int32[1,2,3,4], Int32[1,2,3,4], Float64[1,4,16,64])) - @test_throws MethodError cholesky(sparse(Int32[1,2,3,4], Int32[1,2,3,4], Float32[1,4,16,64])) - @test_throws MethodError ldlt(sparse(Int32[1,2,3,4], Int32[1,2,3,4], Float64[1,4,16,64])) - @test_throws MethodError ldlt(sparse(Int32[1,2,3,4], Int32[1,2,3,4], Float32[1,4,16,64])) - end -end - -@testset "Issue 14134" begin - A = CHOLMOD.Sparse(sprandn(10,5,0.1) + I |> t -> t't) - b = IOBuffer() - serialize(b, A) - seekstart(b) - Anew = deserialize(b) - @test_throws ArgumentError show(Anew) - @test_throws ArgumentError size(Anew) - @test_throws ArgumentError Anew[1] - @test_throws ArgumentError Anew[2,1] - F = cholesky(A) - serialize(b, F) - seekstart(b) - Fnew = deserialize(b) - @test_throws ArgumentError Fnew\fill(1., 5) - @test_throws ArgumentError show(Fnew) - @test_throws ArgumentError size(Fnew) - @test_throws ArgumentError diag(Fnew) - @test_throws ArgumentError logdet(Fnew) -end - -@testset "Issue #28985" begin - @test typeof(cholesky(sparse(I, 4, 4))'\rand(4)) == Array{Float64, 1} - @test typeof(cholesky(sparse(I, 4, 4))'\rand(4,1)) == Array{Float64, 2} -end - -@testset "Issue with promotion during conversion to CHOLMOD.Dense" begin - @test CHOLMOD.Dense(fill(1, 5)) == fill(1, 5, 1) - @test CHOLMOD.Dense(fill(1f0, 5)) == fill(1, 5, 1) - @test CHOLMOD.Dense(fill(1f0 + 0im, 5, 2)) == fill(1, 5, 2) -end - -@testset "Further issue with promotion #14894" begin - x = fill(1., 5) - @test cholesky(sparse(Float16(1)I, 5, 5))\x == x - @test cholesky(Symmetric(sparse(Float16(1)I, 5, 5)))\x == x - @test cholesky(Hermitian(sparse(Complex{Float16}(1)I, 5, 5)))\x == x - @test_throws TypeError cholesky(sparse(BigFloat(1)I, 5, 5)) - @test_throws TypeError cholesky(Symmetric(sparse(BigFloat(1)I, 5, 5))) - @test_throws TypeError cholesky(Hermitian(sparse(Complex{BigFloat}(1)I, 5, 5))) -end - -@testset "test \\ for Factor and StridedVecOrMat" begin - x = rand(5) - A = cholesky(sparse(Diagonal(x.\1))) - @test A\view(fill(1.,10),1:2:10) ≈ x - @test A\view(Matrix(1.0I, 5, 5), :, :) ≈ Matrix(Diagonal(x)) -end - -@testset "Test \\ for Factor and SparseVecOrMat" begin - sparseI = sparse(1.0I, 100, 100) - sparseb = sprandn(100, 0.5) - sparseB = sprandn(100, 100, 0.5) - chI = cholesky(sparseI) - @test chI \ sparseb ≈ sparseb - @test chI \ sparseB ≈ sparseB - @test chI \ sparseI ≈ sparseI -end - -@testset "Real factorization and complex rhs" begin - A = sprandn(5, 5, 0.4) |> t -> t't + I - B = complex.(randn(5, 2), randn(5, 2)) - @test cholesky(A)\B ≈ A\B -end - -@testset "Make sure that ldlt performs an LDLt (Issue #19032)" begin - m, n = 400, 500 - A = sprandn(m, n, .2) - M = [I copy(A'); A -I] - b = M * fill(1., m+n) - F = ldlt(M) - s = unsafe_load(pointer(F)) - @test s.is_super == 0 - @test F\b ≈ fill(1., m+n) - F2 = cholesky(M; check = false) - @test !issuccess(F2) - ldlt!(F2, M) - @test issuccess(F2) - @test F2\b ≈ fill(1., m+n) -end - -@testset "Test that imaginary parts in Hermitian{T,SparseMatrixCSC{T}} are ignored" begin - A = sparse([1,2,3,4,1], [1,2,3,4,2], [complex(2.0,1),2,2,2,1]) - Fs = cholesky(Hermitian(A)) - Fd = cholesky(Hermitian(Array(A))) - @test sparse(Fs) ≈ Hermitian(A) - @test Fs\fill(1., 4) ≈ Fd\fill(1., 4) -end - -@testset "\\ '\\ and transpose(...)\\" begin - # Test that \ and '\ and transpose(...)\ work for Symmetric and Hermitian. This is just - # a dispatch exercise so it doesn't matter that the complex matrix has - # zero imaginary parts - Apre = sprandn(10, 10, 0.2) - I - for A in (Symmetric(Apre), Hermitian(Apre), - Symmetric(Apre + 10I), Hermitian(Apre + 10I), - Hermitian(complex(Apre)), Hermitian(complex(Apre) + 10I)) - local A, x, b - x = fill(1., 10) - b = A*x - @test x ≈ A\b - @test transpose(A)\b ≈ A'\b - end -end - -@testset "Check that Symmetric{SparseMatrixCSC} can be constructed from CHOLMOD.Sparse" begin - Int === Int32 && Random.seed!(124) - A = sprandn(10, 10, 0.1) - B = CHOLMOD.Sparse(A) - C = B'B - # Change internal representation to symmetric (upper/lower) - o = fieldoffset(CHOLMOD.C_Sparse{eltype(C)}, findall(fieldnames(CHOLMOD.C_Sparse{eltype(C)}) .== :stype)[1]) - for uplo in (1, -1) - unsafe_store!(Ptr{Int8}(pointer(C)), uplo, Int(o) + 1) - @test convert(Symmetric{Float64,SparseMatrixCSC{Float64,Int}}, C) ≈ Symmetric(A'A) - end -end - -@testset "Check inputs to Sparse. Related to #20024" for A_ in ( - SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[]), - SparseMatrixCSC(2, 2, [1, 2, 3], CHOLMOD.SuiteSparse_long[1,2], Float64[1.0])) - args = (size(A_)..., getcolptr(A_) .- 1, rowvals(A_) .- 1, nonzeros(A_)) - @test_throws ArgumentError CHOLMOD.Sparse(args...) - @test_throws ArgumentError CHOLMOD.Sparse(A_) -end - -@testset "sparse right multiplication of Symmetric and Hermitian matrices #21431" begin - S = sparse(1.0I, 2, 2) - @test issparse(S*S*S) - for T in (Symmetric, Hermitian) - @test issparse(S*T(S)*S) - @test issparse(S*(T(S)*S)) - @test issparse((S*T(S))*S) - end -end - -@testset "Test sparse low rank update for cholesky decomposion" begin - A = SparseMatrixCSC{Float64,CHOLMOD.SuiteSparse_long}(10, 5, [1,3,6,8,10,13], [6,7,1,2,9,3,5,1,7,6,7,9], - [-0.138843, 2.99571, -0.556814, 0.669704, -1.39252, 1.33814, - 1.02371, -0.502384, 1.10686, 0.262229, -1.6935, 0.525239]) - AtA = A'*A - C0 = [1., 2., 0, 0, 0] - # Test both cholesky and LDLt with and without automatic permutations - for F in (cholesky(AtA), cholesky(AtA, perm=1:5), ldlt(AtA), ldlt(AtA, perm=1:5)) - local F - x0 = F\(b = fill(1., 5)) - #Test both sparse/dense and vectors/matrices - for Ctest in (C0, sparse(C0), [C0 2*C0], sparse([C0 2*C0])) - local x, C, F1 - C = copy(Ctest) - F1 = copy(F) - x = (AtA+C*C')\b - - #Test update - F11 = CHOLMOD.lowrankupdate(F1, C) - @test Array(sparse(F11)) ≈ AtA+C*C' - @test F11\b ≈ x - #Make sure we get back the same factor again - F10 = CHOLMOD.lowrankdowndate(F11, C) - @test Array(sparse(F10)) ≈ AtA - @test F10\b ≈ x0 - - #Test in-place update - CHOLMOD.lowrankupdate!(F1, C) - @test Array(sparse(F1)) ≈ AtA+C*C' - @test F1\b ≈ x - #Test in-place downdate - CHOLMOD.lowrankdowndate!(F1, C) - @test Array(sparse(F1)) ≈ AtA - @test F1\b ≈ x0 - - @test C == Ctest #Make sure C didn't change - end - end -end - -@testset "Issue #22335" begin - local A, F - A = sparse(1.0I, 3, 3) - @test issuccess(cholesky(A)) - A[3, 3] = -1 - F = cholesky(A; check = false) - @test !issuccess(F) - @test issuccess(ldlt!(F, A)) - A[3, 3] = 1 - @test A[:, 3:-1:1]\fill(1., 3) == [1, 1, 1] -end - -@testset "Non-positive definite matrices" begin - A = sparse(Float64[1 2; 2 1]) - B = sparse(ComplexF64[1 2; 2 1]) - for M in (A, B, Symmetric(A), Hermitian(B)) - F = cholesky(M; check = false) - @test_throws PosDefException cholesky(M) - @test_throws PosDefException cholesky!(F, M) - @test !issuccess(cholesky(M; check = false)) - @test !issuccess(cholesky!(F, M; check = false)) - end - A = sparse(Float64[0 0; 0 0]) - B = sparse(ComplexF64[0 0; 0 0]) - for M in (A, B, Symmetric(A), Hermitian(B)) - F = ldlt(M; check = false) - @test_throws ZeroPivotException ldlt(M) - @test_throws ZeroPivotException ldlt!(F, M) - @test !issuccess(ldlt(M; check = false)) - @test !issuccess(ldlt!(F, M; check = false)) - end -end - -@testset "Issues #27860 & #28363" begin - for typeA in (Float64, ComplexF64), typeB in (Float64, ComplexF64), transform in (identity, adjoint, transpose) - A = sparse(typeA[2.0 0.1; 0.1 2.0]) - B = randn(typeB, 2, 2) - @test A \ transform(B) ≈ cholesky(A) \ transform(B) ≈ Matrix(A) \ transform(B) - C = randn(typeA, 2, 2) - sC = sparse(C) - sF = typeA <: Real ? cholesky(Symmetric(A)) : cholesky(Hermitian(A)) - @test cholesky(A) \ transform(sC) ≈ Matrix(A) \ transform(C) - @test sF.PtL \ transform(A) ≈ sF.PtL \ Matrix(transform(A)) - end -end - -@testset "Issue #33365" begin - A = Sparse(spzeros(0, 0)) - @test A * A' == A - @test A' * A == A - B = Sparse(spzeros(0, 4)) - @test B * B' == Sparse(spzeros(0, 0)) - @test B' * B == Sparse(spzeros(4, 4)) - C = Sparse(spzeros(3, 0)) - @test C * C' == Sparse(spzeros(3, 3)) - @test C' * C == Sparse(spzeros(0, 0)) -end diff --git a/stdlib/SuiteSparse/test/runtests.jl b/stdlib/SuiteSparse/test/runtests.jl deleted file mode 100644 index cde54e9488818..0000000000000 --- a/stdlib/SuiteSparse/test/runtests.jl +++ /dev/null @@ -1,30 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using Test, Random -using SuiteSparse, LinearAlgebra, SparseArrays - -if Base.USE_GPL_LIBS - include("umfpack.jl") - include("cholmod.jl") - include("spqr.jl") - - # Test multithreaded execution - let p, cmd = `$(Base.julia_cmd()) --depwarn=error --startup-file=no threads.jl` - # test both nthreads==1 and nthreads>1. spawn a process to test whichever - # case we are not running currently. - other_nthreads = Threads.nthreads() == 1 ? 4 : 1 - p = run( - pipeline( - setenv( - cmd, - "JULIA_NUM_THREADS" => other_nthreads, - dir=@__DIR__()), - stdout = stdout, - stderr = stderr), - wait = false) - include("threads.jl") - if !success(p) - error("SuiteSparse threads test failed with nthreads == $other_nthreads") - end - end -end diff --git a/stdlib/SuiteSparse/test/spqr.jl b/stdlib/SuiteSparse/test/spqr.jl deleted file mode 100644 index d1802c7ccc3b3..0000000000000 --- a/stdlib/SuiteSparse/test/spqr.jl +++ /dev/null @@ -1,136 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using SuiteSparse.SPQR -using SuiteSparse.CHOLMOD -using SuiteSparse -using LinearAlgebra: I, istriu, norm, qr, rank, rmul!, lmul!, Adjoint, Transpose -using SparseArrays: sparse, sprandn, spzeros, SparseMatrixCSC - -@testset "Sparse QR" begin -m, n = 100, 10 -nn = 100 - -@test size(qr(sprandn(m, n, 0.1)).Q) == (m, m) - -@testset "element type of A: $eltyA" for eltyA in (Float64, ComplexF64) - if eltyA <: Real - A = sparse([1:n; rand(1:m, nn - n)], [1:n; rand(1:n, nn - n)], randn(nn), m, n) - else - A = sparse([1:n; rand(1:m, nn - n)], [1:n; rand(1:n, nn - n)], complex.(randn(nn), randn(nn)), m, n) - end - - F = qr(A) - @test size(F) == (m,n) - @test size(F, 1) == m - @test size(F, 2) == n - @test size(F, 3) == 1 - @test_throws ArgumentError size(F, 0) - - @testset "getindex" begin - @test istriu(F.R) - @test isperm(F.pcol) - @test isperm(F.prow) - @test_throws ErrorException F.T - end - - @testset "apply Q" begin - Q = F.Q - Imm = Matrix{Float64}(I, m, m) - @test Q' * (Q*Imm) ≈ Imm - @test (Imm*Q) * Q' ≈ Imm - - # test that Q'Pl*A*Pr = R - R0 = Q'*Array(A[F.prow, F.pcol]) - @test R0[1:n, :] ≈ F.R - @test norm(R0[n + 1:end, :], 1) < 1e-12 - - offsizeA = Matrix{Float64}(I, m+1, m+1) - @test_throws DimensionMismatch lmul!(Q, offsizeA) - @test_throws DimensionMismatch lmul!(adjoint(Q), offsizeA) - @test_throws DimensionMismatch rmul!(offsizeA, Q) - @test_throws DimensionMismatch rmul!(offsizeA, adjoint(Q)) - end - - @testset "element type of B: $eltyB" for eltyB in (Int, Float64, ComplexF64) - if eltyB == Int - B = rand(1:10, m, 2) - elseif eltyB <: Real - B = randn(m, 2) - else - B = complex.(randn(m, 2), randn(m, 2)) - end - - @inferred A\B - @test A\B[:,1] ≈ Array(A)\B[:,1] - @test A\B ≈ Array(A)\B - @test_throws DimensionMismatch A\B[1:m-1,:] - C, x = A[1:9, :], fill(eltyB(1), 9) - @test C*(C\x) ≈ x # Underdetermined system - end - - # Make sure that conversion to Sparse doesn't use SuiteSparse's symmetric flag - @test qr(SparseMatrixCSC{eltyA}(I, 5, 5)) \ fill(eltyA(1), 5) == fill(1, 5) -end - -@testset "basic solution of rank deficient ls" begin - A = sprandn(m, 5, 0.9)*sprandn(5, n, 0.9) - b = randn(m) - xs = A\b - xd = Array(A)\b - - # check that basic solution has more zeros - @test count(!iszero, xs) < count(!iszero, xd) - @test A*xs ≈ A*xd -end - -@testset "Issue 26367" begin - A = sparse([0.0 1 0 0; 0 0 0 0]) - @test Matrix(qr(A).Q) == Matrix(qr(Matrix(A)).Q) == Matrix(I, 2, 2) -end - -@testset "Issue 26368" begin - A = sparse([0.0 1 0 0; 0 0 0 0]) - F = qr(A) - @test F.Q*F.R == A[F.prow,F.pcol] -end - -@testset "select ordering overdetermined" begin - A = sparse([1:n; rand(1:m, nn - n)], [1:n; rand(1:n, nn - n)], randn(nn), m, n) - b = randn(m) - xref = Array(A) \ b - for ordering ∈ SuiteSparse.SPQR.ORDERINGS - QR = qr(A, ordering=ordering) - x = QR \ b - @test x ≈ xref - end - @test_throws ErrorException qr(A, ordering=Int32(10)) -end - -@testset "select ordering underdetermined" begin - A = sparse([1:n; rand(1:n, nn - n)], [1:n; rand(1:m, nn - n)], randn(nn), n, m) - b = A * ones(m) - for ordering ∈ SuiteSparse.SPQR.ORDERINGS - QR = qr(A, ordering=ordering) - x = QR \ b - # x ≂̸ Array(A) \ b; LAPACK returns a min-norm x while SPQR returns a basic x - @test A * x ≈ b - end - @test_throws ErrorException qr(A, ordering=Int32(10)) -end - -@testset "propertynames of QRSparse" begin - A = sparse([0.0 1 0 0; 0 0 0 0]) - F = qr(A) - @test propertynames(F) == (:R, :Q, :prow, :pcol) - @test propertynames(F, true) == (:R, :Q, :prow, :pcol, :factors, :τ, :cpiv, :rpivinv) -end - -@testset "rank" begin - S = sprandn(10, 5, 1.0)*sprandn(5, 10, 1.0) - @test rank(qr(S)) == 5 - @test rank(S) == 5 - @test all(iszero, (rank(qr(spzeros(10, i))) for i in 1:10)) - @test all(iszero, (rank(spzeros(10, i)) for i in 1:10)) -end - -end diff --git a/stdlib/SuiteSparse/test/threads.jl b/stdlib/SuiteSparse/test/threads.jl deleted file mode 100644 index 29e97500dc988..0000000000000 --- a/stdlib/SuiteSparse/test/threads.jl +++ /dev/null @@ -1,22 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using Test, LinearAlgebra, SparseArrays - -@testset "threaded SuiteSparse tests" begin - A = sprandn(200, 200, 0.2) - b = rand(200) - - function test(n::Integer) - _A = A[1:n, 1:n] - _b = b[1:n] - x = qr(_A) \ _b - return norm(x) - end - - res_threads = zeros(100) - Threads.@threads for i in 1:100 - res_threads[i] = test(i + 100) - end - - @test res_threads ≈ [test(i + 100) for i in 1:100] -end diff --git a/stdlib/SuiteSparse/test/umfpack.jl b/stdlib/SuiteSparse/test/umfpack.jl deleted file mode 100644 index a4f749f1ce58b..0000000000000 --- a/stdlib/SuiteSparse/test/umfpack.jl +++ /dev/null @@ -1,240 +0,0 @@ -# This file is a part of Julia. License is MIT: https://julialang.org/license - -using SuiteSparse.UMFPACK -using SuiteSparse -using SuiteSparse: increment! -using Serialization -using LinearAlgebra: - I, det, issuccess, ldiv!, lu, lu!, Adjoint, Transpose, SingularException, Diagonal -using SparseArrays: nnz, sparse, sprand, sprandn, SparseMatrixCSC - -@testset "UMFPACK wrappers" begin - se33 = sparse(1.0I, 3, 3) - do33 = fill(1., 3) - @test isequal(se33 \ do33, do33) - - # based on deps/Suitesparse-4.0.2/UMFPACK/Demo/umfpack_di_demo.c - - A0 = sparse(increment!([0,4,1,1,2,2,0,1,2,3,4,4]), - increment!([0,4,0,2,1,2,1,4,3,2,1,2]), - [2.,1.,3.,4.,-1.,-3.,3.,6.,2.,1.,4.,2.], 5, 5) - - @testset "Core functionality for $Tv elements" for Tv in (Float64, ComplexF64) - # We might be able to support two index sizes one day - for Ti in Base.uniontypes(SuiteSparse.UMFPACK.UMFITypes) - A = convert(SparseMatrixCSC{Tv,Ti}, A0) - lua = lu(A) - @test nnz(lua) == 18 - @test_throws ErrorException lua.Z - L,U,p,q,Rs = lua.:(:) - @test (Diagonal(Rs) * A)[p,q] ≈ L * U - - det(lua) ≈ det(Array(A)) - - b = [8., 45., -3., 3., 19.] - x = lua\b - @test x ≈ float([1:5;]) - - @test A*x ≈ b - z = complex.(b) - x = ldiv!(lua, z) - @test x ≈ float([1:5;]) - @test z === x - y = similar(z) - ldiv!(y, lua, complex.(b)) - @test y ≈ x - - @test A*x ≈ b - - b = [8., 20., 13., 6., 17.] - x = lua'\b - @test x ≈ float([1:5;]) - - @test A'*x ≈ b - z = complex.(b) - x = ldiv!(adjoint(lua), z) - @test x ≈ float([1:5;]) - @test x === z - y = similar(x) - ldiv!(y, adjoint(lua), complex.(b)) - @test y ≈ x - - @test A'*x ≈ b - x = transpose(lua) \ b - @test x ≈ float([1:5;]) - - @test transpose(A) * x ≈ b - x = ldiv!(transpose(lua), complex.(b)) - @test x ≈ float([1:5;]) - y = similar(x) - ldiv!(y, transpose(lua), complex.(b)) - @test y ≈ x - - @test transpose(A) * x ≈ b - - # Element promotion and type inference - @inferred lua\fill(1, size(A, 2)) - end - end - - @testset "More tests for complex cases" begin - Ac0 = complex.(A0,A0) - for Ti in Base.uniontypes(SuiteSparse.UMFPACK.UMFITypes) - Ac = convert(SparseMatrixCSC{ComplexF64,Ti}, Ac0) - x = fill(1.0 + im, size(Ac,1)) - lua = lu(Ac) - L,U,p,q,Rs = lua.:(:) - @test (Diagonal(Rs) * Ac)[p,q] ≈ L * U - b = Ac*x - @test Ac\b ≈ x - b = Ac'*x - @test Ac'\b ≈ x - b = transpose(Ac)*x - @test transpose(Ac)\b ≈ x - end - end - - @testset "Rectangular cases. elty=$elty, m=$m, n=$n" for - elty in (Float64, ComplexF64), - (m, n) in ((10,5), (5, 10)) - - Random.seed!(30072018) - A = sparse([1:min(m,n); rand(1:m, 10)], [1:min(m,n); rand(1:n, 10)], elty == Float64 ? randn(min(m, n) + 10) : complex.(randn(min(m, n) + 10), randn(min(m, n) + 10))) - F = lu(A) - L, U, p, q, Rs = F.:(:) - @test (Diagonal(Rs) * A)[p,q] ≈ L * U - end - - @testset "Issue #4523 - complex sparse \\" begin - A, b = sparse((1.0 + im)I, 2, 2), fill(1., 2) - @test A * (lu(A)\b) ≈ b - - @test det(sparse([1,3,3,1], [1,1,3,3], [1,1,1,1])) == 0 - end - - @testset "UMFPACK_ERROR_n_nonpositive" begin - @test_throws ArgumentError lu(sparse(Int[], Int[], Float64[], 5, 0)) - end - - @testset "Issue #15099" for (Tin, Tout) in ( - (ComplexF16, ComplexF64), - (ComplexF32, ComplexF64), - (ComplexF64, ComplexF64), - (Float16, Float64), - (Float32, Float64), - (Float64, Float64), - (Int, Float64), - ) - - F = lu(sparse(fill(Tin(1), 1, 1))) - L = sparse(fill(Tout(1), 1, 1)) - @test F.p == F.q == [1] - @test F.Rs == [1.0] - @test F.L == F.U == L - @test F.:(:) == (L, L, [1], [1], [1.0]) - end - - @testset "BigFloat not supported" for T in (BigFloat, Complex{BigFloat}) - @test_throws ArgumentError lu(sparse(fill(T(1), 1, 1))) - end - - @testset "size(::UmfpackLU)" begin - m = n = 1 - F = lu(sparse(fill(1., m, n))) - @test size(F) == (m, n) - @test size(F, 1) == m - @test size(F, 2) == n - @test size(F, 3) == 1 - @test_throws ArgumentError size(F,-1) - end - - @testset "Test aliasing" begin - a = rand(5) - @test_throws ArgumentError SuiteSparse.UMFPACK.solve!(a, lu(sparse(1.0I, 5, 5)), a, SuiteSparse.UMFPACK.UMFPACK_A) - aa = complex(a) - @test_throws ArgumentError SuiteSparse.UMFPACK.solve!(aa, lu(sparse((1.0im)I, 5, 5)), aa, SuiteSparse.UMFPACK.UMFPACK_A) - end - - @testset "Issues #18246,18244 - lu sparse pivot" begin - A = sparse(1.0I, 4, 4) - A[1:2,1:2] = [-.01 -200; 200 .001] - F = lu(A) - @test F.p == [3 ; 4 ; 2 ; 1] - end - - @testset "Test that A[c|t]_ldiv_B!{T<:Complex}(X::StridedMatrix{T}, lu::UmfpackLU{Float64}, B::StridedMatrix{T}) works as expected." begin - N = 10 - p = 0.5 - A = N*I + sprand(N, N, p) - X = zeros(ComplexF64, N, N) - B = complex.(rand(N, N), rand(N, N)) - luA, lufA = lu(A), lu(Array(A)) - @test ldiv!(copy(X), luA, B) ≈ ldiv!(copy(X), lufA, B) - @test ldiv!(copy(X), adjoint(luA), B) ≈ ldiv!(copy(X), adjoint(lufA), B) - @test ldiv!(copy(X), transpose(luA), B) ≈ ldiv!(copy(X), transpose(lufA), B) - end - - @testset "singular matrix" begin - for A in sparse.((Float64[1 2; 0 0], ComplexF64[1 2; 0 0])) - @test_throws SingularException lu(A) - @test !issuccess(lu(A; check = false)) - end - end - - @testset "deserialization" begin - A = 10*I + sprandn(10, 10, 0.4) - F1 = lu(A) - b = IOBuffer() - serialize(b, F1) - seekstart(b) - F2 = deserialize(b) - for nm in (:colptr, :m, :n, :nzval, :rowval, :status) - @test getfield(F1, nm) == getfield(F2, nm) - end - end - - @testset "Reuse symbolic LU factorization" begin - A1 = sparse(increment!([0,4,1,1,2,2,0,1,2,3,4,4]), - increment!([0,4,0,2,1,2,1,4,3,2,1,2]), - [2.,1.,3.,4.,-1.,-3.,3.,9.,2.,1.,4.,2.], 5, 5) - for Tv in (Float64, ComplexF64, Float16, Float32, ComplexF16, ComplexF32) - for Ti in Base.uniontypes(SuiteSparse.UMFPACK.UMFITypes) - A = convert(SparseMatrixCSC{Tv,Ti}, A0) - B = convert(SparseMatrixCSC{Tv,Ti}, A1) - b = Tv[8., 45., -3., 3., 19.] - F = lu(A) - lu!(F, B) - @test F\b ≈ B\b ≈ Matrix(B)\b - - # singular matrix - C = copy(B) - C[4, 3] = Tv(0) - F = lu(A) - @test_throws SingularException lu!(F, C) - - # change of nonzero pattern - D = copy(B) - D[5, 1] = Tv(1.0) - F = lu(A) - @test_throws ArgumentError lu!(F, D) - end - end - end - -end - -@testset "REPL printing of UmfpackLU" begin - # regular matrix - A = sparse([1, 2], [1, 2], Float64[1.0, 1.0]) - F = lu(A) - facstring = sprint((t, s) -> show(t, "text/plain", s), F) - lstring = sprint((t, s) -> show(t, "text/plain", s), F.L) - ustring = sprint((t, s) -> show(t, "text/plain", s), F.U) - @test facstring == "$(summary(F))\nL factor:\n$lstring\nU factor:\n$ustring" - - # singular matrix - B = sparse(zeros(Float64, 2, 2)) - F = lu(B; check=false) - facstring = sprint((t, s) -> show(t, "text/plain", s), F) - @test facstring == "Failed factorization of type $(summary(F))" -end diff --git a/stdlib/SuiteSparse_jll/Project.toml b/stdlib/SuiteSparse_jll/Project.toml index 6b704c4bf1112..c360967a2acc1 100644 --- a/stdlib/SuiteSparse_jll/Project.toml +++ b/stdlib/SuiteSparse_jll/Project.toml @@ -1,6 +1,6 @@ name = "SuiteSparse_jll" uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" -version = "5.8.1+0" +version = "5.10.1+0" [deps] libblastrampoline_jll = "8e850b90-86db-534c-a0d3-1478176c7d93" diff --git a/stdlib/SuiteSparse_jll/src/SuiteSparse_jll.jl b/stdlib/SuiteSparse_jll/src/SuiteSparse_jll.jl index 19cf398feec25..2940970ceff9f 100644 --- a/stdlib/SuiteSparse_jll/src/SuiteSparse_jll.jl +++ b/stdlib/SuiteSparse_jll/src/SuiteSparse_jll.jl @@ -8,7 +8,7 @@ Base.Experimental.@compiler_options compile=min optimize=0 infer=false const PATH_list = String[] const LIBPATH_list = String[] -export libamd, libbtf, libcamd, libccolamd, libcholmod, libcolamd, libklu, libldl, librbio, libspqr, libsuitesparse_wrapper, libsuitesparseconfig, libumfpack +export libamd, libbtf, libcamd, libccolamd, libcholmod, libcolamd, libklu, libldl, librbio, libspqr, libsuitesparseconfig, libumfpack # These get calculated in __init__() # Man I can't wait until these are automatically handled by an in-Base JLLWrappers clone. @@ -35,8 +35,6 @@ librbio_handle = C_NULL librbio_path = "" libspqr_handle = C_NULL libspqr_path = "" -libsuitesparse_wrapper_handle = C_NULL -libsuitesparse_wrapper_path = "" libsuitesparseconfig_handle = C_NULL libsuitesparseconfig_path = "" libumfpack_handle = C_NULL @@ -53,7 +51,6 @@ if Sys.iswindows() const libldl = "libldl.dll" const librbio = "librbio.dll" const libspqr = "libspqr.dll" - const libsuitesparse_wrapper = "libsuitesparse_wrapper.dll" const libsuitesparseconfig = "libsuitesparseconfig.dll" const libumfpack = "libumfpack.dll" elseif Sys.isapple() @@ -67,7 +64,6 @@ elseif Sys.isapple() const libldl = "@rpath/libldl.2.dylib" const librbio = "@rpath/librbio.2.dylib" const libspqr = "@rpath/libspqr.2.dylib" - const libsuitesparse_wrapper = "@rpath/libsuitesparse_wrapper.dylib" const libsuitesparseconfig = "@rpath/libsuitesparseconfig.5.dylib" const libumfpack = "@rpath/libumfpack.5.dylib" else @@ -81,7 +77,6 @@ else const libldl = "libldl.so.2" const librbio = "librbio.so.2" const libspqr = "libspqr.so.2" - const libsuitesparse_wrapper = "libsuitesparse_wrapper.so" const libsuitesparseconfig = "libsuitesparseconfig.so.5" const libumfpack = "libumfpack.so.5" end @@ -107,15 +102,11 @@ function __init__() global librbio_path = dlpath(librbio_handle) global libspqr_handle = dlopen(libspqr) global libspqr_path = dlpath(libspqr_handle) - global libsuitesparse_wrapper_handle = dlopen(libsuitesparse_wrapper) - global libsuitesparse_wrapper_path = dlpath(libsuitesparse_wrapper_handle) global libsuitesparseconfig_handle = dlopen(libsuitesparseconfig) global libsuitesparseconfig_path = dlpath(libsuitesparseconfig_handle) global libumfpack_handle = dlopen(libumfpack) global libumfpack_path = dlpath(libumfpack_handle) global artifact_dir = dirname(Sys.BINDIR) - LIBPATH[] = dirname(libsuitesparse_wrapper_path) - push!(LIBPATH_list, LIBPATH[]) end # JLLWrappers API compatibility shims. Note that not all of these will really make sense. @@ -135,7 +126,6 @@ get_libklu_path() = libklu_path get_libldl_path() = libldl_path get_librbio_path() = librbio_path get_libspqr_path() = libspqr_path -get_libsuitesparse_wrapper_path() = libsuitesparse_wrapper_path get_libsuitesparseconfig_path() = libsuitesparseconfig_path get_libumfpack_path() = libumfpack_path diff --git a/stdlib/SuiteSparse_jll/test/runtests.jl b/stdlib/SuiteSparse_jll/test/runtests.jl index 60e5cf74d6534..ca356951f99e2 100644 --- a/stdlib/SuiteSparse_jll/test/runtests.jl +++ b/stdlib/SuiteSparse_jll/test/runtests.jl @@ -3,5 +3,5 @@ using Test, SuiteSparse_jll @testset "SuiteSparse_jll" begin - @test ccall((:SuiteSparse_version, libsuitesparseconfig), Cint, (Ptr{Cint},), C_NULL) == 5008 + @test ccall((:SuiteSparse_version, libsuitesparseconfig), Cint, (Ptr{Cint},), C_NULL) == 5010 end diff --git a/stdlib/TOML/docs/src/index.md b/stdlib/TOML/docs/src/index.md index e34bb8d85f2f1..36e8ec6248108 100644 --- a/stdlib/TOML/docs/src/index.md +++ b/stdlib/TOML/docs/src/index.md @@ -65,8 +65,6 @@ format. ```jldoctest julia> using TOML -julia> fname = tempname(); - julia> data = Dict( "names" => ["Julia", "Julio"], "age" => [10, 20], @@ -75,6 +73,17 @@ julia> data = Dict( julia> TOML.print(data) names = ["Julia", "Julio"] age = [10, 20] + +julia> fname = tempname(); + +julia> open(fname, "w") do io + TOML.print(io, data) + end + +julia> TOML.parsefile(fname) +Dict{String, Any} with 2 entries: + "names" => ["Julia", "Julio"] + "age" => [10, 20] ``` Keys can be sorted according to some value diff --git a/stdlib/TOML/src/TOML.jl b/stdlib/TOML/src/TOML.jl index a8ad706d0b8b4..4765a05c05f52 100644 --- a/stdlib/TOML/src/TOML.jl +++ b/stdlib/TOML/src/TOML.jl @@ -38,7 +38,7 @@ const Parser = Internals.Parser Parse file `f` and return the resulting table (dictionary). Throw a [`ParserError`](@ref) upon failure. -See also: [`TOML.tryparsefile`](@ref) +See also [`TOML.tryparsefile`](@ref). """ parsefile(f::AbstractString) = Internals.parse(Parser(readstring(f); filepath=abspath(f))) @@ -52,7 +52,7 @@ parsefile(p::Parser, f::AbstractString) = Parse file `f` and return the resulting table (dictionary). Return a [`ParserError`](@ref) upon failure. -See also: [`TOML.parsefile`](@ref) +See also [`TOML.parsefile`](@ref). """ tryparsefile(f::AbstractString) = Internals.tryparse(Parser(readstring(f); filepath=abspath(f))) @@ -66,7 +66,7 @@ tryparsefile(p::Parser, f::AbstractString) = Parse the string or stream `x`, and return the resulting table (dictionary). Throw a [`ParserError`](@ref) upon failure. -See also: [`TOML.tryparse`](@ref) +See also [`TOML.tryparse`](@ref). """ parse(str::AbstractString) = Internals.parse(Parser(String(str))) @@ -82,7 +82,7 @@ parse(p::Parser, io::IO) = parse(p, read(io, String)) Parse the string or stream `x`, and return the resulting table (dictionary). Return a [`ParserError`](@ref) upon failure. -See also: [`TOML.parse`](@ref) +See also [`TOML.parse`](@ref). """ tryparse(str::AbstractString) = Internals.tryparse(Parser(String(str))) diff --git a/stdlib/TOML/src/print.jl b/stdlib/TOML/src/print.jl index 71896b7a1d717..0cbee990d8ae1 100644 --- a/stdlib/TOML/src/print.jl +++ b/stdlib/TOML/src/print.jl @@ -2,6 +2,7 @@ import Dates +import Base: @invokelatest import ..isvalid_barekey_char function printkey(io::IO, keys::Vector{String}) @@ -20,46 +21,36 @@ function printkey(io::IO, keys::Vector{String}) end const MbyFunc = Union{Function, Nothing} -const TOMLValue = Union{AbstractVector, AbstractDict, Dates.DateTime, Dates.Time, Dates.Date, Bool, Integer, AbstractFloat, String} -function printvalue(f::MbyFunc, io::IO, value::AbstractVector; sorted=false) +const TOMLValue = Union{AbstractVector, AbstractDict, Dates.DateTime, Dates.Time, Dates.Date, Bool, Integer, AbstractFloat, AbstractString} +function printvalue(f::MbyFunc, io::IO, value::AbstractVector; sorted=false, by=identity) Base.print(io, "[") for (i, x) in enumerate(value) i != 1 && Base.print(io, ", ") if isa(x, AbstractDict) - _print(f, io, x; sorted) + _print(f, io, x; sorted, by) else - printvalue(f, io, x; sorted) + printvalue(f, io, x; sorted, by) end end Base.print(io, "]") end -function printvalue(f::MbyFunc, io::IO, value; sorted) - if f === nothing - error("type `$(typeof(value))` is not a valid TOML type, pass a conversion function to `TOML.print`") - end - toml_value = f(value) - if !(toml_value isa TOMLValue) - error("TOML syntax function for type `$(typeof(value))` did not return a valid TOML type but a `$(typeof(toml_value))`") - end - Base.invokelatest(printvalue, f, io, toml_value; sorted) -end -printvalue(f::MbyFunc, io::IO, value::AbstractDict; sorted) = - _print(f, io, value; sorted) -printvalue(f::MbyFunc, io::IO, value::Dates.DateTime; sorted) = +printvalue(f::MbyFunc, io::IO, value::AbstractDict; sorted=false, by=identity) = + _print(f, io, value; sorted, by) +printvalue(f::MbyFunc, io::IO, value::Dates.DateTime; _...) = Base.print(io, Dates.format(value, Dates.dateformat"YYYY-mm-dd\THH:MM:SS.sss\Z")) -printvalue(f::MbyFunc, io::IO, value::Dates.Time; sorted) = +printvalue(f::MbyFunc, io::IO, value::Dates.Time; _...) = Base.print(io, Dates.format(value, Dates.dateformat"HH:MM:SS.sss")) -printvalue(f::MbyFunc, io::IO, value::Dates.Date; sorted) = +printvalue(f::MbyFunc, io::IO, value::Dates.Date; _...) = Base.print(io, Dates.format(value, Dates.dateformat"YYYY-mm-dd")) -printvalue(f::MbyFunc, io::IO, value::Bool; sorted) = +printvalue(f::MbyFunc, io::IO, value::Bool; _...) = Base.print(io, value ? "true" : "false") -printvalue(f::MbyFunc, io::IO, value::Integer; sorted) = +printvalue(f::MbyFunc, io::IO, value::Integer; _...) = Base.print(io, Int64(value)) # TOML specifies 64-bit signed long range for integer -printvalue(f::MbyFunc, io::IO, value::AbstractFloat; sorted) = +printvalue(f::MbyFunc, io::IO, value::AbstractFloat; _...) = Base.print(io, isnan(value) ? "nan" : isinf(value) ? string(value > 0 ? "+" : "-", "inf") : Float64(value)) # TOML specifies IEEE 754 binary64 for float -printvalue(f::MbyFunc, io::IO, value::AbstractString; sorted) = Base.print(io, "\"", escape_string(value), "\"") +printvalue(f::MbyFunc, io::IO, value::AbstractString; _...) = Base.print(io, "\"", escape_string(value), "\"") is_table(value) = isa(value, AbstractDict) is_array_of_tables(value) = isa(value, AbstractArray) && @@ -70,8 +61,8 @@ function _print(f::MbyFunc, io::IO, a::AbstractDict, ks::Vector{String} = String[]; indent::Int = 0, first_block::Bool = true, - sorted::Bool, - by::Function, + sorted::Bool = false, + by::Function = identity, ) akeys = keys(a) if sorted @@ -82,11 +73,25 @@ function _print(f::MbyFunc, io::IO, a::AbstractDict, for key in akeys value = a[key] is_tabular(value) && continue - Base.print(io, ' '^4max(0,indent-1)) - printkey(io, [String(key)]) - Base.print(io, " = ") # print separator - printvalue(f, io, value; sorted) - Base.print(io, "\n") # new line? + if !isa(value, TOMLValue) + if f === nothing + error("type `$(typeof(value))` is not a valid TOML type, pass a conversion function to `TOML.print`") + end + toml_value = f(value) + if !(toml_value isa TOMLValue) + error("TOML syntax function for type `$(typeof(value))` did not return a valid TOML type but a `$(typeof(toml_value))`") + end + value = toml_value + end + if is_tabular(value) + _print(f, io, Dict(key => value); indent, first_block, sorted, by) + else + Base.print(io, ' '^4max(0,indent-1)) + printkey(io, [String(key)]) + Base.print(io, " = ") # print separator + printvalue(f, io, value; sorted, by) + Base.print(io, "\n") # new line? + end first_block = false end @@ -105,7 +110,7 @@ function _print(f::MbyFunc, io::IO, a::AbstractDict, Base.print(io,"]\n") end # Use runtime dispatch here since the type of value seems not to be enforced other than as AbstractDict - Base.invokelatest(_print, f, io, value, ks; indent = indent + header, first_block = header, sorted, by) + @invokelatest _print(f, io, value, ks; indent = indent + header, first_block = header, sorted, by) pop!(ks) elseif is_array_of_tables(value) # print array of tables @@ -119,7 +124,7 @@ function _print(f::MbyFunc, io::IO, a::AbstractDict, Base.print(io,"]]\n") # TODO, nicer error here !isa(v, AbstractDict) && error("array should contain only tables") - Base.invokelatest(_print, f, io, v, ks; indent = indent + 1, sorted, by) + @invokelatest _print(f, io, v, ks; indent = indent + 1, sorted, by) end pop!(ks) end diff --git a/stdlib/TOML/test/print.jl b/stdlib/TOML/test/print.jl index d6bcdf10d4f17..10bb48ffae411 100644 --- a/stdlib/TOML/test/print.jl +++ b/stdlib/TOML/test/print.jl @@ -21,12 +21,34 @@ struct MyStruct a::Int end @test_throws ErrorException toml_str(Dict("foo" => MyStruct(1))) +# simple value @test toml_str(Dict("foo" => MyStruct(1))) do x x isa MyStruct && return x.a end == """ foo = 1 """ +# tabular values +@test toml_str(Dict("foo" => MyStruct(1)); sorted=true) do x + x isa MyStruct && return [x.a] + end == """ + foo = [1] + """ +@test toml_str(Dict("foo" => MyStruct(1)); sorted=true) do x + x isa MyStruct && return Dict(:bar => x.a) + end == """ + [foo] + bar = 1 + """ + +# validation against the usual case +@test toml_str(Dict("foo" => MyStruct(1)); sorted=true) do x + x isa MyStruct && return [x.a] + end == toml_str(Dict("foo" => [1]); sorted=true) +@test toml_str(Dict("foo" => MyStruct(1)); sorted=true) do x + x isa MyStruct && return Dict(:bar => x.a) + end == toml_str(Dict("foo" => Dict(:bar => 1)); sorted=true) + @test toml_str(Dict("b" => SubString("foo"))) == "b = \"foo\"\n" @testset "empty dict print" begin diff --git a/stdlib/TOML/test/values.jl b/stdlib/TOML/test/values.jl index 9f09e26b01cda..8337bb5a54714 100644 --- a/stdlib/TOML/test/values.jl +++ b/stdlib/TOML/test/values.jl @@ -39,6 +39,7 @@ end @test testval("1.0e0" , 1.0) @test testval("1.0e+0" , 1.0) @test testval("1.0e-0" , 1.0) + @test testval("0e-3" , 0.0) @test testval("1.001e-0" , 1.001) @test testval("2e10" , 2e10) @test testval("2e+10" , 2e10) @@ -53,8 +54,8 @@ end @test testval("+1_000" , 1000 |> Int64) @test testval("-1_000" , -1000 |> Int64) - @test failval("0_" , Internals.ErrLeadingZeroNotAllowedInteger) - @test failval("0__0" , Internals.ErrLeadingZeroNotAllowedInteger) + @test failval("0_" , Internals.ErrUnderscoreNotSurroundedByDigits) + @test failval("0__0" , Internals.ErrUnderscoreNotSurroundedByDigits) @test failval("__0" , Internals.ErrUnexpectedStartOfValue) @test failval("1_0_" , Internals.ErrTrailingUnderscoreNumber) @test failval("1_0__0" , Internals.ErrUnderscoreNotSurroundedByDigits) diff --git a/stdlib/Tar.version b/stdlib/Tar.version index 0ab47a82fd468..2997467cdd1bd 100644 --- a/stdlib/Tar.version +++ b/stdlib/Tar.version @@ -1,2 +1,2 @@ TAR_BRANCH = master -TAR_SHA1 = ac4d442266a676ce2d1a43acb55fc07d1edc6566 +TAR_SHA1 = 86825ecf1e8b6f57105bf0632e93c532cee200a4 diff --git a/stdlib/Test/docs/src/index.md b/stdlib/Test/docs/src/index.md index 8e3ba439ab155..98fdf45706bf7 100644 --- a/stdlib/Test/docs/src/index.md +++ b/stdlib/Test/docs/src/index.md @@ -42,9 +42,13 @@ If the condition is true, a `Pass` is returned: ```jldoctest testfoo julia> @test foo("bar") == 9 Test Passed + Expression: foo("bar") == 9 + Evaluated: 9 == 9 julia> @test foo("fizz") >= 10 Test Passed + Expression: foo("fizz") >= 10 + Evaluated: 16 >= 10 ``` If the condition is false, then a `Fail` is returned and an exception is thrown: @@ -83,6 +87,7 @@ to check that this occurs: ```jldoctest testfoo julia> @test_throws MethodError foo(:cat) Test Passed + Expression: foo(:cat) Thrown: MethodError ``` @@ -102,6 +107,7 @@ or could not be evaluated due to an error, the test set will then throw a `TestS ```@docs Test.@testset +Test.TestSetException ``` We can put our tests for the `foo(x)` function in a test set: @@ -193,6 +199,8 @@ checks using either `@test a ≈ b` (where `≈`, typed via tab completion of `\ ```jldoctest julia> @test 1 ≈ 0.999999999 Test Passed + Expression: 1 ≈ 0.999999999 + Evaluated: 1 ≈ 0.999999999 julia> @test 1 ≈ 0.999999 Test Failed at none:1 @@ -200,6 +208,15 @@ Test Failed at none:1 Evaluated: 1 ≈ 0.999999 ERROR: There was an error during testing ``` +You can specify relative and absolute tolerances by setting the `rtol` and `atol` keyword arguments of `isapprox`, respectively, +after the `≈` comparison: +```jldoctest +julia> @test 1 ≈ 0.999999 rtol=1e-5 +Test Passed + Expression: ≈(1, 0.999999, rtol = 1.0e-5) + Evaluated: ≈(1, 0.999999; rtol = 1.0e-5) +``` +Note that this is not a specific feature of the `≈` but rather a general feature of the `@test` macro: `@test a b key=val` is transformed by the macro into `@test op(a, b, key=val)`. It is, however, particularly useful for `≈` tests. ```@docs Test.@inferred @@ -288,6 +305,18 @@ And using that testset looks like: end ``` +## Test utilities + +```@docs +Test.GenericArray +Test.GenericDict +Test.GenericOrder +Test.GenericSet +Test.GenericString +Test.detect_ambiguities +Test.detect_unbound_args +``` + ```@meta DocTestSetup = nothing ``` diff --git a/stdlib/Test/src/Test.jl b/stdlib/Test/src/Test.jl index 0a260b68bc2dd..62d084bdcad58 100644 --- a/stdlib/Test/src/Test.jl +++ b/stdlib/Test/src/Test.jl @@ -85,8 +85,9 @@ struct Pass <: Result orig_expr data value - function Pass(test_type::Symbol, orig_expr, data, thrown) - return new(test_type, orig_expr, data, thrown isa String ? "String" : thrown) + source::Union{Nothing,LineNumberNode} + function Pass(test_type::Symbol, orig_expr, data, thrown, source) + return new(test_type, orig_expr, data, thrown isa String ? "String" : thrown, source) end end @@ -236,6 +237,7 @@ function Serialization.serialize(s::Serialization.AbstractSerializer, t::Pass) Serialization.serialize(s, t.orig_expr === nothing ? nothing : string(t.orig_expr)) Serialization.serialize(s, t.data === nothing ? nothing : string(t.data)) Serialization.serialize(s, string(t.value)) + Serialization.serialize(s, t.source === nothing ? nothing : t.source) nothing end @@ -342,6 +344,8 @@ end """ @test ex @test f(args...) key=val ... + @test ex broken=true + @test ex skip=true Tests that the expression `ex` evaluates to `true`. Returns a `Pass` `Result` if it does, a `Fail` `Result` if it is @@ -351,9 +355,12 @@ Returns a `Pass` `Result` if it does, a `Fail` `Result` if it is ```jldoctest julia> @test true Test Passed + Expression: true julia> @test [1, 2] + [2, 1] == [3, 3] Test Passed + Expression: [1, 2] + [2, 1] == [3, 3] + Evaluated: [3, 3] == [3, 3] ``` The `@test f(args...) key=val...` form is equivalent to writing @@ -363,17 +370,82 @@ is a call using infix syntax such as approximate comparisons: ```jldoctest julia> @test π ≈ 3.14 atol=0.01 Test Passed + Expression: ≈(π, 3.14, atol = 0.01) + Evaluated: ≈(π, 3.14; atol = 0.01) ``` This is equivalent to the uglier test `@test ≈(π, 3.14, atol=0.01)`. It is an error to supply more than one expression unless the first is a call expression and the rest are assignments (`k=v`). + +You can use any key for the `key=val` arguments, except for `broken` and `skip`, +which have special meanings in the context of `@test`: + +* `broken=cond` indicates a test that should pass but currently consistently + fails when `cond==true`. Tests that the expression `ex` evaluates to `false` + or causes an exception. Returns a `Broken` `Result` if it does, or an `Error` + `Result` if the expression evaluates to `true`. Regular `@test ex` is + evaluated when `cond==false`. +* `skip=cond` marks a test that should not be executed but should be included in + test summary reporting as `Broken`, when `cond==true`. This can be useful for + tests that intermittently fail, or tests of not-yet-implemented functionality. + Regular `@test ex` is evaluated when `cond==false`. + +# Examples + +```jldoctest +julia> @test 2 + 2 ≈ 6 atol=1 broken=true +Test Broken + Expression: ≈(2 + 2, 6, atol = 1) + +julia> @test 2 + 2 ≈ 5 atol=1 broken=false +Test Passed + Expression: ≈(2 + 2, 5, atol = 1) + Evaluated: ≈(4, 5; atol = 1) + +julia> @test 2 + 2 == 5 skip=true +Test Broken + Skipped: 2 + 2 == 5 + +julia> @test 2 + 2 == 4 skip=false +Test Passed + Expression: 2 + 2 == 4 + Evaluated: 4 == 4 +``` + +!!! compat "Julia 1.7" + The `broken` and `skip` keyword arguments require at least Julia 1.7. """ macro test(ex, kws...) + # Collect the broken/skip keywords and remove them from the rest of keywords + broken = [kw.args[2] for kw in kws if kw.args[1] === :broken] + skip = [kw.args[2] for kw in kws if kw.args[1] === :skip] + kws = filter(kw -> kw.args[1] ∉ (:skip, :broken), kws) + # Validation of broken/skip keywords + for (kw, name) in ((broken, :broken), (skip, :skip)) + if length(kw) > 1 + error("invalid test macro call: cannot set $(name) keyword multiple times") + end + end + if length(skip) > 0 && length(broken) > 0 + error("invalid test macro call: cannot set both skip and broken keywords") + end + + # Build the test expression test_expr!("@test", ex, kws...) orig_ex = Expr(:inert, ex) + result = get_test_result(ex, __source__) - :(do_test($result, $orig_ex)) + + return quote + if $(length(skip) > 0 && esc(skip[1])) + record(get_testset(), Broken(:skipped, $orig_ex)) + else + let _do = $(length(broken) > 0 && esc(broken[1])) ? do_broken_test : do_test + _do($result, $orig_ex) + end + end + end end """ @@ -383,7 +455,8 @@ end Indicates a test that should pass but currently consistently fails. Tests that the expression `ex` evaluates to `false` or causes an exception. Returns a `Broken` `Result` if it does, or an `Error` `Result` -if the expression evaluates to `true`. +if the expression evaluates to `true`. This is equivalent to +[`@test ex broken=true`](@ref @test). The `@test_broken f(args...) key=val...` form works as for the `@test` macro. @@ -412,7 +485,8 @@ end Marks a test that should not be executed but should be included in test summary reporting as `Broken`. This can be useful for tests that intermittently -fail, or tests of not-yet-implemented functionality. +fail, or tests of not-yet-implemented functionality. This is equivalent to +[`@test ex skip=true`](@ref @test). The `@test_skip f(args...) key=val...` form works as for the `@test` macro. @@ -453,6 +527,12 @@ function get_test_result(ex, source) first(string(ex.args[1])) != '.' && !is_splat(ex.args[2]) && !is_splat(ex.args[3]) && (ex.args[1] === :(==) || Base.operator_precedence(ex.args[1]) == comparison_prec) ex = Expr(:comparison, ex.args[2], ex.args[1], ex.args[3]) + + # Mark <: and >: as :comparison expressions + elseif isa(ex, Expr) && length(ex.args) == 2 && + !is_splat(ex.args[1]) && !is_splat(ex.args[2]) && + Base.operator_precedence(ex.head) == comparison_prec + ex = Expr(:comparison, ex.args[1], ex.head, ex.args[2]) end if isa(ex, Expr) && ex.head === :comparison # pass all terms of the comparison to `eval_comparison`, as an Expr @@ -520,7 +600,7 @@ function get_test_result(ex, source) $testret catch _e _e isa InterruptException && rethrow() - Threw(_e, Base.catch_stack(), $(QuoteNode(source))) + Threw(_e, Base.current_exceptions(), $(QuoteNode(source))) end end Base.remove_linenums!(result) @@ -541,7 +621,7 @@ function do_test(result::ExecutionResult, orig_expr) value = result.value testres = if isa(value, Bool) # a true value Passes - value ? Pass(:test, nothing, nothing, value) : + value ? Pass(:test, orig_expr, result.data, value, result.source) : Fail(:test, orig_expr, result.data, value, result.source) else # If the result is non-Boolean, this counts as an Error @@ -583,10 +663,12 @@ Note that `@test_throws` does not support a trailing keyword form. ```jldoctest julia> @test_throws BoundsError [1, 2, 3][4] Test Passed + Expression: ([1, 2, 3])[4] Thrown: BoundsError julia> @test_throws DimensionMismatch [1, 2, 3] + [1, 2] Test Passed + Expression: [1, 2, 3] + [1, 2] Thrown: DimensionMismatch ``` """ @@ -606,6 +688,8 @@ macro test_throws(extype, ex) :(do_test_throws($result, $orig_ex, $(esc(extype)))) end +const MACROEXPAND_LIKE = Symbol.(("@macroexpand", "@macroexpand1", "macroexpand")) + # An internal function, called by the code generated by @test_throws # to evaluate and catch the thrown exception - if it exists function do_test_throws(result::ExecutionResult, orig_expr, extype) @@ -613,9 +697,24 @@ function do_test_throws(result::ExecutionResult, orig_expr, extype) # Check that the right type of exception was thrown success = false exc = result.exception + # NB: Throwing LoadError from macroexpands is deprecated, but in order to limit + # the breakage in package tests we add extra logic here. + from_macroexpand = + orig_expr isa Expr && + orig_expr.head in (:call, :macrocall) && + orig_expr.args[1] in MACROEXPAND_LIKE if isa(extype, Type) - success = isa(exc, extype) + success = + if from_macroexpand && extype == LoadError && exc isa Exception + Base.depwarn("macroexpand no longer throw a LoadError so `@test_throws LoadError ...` is deprecated and passed without checking the error type!", :do_test_throws) + true + else + isa(exc, extype) + end else + if extype isa LoadError && !(exc isa LoadError) && typeof(extype.error) == typeof(exc) + extype = extype.error # deprecated + end if isa(exc, typeof(extype)) success = true for fld in 1:nfields(extype) @@ -627,7 +726,7 @@ function do_test_throws(result::ExecutionResult, orig_expr, extype) end end if success - testres = Pass(:test_throws, nothing, nothing, exc) + testres = Pass(:test_throws, orig_expr, extype, exc, result.source) else testres = Fail(:test_throws_wrong, orig_expr, extype, exc, result.source) end @@ -690,7 +789,26 @@ with this macro. Use [`@test_logs`](@ref) instead. """ macro test_nowarn(expr) quote - @test_warn r"^(?!.)"s $(esc(expr)) + # Duplicate some code from `@test_warn` to allow printing the content of + # `stderr` again to `stderr` here while suppressing it for `@test_warn`. + # If that shouldn't be used, it would be possible to just use + # @test_warn isempty $(esc(expr)) + # here. + let fname = tempname() + try + ret = open(fname, "w") do f + redirect_stderr(f) do + $(esc(expr)) + end + end + stderr_content = read(fname, String) + print(stderr, stderr_content) # this is helpful for debugging + @test isempty(stderr_content) + ret + finally + rm(fname, force=true) + end + end end end @@ -717,9 +835,20 @@ function record end finish(ts::AbstractTestSet) Do any final processing necessary for the given testset. This is called by the -`@testset` infrastructure after a test block executes. One common use for this -function is to record the testset to the parent's results list, using -`get_testset`. +`@testset` infrastructure after a test block executes. + +Custom `AbstractTestSet` subtypes should call `record` on their parent (if there +is one) to add themselves to the tree of test results. This might be implemented +as: + +```julia +if get_testset_depth() != 0 + # Attach this test set to the parent test set + parent_ts = get_testset() + record(parent_ts, self) + return self +end +``` """ function finish end @@ -1156,7 +1285,7 @@ function testset_beginend(args, tests, source) err isa InterruptException && rethrow() # something in the test block threw an error. Count that as an # error in this test set - record(ts, Error(:nontest_error, Expr(:tuple), err, Base.catch_stack(), $(QuoteNode(source)))) + record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source)))) finally copy!(RNG, oldrng) pop_testset() @@ -1230,7 +1359,7 @@ function testset_forloop(args, testloop, source) err isa InterruptException && rethrow() # Something in the test block threw an error. Count that as an # error in this test set - record(ts, Error(:nontest_error, Expr(:tuple), err, Base.catch_stack(), $(QuoteNode(source)))) + record(ts, Error(:nontest_error, Expr(:tuple), err, Base.current_exceptions(), $(QuoteNode(source)))) end end quote diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 7e8659a4c2f2a..71309944fd9d0 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -135,21 +135,26 @@ We can test the info message using If we also wanted to test the debug messages, these need to be enabled with the `min_level` keyword: - @test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Debug foo(2) + @test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Logging.Debug foo(2) If you want to test that some particular messages are generated while ignoring the rest, you can set the keyword `match_mode=:any`: - @test_logs (:info,) (:debug,"Iteration 42") min_level=Debug match_mode=:any foo(100) + @test_logs (:info,) (:debug,"Iteration 42") min_level=Logging.Debug match_mode=:any foo(100) The macro may be chained with `@test` to also test the returned value: @test (@test_logs (:info,"Doing foo with n=2") foo(2)) == 42 -If you want to test an absence of logger messages, you can pass no log_patterns: +If you want to test for the absence of warnings, you can omit specifying log +patterns and set the `min_level` accordingly: - @test_logs min_level=Logging.Warn f() # test `f` logs no messages when the logger level is warn. + # test that the expression logs no messages when the logger level is warn: + @test_logs min_level=Logging.Warn @info("Some information") # passes + @test_logs min_level=Logging.Warn @warn("Some information") # fails +If you want to test the absence of warnings (or error messages) in +[`stderr`](@ref) which are not generated by `@warn`, see [`@test_nowarn`](@ref). """ macro test_logs(exs...) length(exs) >= 1 || throw(ArgumentError("""`@test_logs` needs at least one arguments. @@ -173,13 +178,13 @@ macro test_logs(exs...) $(esc(expression)) end if didmatch - testres = Pass(:test, nothing, nothing, value) + testres = Pass(:test, $orig_expr, nothing, value, $sourceloc) else testres = LogTestFailure($orig_expr, $sourceloc, $(QuoteNode(exs[1:end-1])), logs) end catch e - testres = Error(:test_error, $orig_expr, e, Base.catch_stack(), $sourceloc) + testres = Error(:test_error, $orig_expr, e, Base.current_exceptions(), $sourceloc) end Test.record(Test.get_testset(), testres) value @@ -265,4 +270,3 @@ macro test_deprecated(exs...) res.args[4].args[3].args[2].args[2].args[2] = __source__ res end - diff --git a/stdlib/Test/test/runtests.jl b/stdlib/Test/test/runtests.jl index 541e8dcc2bf7d..ff8ba13841aaa 100644 --- a/stdlib/Test/test/runtests.jl +++ b/stdlib/Test/test/runtests.jl @@ -25,6 +25,18 @@ import Logging: Debug, Info, Warn @test isapprox(1, 2; atol) @test isapprox(1, 3; a.atol) end +@testset "@test with skip/broken kwargs" begin + # Make sure the local variables can be used in conditions + a = 1 + @test 2 + 2 == 4 broken=false + @test error() broken=true + @test !Sys.iswindows() broken=Sys.iswindows() + @test 1 ≈ 2 atol=1 broken=a==2 + @test false skip=true + @test true skip=false + @test Grogu skip=isone(a) + @test 41 ≈ 42 rtol=1 skip=false +end @testset "@test keyword precedence" begin atol = 2 # post-semicolon keyword, suffix keyword, pre-semicolon keyword @@ -134,6 +146,8 @@ let fails = @testset NoThrowTestSet begin @test endswith(str1, str2) # 21 - Fail - contains @test contains(str1, str2) + # 22 - Fail - Type Comparison + @test typeof(1) <: typeof("julia") end for fail in fails @test fail isa Test.Fail @@ -243,6 +257,11 @@ let fails = @testset NoThrowTestSet begin @test occursin("Expression: contains(str1, str2)", str) @test occursin("Evaluated: contains(\"Hello\", \"World\")", str) end + + let str = sprint(show, fails[22]) + @test occursin("Expression: typeof(1) <: typeof(\"julia\")", str) + @test occursin("Evaluated: $(typeof(1)) <: $(typeof("julia"))", str) + end end let errors = @testset NoThrowTestSet begin @@ -269,7 +288,7 @@ end let retval_tests = @testset NoThrowTestSet begin ts = Test.DefaultTestSet("Mock for testing retval of record(::DefaultTestSet, ::T <: Result) methods") - pass_mock = Test.Pass(:test, 1, 2, LineNumberNode(0, "A Pass Mock")) + pass_mock = Test.Pass(:test, 1, 2, 3, LineNumberNode(0, "A Pass Mock")) @test Test.record(ts, pass_mock) isa Test.Pass error_mock = Test.Error(:test, 1, 2, 3, LineNumberNode(0, "An Error Mock")) @test Test.record(ts, error_mock) isa Test.Error @@ -491,7 +510,7 @@ import Test: record, finish using Test: get_testset_depth, get_testset using Test: AbstractTestSet, Result, Pass, Fail, Error struct CustomTestSet <: Test.AbstractTestSet - description::AbstractString + description::String foo::Int results::Vector # constructor takes a description string and options keyword arguments @@ -969,7 +988,7 @@ end let ex = :(something_complex + [1, 2, 3]) b = PipeBuffer() - let t = Test.Pass(:test, (ex, 1), (ex, 2), (ex, 3)) + let t = Test.Pass(:test, (ex, 1), (ex, 2), (ex, 3), LineNumberNode(@__LINE__, @__FILE__)) serialize(b, t) @test string(t) == string(deserialize(b)) @test eof(b) @@ -1138,3 +1157,49 @@ let errors = @testset NoThrowTestSet begin @test occursin("Expression: !(1 < 2 < missing < 4)", str) end end + +macro test_macro_throw_1() + throw(ErrorException("Real error")) +end +macro test_macro_throw_2() + throw(LoadError("file", 111, ErrorException("Real error"))) +end + +@testset "Soft deprecation of @test_throws LoadError [@]macroexpand[1]" begin + # If a macroexpand was detected, undecorated LoadErrors can stand in for any error. + # This will throw a deprecation warning. + @test_deprecated (@test_throws LoadError macroexpand(@__MODULE__, :(@test_macro_throw_1))) + @test_deprecated (@test_throws LoadError @macroexpand @test_macro_throw_1) + # Decorated LoadErrors are unwrapped if the actual exception matches the inner, but not the outer, exception, regardless of whether or not a macroexpand is detected. + # This will not throw a deprecation warning. + @test_throws LoadError("file", 111, ErrorException("Real error")) macroexpand(@__MODULE__, :(@test_macro_throw_1)) + @test_throws LoadError("file", 111, ErrorException("Real error")) @macroexpand @test_macro_throw_1 + # Decorated LoadErrors are not unwrapped if a LoadError was thrown. + @test_throws LoadError("file", 111, ErrorException("Real error")) @macroexpand @test_macro_throw_2 +end + +# Issue 25483 +mutable struct PassInformationTestSet <: Test.AbstractTestSet + results::Vector + PassInformationTestSet(desc) = new([]) +end +Test.record(ts::PassInformationTestSet, t::Test.Result) = (push!(ts.results, t); t) +Test.finish(ts::PassInformationTestSet) = ts +@testset "Information in Pass result (Issue 25483)" begin + ts = @testset PassInformationTestSet begin + @test 1 == 1 + @test_throws ErrorException throw(ErrorException("Msg")) + end + test_line_number = (@__LINE__) - 3 + test_throws_line_number = (@__LINE__) - 3 + @test ts.results[1].test_type == :test + @test ts.results[1].orig_expr == :(1 == 1) + @test ts.results[1].data == Expr(:comparison, 1, :(==), 1) + @test ts.results[1].value == true + @test ts.results[1].source == LineNumberNode(test_line_number, @__FILE__) + @test ts.results[2].test_type == :test_throws + @test ts.results[2].orig_expr == :(throw(ErrorException("Msg"))) + @test ts.results[2].data == ErrorException + @test ts.results[2].value == ErrorException("Msg") + @test ts.results[2].source == LineNumberNode(test_throws_line_number, @__FILE__) +end \ No newline at end of file diff --git a/stdlib/libLLVM_jll/Project.toml b/stdlib/libLLVM_jll/Project.toml index 6954f96dff80c..5db781e86a88c 100644 --- a/stdlib/libLLVM_jll/Project.toml +++ b/stdlib/libLLVM_jll/Project.toml @@ -1,10 +1,10 @@ name = "libLLVM_jll" uuid = "8f36deef-c2a5-5394-99ed-8e07531fb29a" -version = "11.0.1+3" +version = "12.0.0+0" [deps] Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" [compat] -julia = "1.6" +julia = "1.7" diff --git a/stdlib/libLLVM_jll/src/libLLVM_jll.jl b/stdlib/libLLVM_jll/src/libLLVM_jll.jl index 702ed5c0ef867..5186cb13e0be9 100644 --- a/stdlib/libLLVM_jll/src/libLLVM_jll.jl +++ b/stdlib/libLLVM_jll/src/libLLVM_jll.jl @@ -19,11 +19,11 @@ libLLVM_handle = C_NULL libLLVM_path = "" if Sys.iswindows() - const libLLVM = "LLVM.dll" + const libLLVM = "libLLVM.dll" elseif Sys.isapple() const libLLVM = "@rpath/libLLVM.dylib" else - const libLLVM = "libLLVM-11jl.so" + const libLLVM = "libLLVM-12jl.so" end function __init__() diff --git a/stdlib/libblastrampoline_jll/Project.toml b/stdlib/libblastrampoline_jll/Project.toml index 6b107b1348090..d44c420b56332 100644 --- a/stdlib/libblastrampoline_jll/Project.toml +++ b/stdlib/libblastrampoline_jll/Project.toml @@ -1,6 +1,6 @@ name = "libblastrampoline_jll" uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" -version = "3.0.2+0" +version = "3.0.4+0" [deps] Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" diff --git a/stdlib/p7zip_jll/src/p7zip_jll.jl b/stdlib/p7zip_jll/src/p7zip_jll.jl index e1c94eb8d84be..99b346017ad97 100644 --- a/stdlib/p7zip_jll/src/p7zip_jll.jl +++ b/stdlib/p7zip_jll/src/p7zip_jll.jl @@ -77,7 +77,7 @@ function init_p7zip_path() return end end - global p7zip_path = Sys.which(p7zip_exe) + global p7zip_path = something(Sys.which(p7zip_exe), p7zip_exe) end function __init__() diff --git a/sysimage.mk b/sysimage.mk index ebc991bdd40f0..57479da366583 100644 --- a/sysimage.mk +++ b/sysimage.mk @@ -60,12 +60,13 @@ RELBUILDROOT := $(call rel_path,$(JULIAHOME)/base,$(BUILDROOT)/base)/ # <-- make $(build_private_libdir)/corecompiler.ji: $(COMPILER_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ $(call spawn,$(JULIA_EXECUTABLE)) -C "$(JULIA_CPU_TARGET)" --output-ji $(call cygpath_w,$@).tmp \ - --startup-file=no --warn-overwrite=yes -g0 -O0 compiler/compiler.jl) + --startup-file=no --warn-overwrite=yes -g1 -O0 compiler/compiler.jl) @mv $@.tmp $@ $(build_private_libdir)/sys.ji: $(build_private_libdir)/corecompiler.ji $(JULIAHOME)/VERSION $(BASE_SRCS) $(STDLIB_SRCS) @$(call PRINT_JULIA, cd $(JULIAHOME)/base && \ - if ! JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O0 -C "$(JULIA_CPU_TARGET)" --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ + if ! JULIA_BINDIR=$(call cygpath_w,$(build_bindir)) WINEPATH="$(call cygpath_w,$(build_bindir));$$WINEPATH" \ + $(call spawn, $(JULIA_EXECUTABLE)) -g1 -O0 -C "$(JULIA_CPU_TARGET)" --output-ji $(call cygpath_w,$@).tmp $(JULIA_SYSIMG_BUILD_FLAGS) \ --startup-file=no --warn-overwrite=yes --sysimage $(call cygpath_w,$<) sysimg.jl $(RELBUILDROOT); then \ echo '*** This error might be fixed by running `make clean`. If the error persists$(COMMA) try `make cleanall`. ***'; \ false; \ @@ -75,8 +76,9 @@ $(build_private_libdir)/sys.ji: $(build_private_libdir)/corecompiler.ji $(JULIAH define sysimg_builder $$(build_private_libdir)/sys$1-o.a $$(build_private_libdir)/sys$1-bc.a : $$(build_private_libdir)/sys$1-%.a : $$(build_private_libdir)/sys.ji @$$(call PRINT_JULIA, cd $$(JULIAHOME)/base && \ - if ! JULIA_BINDIR=$$(call cygpath_w,$(build_bindir)) $$(call spawn, $3) $2 -C "$$(JULIA_CPU_TARGET)" --output-$$* $$(call cygpath_w,$$@).tmp $$(JULIA_SYSIMG_BUILD_FLAGS) \ - --startup-file=no --warn-overwrite=yes --sysimage $$(call cygpath_w,$$<) $$(call cygpath_w,$$(JULIAHOME)/contrib/generate_precompile.jl) $(JULIA_PRECOMPILE); then \ + if ! JULIA_BINDIR=$$(call cygpath_w,$(build_bindir)) WINEPATH="$$(call cygpath_w,$$(build_bindir));$$$$WINEPATH" \ + $$(call spawn, $3) $2 -C "$$(JULIA_CPU_TARGET)" --output-$$* $$(call cygpath_w,$$@).tmp $$(JULIA_SYSIMG_BUILD_FLAGS) \ + --startup-file=no --warn-overwrite=yes --sysimage $$(call cygpath_w,$$<) $$(call cygpath_w,$$(JULIAHOME)/contrib/generate_precompile.jl) $(JULIA_PRECOMPILE); then \ echo '*** This error is usually fixed by running `make clean`. If the error persists$$(COMMA) try `make cleanall`. ***'; \ false; \ fi ) diff --git a/test/Makefile b/test/Makefile index 9ca65ffa9d7c7..3d16f88a741b8 100644 --- a/test/Makefile +++ b/test/Makefile @@ -35,8 +35,11 @@ embedding: gcext: @$(MAKE) -C $(SRCDIR)/$@ check $(GCEXT_ARGS) +clangsa: + @$(MAKE) -C $(SRCDIR)/$@ + clean: @$(MAKE) -C embedding $@ $(EMBEDDING_ARGS) @$(MAKE) -C gcext $@ $(GCEXT_ARGS) -.PHONY: $(TESTS) $(addprefix revise-, $(TESTS)) embedding gcext clean +.PHONY: $(TESTS) $(addprefix revise-, $(TESTS)) embedding gcext clangsa clean diff --git a/test/abstractarray.jl b/test/abstractarray.jl index dd24dc28364c7..9af20b8047701 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -299,10 +299,10 @@ function test_scalar_indexing(::Type{T}, shape, ::Type{TestAbstractArray}) where B = T(A) @test A == B # Test indexing up to 5 dimensions - trailing5 = CartesianIndex(ntuple(x->1, max(ndims(B)-5, 0))) - trailing4 = CartesianIndex(ntuple(x->1, max(ndims(B)-4, 0))) - trailing3 = CartesianIndex(ntuple(x->1, max(ndims(B)-3, 0))) - trailing2 = CartesianIndex(ntuple(x->1, max(ndims(B)-2, 0))) + trailing5 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-5, 0))) + trailing4 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-4, 0))) + trailing3 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-3, 0))) + trailing2 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-2, 0))) i=0 for i5 = 1:size(B, 5) for i4 = 1:size(B, 4) @@ -419,10 +419,10 @@ function test_vector_indexing(::Type{T}, shape, ::Type{TestAbstractArray}) where N = prod(shape) A = reshape(Vector(1:N), shape) B = T(A) - trailing5 = CartesianIndex(ntuple(x->1, max(ndims(B)-5, 0))) - trailing4 = CartesianIndex(ntuple(x->1, max(ndims(B)-4, 0))) - trailing3 = CartesianIndex(ntuple(x->1, max(ndims(B)-3, 0))) - trailing2 = CartesianIndex(ntuple(x->1, max(ndims(B)-2, 0))) + trailing5 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-5, 0))) + trailing4 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-4, 0))) + trailing3 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-3, 0))) + trailing2 = CartesianIndex(ntuple(Returns(1), max(ndims(B)-2, 0))) idxs = rand(1:N, 3, 3, 3) @test B[idxs] == A[idxs] == idxs @test B[vec(idxs)] == A[vec(idxs)] == vec(idxs) @@ -835,6 +835,11 @@ end @testset "ndims and friends" begin @test ndims(Diagonal(rand(1:5,5))) == 2 @test ndims(Diagonal{Float64}) == 2 + @test ndims(Diagonal) == 2 + @test ndims(Vector) == 1 + @test ndims(Matrix) == 2 + @test ndims(Array{<:Any, 0}) == 0 + @test_throws MethodError ndims(Array) end @testset "Issue #17811" begin @@ -857,6 +862,18 @@ end @testset "to_shape" begin @test Base.to_shape(()) === () @test Base.to_shape(1) === 1 + @test Base.to_shape(big(1)) === Base.to_shape(1) + @test Base.to_shape(Int8(1)) === Base.to_shape(1) +end + +@testset "issue #39923: similar" begin + for ax in [(big(2), big(3)), (big(2), 3), (UInt64(2), 3), (2, UInt32(3)), + (big(2), Base.OneTo(3)), (Base.OneTo(2), Base.OneTo(big(3)))] + + A = similar(ones(), Int, ax) + @test axes(A) === (Base.OneTo(2), Base.OneTo(3)) + @test eltype(A) === Int + end end @testset "issue #19267" begin @@ -1280,3 +1297,91 @@ end @test Int[0 t...; t... 0] == [0 1 2; 1 2 0] @test_throws ArgumentError Int[t...; 3 4 5] end + +@testset "issue #39896, modified getindex " begin + for arr = ([1:10;], reshape([1.0:16.0;],4,4), reshape(['a':'h';],2,2,2)) + for inds = (2:5, Base.OneTo(5), BigInt(3):BigInt(5), UInt(4):UInt(3)) + @test arr[inds] == arr[collect(inds)] + @test arr[inds] isa AbstractVector{eltype(arr)} + end + end + for arr = ([1], reshape([1.0],1,1), reshape(['a'],1,1,1)) + @test arr[true:true] == [arr[1]] + @test arr[true:true] isa AbstractVector{eltype(arr)} + @test arr[false:false] == [] + @test arr[false:false] isa AbstractVector{eltype(arr)} + end + for arr = ([1:10;], reshape([1.0:16.0;],4,4), reshape(['a':'h';],2,2,2)) + @test_throws BoundsError arr[true:true] + @test_throws BoundsError arr[false:false] + end +end + +@testset "hvncat" begin + a = fill(1, (2,3,2,4,5)) + b = fill(2, (1,1,2,4,5)) + c = fill(3, (1,2,2,4,5)) + d = fill(4, (1,1,1,4,5)) + e = fill(5, (1,1,1,4,5)) + f = fill(6, (1,1,1,4,5)) + g = fill(7, (2,3,1,4,5)) + h = fill(8, (3,3,3,1,2)) + i = fill(9, (3,2,3,3,2)) + j = fill(10, (3,1,3,3,2)) + + result = [a; b c ;;; d e f ; g ;;;;; h ;;;; i j] + @test size(result) == (3,3,3,4,7) + @test result == [a; [b ;; c] ;;; [d e f] ; g ;;;;; h ;;;; i ;; j] + @test result == cat(cat([a ; b c], [d e f ; g], dims = 3), cat(h, [i j], dims = 4), dims = 5) + + # terminating semicolons extend dimensions + @test [1;] == [1] + @test [1;;] == fill(1, (1,1)) + + for v in (1, fill(1), fill(1,1,1), fill(1, 1, 1, 1)) + @test_throws ArgumentError [v; v;; v] + @test_throws ArgumentError [v; v;; v; v; v] + @test_throws ArgumentError [v; v; v;; v; v] + @test_throws ArgumentError [v; v;; v; v;;; v; v;; v; v;; v; v] + @test_throws ArgumentError [v; v;; v; v;;; v; v] + @test_throws ArgumentError [v; v;; v; v;;; v; v; v;; v; v] + @test_throws ArgumentError [v; v;; v; v;;; v; v;; v; v; v] + # ensure a wrong shape with the right number of elements doesn't pass through + @test_throws ArgumentError [v; v;; v; v;;; v; v; v; v] + + @test [v; v;; v; v] == fill(1, ndims(v) == 3 ? (2, 2, 1) : (2,2)) + @test [v; v;; v; v;;;] == fill(1, 2, 2, 1) + @test [v; v;; v; v] == fill(1, ndims(v) == 3 ? (2, 2, 1) : (2,2)) + @test [v v; v v;;;] == fill(1, 2, 2, 1) + @test [v; v;; v; v;;; v; v;; v; v;;] == fill(1, 2, 2, 2) + @test [v; v; v;; v; v; v;;; v; v; v;; v; v; v;;] == fill(1, 3, 2, 2) + @test [v v; v v;;; v v; v v] == fill(1, 2, 2, 2) + @test [v v v; v v v;;; v v v; v v v] == fill(1, 2, 3, 2) + end + + # mixed scalars and arrays work, for numbers and strings + for v = (1, "test") + @test [v v;;; fill(v, 1, 2)] == fill(v, 1, 2, 2) + end +end + +@testset "keepat!" begin + a = [1:6;] + @test a === keepat!(a, 1:5) + @test a == 1:5 + @test keepat!(a, [2, 4]) == [2, 4] + @test isempty(keepat!(a, [])) + + a = [1:6;] + @test_throws BoundsError keepat!(a, 1:10) # make sure this is not a no-op + @test_throws BoundsError keepat!(a, 2:10) + @test_throws ArgumentError keepat!(a, [2, 4, 3]) + + b = BitVector([1, 1, 1, 0, 0]) + @test b === keepat!(b, 1:5) + @test b == [1, 1, 1, 0, 0] + @test keepat!(b, 2:4) == [1, 1, 0] + @test_throws BoundsError keepat!(a, -1:10) + @test_throws ArgumentError keepat!(a, [2, 1]) + @test isempty(keepat!(a, [])) +end diff --git a/test/ambiguous.jl b/test/ambiguous.jl index bad5f19f389c9..8d0c2092f21c2 100644 --- a/test/ambiguous.jl +++ b/test/ambiguous.jl @@ -369,4 +369,21 @@ let ambig = Int32[0] @test ambig[1] == 1 end +# issue #11407 +f11407(::Dict{K,V}, ::Dict{Any,V}) where {K,V} = 1 +f11407(::Dict{K,V}, ::Dict{K,Any}) where {K,V} = 2 +@test_throws MethodError f11407(Dict{Any,Any}(), Dict{Any,Any}()) # ambiguous +@test f11407(Dict{Any,Int}(), Dict{Any,Int}()) == 1 +f11407(::Dict{Any,Any}, ::Dict{Any,Any}) where {K,V} = 3 +@test f11407(Dict{Any,Any}(), Dict{Any,Any}()) == 3 + +# issue #12814 +abstract type A12814{N, T} end +struct B12814{N, T} <: A12814{N, T} + x::NTuple{N, T} +end +(::Type{T})(x::X) where {T <: A12814, X <: Array} = 1 +@test_throws MethodError B12814{3, Float64}([1, 2, 3]) # ambiguous +@test B12814{3,Float64}((1, 2, 3)).x === (1.0, 2.0, 3.0) + nothing diff --git a/test/arrayops.jl b/test/arrayops.jl index 7ea2cf15d812d..27e366f1ce3cc 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -701,6 +701,10 @@ end perm = randperm(4) @test isequal(A,permutedims(permutedims(A,perm),invperm(perm))) @test isequal(A,permutedims(permutedims(A,invperm(perm)),perm)) + + @test sum(permutedims(A,perm)) ≈ sum(PermutedDimsArray(A,perm)) + @test sum(permutedims(A,perm), dims=2) ≈ sum(PermutedDimsArray(A,perm), dims=2) + @test sum(permutedims(A,perm), dims=(2,4)) ≈ sum(PermutedDimsArray(A,perm), dims=(2,4)) end m = [1 2; 3 4] @@ -1153,17 +1157,17 @@ end # issue #5177 c = fill(1,2,3,4) - m1 = mapslices(x-> fill(1,2,3), c, dims=[1,2]) - m2 = mapslices(x-> fill(1,2,4), c, dims=[1,3]) - m3 = mapslices(x-> fill(1,3,4), c, dims=[2,3]) + m1 = mapslices(_ -> fill(1,2,3), c, dims=[1,2]) + m2 = mapslices(_ -> fill(1,2,4), c, dims=[1,3]) + m3 = mapslices(_ -> fill(1,3,4), c, dims=[2,3]) @test size(m1) == size(m2) == size(m3) == size(c) - n1 = mapslices(x-> fill(1,6), c, dims=[1,2]) - n2 = mapslices(x-> fill(1,6), c, dims=[1,3]) - n3 = mapslices(x-> fill(1,6), c, dims=[2,3]) - n1a = mapslices(x-> fill(1,1,6), c, dims=[1,2]) - n2a = mapslices(x-> fill(1,1,6), c, dims=[1,3]) - n3a = mapslices(x-> fill(1,1,6), c, dims=[2,3]) + n1 = mapslices(_ -> fill(1,6) , c, dims=[1,2]) + n2 = mapslices(_ -> fill(1,6) , c, dims=[1,3]) + n3 = mapslices(_ -> fill(1,6) , c, dims=[2,3]) + n1a = mapslices(_ -> fill(1,1,6), c, dims=[1,2]) + n2a = mapslices(_ -> fill(1,1,6), c, dims=[1,3]) + n3a = mapslices(_ -> fill(1,1,6), c, dims=[2,3]) @test size(n1a) == (1,6,4) && size(n2a) == (1,3,6) && size(n3a) == (2,1,6) @test size(n1) == (6,1,4) && size(n2) == (6,3,1) && size(n3) == (2,6,1) @@ -1659,7 +1663,7 @@ end Nmax = 3 # TODO: go up to CARTESIAN_DIMS+2 (currently this exposes problems) for N = 1:Nmax #indexing with (UnitRange, UnitRange, UnitRange) - args = ntuple(d->UnitRange{Int}, N) + args = ntuple(Returns(UnitRange{Int}), N) @test Base.return_types(getindex, Tuple{Array{Float32, N}, args...}) == [Array{Float32, N}] @test Base.return_types(getindex, Tuple{BitArray{N}, args...}) == Any[BitArray{N}] @test Base.return_types(setindex!, Tuple{Array{Float32, N}, Array{Int, 1}, args...}) == [Array{Float32, N}] @@ -1786,7 +1790,7 @@ end @test mdsum(A) == 15 @test mdsum2(A) == 15 AA = reshape(aa, tuple(2, shp...)) - B = view(AA, 1:1, ntuple(i->Colon(), i)...) + B = view(AA, 1:1, ntuple(Returns(:), i)...) @test isa(Base.IndexStyle(B), Base.IteratorsMD.IndexCartesian) @test mdsum(B) == 15 @test mdsum2(B) == 15 @@ -1799,7 +1803,7 @@ end A = reshape(a, tuple(shp...)) @test mdsum(A) == 55 @test mdsum2(A) == 55 - B = view(A, ntuple(i->Colon(), i)...) + B = view(A, ntuple(Returns(:), i)...) @test mdsum(B) == 55 @test mdsum2(B) == 55 insert!(shp, 2, 1) diff --git a/test/bitarray.jl b/test/bitarray.jl index f246942452020..cee7624d9a81a 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -832,6 +832,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, b2) BitMatrix @check_bit_operation broadcast(|, b1, b2) BitMatrix @check_bit_operation broadcast(xor, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix @check_bit_operation (+)(b1, b2) Matrix{Int} @check_bit_operation (-)(b1, b2) Matrix{Int} @check_bit_operation broadcast(*, b1, b2) BitMatrix @@ -861,6 +863,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b0, b0) BitVector @check_bit_operation broadcast(|, b0, b0) BitVector @check_bit_operation broadcast(xor, b0, b0) BitVector + @check_bit_operation broadcast(nand, b0, b0) BitVector + @check_bit_operation broadcast(nor, b0, b0) BitVector @check_bit_operation broadcast(*, b0, b0) BitVector @check_bit_operation (*)(b0, b0') BitMatrix end @@ -871,6 +875,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, i2) Matrix{Int} @check_bit_operation broadcast(|, b1, i2) Matrix{Int} @check_bit_operation broadcast(xor, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nand, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nor, b1, i2) Matrix{Int} @check_bit_operation (+)(b1, i2) Matrix{Int} @check_bit_operation (-)(b1, i2) Matrix{Int} @check_bit_operation broadcast(*, b1, i2) Matrix{Int} @@ -902,6 +908,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, i1, b2) Matrix{Int} @check_bit_operation broadcast(|, i1, b2) Matrix{Int} @check_bit_operation broadcast(xor, i1, b2) Matrix{Int} + @check_bit_operation broadcast(nand, i1, b2) Matrix{Int} + @check_bit_operation broadcast(nor, i1, b2) Matrix{Int} @check_bit_operation broadcast(+, i1, b2) Matrix{Int} @check_bit_operation broadcast(-, i1, b2) Matrix{Int} @check_bit_operation broadcast(*, i1, b2) Matrix{Int} @@ -909,6 +917,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(|, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(xor, u1, b2) Matrix{UInt8} + @check_bit_operation broadcast(nand, u1, b2) Matrix{UInt8} + @check_bit_operation broadcast(nor, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(+, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(-, u1, b2) Matrix{UInt8} @check_bit_operation broadcast(*, u1, b2) Matrix{UInt8} @@ -986,6 +996,14 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(xor, b1, false) BitMatrix @check_bit_operation broadcast(xor, true, b1) BitMatrix @check_bit_operation broadcast(xor, false, b1) BitMatrix + @check_bit_operation broadcast(nand, b1, true) BitMatrix + @check_bit_operation broadcast(nand, b1, false) BitMatrix + @check_bit_operation broadcast(nand, true, b1) BitMatrix + @check_bit_operation broadcast(nand, false, b1) BitMatrix + @check_bit_operation broadcast(nor, b1, true) BitMatrix + @check_bit_operation broadcast(nor, b1, false) BitMatrix + @check_bit_operation broadcast(nor, true, b1) BitMatrix + @check_bit_operation broadcast(nor, false, b1) BitMatrix @check_bit_operation broadcast(+, b1, true) Matrix{Int} @check_bit_operation broadcast(+, b1, false) Matrix{Int} @check_bit_operation broadcast(-, b1, true) Matrix{Int} @@ -1002,12 +1020,18 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, b2) BitMatrix @check_bit_operation broadcast(|, b1, b2) BitMatrix @check_bit_operation broadcast(xor, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix @check_bit_operation broadcast(&, b2, b1) BitMatrix @check_bit_operation broadcast(|, b2, b1) BitMatrix @check_bit_operation broadcast(xor, b2, b1) BitMatrix + @check_bit_operation broadcast(nand, b2, b1) BitMatrix + @check_bit_operation broadcast(nor, b2, b1) BitMatrix @check_bit_operation broadcast(&, b1, i2) Matrix{Int} @check_bit_operation broadcast(|, b1, i2) Matrix{Int} @check_bit_operation broadcast(xor, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nand, b1, i2) Matrix{Int} + @check_bit_operation broadcast(nor, b1, i2) Matrix{Int} @check_bit_operation broadcast(+, b1, i2) Matrix{Int} @check_bit_operation broadcast(-, b1, i2) Matrix{Int} @check_bit_operation broadcast(*, b1, i2) Matrix{Int} @@ -1018,6 +1042,8 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(&, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(|, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(xor, b1, u2) Matrix{UInt8} + @check_bit_operation broadcast(nand, b1, u2) Matrix{UInt8} + @check_bit_operation broadcast(nor, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(+, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(-, b1, u2) Matrix{UInt8} @check_bit_operation broadcast(*, b1, u2) Matrix{UInt8} @@ -1086,6 +1112,14 @@ timesofar("unary arithmetic") @check_bit_operation broadcast(xor, b1, transpose(b3)) BitMatrix @check_bit_operation broadcast(xor, b2, b1) BitMatrix @check_bit_operation broadcast(xor, transpose(b3), b1) BitMatrix + @check_bit_operation broadcast(nand, b1, b2) BitMatrix + @check_bit_operation broadcast(nand, b1, transpose(b3)) BitMatrix + @check_bit_operation broadcast(nand, b2, b1) BitMatrix + @check_bit_operation broadcast(nand, transpose(b3), b1) BitMatrix + @check_bit_operation broadcast(nor, b1, b2) BitMatrix + @check_bit_operation broadcast(nor, b1, transpose(b3)) BitMatrix + @check_bit_operation broadcast(nor, b2, b1) BitMatrix + @check_bit_operation broadcast(nor, transpose(b3), b1) BitMatrix @check_bit_operation broadcast(+, b1, b2) Matrix{Int} @check_bit_operation broadcast(+, b1, transpose(b3)) Matrix{Int} @check_bit_operation broadcast(+, b2, b1) Matrix{Int} @@ -1180,8 +1214,8 @@ timesofar("datamove") @check_bit_operation findfirst(x->x, b1) Union{Int,Nothing} @check_bit_operation findfirst(x->!x, b1) Union{Int,Nothing} - @check_bit_operation findfirst(x->true, b1) Union{Int,Nothing} - @check_bit_operation findfirst(x->false, b1) Union{Int,Nothing} + @check_bit_operation findfirst(Returns(true ), b1) Union{Int,Nothing} + @check_bit_operation findfirst(Returns(false), b1) Union{Int,Nothing} @check_bit_operation findall(b1) Vector{Int} end @@ -1275,49 +1309,51 @@ timesofar("find") @test_throws BoundsError findprevnot(b2, 1001) @test_throws BoundsError findprev(!, b2, 1001) @test_throws BoundsError findprev(identity, b1, 1001) - @test_throws BoundsError findprev(x->false, b1, 1001) - @test_throws BoundsError findprev(x->true, b1, 1001) + @test_throws BoundsError findprev(Returns(false), b1, 1001) + @test_throws BoundsError findprev(Returns(true ), b1, 1001) @test findprev(b1, 1000) == findprevnot(b2, 1000) == findprev(!, b2, 1000) == 777 @test findprev(b1, 777) == findprevnot(b2, 777) == findprev(!, b2, 777) == 777 @test findprev(b1, 776) == findprevnot(b2, 776) == findprev(!, b2, 776) == 77 @test findprev(b1, 77) == findprevnot(b2, 77) == findprev(!, b2, 77) == 77 @test findprev(b1, 76) == findprevnot(b2, 76) == findprev(!, b2, 76) == nothing @test findprev(b1, -1) == findprevnot(b2, -1) == findprev(!, b2, -1) == nothing - @test findprev(identity, b1, -1) == findprev(x->false, b1, -1) == findprev(x->true, b1, -1) == nothing + @test findprev(identity, b1, -1) == nothing + @test findprev(Returns(false), b1, -1) == nothing + @test findprev(Returns(true), b1, -1) == nothing @test_throws BoundsError findnext(b1, -1) @test_throws BoundsError findnextnot(b2, -1) @test_throws BoundsError findnext(!, b2, -1) @test_throws BoundsError findnext(identity, b1, -1) - @test_throws BoundsError findnext(x->false, b1, -1) - @test_throws BoundsError findnext(x->true, b1, -1) + @test_throws BoundsError findnext(Returns(false), b1, -1) + @test_throws BoundsError findnext(Returns(true), b1, -1) @test findnext(b1, 1) == findnextnot(b2, 1) == findnext(!, b2, 1) == 77 @test findnext(b1, 77) == findnextnot(b2, 77) == findnext(!, b2, 77) == 77 @test findnext(b1, 78) == findnextnot(b2, 78) == findnext(!, b2, 78) == 777 @test findnext(b1, 777) == findnextnot(b2, 777) == findnext(!, b2, 777) == 777 @test findnext(b1, 778) == findnextnot(b2, 778) == findnext(!, b2, 778) == nothing @test findnext(b1, 1001) == findnextnot(b2, 1001) == findnext(!, b2, 1001) == nothing - @test findnext(identity, b1, 1001) == findnext(x->false, b1, 1001) == findnext(x->true, b1, 1001) == nothing + @test findnext(identity, b1, 1001) == findnext(Returns(false), b1, 1001) == findnext(Returns(true), b1, 1001) == nothing @test findlast(b1) == Base.findlastnot(b2) == 777 @test findfirst(b1) == Base.findfirstnot(b2) == 77 b0 = BitVector() - @test findprev(x->true, b0, -1) == nothing - @test_throws BoundsError findprev(x->true, b0, 1) - @test_throws BoundsError findnext(x->true, b0, -1) - @test findnext(x->true, b0, 1) == nothing + @test findprev(Returns(true), b0, -1) == nothing + @test_throws BoundsError findprev(Returns(true), b0, 1) + @test_throws BoundsError findnext(Returns(true), b0, -1) + @test findnext(Returns(true), b0, 1) == nothing b1 = falses(10) - @test findprev(x->true, b1, 5) == 5 - @test findnext(x->true, b1, 5) == 5 - @test findprev(x->true, b1, -1) == nothing - @test findnext(x->true, b1, 11) == nothing - @test findprev(x->false, b1, 5) == nothing - @test findnext(x->false, b1, 5) == nothing - @test findprev(x->false, b1, -1) == nothing - @test findnext(x->false, b1, 11) == nothing - @test_throws BoundsError findprev(x->true, b1, 11) - @test_throws BoundsError findnext(x->true, b1, -1) + @test findprev(Returns(true), b1, 5) == 5 + @test findnext(Returns(true), b1, 5) == 5 + @test findprev(Returns(true), b1, -1) == nothing + @test findnext(Returns(true), b1, 11) == nothing + @test findprev(Returns(false), b1, 5) == nothing + @test findnext(Returns(false), b1, 5) == nothing + @test findprev(Returns(false), b1, -1) == nothing + @test findnext(Returns(false), b1, 11) == nothing + @test_throws BoundsError findprev(Returns(true), b1, 11) + @test_throws BoundsError findnext(Returns(true), b1, -1) @testset "issue 32568" for T = (UInt, BigInt) for x = (1, 2) @@ -1382,12 +1418,14 @@ timesofar("reductions") b2 = bitrand(l) @test map(~, b1) == map(x->~x, b1) == broadcast(~, b1) @test map(identity, b1) == map(x->x, b1) == b1 - @test map(zero, b1) == map(x->false, b1) == falses(l) - @test map(one, b1) == map(x->true, b1) == trues(l) + @test map(zero, b1) == map(Returns(false), b1) == falses(l) + @test map(one, b1) == map(Returns(true), b1) == trues(l) @test map(&, b1, b2) == map((x,y)->x&y, b1, b2) == broadcast(&, b1, b2) @test map(|, b1, b2) == map((x,y)->x|y, b1, b2) == broadcast(|, b1, b2) @test map(⊻, b1, b2) == map((x,y)->x⊻y, b1, b2) == broadcast(⊻, b1, b2) == broadcast(xor, b1, b2) + @test map(⊼, b1, b2) == map((x,y)->x⊼y, b1, b2) == broadcast(⊼, b1, b2) == broadcast(nand, b1, b2) + @test map(⊽, b1, b2) == map((x,y)->x⊽y, b1, b2) == broadcast(⊽, b1, b2) == broadcast(nor, b1, b2) @test map(^, b1, b2) == map((x,y)->x^y, b1, b2) == b1 .^ b2 @test map(*, b1, b2) == map((x,y)->x*y, b1, b2) == b1 .* b2 @@ -1407,8 +1445,8 @@ timesofar("reductions") @test map!(~, b, b1) == map!(x->~x, b, b1) == broadcast(~, b1) == b @test map!(!, b, b1) == map!(x->!x, b, b1) == broadcast(~, b1) == b @test map!(identity, b, b1) == map!(x->x, b, b1) == b1 == b - @test map!(zero, b, b1) == map!(x->false, b, b1) == falses(l) == b - @test map!(one, b, b1) == map!(x->true, b, b1) == trues(l) == b + @test map!(zero, b, b1) == map!(Returns(false), b, b1) == falses(l) == b + @test map!(one, b, b1) == map!(Returns(true), b, b1) == trues(l) == b @test map!(&, b, b1, b2) == map!((x,y)->x&y, b, b1, b2) == broadcast(&, b1, b2) == b @test map!(|, b, b1, b2) == map!((x,y)->x|y, b, b1, b2) == broadcast(|, b1, b2) == b diff --git a/test/boundscheck_exec.jl b/test/boundscheck_exec.jl index 62a20921bd44e..e1a7029334a3d 100644 --- a/test/boundscheck_exec.jl +++ b/test/boundscheck_exec.jl @@ -251,5 +251,12 @@ if bc_opt == bc_default || bc_opt == bc_off @test occursin("vector.body", sprint(code_llvm, g27079, Tuple{Vector{Int}})) end +# Boundschecking removal of indices with different type, see #40281 +getindex_40281(v, a, b, c) = @inbounds getindex(v, a, b, c) +typed_40281 = sprint((io, args...) -> code_warntype(io, args...; optimize=true), getindex_40281, Tuple{Array{Float64, 3}, Int, UInt8, Int}) +if bc_opt == bc_default || bc_opt == bc_off + @test occursin("arrayref(false", typed_40281) + @test !occursin("arrayref(true", typed_40281) +end end diff --git a/test/broadcast.jl b/test/broadcast.jl index 6e97d609a42b0..57a65110a413a 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -951,6 +951,35 @@ p0 = copy(p) @test repr(.!) == "Base.Broadcast.BroadcastFunction(!)" @test eval(:(.+)) == Base.BroadcastFunction(+) +@testset "Issue #5187: Broadcasting of short-circuiting ops" begin + ex = Meta.parse("A .< 1 .|| A .> 2") + @test ex == :((A .< 1) .|| (A .> 2)) + @test ex.head == :.|| + ex = Meta.parse("A .< 1 .&& A .> 2") + @test ex == :((A .< 1) .&& (A .> 2)) + @test ex.head == :.&& + + A = -1:4 + @test (A .< 1 .|| A .> 2) == [true, true, false, false, true, true] + @test (A .>= 1 .&& A .<= 2) == [false, false, true, true, false, false] + + mutable struct F5187; x; end + (f::F5187)(x) = (f.x += x) + @test (iseven.(1:4) .&& (F5187(0)).(ones(4))) == [false, 1, false, 2] + @test (iseven.(1:4) .|| (F5187(0)).(ones(4))) == [1, true, 2, true] + r = 1:4; o = ones(4); f = F5187(0); + @test (@. iseven(r) && f(o)) == [false, 1, false, 2] + @test (@. iseven(r) || f(o)) == [3, true, 4, true] + + @test (iseven.(1:8) .&& iseven.((F5187(0)).(ones(8))) .&& (F5187(0)).(ones(8))) == [false,false,false,1,false,false,false,2] + @test (iseven.(1:8) .|| iseven.((F5187(0)).(ones(8))) .|| (F5187(0)).(ones(8))) == [1,true,true,true,2,true,true,true] + r = 1:8; o = ones(8); f1 = F5187(0); f2 = F5187(0) + @test (@. iseven(r) && iseven(f1(o)) && f2(o)) == [false,false,false,1,false,false,false,2] + @test (@. iseven(r) || iseven(f1(o)) || f2(o)) == [3,true,true,true,4,true,true,true] + @test (iseven.(1:8) .&& iseven.((F5187(0)).(ones(8))) .&& (F5187(0)).(ones(8))) == [false,false,false,1,false,false,false,2] + @test (iseven.(1:8) .|| iseven.((F5187(0)).(ones(8))) .|| (F5187(0)).(ones(8))) == [1,true,true,true,2,true,true,true] +end + @testset "Issue #28382: inferrability of broadcast with Union eltype" begin @test isequal([1, 2] .+ [3.0, missing], [4.0, missing]) @test Core.Compiler.return_type(broadcast, Tuple{typeof(+), Vector{Int}, @@ -1015,3 +1044,9 @@ end @test a_ == dropdims(a .* c, dims=(findall(==(1), size(c))...,)) end end + +@testset "Issue #40309: still gives a range after #40320" begin + @test Base.broadcasted_kwsyntax(+, [1], [2]) isa Broadcast.Broadcasted{<:Any, <:Any, typeof(+)} + @test Broadcast.BroadcastFunction(+)(2:3, 2:3) == 4:2:6 + @test Broadcast.BroadcastFunction(+)(2:3, 2:3) isa AbstractRange +end diff --git a/test/ccall.jl b/test/ccall.jl index 8cb376c805611..ae29b40784eb6 100644 --- a/test/ccall.jl +++ b/test/ccall.jl @@ -842,7 +842,7 @@ function check_code_trampoline(f, t, n::Int) @nospecialize(f, t) @test Base.return_types(f, t) == Any[Any] llvm = sprint(code_llvm, f, t) - @test count(x -> true, eachmatch(r"@jl_get_cfunction_trampoline\(", llvm)) == n + @test count(Returns(true), eachmatch(r"@jl_get_cfunction_trampoline\(", llvm)) == n end check_code_trampoline(testclosure, (Any, Any, Bool, Type), 2) check_code_trampoline(testclosure, (Any, Int, Bool, Type{Int}), 2) @@ -906,7 +906,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), global function $fname(s::$t) verbose && println("B: ", s) @test s == $v - if($(t).mutable) + if $(t).name.mutable @test !(s === $a) end global c = s @@ -934,7 +934,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end verbose && println("C: ",b) @test b == $v - if ($(t).mutable) + if $(t).name.mutable @test !(b === c) @test !(b === a) end @@ -943,7 +943,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end verbose && println("C: ",b) @test b == $v - if ($(t).mutable) + if $(t).name.mutable @test !(b === c) @test !(b === a) end @@ -953,7 +953,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), verbose && println("C: ",b) @test b == $v @test b === c - if ($(t).mutable) + if $(t).name.mutable @test !(b === a) end let cf = @cfunction($fname, Any, (Ref{$t},)) @@ -962,7 +962,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), verbose && println("C: ",b) @test b == $v @test b === c - if ($(t).mutable) + if $(t).name.mutable @test !(b === a) end let cf = @cfunction($fname, Any, (Ref{Any},)) @@ -970,7 +970,7 @@ for (t, v) in ((Complex{Int32}, :ci32), (Complex{Int64}, :ci64), end @test b == $v @test b === c - if ($(t).mutable) + if $(t).name.mutable @test !(b === a) end let cf = @cfunction($fname, Ref{AbstractString}, (Ref{Any},)) @@ -1443,15 +1443,28 @@ end eval(:(f20835(x) = ccall(:fn, Cvoid, (Ptr{typeof(x)},), x)))) @test_throws(UndefVarError(:Something_not_defined_20835), eval(:(f20835(x) = ccall(:fn, Something_not_defined_20835, (Ptr{typeof(x)},), x)))) - -@noinline f21104at(::Type{T}) where {T} = ccall(:fn, Cvoid, (Some{T},), Some(0)) -@noinline f21104rt(::Type{T}) where {T} = ccall(:fn, Some{T}, ()) -@test code_llvm(devnull, f21104at, (Type{Float64},)) === nothing -@test code_llvm(devnull, f21104rt, (Type{Float64},)) === nothing -@test_throws(ErrorException("ccall argument 1 doesn't correspond to a C type"), - f21104at(Float64)) -@test_throws(ErrorException("ccall return type doesn't correspond to a C type"), - f21104rt(Float64)) +@test isempty(methods(f20835)) + +@test_throws(ErrorException("ccall method definition: argument 1 type doesn't correspond to a C type"), + @eval f21104(::Type{T}) where {T} = ccall(:fn, Cvoid, (Some{T},), Some(0))) +@test_throws(ErrorException("ccall method definition: return type doesn't correspond to a C type"), + @eval f21104(::Type{T}) where {T} = ccall(:fn, Some{T}, ())) +@test isempty(methods(f21104)) +@test_throws(ErrorException("ccall method definition: argument 1 type doesn't correspond to a C type"), + @eval if false; ccall(:fn, Cvoid, (Some.body,), Some(0)); end) +@test_throws(ErrorException("ccall method definition: return type doesn't correspond to a C type"), + @eval if false; ccall(:fn, Some.body, ()); end) +@test_throws(ErrorException("ccall method definition: return type doesn't correspond to a C type"), + @eval if false; ccall(:fn, Tuple, ()); end) +## TODO: lowering is broken on this (throws "syntax: ssavalue with no def") +#@test_throws(ErrorException("ccall method definition: return type doesn't correspond to a C type"), +# @eval if false; ccall(:fn, Tuple{Val{T}} where T, ()); end) +@test_throws(ErrorException("ccall method definition: return type doesn't correspond to a C type"), + @eval if false; ccall(:fn, Tuple{Val}, ()); end) +@test_throws(TypeError, @eval if false; ccall(:fn, Some.var, ()); end) +@test_throws(TypeError, @eval if false; ccall(:fn, Cvoid, (Some.var,), Some(0)); end) +@test_throws(ErrorException("ccall method definition: Vararg not allowed for argument list"), + @eval ccall(+, Int, (Vararg{Int},), 1)) # test for malformed syntax errors @test Expr(:error, "more arguments than types for ccall") == Meta.lower(@__MODULE__, :(ccall(:fn, A, (), x))) @@ -1482,21 +1495,20 @@ end evalf_callback_19805(ci::callinfos_19805{FUNC_FT}) where {FUNC_FT} = ci.f(0.5)::Float64 -evalf_callback_c_19805(ci::callinfos_19805{FUNC_FT}) where {FUNC_FT} = @cfunction( - evalf_callback_19805, Float64, (callinfos_19805{FUNC_FT},)) - -@test_throws(ErrorException("cfunction argument 1 doesn't correspond to a C type"), - evalf_callback_c_19805( callinfos_19805(sin) )) -@test_throws(ErrorException("cfunction argument 2 doesn't correspond to a C type"), - @cfunction(+, Int, (Int, Nothing))) -@test_throws(ErrorException("cfunction: Vararg syntax not allowed for argument list"), - @cfunction(+, Int, (Vararg{Int},))) +@test_throws(ErrorException("cfunction method definition: argument 1 type doesn't correspond to a C type"), + @eval evalf_callback_c_19805(ci::callinfos_19805{FUNC_FT}) where {FUNC_FT} = + @cfunction(evalf_callback_19805, Float64, (callinfos_19805{FUNC_FT},))) +@test isempty(methods(evalf_callback_c_19805)) +@test_throws(ErrorException("cfunction method definition: Vararg not allowed for argument list"), + @eval if false; @cfunction(+, Int, (Vararg{Int},)); end) @test_throws(ErrorException("could not evaluate cfunction argument type (it might depend on a local variable)"), @eval () -> @cfunction(+, Int, (Ref{T}, Ref{T})) where T) @test_throws(ErrorException("could not evaluate cfunction return type (it might depend on a local variable)"), @eval () -> @cfunction(+, Ref{T}, (Int, Int)) where T) +@test_throws(ErrorException("cfunction argument 2 doesn't correspond to a C type"), + @eval @cfunction(+, Int, (Int, Nothing))) @test_throws(ErrorException("cfunction return type Ref{Any} is invalid. Use Any or Ptr{Any} instead."), - @cfunction(+, Ref{Any}, (Int, Int))) + @eval @cfunction(+, Ref{Any}, (Int, Int))) # test Ref{abstract_type} calling parameter passes a heap box abstract type Abstract22734 end @@ -1770,3 +1782,47 @@ ccall_with_undefined_lib() = ccall((:time, xx_nOt_DeFiNeD_xx), Cint, (Ptr{Cvoid} b16 = transcode(UInt16, b8) @test b16 == b end + +# issue 33413 +@testset "cglobal lowering" begin + # crash in cglobal33413_ptrinline[_notype]() specifically requires the library pointer be + # retrieved inside the function; using global pointer variable doesn't trigger the crash + function cglobal33413_ptrvar() + libh = Libdl.dlopen(libccalltest) + sym = Libdl.dlsym(libh, :global_var) + return cglobal(sym, Cint) + end + function cglobal33413_ptrvar_notype() + libh = Libdl.dlopen(libccalltest) + sym = Libdl.dlsym(libh, :global_var) + return cglobal(sym) + end + function cglobal33413_ptrinline() + libh = Libdl.dlopen(libccalltest) + return cglobal(Libdl.dlsym(libh, :global_var), Cint) + end + function cglobal33413_ptrinline_notype() + libh = Libdl.dlopen(libccalltest) + return cglobal(Libdl.dlsym(libh, :global_var)) + end + function cglobal33413_tupleliteral() + return cglobal((:global_var, libccalltest), Cint) + end + function cglobal33413_tupleliteral_notype() + return cglobal((:global_var, libccalltest)) + end + function cglobal33413_literal() + return cglobal(:sin, Cint) + end + function cglobal33413_literal_notype() + return cglobal(:sin) + end + @test unsafe_load(cglobal33413_ptrvar()) == 1 + @test unsafe_load(cglobal33413_ptrinline()) == 1 + @test unsafe_load(cglobal33413_tupleliteral()) == 1 + @test unsafe_load(convert(Ptr{Cint}, cglobal33413_ptrvar_notype())) == 1 + @test unsafe_load(convert(Ptr{Cint}, cglobal33413_ptrinline_notype())) == 1 + @test unsafe_load(convert(Ptr{Cint}, cglobal33413_tupleliteral_notype())) == 1 + @test cglobal33413_literal() != C_NULL + @test cglobal33413_literal_notype() != C_NULL +end diff --git a/test/channels.jl b/test/channels.jl index c5b1b3f6db9a5..0611b387e6f88 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -333,7 +333,7 @@ end # interpreting the calling function. @noinline garbage_finalizer(f) = (finalizer(f, "gar" * "bage"); nothing) run = Ref(0) - garbage_finalizer(x -> nothing) # warmup + garbage_finalizer(Returns(nothing)) # warmup @test GC.enable(false) # test for finalizers trying to yield leading to failed attempts to context switch garbage_finalizer((x) -> (run[] += 1; sleep(1))) @@ -533,7 +533,7 @@ end # make sure that we don't accidentally create a one-shot timer let - t = Timer(t->nothing, 10, interval=0.00001) + t = Timer(Returns(nothing), 10, interval=0.00001) @test ccall(:uv_timer_get_repeat, UInt64, (Ptr{Cvoid},), t) == 1 close(t) end diff --git a/test/char.jl b/test/char.jl index abc8db33cb4a7..279adb628ed17 100644 --- a/test/char.jl +++ b/test/char.jl @@ -99,6 +99,7 @@ end #getindex(c::Char) = c for x in testarrays @test getindex(x) == x + @test getindex(x, CartesianIndex()) == x end #first(c::Char) = c @@ -290,6 +291,7 @@ end @testset "broadcasting of Char" begin @test identity.('a') == 'a' + @test 'a' .* ['b', 'c'] == ["ab", "ac"] end @testset "code point format of U+ syntax (PR 33291)" begin diff --git a/test/client.jl b/test/client.jl index 497cc54b13534..f917e45fb412d 100644 --- a/test/client.jl +++ b/test/client.jl @@ -18,14 +18,22 @@ nested_error_pattern = r""" @testset "display_error" begin # Display of errors which cause more than one entry on the exception stack - err_str = try + excs = try eval(nested_error_expr) catch - excs = Base.catch_stack() - @test typeof.(first.(excs)) == [UndefVarError, DivideError] - sprint(Base.display_error, excs) + Base.current_exceptions() end - @test occursin(nested_error_pattern, err_str) + @test typeof.(first.(excs)) == [UndefVarError, DivideError] + @test occursin(nested_error_pattern, sprint(Base.display_error, excs)) + + @test occursin(r""" + 2-element ExceptionStack: + DivideError: integer division error + Stacktrace:.* + + caused by: UndefVarError: __not_a_binding__ not defined + Stacktrace:.* + """s, sprint(show, excs)) end @testset "Fallback REPL" begin diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index fdc4ecd528389..13e7251ba3a95 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -110,9 +110,16 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # ~ expansion in --project and JULIA_PROJECT if !Sys.iswindows() - expanded = abspath(expanduser("~/foo")) - @test occursin(expanded, readchomp(`$exename --project='~/foo' -E 'Base.active_project()'`)) - @test occursin(expanded, readchomp(setenv(`$exename -E 'Base.active_project()'`, "JULIA_PROJECT" => "~/foo", "HOME" => homedir()))) + let expanded = abspath(expanduser("~/foo/Project.toml")) + @test expanded == readchomp(`$exename --project='~/foo' -e 'println(Base.active_project())'`) + @test expanded == readchomp(setenv(`$exename -e 'println(Base.active_project())'`, "JULIA_PROJECT" => "~/foo", "HOME" => homedir())) + end + end + + # handling of @projectname in --project and JULIA_PROJECT + let expanded = abspath(Base.load_path_expand("@foo")) + @test expanded == readchomp(`$exename --project='@foo' -e 'println(Base.active_project())'`) + @test expanded == readchomp(setenv(`$exename -e 'println(Base.active_project())'`, "JULIA_PROJECT" => "@foo", "HOME" => homedir())) end # --quiet, --banner @@ -343,6 +350,9 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test readchomp(`$exename -E "Base.JLOptions().opt_level" --optimize`) == "3" @test readchomp(`$exename -E "Base.JLOptions().opt_level" -O0`) == "0" + @test readchomp(`$exename -E "Base.JLOptions().opt_level_min"`) == "0" + @test readchomp(`$exename -E "Base.JLOptions().opt_level_min" --min-optlevel=2`) == "2" + # -g @test readchomp(`$exename -E "Base.JLOptions().debug_level" -g`) == "2" let code = writereadpipeline("code_llvm(stdout, +, (Int64, Int64), raw=true, dump_module=true)", `$exename -g0`) diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index 47f419d9937a2..a080cd550d10f 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -553,3 +553,20 @@ end end @test occursin("llvm.julia.gc_preserve_begin", get_llvm(f4, Tuple{Bool}, true, false, false)) end + +# issue #32843 +function f32843(vals0, v) + (length(vals0) > 1) && (vals = v[1]) + (length(vals0) == 1 && vals0[1]==1) && (vals = 1:2) + vals +end +@test_throws UndefVarError f32843([6], Vector[[1]]) + +# issue #40855, struct constants with union fields +@enum T40855 X40855 +struct A40855 + d::Union{Nothing, T40855} + b::Union{Nothing, Int} +end +g() = string(A40855(X40855, 1)) +@test g() == "$(@__MODULE__).A40855($(@__MODULE__).X40855, 1)" diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 754fd7a3f5ce8..5cbd39d8468a6 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -44,6 +44,13 @@ let t = Tuple{Ref{T},T,T} where T, c = Tuple{Ref, T, T} where T # #36407 @test t <: Core.Compiler.limit_type_size(t, c, Union{}, 1, 100) end +let # 40336 + t = Type{Type{Int}} + c = Type{Int} + r = Core.Compiler.limit_type_size(t, c, c, 100, 100) + @test t !== r && t <: r +end + @test Core.Compiler.unionlen(Union{}) == 1 @test Core.Compiler.unionlen(Int8) == 1 @test Core.Compiler.unionlen(Union{Int8, Int16}) == 2 @@ -670,8 +677,8 @@ let fieldtype_tfunc = Core.Compiler.fieldtype_tfunc, @test fieldtype_tfunc(Union{Type{Base.RefValue{<:Real}}, Type{Int32}}, Const(:x)) == Const(Real) @test fieldtype_tfunc(Const(Union{Base.RefValue{<:Real}, Type{Int32}}), Const(:x)) == Const(Real) @test fieldtype_tfunc(Type{Union{Base.RefValue{T}, Type{Int32}}} where {T<:Real}, Const(:x)) == Type{<:Real} - @test fieldtype_tfunc(Type{<:Tuple}, Const(1)) == Type - @test fieldtype_tfunc(Type{<:Tuple}, Any) == Type + @test fieldtype_tfunc(Type{<:Tuple}, Const(1)) == Any + @test fieldtype_tfunc(Type{<:Tuple}, Any) == Any @test fieldtype_nothrow(Type{Base.RefValue{<:Real}}, Const(:x)) @test !fieldtype_nothrow(Type{Union{}}, Const(:x)) @test !fieldtype_nothrow(Union{Type{Base.RefValue{T}}, Int32} where {T<:Real}, Const(:x)) @@ -1544,9 +1551,9 @@ f_pure_add() = (1 + 1 == 2) ? true : "FAIL" @test @inferred f_pure_add() # inference of `T.mutable` -@test Core.Compiler.getfield_tfunc(Const(Int), Const(:mutable)) == Const(false) -@test Core.Compiler.getfield_tfunc(Const(Vector{Int}), Const(:mutable)) == Const(true) -@test Core.Compiler.getfield_tfunc(DataType, Const(:mutable)) == Bool +@test Core.Compiler.getfield_tfunc(Const(Int.name), Const(:mutable)) == Const(false) +@test Core.Compiler.getfield_tfunc(Const(Vector{Int}.name), Const(:mutable)) == Const(true) +@test Core.Compiler.getfield_tfunc(Core.TypeName, Const(:mutable)) == Bool # getfield on abstract named tuples. issue #32698 import Core.Compiler.getfield_tfunc @@ -1826,6 +1833,24 @@ end end == Any[Tuple{Int,Int}] end +@testset "conditional constraint propagation from non-`Conditional` object" begin + @test Base.return_types((Bool,)) do b + if b + return !b ? nothing : 1 # ::Int + else + return 0 + end + end == Any[Int] + + @test Base.return_types((Any,)) do b + if b + return b # ::Bool + else + return nothing + end + end == Any[Union{Bool,Nothing}] +end + function f25579(g) h = g[] t = (h === nothing) @@ -2940,10 +2965,10 @@ end @test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Tuple{Int}, Any, Vararg}) == Int @test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Tuple{Int}, Any, Any, Vararg}) == Int @test Core.Compiler.return_type(apply26826, Tuple{typeof(getfield), Any, Any, Any, Any, Vararg}) == Union{} -@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Vararg}) == Union{Type, TypeVar} -@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Vararg}) == Union{Type, TypeVar} -@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Vararg}) == Union{Type, TypeVar} -@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Vararg}) == Union{Type, TypeVar} +@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Vararg}) == Any +@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Vararg}) == Any +@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Vararg}) == Any +@test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Vararg}) == Any @test Core.Compiler.return_type(apply26826, Tuple{typeof(fieldtype), Any, Any, Any, Any, Vararg}) == Union{} @test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Vararg}) == Any @test Core.Compiler.return_type(apply26826, Tuple{typeof(Core.apply_type), Any, Vararg}) == Any @@ -3171,8 +3196,6 @@ end end @testset "constant prop' for union split signature" begin - anonymous_module() = Core.eval(@__MODULE__, :(module $(gensym()) end))::Module - # indexing into tuples really relies on constant prop', and we will get looser result # (`Union{Int,String,Char}`) if constant prop' doesn't happen for splitunion signatures tt = (Union{Tuple{Int,String},Tuple{Int,Char}},) @@ -3191,7 +3214,7 @@ end b end == Any[Union{String,Char}] - @test (@eval anonymous_module() begin + @test (@eval Module() begin struct F32 val::Float32 _v::Int @@ -3205,7 +3228,7 @@ end end end) == Any[Union{Float32,Float64}] - @test (@eval anonymous_module() begin + @test (@eval Module() begin struct F32 val::Float32 _v @@ -3243,3 +3266,50 @@ end Some(0x2) end end == [Union{Some{Float64}, Some{Int}, Some{UInt8}}] + +# https://github.com/JuliaLang/julia/issues/40336 +@testset "make sure a call with signatures with recursively nested Types terminates" begin + @test @eval Module() begin + f(@nospecialize(t)) = f(Type{t}) + + code_typed() do + f(Int) + end + true + end + + @test @eval Module() begin + f(@nospecialize(t)) = tdepth(t) == 10 ? t : f(Type{t}) + tdepth(@nospecialize(t)) = isempty(t.parameters) ? 1 : 1+tdepth(t.parameters[1]) + + code_typed() do + f(Int) + end + true + end +end + +# Make sure that const prop doesn't fall into cycles that aren't problematic +# in the type domain +f_recurse(x) = x > 1000000 ? x : f_recurse(x+1) +@test Base.return_types() do + f_recurse(1) +end |> first === Int + +# issue #39915 +function f33915(a_tuple, which_ones) + rest = f33915(Base.tail(a_tuple), Base.tail(which_ones)) + if first(which_ones) + (first(a_tuple), rest...) + else + rest + end +end +f33915(a_tuple::Tuple{}, which_ones::Tuple{}) = () +g39915(a_tuple) = f33915(a_tuple, (true, false, true, false)) +@test Base.return_types() do + g39915((1, 1.0, "a", :a)) +end |> first === Tuple{Int, String} + +# issue #40742 +@test Base.return_types(string, (Vector{Tuple{:x}},)) == Any[String] diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 42839d4d954e6..ea0761320e700 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -162,8 +162,8 @@ function fully_eliminated(f, args, retval) end end -# check that type.mutable can be fully eliminated -f_mutable_nothrow(s::String) = Val{typeof(s).mutable} +# check that ismutabletype(type) can be fully eliminated +f_mutable_nothrow(s::String) = Val{typeof(s).name.mutable} @test fully_eliminated(f_mutable_nothrow, (String,)) # check that ifelse can be fully eliminated diff --git a/test/complex.jl b/test/complex.jl index 56c446896bf53..6fe3046ca9a07 100644 --- a/test/complex.jl +++ b/test/complex.jl @@ -1088,16 +1088,8 @@ end @test isequal(one(T) / complex(T(-NaN), T(-Inf)), complex(-zero(T), zero(T))) # divide complex by complex Inf - if T == Float64 - @test_broken isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) - @test_broken isequal(complex(one(T)) / complex(T(-Inf), T(Inf)), complex(-zero(T), -zero(T))) - elseif T == Float32 - @test isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) - @test_broken isequal(complex(one(T)) / complex(T(-Inf), T(Inf)), complex(-zero(T), -zero(T))) - else - @test isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) - @test isequal(complex(one(T)) / complex(T(-Inf), T(Inf)), complex(-zero(T), -zero(T))) - end + @test isequal(complex(one(T)) / complex(T(Inf), T(-Inf)), complex(zero(T), zero(T))) broken=(T==Float64) + @test isequal(complex(one(T)) / complex(T(-Inf), T(Inf)), complex(-zero(T), -zero(T))) broken=(T in (Float32, Float64)) end end diff --git a/test/copy.jl b/test/copy.jl index 34d1c20c5f4fa..28d34e4756a6b 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -233,4 +233,8 @@ end @test copyto!(s, view(Int[],Int[])) == [1, 2] @test copyto!(s, Float64[]) == [1, 2] @test copyto!(s, String[]) == [1, 2] # No error -end \ No newline at end of file +end + +@testset "deepcopy_internal arrays" begin + @test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros() +end diff --git a/test/core.jl b/test/core.jl index c360dc6ba5b13..5036df4ec8218 100644 --- a/test/core.jl +++ b/test/core.jl @@ -2389,19 +2389,14 @@ let ex = Expr(:(=), :(f8338(x;y=4)), :(x*y)) end # call overloading (#2403) -(x::Int)(y::Int) = x + 3y issue2403func(f) = f(7) -let x = 10 - @test x(3) == 19 - @test x((3,)...) == 19 - @test issue2403func(x) == 31 -end mutable struct Issue2403 x end (i::Issue2403)(y) = i.x + 2y let x = Issue2403(20) @test x(3) == 26 + @test x((3,)...) == 26 @test issue2403func(x) == 34 end @@ -5651,11 +5646,9 @@ f_isdefined_unionvar(y, t) = (t > 0 && (x = (t == 1 ? 1 : y)); @isdefined x) @test !f_isdefined_unionvar(1, 0) f_isdefined_splat(x...) = @isdefined x @test f_isdefined_splat(1, 2, 3) -let err = try; @macroexpand @isdefined :x; false; catch ex; ex; end, +let e = try; @macroexpand @isdefined :x; false; catch ex; ex; end, __source__ = LineNumberNode(@__LINE__() - 1, Symbol(@__FILE__)) - @test err.file === string(__source__.file) - @test err.line === __source__.line - e = err.error::MethodError + e::MethodError @test e.f === getfield(@__MODULE__, Symbol("@isdefined")) @test e.args === (__source__, @__MODULE__, :(:x)) end @@ -5972,11 +5965,11 @@ end for U in boxedunions local U for N in (1, 2, 3, 4) - A = Array{U}(undef, ntuple(x->0, N)...) + A = Array{U}(undef, ntuple(Returns(0), N)...) @test isempty(A) @test sizeof(A) == 0 - A = Array{U}(undef, ntuple(x->10, N)...) + A = Array{U}(undef, ntuple(Returns(10), N)...) @test length(A) == 10^N @test sizeof(A) == sizeof(Int) * (10^N) @test !isassigned(A, 1) @@ -6057,11 +6050,11 @@ using Serialization for U in unboxedunions local U for N in (1, 2, 3, 4) - A = Array{U}(undef, ntuple(x->0, N)...) + A = Array{U}(undef, ntuple(Returns(0), N)...) @test isempty(A) @test sizeof(A) == 0 - len = ntuple(x->10, N) + len = ntuple(Returns(10), N) mxsz = maximum(sizeof, Base.uniontypes(U)) A = Array{U}(undef, len) @test length(A) == prod(len) @@ -7227,6 +7220,11 @@ end @test_broken isbitstype(Tuple{B33954}) @test_broken isbitstype(B33954) +struct B40050 <: Ref{Tuple{B40050}} +end +@test string((B40050(),)) == "($B40050(),)" +@test_broken isbitstype(Tuple{B40050}) + # Issue #34206/34207 function mre34206(a, n) va = view(a, :) @@ -7555,3 +7553,12 @@ function f18621() end @test f18621() == 1:5 @test [_ for _ in 1:5] == 1:5 + +# issue #35130 +const T35130 = Tuple{Vector{Int}, <:Any} +@eval struct A35130 + x::Vector{Tuple{Vector{Int}, Any}} + A35130(x) = $(Expr(:new, :A35130, :x)) +end +h35130(x) = A35130(Any[x][1]::Vector{T35130}) +@test h35130(T35130[([1],1)]) isa A35130 diff --git a/test/corelogging.jl b/test/corelogging.jl index 89f69be438810..698209661456b 100644 --- a/test/corelogging.jl +++ b/test/corelogging.jl @@ -341,15 +341,43 @@ end String(take!(io)) end + function genmsg_out(level, message, _module, filepath, line; kws...) + fname = tempname() + f = open(fname, "w") + logger = SimpleLogger() + redirect_stdout(f) do + handle_message(logger, level, message, _module, :group, :id, + filepath, line; kws...) + end + close(f) + buf = read(fname) + rm(fname) + String(buf) + end + + function genmsg_err(level, message, _module, filepath, line; kws...) + fname = tempname() + f = open(fname, "w") + logger = SimpleLogger() + redirect_stderr(f) do + handle_message(logger, level, message, _module, :group, :id, + filepath, line; kws...) + end + close(f) + buf = read(fname) + rm(fname) + String(buf) + end + # Simple - @test genmsg(Info, "msg", Main, "some/path.jl", 101) == + @test genmsg_out(Info, "msg", Main, "some/path.jl", 101) == """ ┌ Info: msg └ @ Main some/path.jl:101 """ # Multiline message - @test genmsg(Warn, "line1\nline2", Main, "some/path.jl", 101) == + @test genmsg_err(Warn, "line1\nline2", Main, "some/path.jl", 101) == """ ┌ Warning: line1 │ line2 diff --git a/test/dict.jl b/test/dict.jl index 534e88ada036c..7cbaf699fc3cc 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -684,6 +684,7 @@ import Base.ImmutableDict d4 = ImmutableDict(d3, k2 => v1) dnan = ImmutableDict{String, Float64}(k2, NaN) dnum = ImmutableDict(dnan, k2 => 1) + f(x) = x^2 @test isempty(collect(d)) @test !isempty(collect(d1)) @@ -729,6 +730,18 @@ import Base.ImmutableDict @test get(d4, "key1", :default) === v2 @test get(d4, "foo", :default) === :default @test get(d, k1, :default) === :default + @test get(d1, "key1") do + f(2) + end === v1 + @test get(d4, "key1") do + f(4) + end === v2 + @test get(d4, "foo") do + f(6) + end === 36 + @test get(d, k1) do + f(8) + end === 64 @test d1["key1"] === v1 @test d4["key1"] === v2 @test empty(d3) === d diff --git a/test/docs.jl b/test/docs.jl index fbe24da9be873..05442df9d4cbe 100644 --- a/test/docs.jl +++ b/test/docs.jl @@ -793,14 +793,7 @@ end # Issue #13905. let err = try; @macroexpand(@doc "" f() = @x); false; catch ex; ex; end - __source__ = LineNumberNode(@__LINE__() - 1, Symbol(@__FILE__)) - err::LoadError - @test err.file === string(__source__.file) - @test err.line === __source__.line - err = err.error::LoadError - @test err.file === string(__source__.file) - @test err.line === __source__.line - err = err.error::UndefVarError + err::UndefVarError @test err.var == Symbol("@x") end @@ -863,11 +856,9 @@ undocumented(x,y) = 3 end # module doc_str = Markdown.parse(""" -No documentation found. - -No docstring found for module `$(curmod_prefix)Undocumented`. +No docstring or readme file found for module `$(curmod_prefix)Undocumented`. -# Exported names: +# Exported names `A`, `B`, `C`, `at0`, `pt2` """) @@ -965,10 +956,10 @@ abstract type $(curmod_prefix)Undocumented.at0{T<:Number, N} # Subtypes ``` -$(curmod_prefix)Undocumented.at1{T, N} where {Integer<:T<:Number, N} -$(curmod_prefix)Undocumented.pt2 -$(curmod_prefix)Undocumented.st3 -$(curmod_prefix)Undocumented.st4{T, N} where {T<:Number, N} +$(curmod_prefix)Undocumented.at1{Integer<:T<:Number, N} +$(curmod_prefix)Undocumented.pt2{T<:Number, N, A>:Integer} +$(curmod_prefix)Undocumented.st3{T<:Integer, N} +$(curmod_prefix)Undocumented.st4{T<:Number, N} ``` """) @test docstrings_equal(@doc(Undocumented.at0), doc"$doc_str") @@ -985,7 +976,7 @@ abstract type $(curmod_prefix)Undocumented.at1{T>:Integer, N} # Subtypes ``` -$(curmod_prefix)Undocumented.mt6{Integer, N} where N +$(curmod_prefix)Undocumented.mt6{Integer, N} ``` # Supertype Hierarchy @@ -1007,9 +998,9 @@ abstract type $(curmod_prefix)Undocumented.at0{Int64, N} # Subtypes ``` -$(curmod_prefix)Undocumented.pt2{Int64, N, A} where {N, A>:Integer} -$(curmod_prefix)Undocumented.st3{Int64, N} where N -$(curmod_prefix)Undocumented.st4{Int64, N} where N +$(curmod_prefix)Undocumented.pt2{Int64, N, A>:Integer} +$(curmod_prefix)Undocumented.st3{Int64, N} +$(curmod_prefix)Undocumented.st4{Int64, N} ``` """) @test docstrings_equal(@doc(Undocumented.at_), doc"$doc_str") @@ -1157,9 +1148,9 @@ No documentation found. # Union Composed of Types - - `$(curmod_prefix)Undocumented.at1{T, N} where {T, N}` - - `$(curmod_prefix)Undocumented.pt2{T, N, A} where {T, N, A>:Integer}` - - `$(curmod_prefix)Undocumented.st3{T, N} where {T, N}` + - `$(curmod_prefix)Undocumented.at1{T} where T` + - `$(curmod_prefix)Undocumented.pt2{T} where T` + - `$(curmod_prefix)Undocumented.st3{T} where T` - `$(curmod_prefix)Undocumented.st4` """) @test docstrings_equal(@doc(Undocumented.ut9), doc"$doc_str") diff --git a/test/errorshow.jl b/test/errorshow.jl index 736e68dee1ef0..24d0241049da0 100644 --- a/test/errorshow.jl +++ b/test/errorshow.jl @@ -86,7 +86,7 @@ method_c2(x::Int32, y::Int32, z::Int32) = true method_c2(x::T, y::T, z::T) where {T<:Real} = true Base.show_method_candidates(buf, Base.MethodError(method_c2,(1., 1., 2))) -@test String(take!(buf)) == "\nClosest candidates are:\n method_c2(!Matched::Int32, ::Float64, ::Any...)$cfile$(c2line+2)\n method_c2(!Matched::Int32, ::Any...)$cfile$(c2line+1)\n method_c2(::T, ::T, !Matched::T) where T<:Real$cfile$(c2line+5)\n ..." +@test String(take!(buf)) == "\nClosest candidates are:\n method_c2(!Matched::Int32, ::Float64, ::Any...)$cfile$(c2line+2)\n method_c2(::T, ::T, !Matched::T) where T<:Real$cfile$(c2line+5)\n method_c2(!Matched::Int32, ::Any...)$cfile$(c2line+1)\n ..." c3line = @__LINE__() + 1 method_c3(x::Float64, y::Float64) = true @@ -475,12 +475,6 @@ let @test (@macroexpand @fastmath + ) == :(Base.FastMath.add_fast) @test (@macroexpand @fastmath min(1) ) == :(Base.FastMath.min_fast(1)) let err = try; @macroexpand @doc "" f() = @x; catch ex; ex; end - file, line = @__FILE__, @__LINE__() - 1 - err = err::LoadError - @test err.file == file && err.line == line - err = err.error::LoadError - @test err.file == file && err.line == line - err = err.error::UndefVarError @test err == UndefVarError(Symbol("@x")) end @test (@macroexpand @seven_dollar $bar) == 7 @@ -634,6 +628,16 @@ catch ex end pop!(Base.Experimental._hint_handlers[DomainError]) # order is undefined, don't copy this +struct ANumber <: Number end +let err_str + err_str = @except_str ANumber()(3 + 4) MethodError + @test occursin("objects of type $(curmod_prefix)ANumber are not callable", err_str) + @test count(==("Maybe you forgot to use an operator such as *, ^, %, / etc. ?"), split(err_str, '\n')) == 1 + # issue 40478 + err_str = @except_str ANumber()(3 + 4) MethodError + @test count(==("Maybe you forgot to use an operator such as *, ^, %, / etc. ?"), split(err_str, '\n')) == 1 +end + # Execute backtrace once before checking formatting, see #38858 backtrace() @@ -649,13 +653,8 @@ backtrace() @test occursin("g28442", output[3]) @test lstrip(output[5])[1:3] == "[2]" @test occursin("f28442", output[5]) - # Issue #30233 - # Note that we can't use @test_broken on FreeBSD here, because the tests actually do - # pass with some compilation options, e.g. with assertions enabled - if !Sys.isfreebsd() - @test occursin("the last 2 lines are repeated 5000 more times", output[7]) - @test lstrip(output[8])[1:7] == "[10003]" - end + @test occursin("the last 2 lines are repeated 5000 more times", output[7]) + @test lstrip(output[8])[1:7] == "[10003]" end @testset "Line number correction" begin diff --git a/test/exceptions.jl b/test/exceptions.jl index 7b8a54da2c6eb..d8d1e7b45b8b5 100644 --- a/test/exceptions.jl +++ b/test/exceptions.jl @@ -1,52 +1,51 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Test -using Base: catch_stack @testset "Basic exception stack handling" begin # Exiting the catch block normally pops the exception try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # Exiting via a finally block does not pop the exception try try error("A") finally - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 end catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 end # The combined try-catch-finally form obeys the same rules as above try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 finally - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # Errors are pushed onto the stack according to catch block nesting try error("RootCause") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 try error("B") catch - stack = catch_stack() + stack = current_exceptions() @test length(stack) == 2 - @test stack[1][1].msg == "RootCause" - @test stack[2][1].msg == "B" + @test stack[1].exception.msg == "RootCause" + @test stack[2].exception.msg == "B" end # Stack pops correctly - stack = catch_stack() + stack = current_exceptions() @test length(stack) == 1 - @test stack[1][1].msg == "RootCause" + @test stack[1].exception.msg == "RootCause" end end @@ -55,7 +54,7 @@ end val = try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 1 end @test val == 1 @@ -64,11 +63,11 @@ end try error("A") catch - length(catch_stack()) + length(current_exceptions()) end end @test test_exc_stack_tailpos() == 1 - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end @testset "Exception stacks - early exit from try or catch" begin @@ -78,7 +77,7 @@ end try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 return end end @@ -88,7 +87,7 @@ end try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 break end end @@ -97,19 +96,19 @@ end try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 break finally - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 for i=1:1 try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 continue end end @@ -117,38 +116,38 @@ end try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 continue finally - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 @goto outofcatch end @label outofcatch try error("A") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 @goto outofcatch2 finally - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end @label outofcatch2 - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # Exiting from a try block in various ways should not affect the exception # stack state. try error("ExceptionInOuterTry") catch - @test length(catch_stack()) == 1 + @test length(current_exceptions()) == 1 function test_exc_stack_try_return() try return @@ -173,8 +172,8 @@ end catch end @label outoftry - @test length(catch_stack()) == 1 - @test catch_stack()[1][1] == ErrorException("ExceptionInOuterTry") + @test length(current_exceptions()) == 1 + @test current_exceptions()[1].exception == ErrorException("ExceptionInOuterTry") end end @@ -195,10 +194,10 @@ end # Explicit return => exception should be popped before finally block return finally - @test length(Base.catch_stack()) == 0 + @test length(Base.current_exceptions()) == 0 end end)() - @test length(Base.catch_stack()) == 0 + @test length(Base.current_exceptions()) == 0 while true try @@ -209,11 +208,11 @@ end # exception should not be popped inside finally block break finally - @test length(Base.catch_stack()) == 1 + @test length(Base.current_exceptions()) == 1 end end end - @test length(Base.catch_stack()) == 0 + @test length(Base.current_exceptions()) == 0 # Nested finally handling with `return`: each finally block should observe # only the active exceptions as according to its nesting depth. @@ -232,16 +231,16 @@ end end finally # At this point err2 is dealt with - @test length(Base.catch_stack()) == 1 - @test Base.catch_stack()[1][1] == ErrorException("err1") + @test length(Base.current_exceptions()) == 1 + @test Base.current_exceptions()[1].exception == ErrorException("err1") end end finally # At this point err1 is dealt with - @test length(Base.catch_stack()) == 0 + @test length(Base.current_exceptions()) == 0 end end)() - @test length(Base.catch_stack()) == 0 + @test length(Base.current_exceptions()) == 0 end @testset "Deep exception stacks" begin @@ -260,10 +259,10 @@ end @test try test_exc_stack_deep(100) catch - @test catch_stack()[1][1] == ErrorException("RootCause") - length(catch_stack()) + @test current_exceptions()[1].exception == ErrorException("RootCause") + length(current_exceptions()) end == 100 - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 end @testset "Exception stacks and Tasks" begin @@ -280,10 +279,10 @@ end @test t.state == :done @test t.result == ErrorException("B") # Task exception state is preserved around task switches - @test length(catch_stack()) == 1 - @test catch_stack()[1][1] == ErrorException("A") + @test length(current_exceptions()) == 1 + @test current_exceptions()[1].exception == ErrorException("A") end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # test rethrow() rethrows correct state bt = [] try @@ -306,7 +305,7 @@ end @test exc == ErrorException("A") @test bt == catch_backtrace() end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # test rethrow with argument bt = [] try @@ -328,7 +327,7 @@ end @test exc == ErrorException("C") @test bt == catch_backtrace() end - @test length(catch_stack()) == 0 + @test length(current_exceptions()) == 0 # Exception stacks on other tasks t = @task try error("A") @@ -338,7 +337,10 @@ end yield(t) @test t.state == :failed @test t.result == ErrorException("B") - @test catch_stack(t, include_bt=false) == [ErrorException("A"), ErrorException("B")] + @test current_exceptions(t, backtrace=false) == [ + (exception=ErrorException("A"),backtrace=nothing), + (exception=ErrorException("B"),backtrace=nothing) + ] # Exception stacks for tasks which never get the chance to start t = @task nothing @test (try @@ -347,12 +349,12 @@ end catch e e end).task.exception == ErrorException("expected") - @test length(catch_stack(t)) == 1 - @test length(catch_stack(t)[1][2]) > 0 # backtrace is nonempty + @test length(current_exceptions(t)) == 1 + @test length(current_exceptions(t)[1].backtrace) > 0 # backtrace is nonempty # Exception stacks should not be accessed on concurrently running tasks t = @task ()->nothing @test_throws ErrorException("Inspecting the exception stack of a task which might "* - "be running concurrently isn't allowed.") catch_stack(t) + "be running concurrently isn't allowed.") current_exceptions(t) end @testset "rethrow" begin @@ -396,5 +398,5 @@ end undef_var_in_catch() [] catch - catch_stack() + current_exceptions() end) == 2 diff --git a/test/float16.jl b/test/float16.jl index 5ac9582f900c4..916032131bf5d 100644 --- a/test/float16.jl +++ b/test/float16.jl @@ -21,6 +21,20 @@ g = Float16(1.) @test isequal(Float16(0.0), Float16(0.0)) @test !isequal(Float16(-0.0), Float16(0.0)) @test !isequal(Float16(0.0), Float16(-0.0)) + + for T = Base.BitInteger_types + @test -Inf16 < typemin(T) + @test -Inf16 <= typemin(T) + @test typemin(T) > -Inf16 + @test typemin(T) >= -Inf16 + @test typemin(T) != -Inf16 + + @test Inf16 > typemax(T) + @test Inf16 >= typemax(T) + @test typemax(T) < Inf16 + @test typemax(T) <= Inf16 + @test typemax(T) != Inf16 + end end @testset "convert" begin @@ -157,6 +171,10 @@ end # halfway between and last bit is 0 ff = reinterpret(Float32, 0b00111110101010100001000000000000) @test Float32(Float16(ff)) === reinterpret(Float32, 0b00111110101010100000000000000000) + + for x = (typemin(Int64), typemin(Int128)), R = (RoundUp, RoundToZero) + @test Float16(x, R) == nextfloat(-Inf16) + end end # issue #5948 diff --git a/test/generic_map_tests.jl b/test/generic_map_tests.jl index 8fde731770bf3..8e77533362fe3 100644 --- a/test/generic_map_tests.jl +++ b/test/generic_map_tests.jl @@ -76,6 +76,6 @@ function run_map_equivalence_tests(mapf) testmap_equivalence(mapf, identity, (1,2,3,4)) testmap_equivalence(mapf, (x,y,z)->x+y+z, 1,2,3) testmap_equivalence(mapf, x->x ? false : true, BitMatrix(undef, 10,10)) - testmap_equivalence(mapf, x->"foobar", BitMatrix(undef, 10,10)) + testmap_equivalence(mapf, Returns("foobar"), BitMatrix(undef, 10,10)) testmap_equivalence(mapf, (x,y,z)->string(x,y,z), BitVector(undef, 10), fill(1.0, 10), "1234567890") end diff --git a/test/gmp.jl b/test/gmp.jl index 96ffdedb7a93c..1f34f67ecf1f5 100644 --- a/test/gmp.jl +++ b/test/gmp.jl @@ -69,6 +69,18 @@ ee = typemax(Int64) @test big(typeof(complex(x, x))) == typeof(big(complex(x, x))) end end + @testset "division" begin + oz = big(1 // 0) + zo = big(0 // 1) + + @test_throws DivideError() oz / oz + @test oz == oz / one(oz) + @test -oz == oz / (-one(oz)) + @test zero(oz) == one(oz) / oz + @test_throws DivideError() zo / zo + @test one(zo) / zo == big(1//0) + @test -one(zo) / zo == big(-1//0) + end end @testset "div, fld, mod, rem" begin for i = -10:10, j = [-10:-1; 1:10] @@ -241,6 +253,12 @@ end @test xor(a, b, c, d, f) == parse(BigInt,"-2413804710837418037418307081437316711364709261074607933698") @test xor(a, b, c, d, f, g) == parse(BigInt,"2413804710837418037418307081437316711364709261074607933697") + @test nand(a, b) == parse(BigInt,"-125") + @test ⊼(a, b) == parse(BigInt,"-125") + + @test nor(a, b) == parse(BigInt,"-327424") + @test ⊽(a, b) == parse(BigInt,"-327424") + @test (&)(a, b) == parse(BigInt,"124") @test (&)(a, b, c) == parse(BigInt,"72") @test (&)(a, b, c, d) == parse(BigInt,"8") diff --git a/test/hashing.jl b/test/hashing.jl index c2afd7426ecb3..e5223ed407062 100644 --- a/test/hashing.jl +++ b/test/hashing.jl @@ -260,3 +260,27 @@ end # PR #40083 @test hash(1:1000) == hash(collect(1:1000)) + +@testset "test the other core data hashing functions" begin + @testset "hash_64_32" begin + vals = vcat( + typemin(UInt64) .+ UInt64[1:4;], + typemax(UInt64) .- UInt64[4:-1:0;] + ) + + for a in vals, b in vals + @test isequal(a, b) == (Base.hash_64_32(a) == Base.hash_64_32(b)) + end + end + + @testset "hash_32_32" begin + vals = vcat( + typemin(UInt32) .+ UInt32[1:4;], + typemax(UInt32) .- UInt32[4:-1:0;] + ) + + for a in vals, b in vals + @test isequal(a, b) == (Base.hash_32_32(a) == Base.hash_32_32(b)) + end + end +end \ No newline at end of file diff --git a/test/int.jl b/test/int.jl index f0e157711c808..52f554718645e 100644 --- a/test/int.jl +++ b/test/int.jl @@ -141,6 +141,10 @@ SItypes = Base.BitSigned_types R = sizeof(S) < sizeof(Int) ? Int : S @test promote(R(3), T(3)) === (sizeof(R) < sizeof(T) ? (T(3), T(3)) : (R(3), R(3))) end + + for i in 1:length(UItypes) + @test promote(UItypes[i](3), SItypes[i](3)) === (UItypes[i](3), UItypes[i](3)) + end end @testset "limiting conversions" begin for T in (Int8, Int16, Int32, Int64) diff --git a/test/intfuncs.jl b/test/intfuncs.jl index 24505935a2fed..8a8f046310622 100644 --- a/test/intfuncs.jl +++ b/test/intfuncs.jl @@ -12,6 +12,7 @@ using Random @test gcd(T(0), T(15)) === T(15) @test gcd(T(15), T(0)) === T(15) if T <: Signed + @test gcd(T(-12)) === T(12) @test gcd(T(0), T(-15)) === T(15) @test gcd(T(-15), T(0)) === T(15) @test gcd(T(3), T(-15)) === T(3) @@ -78,6 +79,7 @@ using Random @test lcm(T(0), T(3)) === T(0) @test lcm(T(0), T(0)) === T(0) if T <: Signed + @test lcm(T(-12)) === T(12) @test lcm(T(0), T(-4)) === T(0) @test lcm(T(-4), T(0)) === T(0) @test lcm(T(4), T(-6)) === T(12) @@ -154,6 +156,7 @@ end @test gcd(T[3, 15]) === T(3) @test gcd(T[0, 15]) === T(15) if T <: Signed + @test gcd(T[-12]) === T(12) @test gcd(T[3,-15]) === T(3) @test gcd(T[-3,-15]) === T(3) end @@ -163,12 +166,12 @@ end @test gcd(T[2, 4, 3, 5]) === T(1) @test lcm(T[]) === T(1) - @test lcm(T[2]) === T(2) @test lcm(T[2, 3]) === T(6) @test lcm(T[4, 6]) === T(12) @test lcm(T[3, 0]) === T(0) @test lcm(T[0, 0]) === T(0) if T <: Signed + @test lcm(T[-2]) === T(2) @test lcm(T[4, -6]) === T(12) @test lcm(T[-4, -6]) === T(12) end diff --git a/test/iterators.jl b/test/iterators.jl index b45a51fd87042..de3dbda921cbd 100644 --- a/test/iterators.jl +++ b/test/iterators.jl @@ -2,6 +2,7 @@ using Base.Iterators using Random +using Base: IdentityUnitRange @test Base.IteratorSize(Any) isa Base.SizeUnknown @@ -198,7 +199,7 @@ end @test collect(takewhile(<(4),1:10)) == [1,2,3] @test collect(takewhile(<(4),Iterators.countfrom(1))) == [1,2,3] @test collect(takewhile(<(4),5:10)) == [] - @test collect(takewhile(_->true,5:10)) == 5:10 + @test collect(takewhile(Returns(true),5:10)) == 5:10 @test collect(takewhile(isodd,[1,1,2,3])) == [1,1] @test collect(takewhile(<(2), takewhile(<(3), [1,1,2,3]))) == [1,1] end @@ -209,8 +210,8 @@ end @test collect(dropwhile(<(4), 1:10)) == 4:10 @test collect(dropwhile(<(4), 1:10)) isa Vector{Int} @test isempty(dropwhile(<(4), [])) - @test collect(dropwhile(_->false,1:3)) == 1:3 - @test isempty(dropwhile(_->true, 1:3)) + @test collect(dropwhile(Returns(false),1:3)) == 1:3 + @test isempty(dropwhile(Returns(true), 1:3)) @test collect(dropwhile(isodd,[1,1,2,3])) == [2,3] @test collect(dropwhile(iseven,dropwhile(isodd,[1,1,2,3]))) == [3] end @@ -381,7 +382,7 @@ let a = 1:2, end # size infinite or unknown raises an error - for itr in Any[countfrom(1), Iterators.filter(i->0, 1:10)] + for itr in Any[countfrom(1), Iterators.filter(Returns(0), 1:10)] @test_throws ArgumentError length(product(itr)) @test_throws ArgumentError size(product(itr)) @test_throws ArgumentError ndims(product(itr)) @@ -592,7 +593,7 @@ end end @testset "filter empty iterable #16704" begin - arr = filter(n -> true, 1:0) + arr = filter(Returns(true), 1:0) @test length(arr) == 0 @test eltype(arr) == Int end @@ -848,3 +849,7 @@ end @test cumprod(x + 1 for x in 1:3) == [2, 6, 24] @test accumulate(+, (x^2 for x in 1:3); init=100) == [101, 105, 114] end + +@testset "proper patition for non-1-indexed vector" begin + @test partition(IdentityUnitRange(11:19), 5) |> collect == [11:15,16:19] # IdentityUnitRange +end diff --git a/test/keywordargs.jl b/test/keywordargs.jl index f9be8edd80dc0..348eaea2ee4c3 100644 --- a/test/keywordargs.jl +++ b/test/keywordargs.jl @@ -374,3 +374,9 @@ using InteractiveUtils no_kw_args(x::Int) = 0 @test_throws MethodError no_kw_args(1, k=1) @test_throws MethodError no_kw_args("", k=1) + +# issue #40964 +f40964(xs::Int...=1; k = 2) = (xs, k) +@test f40964() === ((1,), 2) +@test f40964(7, 8) === ((7,8), 2) +@test f40964(7, 8, k=0) === ((7,8), 0) diff --git a/test/llvmpasses/noinline.jl b/test/llvmpasses/noinline.jl index f542968b21979..c4aa22bf80a71 100644 --- a/test/llvmpasses/noinline.jl +++ b/test/llvmpasses/noinline.jl @@ -17,5 +17,5 @@ include(joinpath("..", "testhelpers", "llvmpasses.jl")) return A + B end -# CHECK: attributes #{{[0-9]+}} = {{{([a-z]+ )*}} noinline {{([a-z]+ )*}}} +# CHECK: attributes #{{[0-9]+}} = {{{[^}]*}} noinline {{[^}]*}}} emit(simple_noinline, Float64, Float64) diff --git a/test/loading.jl b/test/loading.jl index 377087a63f558..d94abd889dcfc 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -314,6 +314,11 @@ module NotPkgModule; end @test pkgdir(Foo.SubFoo1) == normpath(abspath(@__DIR__, "project/deps/Foo1")) @test pkgdir(Foo.SubFoo2) == normpath(abspath(@__DIR__, "project/deps/Foo1")) @test pkgdir(NotPkgModule) === nothing + + @test pkgdir(Foo, "src") == normpath(abspath(@__DIR__, "project/deps/Foo1/src")) + @test pkgdir(Foo.SubFoo1, "src") == normpath(abspath(@__DIR__, "project/deps/Foo1/src")) + @test pkgdir(Foo.SubFoo2, "src") == normpath(abspath(@__DIR__, "project/deps/Foo1/src")) + @test pkgdir(NotPkgModule, "src") === nothing end end @@ -718,3 +723,10 @@ import .Foo.Libdl; import Libdl end end end + +@testset "`Base.project_names` and friends" begin + # Some functions in Pkg assumes that these tuples have the same length + n = length(Base.project_names) + @test length(Base.manifest_names) == n + @test length(Base.preferences_names) == n +end diff --git a/test/math.jl b/test/math.jl index 074358da9c791..67522b9be4c7b 100644 --- a/test/math.jl +++ b/test/math.jl @@ -196,11 +196,13 @@ end @test isequal(cos(T(0)), T(1)) @test cos(T(pi)/2) ≈ T(0) atol=eps(T) @test isequal(cos(T(pi)), T(-1)) - @test exp(T(1)) ≈ T(ℯ) atol=10*eps(T) + @test exp(T(1)) ≈ T(ℯ) atol=2*eps(T) @test isequal(exp10(T(1)), T(10)) @test isequal(exp2(T(1)), T(2)) @test isequal(expm1(T(0)), T(0)) - @test expm1(T(1)) ≈ T(ℯ)-1 atol=10*eps(T) + @test isequal(expm1(-floatmax(T)), -one(T)) + @test isequal(expm1(floatmax(T)), T(Inf)) + @test expm1(T(1)) ≈ T(ℯ)-1 atol=2*eps(T) @test isequal(hypot(T(3),T(4)), T(5)) @test isequal(hypot(floatmax(T),T(1)),floatmax(T)) @test isequal(hypot(floatmin(T)*sqrt(eps(T)),T(0)),floatmin(T)*sqrt(eps(T))) @@ -286,6 +288,13 @@ end @test tanh(T(Inf)) === T(1) end end + @testset "Float16 expm1" begin + T=Float16 + @test isequal(expm1(T(0)), T(0)) + @test isequal(expm1(-floatmax(T)), -one(T)) + @test isequal(expm1(floatmax(T)), T(Inf)) + @test expm1(T(1)) ≈ T(ℯ)-1 atol=2*eps(T) + end end @testset "exp function" for T in (Float64, Float32) @@ -341,6 +350,35 @@ end @test Array(acosh.(STAA)) == acosh.(TAA) @test Array(acsch.(STAA)) == acsch.(TAA) @test Array(acoth.(STAA)) == acoth.(TAA) + @test sind(TAA) == sin(deg2rad.(TAA)) + @test cosd(TAA) == cos(deg2rad.(TAA)) + @test tand(TAA) == tan(deg2rad.(TAA)) + @test asind(TAA) == rad2deg.(asin(TAA)) + @test acosd(TAA) == rad2deg.(acos(TAA)) + @test atand(TAA) == rad2deg.(atan(TAA)) + @test asecd(TAA) == rad2deg.(asec(TAA)) + @test acscd(TAA) == rad2deg.(acsc(TAA)) + @test acotd(TAA) == rad2deg.(acot(TAA)) + + m = rand(3,2) # not square matrix + ex = @test_throws DimensionMismatch sind(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch cosd(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch tand(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch asind(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch acosd(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch atand(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch asecd(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch acscd(m) + @test startswith(ex.value.msg, "matrix is not square") + ex = @test_throws DimensionMismatch acotd(m) + @test startswith(ex.value.msg, "matrix is not square") end @testset "check exp2(::Integer) matches exp2(::Float)" begin diff --git a/test/misc.jl b/test/misc.jl index da9591ed2770d..2305b78250ef2 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -621,6 +621,26 @@ let buf = IOBuffer() # Check that boldness is turned off printstyled(buf_color, "foo"; bold=true, color=:red) @test String(take!(buf)) == "\e[31m\e[1mfoo\e[22m\e[39m" + + # Check that underline is turned off + printstyled(buf_color, "foo"; color = :red, underline = true) + @test String(take!(buf)) == "\e[31m\e[4mfoo\e[24m\e[39m" + + # Check that blink is turned off + printstyled(buf_color, "foo"; color = :red, blink = true) + @test String(take!(buf)) == "\e[31m\e[5mfoo\e[25m\e[39m" + + # Check that reverse is turned off + printstyled(buf_color, "foo"; color = :red, reverse = true) + @test String(take!(buf)) == "\e[31m\e[7mfoo\e[27m\e[39m" + + # Check that hidden is turned off + printstyled(buf_color, "foo"; color = :red, hidden = true) + @test String(take!(buf)) == "\e[31m\e[8mfoo\e[28m\e[39m" + + # Check that all options can be turned on simultaneously + printstyled(buf_color, "foo"; color = :red, bold = true, underline = true, blink = true, reverse = true, hidden = true) + @test String(take!(buf)) == "\e[31m\e[1m\e[4m\e[5m\e[7m\e[8mfoo\e[28m\e[27m\e[25m\e[24m\e[22m\e[39m" end abstract type DA_19281{T, N} <: AbstractArray{T, N} end diff --git a/test/missing.jl b/test/missing.jl index 4c704c4ce64f8..e1042f76fc7a7 100644 --- a/test/missing.jl +++ b/test/missing.jl @@ -1,5 +1,8 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl") +using .Main.OffsetArrays + @testset "MissingException" begin @test sprint(showerror, MissingException("test")) == "MissingException: test" end @@ -83,7 +86,7 @@ end arithmetic_operators = [+, -, *, /, ^, Base.div, Base.mod, Base.fld, Base.rem] # All unary operators return missing when evaluating missing - for f in [!, ~, +, -, *, &, |, xor] + for f in [!, ~, +, -, *, &, |, xor, nand, nor] @test ismissing(f(missing)) end @@ -128,6 +131,22 @@ end @test ismissing(xor(true, missing)) @test ismissing(xor(missing, false)) @test ismissing(xor(false, missing)) + @test ismissing(nand(missing, true)) + @test ismissing(nand(true, missing)) + @test nand(missing, false) == true + @test nand(false, missing) == true + @test ismissing(⊼(missing, true)) + @test ismissing(⊼(true, missing)) + @test ⊼(missing, false) == true + @test ⊼(false, missing) == true + @test nor(missing, true) == false + @test nor(true, missing) == false + @test ismissing(nor(missing, false)) + @test ismissing(nor(false, missing)) + @test ⊽(missing, true) == false + @test ⊽(true, missing) == false + @test ismissing(⊽(missing, false)) + @test ismissing(⊽(false, missing)) @test ismissing(missing & 1) @test ismissing(1 & missing) @@ -135,11 +154,21 @@ end @test ismissing(1 | missing) @test ismissing(xor(missing, 1)) @test ismissing(xor(1, missing)) + @test ismissing(nand(missing, 1)) + @test ismissing(nand(1, missing)) + @test ismissing(⊼(missing, 1)) + @test ismissing(⊼(1, missing)) + @test ismissing(nor(missing, 1)) + @test ismissing(nor(1, missing)) + @test ismissing(⊽(missing, 1)) + @test ismissing(⊽(1, missing)) end -@testset "* string concatenation" begin +@testset "* string/char concatenation" begin @test ismissing("a" * missing) + @test ismissing('a' * missing) @test ismissing(missing * "a") + @test ismissing(missing * 'a') end # Emulate a unitful type such as Dates.Minute @@ -504,6 +533,19 @@ end nt = NamedTuple{(:x, :y),Tuple{Union{Missing, Int},Union{Missing, Float64}}}( (missing, missing)) @test sum(skipmissing(nt)) === 0 + + # issues #38627 and #124 + @testset for len in [1, 2, 15, 16, 1024, 1025] + v = repeat(Union{Int,Missing}[1], len) + oa = OffsetArray(v, typemax(Int)-length(v)) + sm = skipmissing(oa) + @test sum(sm) == len + + v = repeat(Union{Int,Missing}[missing], len) + oa = OffsetArray(v, typemax(Int)-length(v)) + sm = skipmissing(oa) + @test sum(sm) == 0 + end end @testset "filter" begin @@ -533,6 +575,16 @@ end @test coalesce(missing, nothing) === nothing end +@testset "@coalesce" begin + @test @coalesce() === missing + @test @coalesce(1) === 1 + @test @coalesce(nothing) === nothing + @test @coalesce(missing) === missing + + @test @coalesce(1, error("failed")) === 1 + @test_throws ErrorException @coalesce(missing, error("failed")) +end + mutable struct Obj; x; end @testset "weak references" begin @noinline function mk_wr(r, wr) @@ -577,4 +629,4 @@ end @test isequal(sort(X, alg=MergeSort, rev=true), XRP) end -sortperm(reverse([NaN, missing, NaN, missing])) \ No newline at end of file +sortperm(reverse([NaN, missing, NaN, missing])) diff --git a/test/mpfr.jl b/test/mpfr.jl index 86c7d345f49fd..a4fac9c93c79a 100644 --- a/test/mpfr.jl +++ b/test/mpfr.jl @@ -338,23 +338,6 @@ end @test *(a, b, c, d, f) == parse(BigFloat,"5.214588134765625e+04") @test *(a, b, c, d, f, g) == parse(BigFloat,"1.6295587921142578125e+03") end -@testset "< / > / <= / >=" begin - x = BigFloat(12) - y = BigFloat(42) - z = BigFloat(30) - @test y > x - @test y >= x - @test y > z - @test y >= z - @test x < y - @test x <= y - @test z < y - @test z <= y - @test y - x >= z - @test y - x <= z - @test !(x >= z) - @test !(y <= z) -end @testset "rounding modes" begin setprecision(4) do # default mode is round to nearest @@ -371,7 +354,6 @@ end end end end - @testset "copysign / sign" begin x = BigFloat(1) y = BigFloat(-1) @@ -473,10 +455,11 @@ end @test isnan(nextfloat(BigFloat(NaN), 1)) @test isnan(prevfloat(BigFloat(NaN), 1)) end + # sqrt DomainError @test_throws DomainError sqrt(BigFloat(-1)) -@testset "precision" begin +@testset "setprecision" begin old_precision = precision(BigFloat) x = BigFloat(0) @test precision(x) == old_precision @@ -512,7 +495,6 @@ end @test !isinteger(-BigFloat(Inf)) @test !isinteger(BigFloat(NaN)) end - @testset "comparisons" begin x = BigFloat(1) y = BigFloat(-1) @@ -521,9 +503,11 @@ end imi = BigFloat(-Inf) @test x > y @test x >= y + @test !(y >= x) @test x >= x @test y < x @test y <= x + @test !(x <= y) @test y <= y @test x < ipl @test x <= ipl @@ -675,14 +659,17 @@ end end setprecision(21) do @test string(parse(BigFloat, "0.1")) == "0.10000002" + @test string(parse(BigFloat, "0.5")) == "0.5" @test string(parse(BigFloat, "-9.9")) == "-9.9000015" end setprecision(40) do @test string(parse(BigFloat, "0.1")) == "0.10000000000002" + @test string(parse(BigFloat, "0.5")) == "0.5" @test string(parse(BigFloat, "-9.9")) == "-9.8999999999942" end setprecision(123) do @test string(parse(BigFloat, "0.1")) == "0.0999999999999999999999999999999999999953" + @test string(parse(BigFloat, "0.5")) == "0.5" @test string(parse(BigFloat, "-9.9")) == "-9.8999999999999999999999999999999999997" end end @@ -927,6 +914,7 @@ end @test i3+1 > f @test i3+1 >= f end + # issue #8318 @test convert(Int64,big(500_000_000_000_000.)) == 500_000_000_000_000 @@ -935,6 +923,7 @@ end @test MPFR.get_emin() == MPFR.get_emin_min() @test MPFR.get_emax() == MPFR.get_emax_max() end + # issue #10994: handle embedded NUL chars for string parsing @test_throws ArgumentError parse(BigFloat, "1\0") @@ -1025,7 +1014,6 @@ end @test to_string(big"-1.0") == "-1.0" end end - @testset "big(::Type)" begin for x in (2f0, pi, 7.8, big(ℯ)) @test big(typeof(x)) == typeof(big(x)) diff --git a/test/namedtuple.jl b/test/namedtuple.jl index 128cff5f53731..82bbc26349a7a 100644 --- a/test/namedtuple.jl +++ b/test/namedtuple.jl @@ -90,11 +90,20 @@ end @test Tuple((a=1, b=2, c=3)) == (1, 2, 3) @test isless((a=1,b=2), (a=1,b=3)) -@test_broken isless((a=1,), (a=1,b=2)) +@test_throws MethodError isless((a=1,), (a=1,b=2)) @test !isless((a=1,b=2), (a=1,b=2)) @test !isless((a=2,b=1), (a=1,b=2)) @test_throws MethodError isless((a=1,), (x=2,)) +@test (a=1,b=2) < (a=1,b=3) +@test_throws MethodError (a=1,) < (a=1,b=2) +@test !((a=1,b=2) < (a=1,b=2)) +@test !((a=2,b=1) < (a=1,b=2)) +@test_throws MethodError (a=1,) < (x=2,) +@test !((a=-0.0,) < (a=0.0,)) +@test ismissing((a=missing,) < (a=1,)) +@test ismissing((a=missing,) < (a=missing,)) + @test map(-, (x=1, y=2)) == (x=-1, y=-2) @test map(+, (x=1, y=2), (x=10, y=20)) == (x=11, y=22) @test_throws ArgumentError map(+, (x=1, y=2), (y=10, x=20)) diff --git a/test/numbers.jl b/test/numbers.jl index a76f5726492df..e62e1a798221d 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -38,6 +38,24 @@ const ≣ = isequal # convenient for comparing NaNs @test xor(true, false) == true @test xor(false, true) == true @test xor(true, true) == false + + @test false ⊼ false == true + @test true ⊼ false == true + @test false ⊼ true == true + @test true ⊼ true == false + @test nand(false, false) == true + @test nand(true, false) == true + @test nand(false, true) == true + @test nand(true, true) == false + + @test false ⊽ false == true + @test true ⊽ false == false + @test false ⊽ true == false + @test true ⊽ true == false + @test nor(false, false) == true + @test nor(true, false) == false + @test nor(false, true) == false + @test nor(true, true) == false end @testset "bool operator" begin @test Bool(false) == false diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 5deb442f36222..811d3dd26f509 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -2,6 +2,7 @@ isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl") using .Main.OffsetArrays +import .Main.OffsetArrays: IdOffsetRange using DelimitedFiles using Random using LinearAlgebra @@ -231,11 +232,11 @@ targets1 = ["0-dimensional OffsetArray(::Array{Float64, 0}) with eltype Float64: "1×1×1×1 OffsetArray(::Array{Float64, 4}, 2:2, 3:3, 4:4, 5:5) with eltype Float64 with indices 2:2×3:3×4:4×5:5:\n[:, :, 4, 5] =\n 1.0"] targets2 = ["(fill(1.0), fill(1.0))", "([1.0], [1.0])", - "([1.0], [1.0])", - "([1.0], [1.0])", - "([1.0], [1.0])"] + "([1.0;;], [1.0;;])", + "([1.0;;;], [1.0;;;])", + "([1.0;;;;], [1.0;;;;])"] @testset "printing of OffsetArray with n=$n" for n = 0:4 - a = OffsetArray(fill(1.,ntuple(d->1,n)), ntuple(identity,n)) + a = OffsetArray(fill(1.,ntuple(Returns(1),n)), ntuple(identity,n)) show(IOContext(io, :limit => true), MIME("text/plain"), a) @test String(take!(io)) == targets1[n+1] show(IOContext(io, :limit => true), MIME("text/plain"), (a,a)) @@ -776,3 +777,21 @@ end strY = String(take!(io)) @test strX == strY end + +@testset "vector indexing (issue #39896)" begin + a = collect(1:10) + r = Base.IdentityUnitRange(2:3) + b = a[r] + @test axes(b) == axes(r) + for i in r + @test b[i] == a[r[i]] + end +end + +@testset "proper patition for non-1-indexed vector" begin + @test Iterators.partition(OffsetArray(1:10,10), 5) |> collect == [1:5,6:10] # OffsetVector + @test Iterators.partition(OffsetArray(collect(1:10),10), 5) |> collect == [1:5,6:10] # OffsetVector + @test Iterators.partition(OffsetArray(reshape(1:9,3,3), (3,3)), 5) |> collect == [1:5,6:9] #OffsetMatrix + @test Iterators.partition(OffsetArray(reshape(collect(1:9),3,3), (3,3)), 5) |> collect == [1:5,6:9] #OffsetMatrix + @test Iterators.partition(IdOffsetRange(2:7,10), 5) |> collect == [12:16,17:17] # IdOffsetRange +end diff --git a/test/operators.jl b/test/operators.jl index 070a924b41cdc..d07f3382f53a5 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -281,3 +281,17 @@ end end @test [Base.afoldl(+, 1:i...) for i = 1:40] == [i * (i + 1) ÷ 2 for i = 1:40] + +@testset "Returns" begin + @test @inferred(Returns(1)() ) === 1 + @test @inferred(Returns(1)(23) ) === 1 + @test @inferred(Returns("a")(2,3)) == "a" + @test @inferred(Returns(1)(x=1, y=2)) === 1 + @test @inferred(Returns(Int)()) === Int + @test @inferred(Returns(Returns(1))()) === Returns(1) + f = @inferred Returns(Int) + @inferred f(1,2) + val = [1,2,3] + @test Returns(val)(1) === val + @test sprint(show, Returns(1.0)) == "Returns{Float64}(1.0)" +end diff --git a/test/osutils.jl b/test/osutils.jl index c9e3b9d91a377..5f597292c5cc9 100644 --- a/test/osutils.jl +++ b/test/osutils.jl @@ -44,6 +44,7 @@ end @test (@static if false 1 elseif false 2 else 3 end) === 3 @test (@static if false 1 elseif false 2 elseif true && false 3 else 4 end) === 4 @test (@static if false 1 elseif false 2 elseif true && false 3 end) === nothing + @test_throws ArgumentError("invalid @static macro") @macroexpand @static 1 end if Sys.iswindows() diff --git a/test/path.jl b/test/path.jl index bbd9159c59295..31de4baffd1a0 100644 --- a/test/path.jl +++ b/test/path.jl @@ -9,6 +9,23 @@ @test isabspath(S(homedir())) @test !isabspath(S("foo")) end + if Sys.iswindows() + @testset "issue #38491" begin + pwd_drive = uppercase(splitdrive(pwd())[1]) + drive = (pwd_drive == "X:") ? "Y:" : "X:" + @test abspath("$(lowercase(drive))a\\b\\c") == "$(lowercase(drive))\\a\\b\\c" + @test abspath("$(uppercase(drive))a\\b\\c") == "$(uppercase(drive))\\a\\b\\c" + @test abspath("$(lowercase(drive))a") == "$(lowercase(drive))\\a" + @test abspath("$(uppercase(drive))a") == "$(uppercase(drive))\\a" + @test abspath(lowercase(drive)) == "$(lowercase(drive))\\" + @test abspath(uppercase(drive)) == "$(uppercase(drive))\\" + + @test lowercase(abspath("$(pwd_drive)a\\b\\c")) == lowercase(joinpath(pwd(), "a\\b\\c")) + @test lowercase(abspath("$(pwd_drive)a")) == lowercase(joinpath(pwd(), "a")) + @test lowercase(abspath(lowercase(pwd_drive))) == lowercase("$(pwd())\\") + @test lowercase(abspath(uppercase(pwd_drive))) == lowercase("$(pwd())\\") + end + end @test basename(S("foo$(sep)bar")) == "bar" @test dirname(S("foo$(sep)bar")) == "foo" @@ -42,6 +59,11 @@ @test joinpath(S("foo"), S(homedir())) == homedir() @test joinpath(S(abspath("foo")), S(homedir())) == homedir() + for str in map(S, [sep, "a$(sep)b", "a$(sep)b$(sep)c", "a$(sep)b$(sep)c$(sep)d"]) + @test str == joinpath(splitpath(str)) + @test joinpath(splitpath(str)) == joinpath(splitpath(str)...) + end + if Sys.iswindows() @test joinpath(S("foo"),S("bar:baz")) == "bar:baz" @test joinpath(S("C:"),S("foo"),S("D:"),S("bar")) == "D:bar" @@ -58,6 +80,11 @@ @test joinpath(S("\\\\server\\share"),S("a")) == "\\\\server\\share\\a" @test joinpath(S("\\\\server\\share\\"), S("a")) == "\\\\server\\share\\a" + for str in map(S, ["c:\\", "c:\\a", "c:\\a\\b", "c:\\a\\b\\c", "c:\\a\\b\\c\\d"]) + @test str == joinpath(splitpath(str)) + @test joinpath(splitpath(str)) == joinpath(splitpath(str)...) + end + elseif Sys.isunix() @test joinpath(S("foo"),S("bar:baz")) == "foo$(sep)bar:baz" @test joinpath(S("C:"),S("foo"),S("D:"),S("bar")) == "C:$(sep)foo$(sep)D:$(sep)bar" @@ -273,6 +300,10 @@ # Additional cases @test_throws ArgumentError relpath(S("$(sep)home$(sep)user$(sep)dir_withendsep$(sep)"), "") @test_throws ArgumentError relpath(S(""), S("$(sep)home$(sep)user$(sep)dir_withendsep$(sep)")) + + # issue 40237 + path = "..$(sep)a$(sep)b$(sep)c" + @test relpath(abspath(path)) == path end test_relpath() end diff --git a/test/ranges.jl b/test/ranges.jl index fd12a0829ce5e..eb4fadfac6253 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -618,14 +618,10 @@ end @test broadcast(+, T(1):2:6, 0.3) === T(1)+0.3:2:5+0.3 @test broadcast(-, T(1):2:6, 1) === T(0):2:4 @test broadcast(-, T(1):2:6, 0.3) === T(1)-0.3:2:5-0.3 - if T <: Unsigned - @test_broken broadcast(-, T(1):3) == -T(1):-1:-T(3) - @test_broken broadcast(-, 2, T(1):3) == T(1):-1:-T(1) - else - @test length(broadcast(-, T(1):3, 2)) === length(T(1)-2:T(3)-2) - @test broadcast(-, T(1):3) == -T(1):-1:-T(3) - @test broadcast(-, 2, T(1):3) == T(1):-1:-T(1) - end + is_unsigned = T <: Unsigned + is_unsigned && @test length(broadcast(-, T(1):3, 2)) === length(T(1)-2:T(3)-2) + @test broadcast(-, T(1):3) == -T(1):-1:-T(3) broken=is_unsigned + @test broadcast(-, 2, T(1):3) == T(1):-1:-T(1) broken=is_unsigned end @testset "operations between ranges and arrays" for T in (Int, UInt, Int128) @test all(([T(1):5;] + (T(5):-1:1)) .=== T(6)) @@ -1086,7 +1082,7 @@ end @test sprint(show, StepRange(1, 2, 5)) == "1:2:5" end -@testset "Issue 11049 and related" begin +@testset "Issue 11049, and related" begin @test promote(range(0f0, stop=1f0, length=3), range(0., stop=5., length=2)) === (range(0., stop=1., length=3), range(0., stop=5., length=2)) @test convert(LinRange{Float64}, range(0., stop=1., length=3)) === LinRange(0., 1., 3) @@ -1148,6 +1144,7 @@ end @test [reverse(range(1.0, stop=27.0, length=1275));] == reverse([range(1.0, stop=27.0, length=1275);]) end + @testset "PR 12200 and related" begin for _r in (1:2:100, 1:100, 1f0:2f0:100f0, 1.0:2.0:100.0, range(1, stop=100, length=10), range(1f0, stop=100f0, length=10)) @@ -1292,8 +1289,8 @@ end @test_throws BoundsError r[4] @test_throws BoundsError r[0] @test broadcast(+, r, 1) === 2:4 - @test 2*r === 2:2:6 - @test r + r === 2:2:6 + @test 2*r == 2:2:6 + @test r + r == 2:2:6 k = 0 for i in r @test i == (k += 1) @@ -1436,14 +1433,14 @@ end @test @inferred(r .+ x) === 3:7 @test @inferred(r .- x) === -1:3 @test @inferred(x .- r) === 1:-1:-3 - @test @inferred(x .* r) === 2:2:10 - @test @inferred(r .* x) === 2:2:10 + @test @inferred(x .* r) == 2:2:10 + @test @inferred(r .* x) == 2:2:10 @test @inferred(r ./ x) === 0.5:0.5:2.5 @test @inferred(x ./ r) == 2 ./ [r;] && isa(x ./ r, Vector{Float64}) @test @inferred(r .\ x) == 2 ./ [r;] && isa(x ./ r, Vector{Float64}) @test @inferred(x .\ r) === 0.5:0.5:2.5 - @test @inferred(2 .* (r .+ 1) .+ 2) === 6:2:14 + @test @inferred(2 .* (r .+ 1) .+ 2) == 6:2:14 end @testset "Bad range calls" begin @@ -1568,23 +1565,35 @@ end # module NonStandardIntegerRangeTest end @testset "constant-valued ranges (issues #10391 and #29052)" begin - for r in ((1:4), (1:1:4), (1.0:4.0)) - if eltype(r) === Int - @test_broken @inferred(0 * r) == [0.0, 0.0, 0.0, 0.0] - @test_broken @inferred(0 .* r) == [0.0, 0.0, 0.0, 0.0] - @test_broken @inferred(r + (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] - @test_broken @inferred(r .+ (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] - else - @test @inferred(0 * r) == [0.0, 0.0, 0.0, 0.0] - @test @inferred(0 .* r) == [0.0, 0.0, 0.0, 0.0] - @test @inferred(r + (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] - @test @inferred(r .+ (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] - end + @testset "with $(nameof(typeof(r))) of $(eltype(r))" for r in ((1:4), (1:1:4), StepRangeLen(1,1,4), (1.0:4.0)) + @test @inferred(0 * r) == [0.0, 0.0, 0.0, 0.0] + @test @inferred(0 .* r) == [0.0, 0.0, 0.0, 0.0] + @test @inferred(r .* 0) == [0.0, 0.0, 0.0, 0.0] + @test @inferred(r + (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] + @test @inferred(r .+ (4:-1:1)) == [5.0, 5.0, 5.0, 5.0] + @test @inferred(r - r) == [0.0, 0.0, 0.0, 0.0] + @test @inferred(r .- r) == [0.0, 0.0, 0.0, 0.0] + @test @inferred(r .+ (4.0:-1:1)) == [5.0, 5.0, 5.0, 5.0] @test @inferred(0.0 * r) == [0.0, 0.0, 0.0, 0.0] @test @inferred(0.0 .* r) == [0.0, 0.0, 0.0, 0.0] @test @inferred(r / Inf) == [0.0, 0.0, 0.0, 0.0] @test @inferred(r ./ Inf) == [0.0, 0.0, 0.0, 0.0] + + @test eval(Meta.parse(repr(0 * r))) == [0.0, 0.0, 0.0, 0.0] + + # Not constant-valued, but related methods: + @test @inferred(-1 * r) == [-1,-2,-3,-4] + @test @inferred(r * -1) == [-1,-2,-3,-4] + @test @inferred(r / -1) == [-1,-2,-3,-4] + + @test @inferred(-1.0 .* r) == [-1,-2,-3,-4] + @test @inferred(r .* -1.0) == [-1,-2,-3,-4] + @test @inferred(r ./ -1.0) == [-1,-2,-3,-4] + + @test @inferred(-1 * reverse(r)) == [-4,-3,-2,-1] + @test @inferred(-1.0 .* reverse(r)) == [-4,-3,-2,-1] + @test @inferred(reverse(r) ./ -1.0) == [-4,-3,-2,-1] end @test_broken @inferred(range(0, step=0, length=4)) == [0, 0, 0, 0] @@ -1597,7 +1606,7 @@ end @test @inferred(range(0.0, stop=0, length=4)) == [0.0, 0.0, 0.0, 0.0] z4 = 0.0 * (1:4) - @test @inferred(z4 .+ (1:4)) === 1.0:1.0:4.0 + @test @inferred(z4 .+ (1:4)) == 1.0:1.0:4.0 @test @inferred(z4 .+ z4) === z4 end @@ -1899,3 +1908,28 @@ end @test_throws BoundsError r[true:true:false] @test_throws BoundsError r[true:true:true] end +@testset "Non-Int64 endpoints that are identical (#39798)" begin + for T in DataType[Float16,Float32,Float64,Bool,Int8,Int16,Int32,Int64,Int128,UInt8,UInt16,UInt32,UInt64,UInt128], + r in [ LinRange(1, 1, 10), StepRangeLen(7, 0, 5) ] + if first(r) > typemax(T) + continue + end + let start=T(first(r)), stop=T(last(r)), step=T(step(r)), length=length(r) + @test range( start, stop, length) == r + @test range( start, stop; length) == r + @test range( start; stop, length) == r + @test range(; start, stop, length) == r + end + end +end +@testset "PR 40320 fixes" begin + # found by nanosoldier + @test 0.2 * (-2:2) == -0.4:0.2:0.4 # from tests of AbstractFFTs, needs Base.TwicePrecision + @test 0.2f0 * (-2:2) == Float32.(-0.4:0.2:0.4) # likewise needs Float64 + @test 0.2 * (-2:1:2) == -0.4:0.2:0.4 + + # https://github.com/JuliaLang/julia/issues/40846 + @test 0.1 .* (3:-1:1) ≈ [0.3, 0.2, 0.1] + @test (10:-1:1) * 0.1 == 1:-0.1:0.1 + @test 0.2 * (-2:2:2) == [-0.4, 0, 0.4] +end diff --git a/test/rational.jl b/test/rational.jl index 07e312543318f..aa7d48fb52513 100644 --- a/test/rational.jl +++ b/test/rational.jl @@ -488,6 +488,8 @@ end @test gcd(b, a) === T(2)//T(105) @test lcm(a, b) === T(30)//T(7) if T <: Signed + @test gcd(-a) === a + @test lcm(-b) === b @test gcdx(a, b) === (T(2)//T(105), T(-11), T(4)) @test gcd(-a, b) === T(2)//T(105) @test gcd(a, -b) === T(2)//T(105) diff --git a/test/reduce.jl b/test/reduce.jl index f87b2285480f4..5d49c47204484 100644 --- a/test/reduce.jl +++ b/test/reduce.jl @@ -460,8 +460,8 @@ end @test reduce((a, b) -> a .& b, fill(trues(5), 24)) == trues(5) @test reduce((a, b) -> a .& b, fill(falses(5), 24)) == falses(5) -@test_throws TypeError any(x->0, [false]) -@test_throws TypeError all(x->0, [false]) +@test_throws TypeError any(Returns(0), [false]) +@test_throws TypeError all(Returns(0), [false]) # short-circuiting any and all @@ -646,3 +646,13 @@ end # issue #39281 @test @inferred(extrema(rand(2), dims=1)) isa Vector{Tuple{Float64,Float64}} + +# issue #38627 +@testset "overflow in mapreduce" begin + # at len = 16 and len = 1025 there is a change in codepath + for len in [0, 1, 15, 16, 1024, 1025, 2048, 2049] + oa = OffsetArray(repeat([1], len), typemax(Int)-len) + @test sum(oa) == reduce(+, oa) == len + @test mapreduce(+, +, oa, oa) == 2len + end +end diff --git a/test/reducedim.jl b/test/reducedim.jl index cc07cfff1dad3..93287efc5eb1c 100644 --- a/test/reducedim.jl +++ b/test/reducedim.jl @@ -492,3 +492,16 @@ end @test @inferred(count(false:true, dims=:, init=0x0004)) === 0x0005 @test @inferred(count(isodd, reshape(1:9, 3, 3), dims=:, init=Int128(0))) === Int128(5) + +@testset "reduced_index for BigInt (issue #39995)" begin + for T in [Int8, Int16, Int32, Int64, Int128, BigInt] + r = T(1):T(2) + ax = axes(r, 1) + axred = Base.reduced_index(ax) + @test axred == Base.OneTo(1) + @test typeof(axred) === typeof(ax) + r_red = reduce(+, r, dims = 1) + @test eltype(r_red) == T + @test r_red == [3] + end +end diff --git a/test/reflection.jl b/test/reflection.jl index 63101796804bb..2e0ad68cf8aa1 100644 --- a/test/reflection.jl +++ b/test/reflection.jl @@ -224,7 +224,7 @@ let ex = :(a + b) end foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N} = nothing @test startswith(string(first(methods(foo13825))), - "foo13825(::Array{T, N}, ::Array, ::Vector{T} where T)") + "foo13825(::Array{T, N}, ::Array, ::Vector) where {T, N} in") mutable struct TLayout x::Int8 @@ -883,6 +883,7 @@ _test_at_locals2(1,1,0.5f0) _dump_function(f31687_parent, Tuple{}, #=native=#false, #=wrapper=#false, #=strip=#false, #=dump_module=#true, #=syntax=#:att, #=optimize=#false, :none, + #=binary=#false, params) end diff --git a/test/regex.jl b/test/regex.jl index 0a28d3464579d..0202dc4758e2f 100644 --- a/test/regex.jl +++ b/test/regex.jl @@ -101,6 +101,17 @@ @test keys(m) == ["a", 2, "b"] end + # Unicode named subpatterns and property mixes of scripts and classes (issues #35322/#35459 and #40231) + let m = match(r"(?\d)[\pZs]*(?<文本>[\p{Han}\p{P}]+)", "1 孔生雪笠,聖裔也。為人蘊藉,工詩。") + @test haskey(m, :numéro) + @test haskey(m, "文本") + @test !haskey(m, "ゑ") + @test (m[:numéro], m[:文本]) == ("1", "孔生雪笠,聖裔也。為人蘊藉,工詩。") + @test (m[1], m[2]) == (m[:numéro], m[:文本]) + @test sprint(show, m) == "RegexMatch(\"1 孔生雪笠,聖裔也。為人蘊藉,工詩。\", numéro=\"1\", 文本=\"孔生雪笠,聖裔也。為人蘊藉,工詩。\")" + @test keys(m) == ["numéro", "文本"] + end + # Backcapture reference in substitution string @test replace("abcde", r"(..)(?Pd)" => s"\gxy\\\1") == "adxy\\bce" @test_throws ErrorException replace("a", r"(?P)" => s"\g") diff --git a/test/runtests.jl b/test/runtests.jl index ad029557a3377..ea94fca877057 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -91,6 +91,16 @@ prepend!(tests, linalg_tests) import LinearAlgebra cd(@__DIR__) do + # `net_on` implies that we have access to the loopback interface which is + # necessary for Distributed multi-processing. There are some test + # environments that do not allow access to loopback, so we must disable + # addprocs when `net_on` is false. Note that there exist build environments, + # including Nix, where `net_on` is false but we still have access to the + # loopback interface. It would be great to make this check more specific to + # identify those situations somehow. See + # * https://github.com/JuliaLang/julia/issues/6722 + # * https://github.com/JuliaLang/julia/pull/29384 + # * https://github.com/JuliaLang/julia/pull/40348 n = 1 if net_on n = min(Sys.CPU_THREADS, length(tests)) @@ -353,7 +363,7 @@ cd(@__DIR__) do elseif isa(resp, Test.TestSetException) fake = Test.DefaultTestSet(testname) for i in 1:resp.pass - Test.record(fake, Test.Pass(:test, nothing, nothing, nothing)) + Test.record(fake, Test.Pass(:test, nothing, nothing, nothing, LineNumberNode(@__LINE__, @__FILE__))) end for i in 1:resp.broken Test.record(fake, Test.Broken(:test, nothing)) diff --git a/test/ryu.jl b/test/ryu.jl index 9970942575e0a..cf60e4867e236 100644 --- a/test/ryu.jl +++ b/test/ryu.jl @@ -544,6 +544,15 @@ end # Float16 @test Ryu.writefixed(7.018232e-82, 6) == "0.000000" end + @testset "Trimming of trailing zeros" begin + @test Ryu.writefixed(0.0, 1, false, false, false, UInt8('.'), true) == "0" + @test Ryu.writefixed(1.0, 1, false, false, false, UInt8('.'), true) == "1" + @test Ryu.writefixed(2.0, 1, false, false, false, UInt8('.'), true) == "2" + + @test Ryu.writefixed(1.25e+5, 0, false, false, false, UInt8('.'), true) == "125000" + @test Ryu.writefixed(1.25e+5, 1, false, false, false, UInt8('.'), true) == "125000" + @test Ryu.writefixed(1.25e+5, 2, false, false, false, UInt8('.'), true) == "125000" + end end # fixed @testset "Ryu.writeexp" begin @@ -736,6 +745,12 @@ end @test Ryu.writeexp(1e+83, 1) == "1.0e+83" end +@testset "Consistency of trimtrailingzeros" begin + @test Ryu.writeexp(0.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "0e+00" + @test Ryu.writeexp(1.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "1e+00" + @test Ryu.writeexp(2.0, 1, false, false, false, UInt8('e'), UInt8('.'), true) == "2e+00" +end + end # exp @testset "compact" begin diff --git a/test/show.jl b/test/show.jl index c2db37493ab05..6990323afd1da 100644 --- a/test/show.jl +++ b/test/show.jl @@ -808,13 +808,20 @@ Base.methodloc_callback[] = nothing # test that no spurious visual lines are added when one element spans multiple lines v = fill!(Array{Any}(undef, 9), 0) v[1] = "look I'm wide! --- " ^ 9 - @test replstr(v) == "9-element Vector{Any}:\n \"look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- \"\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0" - @test replstr([fill(0, 9) v]) == "9×2 Matrix{Any}:\n 0 … \"look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- \"\n 0 0\n 0 0\n 0 0\n 0 0\n 0 … 0\n 0 0\n 0 0\n 0 0" + r = replstr(v) + @test startswith(r, "9-element Vector{Any}:\n \"look I'm wide! ---") + @test endswith(r, "look I'm wide! --- \"\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0") + # test vertical/diagonal ellipsis v = fill!(Array{Any}(undef, 50), 0) v[1] = "look I'm wide! --- " ^ 9 - @test replstr(v) == "50-element Vector{Any}:\n \"look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- \"\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n ⋮\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0" - @test replstr([fill(0, 50) v]) == "50×2 Matrix{Any}:\n 0 … \"look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- look I'm wide! --- \"\n 0 0\n 0 0\n 0 0\n 0 0\n 0 … 0\n 0 0\n 0 0\n 0 0\n 0 0\n ⋮ ⋱ \n 0 0\n 0 0\n 0 0\n 0 0\n 0 … 0\n 0 0\n 0 0\n 0 0\n 0 0" + r = replstr(v) + @test startswith(r, "50-element Vector{Any}:\n \"look I'm wide! ---") + @test endswith(r, "look I'm wide! --- \"\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n ⋮\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0\n 0") + + r = replstr([fill(0, 50) v]) + @test startswith(r, "50×2 Matrix{Any}:\n 0 … \"look I'm wide! ---") + @test endswith(r, "look I'm wide! --- \"\n 0 0\n 0 0\n 0 0\n 0 0\n 0 … 0\n 0 0\n 0 0\n 0 0\n 0 0\n ⋮ ⋱ \n 0 0\n 0 0\n 0 0\n 0 0\n 0 … 0\n 0 0\n 0 0\n 0 0\n 0 0") # issue #34659 @test replstr(Int32[]) == "Int32[]" @@ -825,6 +832,45 @@ Base.methodloc_callback[] = nothing @test replstr([zeros(3,0),zeros(2,0)]) == "2-element Vector{Matrix{Float64}}:\n 3×0 Matrix{Float64}\n 2×0 Matrix{Float64}" end +# string show with elision +@testset "string show with elision" begin + @testset "elision logic" begin + strs = ["A", "∀", "∀A", "A∀", "😃"] + for limit = 0:100, len = 0:100, str in strs + str = str^len + str = str[1:nextind(str, 0, len)] + out = sprint() do io + show(io, MIME"text/plain"(), str; limit) + end + lower = length("\"\" ⋯ $(ncodeunits(str)) bytes ⋯ \"\"") + limit = max(limit, lower) + if length(str) + 2 ≤ limit + @test eval(Meta.parse(out)) == str + else + @test limit-!isascii(str) <= length(out) <= limit + re = r"(\"[^\"]*\") ⋯ (\d+) bytes ⋯ (\"[^\"]*\")" + m = match(re, out) + head = eval(Meta.parse(m.captures[1])) + tail = eval(Meta.parse(m.captures[3])) + skip = parse(Int, m.captures[2]) + @test startswith(str, head) + @test endswith(str, tail) + @test ncodeunits(str) == + ncodeunits(head) + skip + ncodeunits(tail) + end + end + end + + @testset "default elision limit" begin + r = replstr("x"^1000) + @test length(r) == 7*80 + @test r == repr("x"^271) * " ⋯ 459 bytes ⋯ " * repr("x"^270) + r = replstr(["x"^1000]) + @test length(r) < 120 + @test r == "1-element Vector{String}:\n " * repr("x"^31) * " ⋯ 939 bytes ⋯ " * repr("x"^30) + end +end + # Issue 14121 @test_repr "(A'x)'" @@ -1148,7 +1194,7 @@ let x = [], y = [], z = Base.ImmutableDict(x => y) """ dz = sprint(dump, z) @test 10 < countlines(IOBuffer(dz)) < 40 - @test sum(x -> 1, eachmatch(r"circular reference", dz)) == 4 + @test sum(Returns(1), eachmatch(r"circular reference", dz)) == 4 end # PR 16221 @@ -1569,12 +1615,77 @@ end end let x = TypeVar(:_), y = TypeVar(:_) - @test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where {_1, _2}" - @test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1, _1} where _1" + @test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair" + @test repr(UnionAll(y, UnionAll(x, Pair{x,y}))) == "Pair{_2, _1} where {_1, _2}" + @test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref}" + @test repr(UnionAll(y, UnionAll(x, Pair{UnionAll(y,Ref{x}),y}))) == "Pair{Ref{_2}, _1} where {_1, _2}" +end + +let x, y, x x = TypeVar(:a) y = TypeVar(:a) z = TypeVar(:a) @test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) == "Tuple{a1, a2, a} where {a, a1, a2}" + @test repr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{z,y,x})))) == "Tuple{a, a2, a1} where {a, a1, a2}" +end + +let x = TypeVar(:_, Number), y = TypeVar(:_, Number) + @test repr(UnionAll(x, UnionAll(y, Pair{x,y}))) == "Pair{_1, _2} where {_1<:Number, _2<:Number}" + @test repr(UnionAll(y, UnionAll(x, Pair{x,y}))) == "Pair{_2, _1} where {_1<:Number, _2<:Number}" + @test repr(UnionAll(x, UnionAll(y, Pair{UnionAll(x,Ref{x}),y}))) == "Pair{Ref{_1} where _1<:Number, _1} where _1<:Number" + @test repr(UnionAll(y, UnionAll(x, Pair{UnionAll(y,Ref{x}),y}))) == "Pair{Ref{_2}, _1} where {_1<:Number, _2<:Number}" +end + + +is_juliarepr(x) = eval(Meta.parse(repr(x))) == x +@testset "unionall types" begin + X = TypeVar(gensym()) + Y = TypeVar(gensym(), Ref, Ref) + x, y, z = TypeVar(:a), TypeVar(:a), TypeVar(:a) + struct TestTVUpper{A<:Integer} end + + # named typevars + @test is_juliarepr(Ref{A} where A) + @test is_juliarepr(Ref{A} where A>:Ref) + @test is_juliarepr(Ref{A} where A<:Ref) + @test is_juliarepr(Ref{A} where Ref<:A<:Ref) + @test is_juliarepr(TestTVUpper{<:Real}) + @test is_juliarepr(TestTVUpper{<:Integer}) + @test is_juliarepr(TestTVUpper{<:Signed}) + + # typearg order + @test is_juliarepr(UnionAll(X, Pair{X,<:Any})) + @test is_juliarepr(UnionAll(X, Pair{<:Any,X})) + + # duplicates + @test is_juliarepr(UnionAll(X, Pair{X,X})) + + # nesting + @test is_juliarepr(UnionAll(X, Ref{Ref{X}})) + @test is_juliarepr(Union{T, Int} where T) + @test is_juliarepr(Pair{A, <:A} where A) + + # renumbered typevars with same names + @test is_juliarepr(UnionAll(z, UnionAll(x, UnionAll(y, Tuple{x,y,z})))) + + # shortened typevar printing + @test repr(Ref{<:Any}) == "Ref" + @test repr(Pair{1, <:Any}) == "Pair{1}" + @test repr(Ref{<:Number}) == "Ref{<:Number}" + @test repr(Pair{1, <:Number}) == "Pair{1, <:Number}" + @test repr(Ref{<:Ref}) == "Ref{<:Ref}" + @test repr(Ref{>:Ref}) == "Ref{>:Ref}" + @test repr(Pair{<:Any, 1}) == "Pair{<:Any, 1}" + yname = sprint(Base.show_unquoted, Y.name) + @test repr(UnionAll(Y, Ref{Y})) == "Ref{$yname} where Ref<:$yname<:Ref" + @test endswith(repr(TestTVUpper{<:Real}), "TestTVUpper{<:Real}") + @test endswith(repr(TestTVUpper), "TestTVUpper") + @test endswith(repr(TestTVUpper{<:Signed}), "TestTVUpper{<:Signed}") + + # exception for tuples + @test is_juliarepr(Tuple) + @test is_juliarepr(Tuple{}) + @test is_juliarepr(Tuple{<:Any}) end @testset "showarg" begin @@ -1602,6 +1713,11 @@ end @test summary(p) == "2-element reinterpret(reshape, Tuple{Float32, Float32}, ::Matrix{Float32}) with eltype Tuple{Float32, Float32}" @test Base.showarg(io, p, false) === nothing @test String(take!(io)) == "reinterpret(reshape, Tuple{Float32, Float32}, ::Matrix{Float32})" + + r = Base.IdentityUnitRange(2:2) + B = @view ones(2)[r] + Base.showarg(io, B, false) + @test String(take!(io)) == "view(::Vector{Float64}, $(repr(r)))" end @testset "Methods" begin @@ -1659,7 +1775,7 @@ end @test showstr([Float16(1)]) == "Float16[1.0]" @test showstr([[Float16(1)]]) == "Vector{Float16}[[1.0]]" @test replstr(Real[Float16(1)]) == "1-element Vector{Real}:\n Float16(1.0)" - @test replstr(Array{Real}[Real[1]]) == "1-element Vector{Array{Real, N} where N}:\n [1]" + @test replstr(Array{Real}[Real[1]]) == "1-element Vector{Array{Real}}:\n [1]" # printing tuples (Issue #25042) @test replstr(fill((Int64(1), zeros(Float16, 3)), 1)) == "1-element Vector{Tuple{Int64, Vector{Float16}}}:\n (1, [0.0, 0.0, 0.0])" @@ -1708,7 +1824,7 @@ end # issue #28159 @test replstr([(a=1, b=2), (a=3,c=4)]) == "2-element Vector{NamedTuple{names, Tuple{$Int, $Int}} where names}:\n (a = 1, b = 2)\n (a = 3, c = 4)" - @test replstr(Vector[Any[1]]) == "1-element Vector{Vector{T} where T}:\n Any[1]" + @test replstr(Vector[Any[1]]) == "1-element Vector{Vector}:\n Any[1]" @test replstr(AbstractDict{Integer,Integer}[Dict{Integer,Integer}(1=>2)]) == "1-element Vector{AbstractDict{Integer, Integer}}:\n Dict(1 => 2)" @@ -1839,7 +1955,7 @@ h_line() = f_line() @test sprint(Base.show_unquoted, Core.Compiler.Argument(-2)) == "_-2" -eval(Meta.parse("""function my_fun28173(x) +eval(Meta._parse_string("""function my_fun28173(x) y = if x == 1 "HI" elseif x == 2 @@ -1856,7 +1972,7 @@ eval(Meta.parse("""function my_fun28173(x) "three" end return y -end""")) # use parse to control the line numbers +end""", "a"^80, 1, :statement)[1]) # use parse to control the line numbers let src = code_typed(my_fun28173, (Int,), debuginfo=:source)[1][1] ir = Core.Compiler.inflate_ir(src) fill!(src.codelocs, 0) # IRCode printing is only capable of printing partial line info @@ -1866,13 +1982,13 @@ let src = code_typed(my_fun28173, (Int,), debuginfo=:source)[1][1] @test repr(src) == repr_ir end lines1 = split(repr(ir), '\n') - @test isempty(pop!(lines1)) + @test all(isspace, pop!(lines1)) Core.Compiler.insert_node!(ir, 1, Core.Compiler.NewInstruction(QuoteNode(1), Val{1}), false) Core.Compiler.insert_node!(ir, 1, Core.Compiler.NewInstruction(QuoteNode(2), Val{2}), true) Core.Compiler.insert_node!(ir, length(ir.stmts.inst), Core.Compiler.NewInstruction(QuoteNode(3), Val{3}), false) Core.Compiler.insert_node!(ir, length(ir.stmts.inst), Core.Compiler.NewInstruction(QuoteNode(4), Val{4}), true) lines2 = split(repr(ir), '\n') - @test isempty(pop!(lines2)) + @test all(isspace, pop!(lines2)) @test popfirst!(lines2) == "2 1 ── $(QuoteNode(1))" @test popfirst!(lines2) == " │ $(QuoteNode(2))" # TODO: this should print after the next statement let line1 = popfirst!(lines1) @@ -1890,6 +2006,12 @@ let src = code_typed(my_fun28173, (Int,), debuginfo=:source)[1][1] @test pop!(lines2) == " │ \$(QuoteNode(4))" @test pop!(lines2) == "17 │ \$(QuoteNode(3))" # TODO: this should print after the next statement @test lines1 == lines2 + + # verbose linetable + io = IOBuffer() + Base.IRShow.show_ir(io, ir, Base.IRShow.default_config(ir; verbose_linetable=true)) + seekstart(io) + @test count(contains(r"@ a{80}:\d+ within `my_fun28173"), eachline(io)) == 10 end # Verify that extra instructions at the end of the IR @@ -1899,8 +2021,8 @@ let src = code_typed(gcd, (Int, Int), debuginfo=:source)[1][1] ir = Core.Compiler.inflate_ir(src) push!(ir.stmts.inst, Core.Compiler.ReturnNode()) lines = split(sprint(show, ir), '\n') - @test isempty(pop!(lines)) - @test pop!(lines) == " ! ── unreachable::#UNDEF" + @test all(isspace, pop!(lines)) + @test pop!(lines) == " !!! ── unreachable::#UNDEF" end @testset "printing and interpolating nothing" begin @@ -1929,7 +2051,7 @@ end @testset """printing "Any" is not skipped with nested arrays""" begin @test replstr(Union{X28004,Vector}[X28004(Any[X28004(1)])], :compact => true) == - "1-element Vector{Union{X28004, Vector{T} where T}}:\n X(Any[X(1)])" + "1-element Vector{Union{X28004, Vector}}:\n X(Any[X(1)])" end # Issue 25589 - Underlines in cmd printing @@ -2096,15 +2218,17 @@ end @test Base.make_typealias(M37012.AStruct{1}) === nothing @test isempty(Base.make_typealiases(M37012.AStruct{1})[1]) @test string(M37012.AStruct{1}) == "$(curmod_prefix)M37012.AStruct{1}" -@test string(Union{Nothing, Number, Vector}) == "Union{Nothing, Number, Vector{T} where T}" -@test string(Union{Nothing, AbstractVecOrMat}) == "Union{Nothing, AbstractVecOrMat{T} where T}" +@test string(Union{Nothing, Number, Vector}) == "Union{Nothing, Number, Vector}" +@test string(Union{Nothing, Number, Vector{<:Integer}}) == "Union{Nothing, Number, Vector{<:Integer}}" +@test string(Union{Nothing, AbstractVecOrMat}) == "Union{Nothing, AbstractVecOrMat}" +@test string(Union{Nothing, AbstractVecOrMat{<:Integer}}) == "Union{Nothing, AbstractVecOrMat{<:Integer}}" @test string(M37012.BStruct{T, T} where T) == "$(curmod_prefix)M37012.B2{T, T} where T" @test string(M37012.BStruct{T, S} where {T<:Unsigned, S<:Signed}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Unsigned, S<:Signed}" @test string(M37012.BStruct{T, S} where {T<:Signed, S<:T}) == "$(curmod_prefix)M37012.B2{S, T} where {T<:Signed, S<:T}" @test string(Union{M37012.SimpleU, Nothing}) == "Union{Nothing, $(curmod_prefix)M37012.SimpleU}" @test string(Union{M37012.SimpleU, Nothing, T} where T) == "Union{Nothing, $(curmod_prefix)M37012.SimpleU, T} where T" @test string(Union{AbstractVector{T}, T} where T) == "Union{AbstractVector{T}, T} where T" -@test string(Union{AbstractVector, T} where T) == "Union{AbstractVector{T} where T, T} where T" +@test string(Union{AbstractVector, T} where T) == "Union{AbstractVector, T} where T" @test sprint(show, :(./)) == ":((./))" @test sprint(show, :((.|).(.&, b))) == ":((.|).((.&), b))" @@ -2162,3 +2286,14 @@ end s = sprint(show, MIME("text/plain"), Function) @test s == "Function" end + +@testset "printing inline n-dimensional arrays and one-column matrices" begin + @test replstr([Int[1 2 3 ;;; 4 5 6]]) == "1-element Vector{Array{$Int, 3}}:\n [1 2 3;;; 4 5 6]" + @test replstr([Int[1 2 3 ;;; 4 5 6;;;;]]) == "1-element Vector{Array{$Int, 4}}:\n [1 2 3;;; 4 5 6;;;;]" + @test replstr([fill(1, (20,20,20))]) == "1-element Vector{Array{$Int, 3}}:\n [1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1;;; 1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1;;; 1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1;;; … ;;; 1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1;;; 1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1;;; 1 1 … 1 1; 1 1 … 1 1; … ; 1 1 … 1 1; 1 1 … 1 1]" + @test replstr([fill(1, 5, 1)]) == "1-element Vector{Matrix{$Int}}:\n [1; 1; … ; 1; 1;;]" + @test replstr([fill(1, 5, 2)]) == "1-element Vector{Matrix{$Int}}:\n [1 1; 1 1; … ; 1 1; 1 1]" + @test replstr([[1;]]) == "1-element Vector{Vector{$Int}}:\n [1]" + @test replstr([[1;;]]) == "1-element Vector{Matrix{$Int}}:\n [1;;]" + @test replstr([[1;;;]]) == "1-element Vector{Array{$Int, 3}}:\n [1;;;]" +end diff --git a/test/simdloop.jl b/test/simdloop.jl index 1920cfa6140b1..88e41364ef222 100644 --- a/test/simdloop.jl +++ b/test/simdloop.jl @@ -92,19 +92,6 @@ import Base.SimdLoop.SimdError # Test that @simd rejects inner loop body with invalid control flow statements # issue #8613 -macro test_throws(ty, ex) - return quote - Test.@test_throws $(esc(ty)) try - $(esc(ex)) - catch err - @test err isa LoadError - @test err.file === $(string(__source__.file)) - @test err.line === $(__source__.line + 1) - rethrow(err.error) - end - end -end - @test_throws SimdError("break is not allowed inside a @simd loop body") @macroexpand begin @simd for x = 1:10 x == 1 && break diff --git a/test/some.jl b/test/some.jl index 224eb8600814c..b2111c8b86085 100644 --- a/test/some.jl +++ b/test/some.jl @@ -79,6 +79,16 @@ @test something(missing, nothing, missing) === missing end +@testset "@something" begin + @test_throws ArgumentError @something() + @test_throws ArgumentError @something(nothing) + @test @something(1) === 1 + @test @something(Some(nothing)) === nothing + + @test @something(1, error("failed")) === 1 + @test_throws ErrorException @something(nothing, error("failed")) +end + # issue #26927 a = [missing, nothing, Some(nothing), Some(missing)] @test a isa Vector{Union{Missing, Nothing, Some}} diff --git a/test/sorting.jl b/test/sorting.jl index 6bf7d60bd859d..718a7f819e203 100644 --- a/test/sorting.jl +++ b/test/sorting.jl @@ -105,7 +105,7 @@ end @test searchsorted(fill(R(1), 15), T(1), 6, 10, Forward) == 6:10 end - for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] + for (rg,I) in Any[(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] rg_r = reverse(rg) rgv, rgv_r = [rg;], [rg_r;] for i = I @@ -144,7 +144,7 @@ end @testset "issue 32568" begin for R in numTypes, T in numTypes - for arr in [R[1:5;], R(1):R(5), R(1):2:R(5)] + for arr in Any[R[1:5;], R(1):R(5), R(1):2:R(5)] @test eltype(searchsorted(arr, T(2))) == keytype(arr) @test eltype(searchsorted(arr, T(2), big(1), big(4), Forward)) == keytype(arr) @test searchsortedfirst(arr, T(2)) isa keytype(arr) @@ -164,35 +164,46 @@ end @test searchsorted([1,2], Inf) === 3:2 @test searchsorted(1:2, Inf) === 3:2 - for coll in [ + for coll in Any[ Base.OneTo(10), 1:2, + 0x01:0x02, -4:6, 5:2:10, [1,2], 1.0:4, [10.0,20.0], ] - for huge in [Inf, 1e300] + for huge in Any[Inf, 1e300, typemax(Int64), typemax(UInt64)] @test searchsortedfirst(coll, huge) === lastindex(coll) + 1 - @test searchsortedfirst(coll, -huge)=== firstindex(coll) @test searchsortedlast(coll, huge) === lastindex(coll) - @test searchsortedlast(coll, -huge) === firstindex(coll) - 1 @test searchsorted(coll, huge) === lastindex(coll)+1 : lastindex(coll) - @test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1 - - @test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll) - @test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1 - @test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1 - @test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll) - @test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1 - @test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll) + if !(eltype(coll) <: Unsigned) + @test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll) + @test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1 + @test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1 + end + + if !(huge isa Unsigned) + @test searchsortedfirst(coll, -huge)=== firstindex(coll) + @test searchsortedlast(coll, -huge) === firstindex(coll) - 1 + @test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1 + if !(eltype(coll) <: Unsigned) + @test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1 + @test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll) + @test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll) + end + end end end - @testset "issue ##34408" begin + + @test_broken length(reverse(0x1:0x2)) == 2 + @testset "issue #34408" begin r = 1f8-10:1f8 # collect(r) = Float32[9.999999e7, 9.999999e7, 9.999999e7, 9.999999e7, 1.0e8, 1.0e8, 1.0e8, 1.0e8, 1.0e8] - @test_broken searchsorted(collect(r)) == searchsorted(r) + for i in r + @test_broken searchsorted(collect(r), i) == searchsorted(r, i) + end end end @testset "issue #35272" begin @@ -329,7 +340,7 @@ end @test insorted(T(10), R.(collect(1:10)), by=(>=(5))) end - for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] + for (rg,I) in Any[(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)] rg_r = reverse(rg) rgv, rgv_r = collect(rg), collect(rg_r) for i = I diff --git a/test/spawn.jl b/test/spawn.jl index dcc1bae234118..fe6912faf0447 100644 --- a/test/spawn.jl +++ b/test/spawn.jl @@ -55,8 +55,8 @@ out = read(`$echocmd hello` & `$echocmd world`, String) @test (run(`$printfcmd " \033[34m[stdio passthrough ok]\033[0m\n"`); true) -# Test for SIGPIPE being treated as normal termination (throws an error if broken) -Sys.isunix() && run(pipeline(yescmd, `head`, devnull)) +# Test for SIGPIPE being a failure condition +@test_throws ProcessFailedException run(pipeline(yescmd, `head`, devnull)) let p = run(pipeline(yescmd, devnull), wait=false) t = @async kill(p) @@ -261,6 +261,74 @@ end end end +@testset "redirect_stdio" begin + + function hello_err_out() + println(stderr, "hello from stderr") + println(stdout, "hello from stdout") + end + @testset "same path for multiple streams" begin + @test_throws ArgumentError redirect_stdio(hello_err_out, + stdin="samepath.txt", stdout="samepath.txt") + @test_throws ArgumentError redirect_stdio(hello_err_out, + stdin="samepath.txt", stderr="samepath.txt") + + @test_throws ArgumentError redirect_stdio(hello_err_out, + stdin=joinpath("tricky", "..", "samepath.txt"), + stderr="samepath.txt") + mktempdir() do dir + path = joinpath(dir, "stdouterr.txt") + redirect_stdio(hello_err_out, stdout=path, stderr=path) + @test read(path, String) == """ + hello from stderr + hello from stdout + """ + end + end + + mktempdir() do dir + path_stdout = joinpath(dir, "stdout.txt") + path_stderr = joinpath(dir, "stderr.txt") + redirect_stdio(hello_err_out, stderr=devnull, stdout=path_stdout) + @test read(path_stdout, String) == "hello from stdout\n" + + open(path_stderr, "w") do ioerr + redirect_stdio(hello_err_out, stderr=ioerr, stdout=devnull) + end + @test read(path_stderr, String) == "hello from stderr\n" + end + + mktempdir() do dir + path_stderr = joinpath(dir, "stderr.txt") + path_stdin = joinpath(dir, "stdin.txt") + path_stdout = joinpath(dir, "stdout.txt") + + content_stderr = randstring() + content_stdout = randstring() + + redirect_stdio(stdout=path_stdout, stderr=path_stderr) do + print(content_stdout) + print(stderr, content_stderr) + end + + @test read(path_stderr, String) == content_stderr + @test read(path_stdout, String) == content_stdout + end + + # stdin is unavailable on the workers. Run test on master. + ret = Core.eval(Main, + quote + remotecall_fetch(1) do + mktempdir() do dir + path = joinpath(dir, "stdin.txt") + write(path, "hello from stdin\n") + redirect_stdio(readline, stdin=path) + end + end + end) + @test ret == "hello from stdin" +end + # issue #36136 @testset "redirect to devnull" begin @test redirect_stdout(devnull) do; println("Hello") end === nothing @@ -582,8 +650,8 @@ end psep = if Sys.iswindows() ";" else ":" end withenv("PATH" => "$(Sys.BINDIR)$(psep)$(ENV["PATH"])") do julia_exe = joinpath(Sys.BINDIR, Base.julia_exename()) - @test Sys.which("julia") == realpath(julia_exe) - @test Sys.which(julia_exe) == realpath(julia_exe) + @test Sys.which("julia") == abspath(julia_exe) + @test Sys.which(julia_exe) == abspath(julia_exe) end # Check that which behaves correctly when passed an empty string @@ -598,8 +666,8 @@ mktempdir() do dir touch(foo_path) chmod(foo_path, 0o777) if !Sys.iswindows() - @test Sys.which("foo") == realpath(foo_path) - @test Sys.which(foo_path) == realpath(foo_path) + @test Sys.which("foo") == abspath(foo_path) + @test Sys.which(foo_path) == abspath(foo_path) chmod(foo_path, 0o666) @test Sys.which("foo") === nothing @@ -636,20 +704,20 @@ mktempdir() do dir touch(foo2_path) chmod(foo1_path, 0o777) chmod(foo2_path, 0o777) - @test Sys.which("foo") == realpath(foo1_path) + @test Sys.which("foo") == abspath(foo1_path) # chmod() doesn't change which() on Windows, so don't bother to test that if !Sys.iswindows() chmod(foo1_path, 0o666) - @test Sys.which("foo") == realpath(foo2_path) + @test Sys.which("foo") == abspath(foo2_path) chmod(foo1_path, 0o777) end if Sys.iswindows() # On windows, check that pwd() takes precedence, except when we provide a path cd(joinpath(dir, "bin2")) do - @test Sys.which("foo") == realpath(foo2_path) - @test Sys.which(foo1_path) == realpath(foo1_path) + @test Sys.which("foo") == abspath(foo2_path) + @test Sys.which(foo1_path) == abspath(foo1_path) end end @@ -662,7 +730,9 @@ mktempdir() do dir touch(bar_path) chmod(bar_path, 0o777) cd(dir) do - @test Sys.which(joinpath("bin1", "bar")) == realpath(bar_path) + p = Sys.which(joinpath("bin1", "bar")) + @test p == abspath("bin1", basename(bar_path)) + @test Base.samefile(p, bar_path) end end end diff --git a/test/strings/util.jl b/test/strings/util.jl index 617ff31106634..e8ea3b643fcda 100644 --- a/test/strings/util.jl +++ b/test/strings/util.jl @@ -275,6 +275,11 @@ end # Issue 13332 @test replace("abc", 'b' => 2.1) == "a2.1c" + # Issue 31456 + @test replace("The fox.", r"fox(es)?" => s"bus\1") == "The bus." + @test replace("The foxes.", r"fox(es)?" => s"bus\1") == "The buses." + @test replace("The quick fox quickly.", r"(quick)?\sfox(es)?\s(run)?" => s"\1 bus\2 \3") == "The quick bus quickly." + # test replace with a count for String and GenericString # check that replace is a no-op if count==0 for s in ["aaa", Test.GenericString("aaa")] @@ -376,6 +381,11 @@ end #non-hex characters @test_throws ArgumentError hex2bytes(b"0123456789abcdefABCDEFGH") end + + @testset "Issue 39284" begin + @test "efcdabefcdab8967452301" == bytes2hex(Iterators.reverse(hex2bytes("0123456789abcdefABCDEF"))) + @test hex2bytes(Iterators.reverse(b"CE1A85EECc")) == UInt8[0xcc, 0xee, 0x58, 0xa1, 0xec] + end end # b"" should be immutable diff --git a/test/subarray.jl b/test/subarray.jl index 76f00ab7948cb..334211d3e3975 100644 --- a/test/subarray.jl +++ b/test/subarray.jl @@ -134,8 +134,8 @@ end function test_bounds(@nospecialize(A)) @test_throws BoundsError A[0] @test_throws BoundsError A[end+1] - trailing2 = ntuple(x->1, max(ndims(A)-2, 0)) - trailing3 = ntuple(x->1, max(ndims(A)-3, 0)) + trailing2 = ntuple(Returns(1), max(ndims(A)-2, 0)) + trailing3 = ntuple(Returns(1), max(ndims(A)-3, 0)) @test_throws BoundsError A[1, 0, trailing2...] @test_throws BoundsError A[1, end+1, trailing2...] @test_throws BoundsError A[1, 1, 0, trailing3...] @@ -214,10 +214,10 @@ end function runviews(SB::AbstractArray, indexN, indexNN, indexNNN) @assert ndims(SB) > 2 for i3 in indexN, i2 in indexN, i1 in indexN - runsubarraytests(SB, i1, i2, i3, ntuple(x->1, max(ndims(SB)-3, 0))...) + runsubarraytests(SB, i1, i2, i3, ntuple(Returns(1), max(ndims(SB)-3, 0))...) end for i2 in indexN, i1 in indexN - runsubarraytests(SB, i1, i2, ntuple(x->1, max(ndims(SB)-2, 0))...) + runsubarraytests(SB, i1, i2, ntuple(Returns(1), max(ndims(SB)-2, 0))...) end for i1 in indexNNN runsubarraytests(SB, i1) diff --git a/test/subtype.jl b/test/subtype.jl index 3c720dc4bf032..244ce3c4b7900 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -140,7 +140,7 @@ function test_diagonal() @test !issub(Type{Tuple{T,Any} where T}, Type{Tuple{T,T}} where T) @test !issub(Type{Tuple{T,Any,T} where T}, Type{Tuple{T,T,T}} where T) @test_broken issub(Type{Tuple{T} where T}, Type{Tuple{T}} where T) - @test_broken issub(Ref{Tuple{T} where T}, Ref{Tuple{T}} where T) + @test issub(Ref{Tuple{T} where T}, Ref{Tuple{T}} where T) @test !issub(Type{Tuple{T,T} where T}, Type{Tuple{T,T}} where T) @test !issub(Type{Tuple{T,T,T} where T}, Type{Tuple{T,T,T}} where T) @test isequal_type(Ref{Tuple{T, T} where Int<:T<:Int}, @@ -1901,3 +1901,16 @@ let A = Tuple{Array{Pair{T, JT} where JT<:Ref{T}, 1} where T, Vector}, @test_broken I <: A @test_broken !Base.has_free_typevars(I) end + +# issue #8915 +struct D8915{T<:Union{Float32,Float64}} + D8915{T}(a) where {T} = 1 + D8915{T}(a::Int) where {T} = 2 +end +@test D8915{Float64}(1) == 2 +@test D8915{Float64}(1.0) == 1 + +# issue #18985 +f18985(x::T, y...) where {T<:Union{Int32,Int64}} = (length(y), f18985(y[1], y[2:end]...)...) +f18985(x::T) where {T<:Union{Int32,Int64}} = 100 +@test f18985(1, 2, 3) == (2, 1, 100) diff --git a/test/syntax.jl b/test/syntax.jl index d97f5aeb251c8..5a3af3b1863cb 100644 --- a/test/syntax.jl +++ b/test/syntax.jl @@ -618,15 +618,12 @@ end @test A15838.@f() === nothing @test A15838.@f(1) === :b let ex = :(A15838.@f(1, 2)), __source__ = LineNumberNode(@__LINE__, Symbol(@__FILE__)) - nometh = try + e = try macroexpand(@__MODULE__, ex) false catch ex ex - end::LoadError - @test nometh.file === string(__source__.file) - @test nometh.line === __source__.line - e = nometh.error::MethodError + end::MethodError @test e.f === getfield(A15838, Symbol("@f")) @test e.args === (__source__, @__MODULE__, 1, 2) end @@ -822,7 +819,7 @@ let f = function (x; kw...) end # normalization of Unicode symbols (#19464) -let ε=1, μ=2, x=3, î=4 +let ε=1, μ=2, x=3, î=4, ⋅=5, (-)=6 # issue #5434 (mu vs micro): @test Meta.parse("\u00b5") === Meta.parse("\u03bc") @test µ == μ == 2 @@ -832,6 +829,20 @@ let ε=1, μ=2, x=3, î=4 # latin vs greek ε (#14751) @test Meta.parse("\u025B") === Meta.parse("\u03B5") @test ɛ == ε == 1 + # middot char · or · vs math dot operator ⋅ (#25098) + @test Meta.parse("\u00b7") === Meta.parse("\u0387") === Meta.parse("\u22c5") + @test (·) == (·) == (⋅) == 5 + # minus − vs hyphen-minus - (#26193) + @test Meta.parse("\u2212") === Meta.parse("-") + @test Meta.parse("\u221242") === Meta.parse("-42") + @test Meta.parse("\u2212 42") == Meta.parse("- 42") + @test Meta.parse("\u2212x") == Meta.parse("-x") + @test Meta.parse("x \u2212 42") == Meta.parse("x - 42") + @test Meta.parse("x \u2212= 42") == Meta.parse("x -= 42") + @test Meta.parse("100.0e\u22122") === Meta.parse("100.0E\u22122") === Meta.parse("100.0e-2") + @test Meta.parse("100.0f\u22122") === Meta.parse("100.0f-2") + @test Meta.parse("0x100p\u22128") === Meta.parse("0x100P\u22128") === Meta.parse("0x100p-8") + @test (−) == (-) == 6 end # issue #8925 @@ -1357,7 +1368,6 @@ end @test Meta.parse("√3x^2") == Expr(:call, :*, Expr(:call, :√, 3), Expr(:call, :^, :x, 2)) @test Meta.parse("-3x^2") == Expr(:call, :*, -3, Expr(:call, :^, :x, 2)) @test_throws ParseError Meta.parse("2!3") -@test_throws ParseError Meta.parse("2√3") # issue #27914 @test Meta.parse("2f(x)") == Expr(:call, :*, 2, Expr(:call, :f, :x)) @@ -1864,7 +1874,7 @@ end @test_throws UndefVarError eval(:(1+$(Symbol("")))) # issue #31404 -f31404(a, b; kws...) = (a, b, kws.data) +f31404(a, b; kws...) = (a, b, values(kws)) @test f31404(+, (Type{T} where T,); optimize=false) === (+, (Type,), (optimize=false,)) # issue #28992 @@ -2158,6 +2168,12 @@ end @test Meta.parse("a ⟂ b ⟂ c") == Expr(:comparison, :a, :⟂, :b, :⟂, :c) @test Meta.parse("a ⟂ b ∥ c") == Expr(:comparison, :a, :⟂, :b, :∥, :c) +# issue 39350 +@testset "binary ⫪ and ⫫" begin + @test Meta.parse("a ⫪ b") == Expr(:call, :⫪, :a, :b) + @test Meta.parse("a ⫫ b") == Expr(:call, :⫫, :a, :b) +end + # only allow certain characters after interpolated vars (#25231) @test Meta.parse("\"\$x෴ \"",raise=false) == Expr(:error, "interpolated variable \$x ends with invalid character \"෴\"; use \"\$(x)\" instead.") @test Base.incomplete_tag(Meta.parse("\"\$foo", raise=false)) == :string @@ -2694,6 +2710,27 @@ end @test Meta.isexpr(Meta.@lower(f((; a, b::Int)) = a + b), :error) end +# #33697 +@testset "N-dimensional concatenation" begin + @test :([1 2 5; 3 4 6;;; 0 9 3; 4 5 4]) == + Expr(:ncat, 3, Expr(:nrow, 1, Expr(:row, 1, 2, 5), Expr(:row, 3, 4, 6)), + Expr(:nrow, 1, Expr(:row, 0, 9, 3), Expr(:row, 4, 5, 4))) + @test :([1 ; 2 ;; 3 ; 4]) == Expr(:ncat, 2, Expr(:nrow, 1, 1, 2), Expr(:nrow, 1, 3, 4)) + + @test_throws ParseError Meta.parse("[1 2 ;; 3 4]") # cannot mix spaces and ;; except as line break + @test :([1 2 ;; + 3 4]) == :([1 2 3 4]) + @test :([1 2 ;; + 3 4 ; 2 3 4 5]) == :([1 2 3 4 ; 2 3 4 5]) + + @test Meta.parse("[1;\n]") == :([1;]) # ensure line breaks following semicolons are treated correctly + @test Meta.parse("[1;\n\n]") == :([1;]) + @test Meta.parse("[1\n;]") == :([1;]) # semicolons following a linebreak are fine + @test Meta.parse("[1\n;;; 2]") == :([1;;; 2]) + @test_throws ParseError Meta.parse("[1;\n;2]") # semicolons cannot straddle a line break + @test_throws ParseError Meta.parse("[1; ;2]") # semicolons cannot be separated by a space +end + # issue #25652 x25652 = 1 x25652_2 = let (x25652, _) = (x25652, nothing) @@ -2751,3 +2788,45 @@ end @test eval(:(x = $(QuoteNode(Core.SlotNumber(1))))) == Core.SlotNumber(1) @test_throws ErrorException("syntax: SSAValue objects should not occur in an AST") eval(:(x = $(Core.SSAValue(1)))) @test_throws ErrorException("syntax: Slot objects should not occur in an AST") eval(:(x = $(Core.SlotNumber(1)))) + +# juxtaposition of radical symbols (#40094) +@test Meta.parse("2√3") == Expr(:call, :*, 2, Expr(:call, :√, 3)) +@test Meta.parse("2∛3") == Expr(:call, :*, 2, Expr(:call, :∛, 3)) +@test Meta.parse("2∜3") == Expr(:call, :*, 2, Expr(:call, :∜, 3)) + +macro m_underscore_hygiene() + return :(_ = 1) +end + +@test @macroexpand(@m_underscore_hygiene()) == :(_ = 1) + +macro m_begin_hygiene(a) + return :($(esc(a))[begin]) +end + +@test @m_begin_hygiene([1, 2, 3]) == 1 + +# issue 40258 +@test "a $("b $("c")")" == "a b c" + +@test "$(([[:a, :b], [:c, :d]]...)...)" == "abcd" + +@test eval(Expr(:string, "a", Expr(:string, "b", "c"))) == "abc" +@test eval(Expr(:string, "a", Expr(:string, "b", Expr(:string, "c")))) == "abc" + +macro m_nospecialize_unnamed_hygiene() + return :(f(@nospecialize(::Any)) = Any) +end + +@test @m_nospecialize_unnamed_hygiene()(1) === Any + +# https://github.com/JuliaLang/julia/issues/40574 +@testset "no mutation while destructuring" begin + x = [1, 2] + x[2], x[1] = x + @test x == [2, 1] + + x = [1, 2, 3] + x[3], x[1:2]... = x + @test x == [2, 3, 1] +end diff --git a/test/testhelpers/Furlongs.jl b/test/testhelpers/Furlongs.jl index 8abe583925d93..73d23a39d2d7b 100644 --- a/test/testhelpers/Furlongs.jl +++ b/test/testhelpers/Furlongs.jl @@ -36,6 +36,7 @@ Base.floatmin(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floa Base.floatmin(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmin(Furlong{p,T}) Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floatmax(T)) Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T}) +Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val)) # convert Furlong exponent p to a canonical form. This # is not type stable, but it doesn't matter since it is used diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 87b3edc7c8025..860f0e03e2f5e 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -738,8 +738,7 @@ end try @macroexpand @threads(for i = 1:10, j = 1:10; end) catch ex - @test ex isa LoadError - @test ex.error isa ArgumentError + @test ex isa ArgumentError end @testset "@spawn interpolation" begin diff --git a/test/tuple.jl b/test/tuple.jl index 80a4323f6d2f2..7c274851ea555 100644 --- a/test/tuple.jl +++ b/test/tuple.jl @@ -278,7 +278,7 @@ end @testset "filter" begin @test filter(isodd, (1,2,3)) == (1, 3) @test filter(isequal(2), (true, 2.0, 3)) === (2.0,) - @test filter(i -> true, ()) == () + @test filter(Returns(true), ()) == () @test filter(identity, (true,)) === (true,) longtuple = ntuple(identity, 20) @test filter(iseven, longtuple) == ntuple(i->2i, 10) diff --git a/test/worlds.jl b/test/worlds.jl index 692f4febd91cd..2b4f575e1905a 100644 --- a/test/worlds.jl +++ b/test/worlds.jl @@ -219,8 +219,8 @@ function instance(f, types) if isa(specs, Nothing) elseif isa(specs, Core.SimpleVector) for i = 1:length(specs) - if isassigned(specs, i) - mi = specs[i]::Core.MethodInstance + mi = specs[i] + if mi isa Core.MethodInstance if mi.specTypes <: tt && tt <: mi.specTypes inst = mi break